// Expression // // The Copyright for this file is shared equally by the // Contributors listed below // // Contributors: Alan Hadley // // You may use, modify and distribute this file as you see // fit, so long as this notice remains intact, you // may add your name to the contributors if you wish if you // distribute modified versions of the file // // The Copyright holder(s) do not guarantee that the software // is fit for any purpose, nor will they accept responsibility // for any consequences of its use. #include "expclass.h" #include "qdebug.h" Exp::Exp(bool (*unknown)(Exp *,int), bool(*sym)(Exp *E,int,int,bool)) { Unknown=unknown; Sym=sym; MyRoot=NewN(Start,0,999999,LRoot,1,0.0,0,0,"Start",Rootfix); AddN(MyRoot); AN.clear(); Symbols.reserve(1024); unknown_key=987654321; } Exp::~Exp() { } int Exp::NewExp(QString e) { int n; ERROR=""; tokens.clear(); an=MyRoot; AN.clear(); AN.append(an); last_added=an; POS.clear(); POS.append(0); pos=0; YourRoot=MyRoot; if(e.isEmpty()) { ERROR="Nothing to do"; goto Quit; } hasnumbers=false; hasbrackets=false; hasquotes=false; Tokenize(e); YourRoot=MyRoot; FindMultiOps(); if(hasquotes) { FindQuotes(); // also remove spaces if(ERROR!="") goto Quit; } if(hasbrackets) { CheckBrackets(); if(ERROR!="") goto Quit; } if(hasnumbers) { FindNumbers(); if(ERROR!="") goto Quit; } IsMinus=false; close_bracket=0; YourRoot=BuildTree(); if(ERROR!="") goto Quit; Simplify(YourRoot); if(ERROR!="") goto Quit; return YourRoot; Quit: if(YourRoot!=MyRoot && N[YourRoot].parent!=-1) Free(YourRoot); while(AN.last()!=MyRoot) AN.takeLast(); an=MyRoot; ERROR.replace("\"+\"","\"+/-\""); n=NewN(Error,0,0,LLeaf,1,__LINE__,0,0,ERROR,Nofix); AddN(n); return n; } bool Exp::ReplaceExp(int node,QString e) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In ReplaceExp"; return false;; } #endif int n; int TempRoot=YourRoot; YourRoot=MyRoot; ERROR=""; tokens.clear(); an=MyRoot; AN.clear(); AN.append(an); last_added=an; POS.clear(); POS.append(0); pos=0; if(e.isEmpty()) { ERROR="Nothing to do"; goto Quit; } hasnumbers=false; hasbrackets=false; hasquotes=false; Tokenize(e); FindMultiOps(); if(hasquotes) { FindQuotes(); // also remove spaces if(ERROR!="") goto Quit; } if(hasbrackets) { CheckBrackets(); if(ERROR!="") goto Quit; } if(hasnumbers) { FindNumbers(); if(ERROR!="") goto Quit; } IsMinus=false; close_bracket=0; YourRoot=BuildTree(); if(ERROR!="") goto Quit; Over(node,YourRoot); while(simplifyN(node) && ERROR==""); YourRoot=TempRoot; return true; Quit: Free(YourRoot); YourRoot=TempRoot; while(AN.last()!=MyRoot) AN.takeLast(); an=MyRoot; ERROR.replace("\"+\"","\"+/-\""); n=NewN(Error,0,0,LLeaf,1,__LINE__,0,0,ERROR,Nofix); AddN(n); return false; } // sort + and * void Exp::Sort(int node) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In Sort"; return; } #endif int nc=N[node].links.count(); int i,t=N[node].type; if(N[node].level==LLeaf) return; if(nc>1 && N[node].max==MAX_LINKS && t!=Comma && t!=Semi) SortLinks(node); if(nc>0) for(i=0; i=RSBracket) Sort(N[node].links[i]); } return; } bool Exp::Free(int node) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In Free"; return false; } #endif int p=N[node].parent; N[p].links.removeOne(node); return free(node); } bool Exp::free(int node) { // Free decendants first int nl=N[node].links.count(),c; if(nl) { for(int i=0; i0) for(i=0; i0) for(i=0; i &syms) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In ListSyms"; return; } #endif // only add sym to list once if(N[node].type==Symbol) { int key=Symbols.value(N[node].text); if(!syms.contains(key)) syms.append(key); return; } // check decendants int nc=N[node].links.count(),i; if(nc) for(i=0; i=N[node].max) ERROR="Invalid Link In GetLink"; } if(!VALID_LINK(node,pos)) { ERROR="Invalid Link In TakeLink"; return -1; } #endif int nc=N[node].links.count(); if(pos<0 || pos>=nc) return FREE; int n=N[node].links.takeAt(pos); return n; } void Exp::Adopt(int parent,int child) { #ifdef QT_DEBUG if(!VALID_NODE(child) || !VALID_NODE(parent)) { ERROR="Invalid Node In Adopt"; return; if(child<0 || child>=N[parent].max) ERROR="Invalid Link In GetLink"; } #endif int p=N[child].parent; N[p].links.removeOne(child); N[parent].links.append(child); N[child].parent=parent; N[child].root=N[parent].root; UpdateNodes(parent); } int Exp::AdoptNumber(int parent,double value) { int child=NewN(Number,0,0,LLeaf,1,value,0,0,"Number",Nofix); SimplyNumber(child); Adopt(parent,child); return child; } int Exp::AdoptFrac(int parent,int Int,int a,int b) { int child=NewN(Frac,0,0,LLeaf,1,(double)Int,a,b,"(`)",Nofix); SimplyFrac(child); Adopt(parent,child); return child; } int Exp::AdoptSym(int parent,QString name,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(Symbol,0,0,LLeaf,s,0.0,0,0,name,Nofix); SimplySym(child); Adopt(parent,child); return child; } int Exp::AdoptPlaceHolder(int parent) { int child=NewN(PlaceHolder,0,0,LLeaf,1,1.0,0,0,"...",Nofix); Adopt(parent,child); return child; } int Exp::AdoptPlus(int parent) { int child=NewN(Plus,2,MAX_LINKS,LPlus,1,1.0,0,0,"+",Infix); Adopt(parent,child); return child; } int Exp::AdoptTimes(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(Times,2,MAX_LINKS,LTimes,s,1.0,0,0,"*",Infix); Adopt(parent,child); return child; } int Exp::AdoptDevide(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(Devide,2,2,LDevide,s,1.0,0,0,"/",Infix); Adopt(parent,child); return child; } int Exp::AdoptPower(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(Power,2,2,LPower,s,1.0,0,0,"^",Infix); Adopt(parent,child); return child; } int Exp::AdoptComma(int parent) { int child=NewN(Comma,2,MAX_LINKS,LComma,1,1.0,0,0,",",Infix); Adopt(parent,child); return child; } int Exp::AdoptSemi(int parent) { int child=NewN(Semi,2,MAX_LINKS,LSemi,1,1.0,0,0,";",Infix); Adopt(parent,child); return child; } int Exp::AdoptPrefix(int parent,NodeType t,int sign) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return FREE; } int s=1; if(sign<0) s=-1; int child=NewN(t,1,1,LPrefix,s,1.0,0,0,text,Prefix); Adopt(parent,child); return child; } int Exp::AdoptPostfix(int parent,NodeType t) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return FREE; } int child=NewN(t,1,1,LPostfix,1,1.0,0,0,text,Postfix); Adopt(parent,child); return child; } int Exp::AdoptEqual(int parent,NodeType t) { QString text; switch(t) { case Equal: text="="; break; case Less: text="<"; break; case More: text=">"; break; case Colon: text=":"; break; default: return FREE; } int child=NewN(t,2,MAX_LINKS,LEqual,1,1.0,0,0,text,Infix); Adopt(parent,child); return child; } int Exp::AdoptRBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(RBracket,1,1,LBracket,s,1.0,0,0,"()",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptRCBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,"(){}",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptRSBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,"()[]",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(CBracket,1,1,LBracket,s,1.0,0,0,"{}",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCRBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,"{}()",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCRCBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,"{}()",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCSBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,"{}[]",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(SBracket,1,1,LBracket,s,1.0,0,0,"[]",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSRBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,"[]()",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSCBracket(int parent,int sign) { int s=1; if(sign<0) s=-1; int child=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,"[]{}",Groupfix); Adopt(parent,child); return child; } int Exp::AdoptRFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(RBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptRCFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptRSFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(CBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCRFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCRCFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptCSFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(SBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSRFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } int Exp::AdoptSCFun(int parent,int sign,QString name) { int s=1; if(sign<0) s=-1; int child=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Adopt(parent,child); return child; } void Exp::Over(int dest,int src) { #ifdef QT_DEBUG if(!VALID_NODE(dest) || !VALID_NODE(src)) { ERROR="Invalid Node In Over"; return; } #endif int p=N[src].parent; N[p].links.removeOne(src); int root=N[dest].root; int parent=N[dest].parent; QList links=N[src].links; N[src].links.clear(); UsedNs.removeOne(dest); FreeNs.append(dest); // to become copy of src Copy(src); // src_copy=dest N[dest].links=links; N[dest].root=root; N[dest].parent=parent; N[src].parent=-1; UsedNs.removeOne(src); FreeNs.append(src); UpdateNodes(dest); } void Exp::ToNumber(int dest,double value) { int src=NewN(Number,0,0,LLeaf,1,value,0,0,"Number",Nofix); SimplyNumber(src); Over(dest,src); } void Exp::ToFrac(int dest,int Int,int a,int b) { int src=NewN(Frac,0,0,LLeaf,1,(double)Int,a,b,"(`)",Nofix); SimplyFrac(src); Over(dest,src); } void Exp::ToSymbol(int dest,QString name) { int src=NewN(Symbol,0,0,LLeaf,1,0.0,0,0,name,Nofix); SimplySym(src); Over(dest,src); } void Exp::ToPlaceHolder(int dest) { int src=NewN(PlaceHolder,0,0,LLeaf,1,1.0,0,0,"...",Nofix); Over(dest,src); } void Exp::ToPlus(int dest) { int src=NewN(Plus,2,MAX_LINKS,LPlus,1,1.0,0,0,"+",Infix); Over(dest,src); } void Exp::ToTimes(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(Times,2,MAX_LINKS,LTimes,s,1.0,0,0,"*",Infix); Over(dest,src); } void Exp::ToDevide(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(Devide,2,2,LDevide,s,1.0,0,0,"/",Infix); Over(dest,src); } void Exp::ToPower(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(Power,2,2,LPower,s,1.0,0,0,"^",Infix); Over(dest,src); } void Exp::ToComma(int dest) { int src=NewN(Comma,2,MAX_LINKS,LComma,1,1.0,0,0,",",Infix); Over(dest,src); } void Exp::ToSemi(int dest) { int src=NewN(Semi,2,MAX_LINKS,LSemi,1,1.0,0,0,";",Infix); Over(dest,src); } void Exp::ToPrefix(int dest,NodeType t,int sign) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return; } int s=1; if(sign<0) s=-1; int src=NewN(t,1,1,LPrefix,s,1.0,0,0,text,Prefix); Over(dest,src); } void Exp::ToPostfix(int dest,NodeType t) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return; } int src=NewN(t,1,1,LPostfix,1,1.0,0,0,text,Postfix); Over(dest,src); } void Exp::ToEqual(int dest,NodeType t) { QString text; switch(t) { case Equal: text="="; break; case Less: text="<"; break; case More: text=">"; break; case Colon: text=":"; break; default: return; } int src=NewN(t,2,MAX_LINKS,LEqual,1,1.0,0,0,text,Infix); Over(dest,src); } void Exp::ToRBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(RBracket,1,1,LBracket,s,1.0,0,0,"()",Groupfix); Over(dest,src); } void Exp::ToRCBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,"(){}",Groupfix); Over(dest,src); } void Exp::ToRSBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,"()[]",Groupfix); Over(dest,src); } void Exp::ToCBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(CBracket,1,1,LBracket,s,1.0,0,0,"{}",Groupfix); Over(dest,src); } void Exp::ToCRBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,"{}()",Groupfix); Over(dest,src); } void Exp::ToCRCBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,"{}()",Groupfix); Over(dest,src); } void Exp::ToCSBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,"{}[]",Groupfix); Over(dest,src); } void Exp::ToSBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(SBracket,1,1,LBracket,s,1.0,0,0,"[]",Groupfix); Over(dest,src); } void Exp::ToSRBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,"[]()",Groupfix); Over(dest,src); } void Exp::ToSCBracket(int dest,int sign) { int s=1; if(sign<0) s=-1; int src=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,"[]{}",Groupfix); Over(dest,src); } void Exp::ToRFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(RBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToRCFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToRSFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToCFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(CBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToCRFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToCRCFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToCSFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToSFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(SBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToSRFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } void Exp::ToSCFun(int dest,int sign,QString name) { int s=1; if(sign<0) s=-1; int src=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); Over(dest,src); } int Exp::Insert(int orig,int insert) { #ifdef QT_DEBUG if(!VALID_NODE(orig) || !VALID_NODE(insert)) { ERROR="Invalid Node In Insert"; return 0; } #endif QList links=N[orig].links; N[orig].links.clear(); int root=N[orig].root; int parent=N[orig].parent; int pos=N[parent].links.indexOf(orig); N[parent].links.removeOne(orig); int copy=Copy(orig); UsedNs.removeOne(orig); FreeNs.append(orig); N[copy].links=links; orig=copy; copy=Copy(insert); UsedNs.removeOne(insert); N[insert].parent=-1; FreeNs.append(insert); insert=copy; if(pos>-1) N[parent].links.insert(pos,insert); else N[parent].links.append(insert); N[insert].root=root; N[insert].parent=parent; N[insert].links.append(orig); N[orig].parent=insert; return orig; } int Exp::InsertPlus(int orig) { int insert=NewN(Plus,2,MAX_LINKS,LPlus,1,1.0,0,0,"+",Infix); return Insert(orig,insert); } int Exp::InsertTimes(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(Times,2,MAX_LINKS,LTimes,s,1.0,0,0,"*",Infix); return Insert(orig,insert); } int Exp::InsertDevide(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(Devide,2,2,LDevide,s,1.0,0,0,"/",Infix); return Insert(orig,insert); } int Exp::InsertPower(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(Power,2,2,LPower,s,1.0,0,0,"^",Infix); return Insert(orig,insert); } int Exp::InsertComma(int orig) { int insert=NewN(Comma,2,MAX_LINKS,LComma,1,1.0,0,0,",",Infix); return Insert(orig,insert); } int Exp::InsertSemi(int orig) { int insert=NewN(Semi,2,MAX_LINKS,LSemi,1,1.0,0,0,";",Infix); return Insert(orig,insert); } int Exp::InsertPrefix(int orig,NodeType t,int sign) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return FREE; } int s=1; if(sign<0) s=-1; int insert=NewN(t,1,1,LPrefix,s,1.0,0,0,text,Prefix); return Insert(orig,insert); } int Exp::InsertPostfix(int orig,NodeType t) { QString text; switch(t) { case Excl: text="!"; break; case Not: text="'"; break; case Dot: text="."; break; case At: text="@"; break; case Tilda: text="~"; break; case Question: text="?"; break; default: return FREE; } int insert=NewN(t,1,1,LPostfix,1,1.0,0,0,text,Postfix); return Insert(orig,insert); } int Exp::InsertEqual(int orig,NodeType t) { QString text; switch(t) { case Equal: text="="; break; case Less: text="<"; break; case More: text=">"; break; case Colon: text=":"; break; default: return FREE; } int insert=NewN(t,2,MAX_LINKS,LEqual,1,1.0,0,0,text,Infix); return Insert(orig,insert); } int Exp::InsertRBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(RBracket,1,1,LBracket,s,1.0,0,0,"()",Groupfix); return Insert(orig,insert); } int Exp::InsertRCBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,"(){}",Groupfix); return Insert(orig,insert); } int Exp::InsertRSBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,"()[]",Groupfix); return Insert(orig,insert); } int Exp::InsertCBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(CBracket,1,1,LBracket,s,1.0,0,0,"{}",Groupfix); return Insert(orig,insert); } int Exp::InsertCRBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,"{}()",Groupfix); return Insert(orig,insert); } int Exp::InsertCRCBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,"{}()",Groupfix); return Insert(orig,insert); } int Exp::InsertCSBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,"{}[]",Groupfix); return Insert(orig,insert); } int Exp::InsertSBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(SBracket,1,1,LBracket,s,1.0,0,0,"[]",Groupfix); return Insert(orig,insert); } int Exp::InsertSRBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,"[]()",Groupfix); return Insert(orig,insert); } int Exp::InsertSCBracket(int orig,int sign) { int s=1; if(sign<0) s=-1; int insert=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,"[]{}",Groupfix); return Insert(orig,insert); } int Exp::InsertRFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(RBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertRCFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(RCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertRSFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(RSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertCFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(CBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertCRFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(CRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertCRCFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(CRCBracket,3,3,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertCSFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(CSBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertSFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(SBracket,1,1,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertSRFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(SRBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } int Exp::InsertSCFun(int orig,int sign,QString name) { int s=1; if(sign<0) s=-1; int insert=NewN(SCBracket,2,2,LBracket,s,1.0,0,0,name,Groupfix); return Insert(orig,insert); } void Exp::Evaluate(int node) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In Evaluate"; return; } #endif bool changed=true; while(changed && ERROR=="") { changed=false; changed|=evaluate(node); if(ERROR!="") break; if(!N[node].links.count()) break; changed|=simplifyN(node); } if(ERROR=="") return; if(YourRoot!=MyRoot) Free(YourRoot); while(AN.last()!=MyRoot) AN.takeLast(); an=MyRoot; int n=NewN(Error,0,0,LLeaf,1,0.0,__LINE__,0,ERROR,Nofix); AddN(n); ERROR=""; } bool Exp::evaluate(int node) { if(ERROR!="") return false; bool changed=false; QList links=N[node].links; int nl=links.count(),i,b,c,d,key; NodeType t; bool (*opfun)(Exp*,int,bool); bool (*ffun)(Exp*,int,int,NodeType,bool); bool (*fffun)(Exp*,int,int,NodeType,int,NodeType,bool); bool (*ffffun)(Exp*,int,int,NodeType,int,NodeType,int,NodeType,bool); bool (*ppfun)(Exp*,int,bool,int,NodeType,bool); t=N[node].type; QString text; switch(t) { case Symbol: if(Sym==0) break; key=Symbols.value(N[node].text,unknown_key); if(key!=unknown_key) changed|=Sym(this,node,key,true); break; case RBracket: c=links[0]; changed|=evaluate(c); ffun=RFuns.value(N[node].text,0); if(ffun) changed|=ffun(this,node,c,N[c].type,true); break; case RCBracket: c=links[0]; changed|=evaluate(c); d=links[1]; fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case CRCBracket: b=links[0]; c=links[1]; changed|=evaluate(c); d=links[2]; ffffun=CRCFuns.value(N[node].text,0); if(ffffun) changed|=ffffun(this,node,b,N[b].type,c,N[c].type,d,N[d].type,true); break; case RSBracket: c=links[0]; changed|=evaluate(c); d=links[1]; changed|=evaluate(d); fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case CBracket: c=links[0]; ffun=CFuns.value(N[c].text,0); if(ffun) changed|=ffun(this,node,c,N[c].type,true); break; case CRBracket: c=links[0]; d=links[1]; changed|=evaluate(d); fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case CSBracket: c=links[0]; d=links[1]; changed|=evaluate(d); fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case SBracket: c=links[0]; changed|=evaluate(c); ffun=SFuns.value(N[c].text,0); if(ffun) changed|=ffun(this,node,c,N[c].type,true); break; case SRBracket: c=links[0]; changed|=evaluate(c); d=links[1]; changed|=evaluate(d); fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case SCBracket: c=links[0]; changed|=evaluate(c); d=links[1]; fffun=RCFuns.value(N[node].text,0); if(fffun) changed|=fffun(this,node,c,N[c].type,d,N[d].type,true); break; case Excl: case Not: case Dot: case At: case Tilda: case Question: { c=links[0]; changed|=evaluate(c); ppfun=PPFuns.value(N[node].text,0); bool pre=false; if(N[node].fix==Prefix) pre=true; if(ppfun) changed|=ppfun(this,node,pre,c,N[c].type,true); break; } default: if(nl) { for(i=0; i0 && an!=MyRoot) { close_bracket--; while(N[AN.last()].level!=LBracket && an!=MyRoot) { AN.takeLast(); an=AN.last(); } if(an==MyRoot) goto Skip; AN.takeLast(); an=AN.last(); last_added=an; POS.takeLast(); pos=POS.last(); int ml=N[an].max; int nl=N[an].links.count(); if(ml==1 && nl==0) { int ph=NewN(PlaceHolder,0,0,LLeaf,1,0.0,0,0,"...",Nofix); N[an].links.append(ph); } else if(ml==2 && nl==1) { int ph=NewN(PlaceHolder,0,0,LLeaf,1,0.0,0,0,"...",Nofix); N[an].links.append(ph); } } Skip: if(an==MyRoot && N[last_added].level!=LLeaf) YourRoot=node; // All except Brackets must connect to a lower level if(N[node].level!=LBracket) while(N[an].level>N[node].level && AN.last()!=MyRoot) { // don't leave a node with too few Links if((N[node].type==Comma || N[node].type==Semi) && N[an].level==LBracket) break; #ifdef QT_DEBUG if(N[an].links.count()N[an].links.count()) { last_added=an; Free(node); break; } } // steal node attach and wait #ifdef QT_DEBUG if(N[an].links.count()==0) goto Error; #endif c=N[an].links.takeLast(); if(c==YourRoot) YourRoot=node; N[an].links.append(node); N[node].root=YourRoot; N[node].parent=an; N[node].links.append(c); N[c].root=YourRoot; N[c].parent=node; if( N[node].type!=Plus && N[node].level!=LEqual && N[node].type!=MultiOp && N[node].type!=MultiEq ) { if(IsMinus) N[node].sign*=-1; IsMinus=false; if(std::signbit(N[c].value)) { // transfer sign c=N[node].links[0]; { N[c].value*=-1.0; N[node].sign*=-1; } } } AN.append(node); an=node; last_added=node; POS.last()++; pos=POS.last(); break; case Postfix: // attach and steal to connection #ifdef QT_DEBUG if(N[an].links.count()==0) goto Error; #endif n=N[an].links.takeLast(); N[an].links.append(node); N[node].root=YourRoot; N[node].parent=an; N[node].links.append(n); N[n].root=YourRoot; N[n].parent=node; last_added=node; POS.last()++; pos=POS.last(); break; case Groupfix: if(IsMinus) N[node].sign*=-1; IsMinus=false; POS.append(0); pos=0; N[an].links.append(node); N[node].root=YourRoot; N[node].parent=an; AN.append(node); an=node; last_added=node; pos=POS.last(); break; } #ifdef QT_DEBUG if(N[an].links.count()>N[an].max) goto Error; #endif return true; #ifdef QT_DEBUG Error: ERROR="Error near \""+N[node].text+"\" or \""+N[an].text+"\""; return false; #endif } int Exp::CompareNs(int n1,int n2,bool Abs) // return -1,0,1 { #ifdef QT_DEBUG if(!VALID_NODE(n1) || !VALID_NODE(n2)) { ERROR="Invalid Node In CompareNs"; return false; } #endif int result=0,i,n; double a=N[n1].value; double b=N[n2].value; if(!Abs) { a*=N[n1].sign; b*=N[n2].sign; } int t1=N[n1].type,c1; int t2=N[n2].type,c2; bool nu1= (t1==Number || t1==Frac); bool nu2= (t2==Number || t2==Frac); if(nu1 && nu2) { if(!Abs) { if(t1==Frac) a+=(N[n1].sign*(double)N[n1].a)/((double)N[n1].b); if(t2==Frac) b+=(N[n2].sign*(double)N[n2].a)/((double)N[n2].b); } else { if(t1==Frac) a+=((double)N[n1].a)/((double)N[n1].b); if(t2==Frac) b+=((double)N[n2].a)/((double)N[n2].b); } if(ab) return 1; return 0; } bool nm1= (t1==Symbol); bool nm2= (t2==Symbol); if(nm1 && nm2) { result=N[n1].text.compare(N[n2].text); if(!Abs && result==0) { if(N[n1].signN[n2].sign) return 1; } if(result<0) return -1; if(result>0) return 1; return 0; } if(nu1 && nm2) return -1; if(nu2 && nm1) return 1; if(nm1 && !(nm2 || nu2)) return -1; if(nm2 && !(nm1 || nu1)) return 1; if(nu1 && !(nm2 || nu2)) return -1; if(nu2 && !(nm1 || nu1)) return 1; result=N[n1].text.compare(N[n2].text); if(!Abs && result==0) { if(N[n1].signN[n2].sign) return 1; } if(result<0) return -1; if(result>0) return 1; if(t1==Plus || t2==Plus) Abs=false; int nc1=N[n1].links.count(); int nc2=N[n2].links.count(); if(nc1==0 || nc2==0) { result=N[n1].text.compare(N[n2].text); if(result<0) return -1; if(result>0) return 1; } n=nc1; if(nc2-1; i--) { c1=N[n1].links[i]; c2=N[n2].links[i]; result=CompareNs(c1,c2,Abs); if(result!=0) break; } else for(i=0; it2) return 1; if(nc1nc2) result=1; } return result; } bool Exp::SortLinks(int node) // for + and *, return true if changed anything; { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In SortLinks"; return false; } #endif int nl=N[node].links.count(),i,q; if(nl<2) return true; QList links; links=N[node].links; nl=N[node].links.count(); bool changed=true; while(changed) { changed=false; for(i=0; i &parts) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In Signature"; return; } #endif QString s="",sig=""; int ninit=parts.count(); signature(node,s,sig,parts,ninit); parts.append(sig); parts.append(s); } void Exp::Consts(int node,QList &parts) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In Consts"; return; } #endif int ninit=parts.count(); if(N[node].type==Number) N[node].text=ExpText(node); int n=N[node].links.count(); if(n==0) return; // do children first for(int i=0; i=0; i--) { int l=N[node].links[i]; int lsign=N[l].sign; N[l].sign=1; bool hasx=false; // see if a sym of interest for(int j=0; j=0; i--) { int l=N[node].links[i]; bool hasx=false; for(int j=0; j &parts,int ninit) { int nl=N[node].links.count(),i,l,n; char ch[4]; QString text; bool bracket=false; if(s!="" && nl!=0) bracket=true; if(bracket){s+="("; sig+="(";} // handle nodes without children if(nl==0) { int t=N[node].type; if(t==Number || t==Frac) text=ExpText(node); else text=N[node].text; n=parts.indexOf(text); if(n<0) { n=parts.count(); parts.append(text); } sprintf_s(ch,"%02i",n); if(n &parts) { int i,n=N[node].links.count(),c; if(n==0) return n; QString text; if(N[node].max>2) for(i=0; i &parts,QList &counts) { parts.clear(); counts.clear(); int i,n=N[node].links.count(),c; int count=0,found=0; bool same=true; if(n==0) return same; for(i=0; i &values) { int i,n=N[node].links.count(),c; if(n==0) return n; double value; if(N[node].max>2) for(i=0; i &values,QList &counts) { values.clear(); counts.clear(); int i,n=N[node].links.count(),c; int count=0,found=0; bool same=true; if(n==0) return same; for(i=0; i0 && N[N[node].links[0]].text==text) return 1; return 0; } QList links=N[node].links; N[node].links.clear(); for(i=0; i links=N[node].links; N[node].links.clear(); j=0; for(i=0; i15) m=15; N[node].links.prepend(links[i]); count+=m<0 && N[N[node].links[0]].type==type) return istype*(count+1); return istype*count; } QList links=N[node].links; N[node].links.clear(); for(i=0; i links=N[node].links; N[node].links.clear(); j=0; for(i=0; i15) m=15; N[node].links.prepend(links[i]); count+=m<0 && N[N[node].links[0]].a==a) return 1; return 0; } QList links=N[node].links; N[node].links.clear(); for(i=0; i links=N[node].links; N[node].links.clear(); j=0; for(i=0; i15) m=15; N[node].links.prepend(links[i]); count+=m<0 && N[N[node].links[0]].b==b) return 1; return 0; } QList links=N[node].links; N[node].links.clear(); for(i=0; i links=N[node].links; N[node].links.clear(); j=0; for(i=0; i15) m=15; N[node].links.prepend(links[i]); count+=m<b) { c=(double)(a/b); v+=c; a-=c*b; } CancelInt(a,b); if(va || p>b) break; changed=true; while(changed) { changed=false; a1=a/p; b1=b/p; if(a1*p==a && b1*p==b) { a/=p; b/=p; changed=true; } if(p>a || p>b) break; } i++; p=Prime[i]; } p=LastPrime; while(pmax_int || b>max_int) { ERROR=QString::number(a)+" or "+QString::number(a)+" is too big for an Integer"; return false; } int ia=(int)a; int ib=(int)b; CancelInt(ia,ib); a=(double)ia; b=(double)ib; return true; } bool Exp::IsInt(double d) { d=abs(d); if(d>max_int) return false; int i=(int)(d+eps); if((d-(double)i)max_int) return false; int i=(int)(d+eps); if((d-(double)i)eps) { for(i=0; i<100; i++) { test=((double)a)/((double)b); if(abs(test-frac)test) a++; b++; } } else { if(IsInt(v)) { found=true; a=b=0; } } if(found && a links; links=N[node].links; nl=links.count(); if(nl) for(i=0; i-1 && N[p].level==LBracket) { Over(node,c); N[node].sign*=s; return true; } // not needed if parent is Start, except , and ; if(p!=-1 && N[p].type==Start && ct!=Comma && ct!=Semi) { Over(node,c); if(N[node].type!=Plus) { N[node].sign*=s; return true; } nl=N[node].links.count(); for(i=0; i=0.0) N[n1].value=v; else { N[n1].value=abs(v); N[n1].sign=-1; } break; case NF: ToNumber(n2,FracToDouble(n2)); N[n2].value*=N[n1].sign; N[n2].sign=1; N[n1].value+=N[n2].value; break; case FN: ToNumber(n1,FracToDouble(n1)); N[n1].value*=N[n1].sign; N[n1].sign=1; N[n1].value+=N[n2].value; break; case FF: v1=N[n1].value; a1=N[n1].a; v2=N[n2].value; a2=N[n2].a; if(a1==0 && a2==0) { N[n1].value=v1+v2; if(N[n1].value>max_int) ToNumber(n1,N[n1].value); break; } if(v1==0.0 && a1==0) { N[n1].value=N[n2].value; N[n1].a=N[n2].a; N[n1].b=N[n2].b; break; } if(v2==0.0 && a2==0.0) break; s1=1; if(signbit(v1)) s1=-1; s2=1; if(signbit(v2)) s2=-1; b1=N[n1].b; b2=N[n2].b; if(v1==0.0 && v2==0.0) { a=s1*a1*b2+s2*a2*b1; b=b1*b2; if(abs(a)>max_int || b>max_int) { ToNumber(n1,a/b); SimplyNumber(n1); break; } v=0.0; if(a<0){a=abs(a); v*=-1;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } if(a1!=0 && a2!=0) { if(v1==0) // v2 is not==0 { a=s1*a1*b2+s2*(a2+b2*abs(v2))*b1; b=b1*b2; if(abs(a)>max_int || b>max_int) { ToNumber(n1,a/b); break; } v=0.0; if(a<0){a=abs(a); v*=-1.0;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } if(v2==0) // v1 is not==0 { a=s2*a2*b1+s1*(a1+b1*abs(v1))*b2; b=b1*b2; if(abs(a)>max_int || b>max_int) { ToNumber(n1,a/b); break; } v=0.0; if(a<0){a=abs(a); v*=-1;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } // full house a=s1*(a1+b1*abs(v1))*b2+s2*(a2+b2*abs(v2))*b1; b=b1*b2; if(abs(a)>max_int || b>max_int) { ToNumber(n1,a/b); break; } v=0.0; if(a<0){a=abs(a); v*=-1;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } if(v1!=0 && a1==0) { a=v1*b2+s2*(a2+abs(v2)*b2); b=b2; if(abs(a)>max_int) { ToNumber(n1,a/b); SimplyNumber(n1); break; } v=0.0; if(a<0){a=abs(a); v*=-1;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } // if(v2!=0 && a2==0) a=v2*b1+s1*(a1+abs(v1)*b1); b=b1; if(abs(a)>max_int) { ToNumber(n1,a/b); break; } v=0.0; if(a<0){a=abs(a); v*=-1;} N[n1].value=v; N[n1].a=a; N[n1].b=b; CancelFrac(n1); break; } Free(n2); } bool Exp::SimplyPlus(int node) { bool changed=false; int i,j,nl,ct,c,dt,d,cct,cc,ddt,dd,n,nn,q,count,p; QList links; bool has_numbers=false; bool has_plus=false; bool has_times=false; bool has_other=false; nl=N[node].links.count(); for(i=0; i-1 && (N[p].type==Times || N[p].type==Devide || N[p].type==Power)) { InsertRBracket(node,1); return true; } links=N[node].links; N[node].links.clear(); nl=links.count(); for(i=0; i1) AddEr(c,links.takeLast()); N[node].links.append(c); } if(changed) goto PlusEnd; } if(has_plus) { // remove nested + a+|b+c|+d links=N[node].links; N[node].links.clear(); nl=links.count(); for(i=0; i0) { int a=Copy(links[i]); int s=N[a].sign; if(N[a].text!="()") InsertRBracket(a,s); int b=Copy(links[i-1]); s=N[b].sign; if(N[b].text!="()") InsertRBracket(b,s); N[a].sign*=-1; q=CompareNs(a,b,false); Free(a); Free(b); if(q==0) { Free(links[i]); links.takeLast(); i--; Free(links[i]); links.takeLast(); i--; changed=true; continue; } Adopt(node,links.takeLast()); i--; } // check for odd one left over if(!links.isEmpty()) Adopt(node,links.takeLast()); if(changed) goto PlusEnd; // convert from adding same to times an int links=N[node].links; nl=links.count(); N[node].links.clear(); i=0; while(i0) while(imax_int) ToNumber(n1,N[n1].value); break; } s=std::signbit(v1)^std::signbit(v2); b1=N[n1].b; v1=abs(v1); b2=N[n2].b; v2=abs(v2); if(a1==0.0) { a=(v1)*(v2*b2+a2); b=b2; } else if(a2==0.0) { a=(v1*b1+a1)*(v2); b=b1; } else { a=(v1*b1+a1)*(v2*b2+a2); b=b1*b2; } if(a>max_int || b>max_int) { if(s) a*=-1; ToNumber(n1,a/b); } else { N[n1].value=0.0; if(s) N[n1].value*=-1.0; CancelDbl(a,b); N[n1].a=a; N[n1].b=b; CancelFrac(n1); } break; } N[n1].sign*=N[n2].sign; Free(n2); } bool Exp::SimplyTimes(int node) { bool changed=false; int i,j,nl,ct,c,d,c0,d0,c1,d1,nd1,n,nn,count,q; double sign; bool found=false; QList links; bool has_numbers=false; bool has_times=false; bool has_devide=false; bool has_brackets=false; bool has_other=false; sign=N[node].sign; N[node].sign=1; nl=N[node].links.count(); for(i=0; i1) { ToDevide(node,1); c=AdoptTimes(node,1); d=AdoptRBracket(node,1); d=AdoptTimes(d,1); for(i=0; i0 && a1==0) {v1-=1; a1=1; b1=1;} if(v2>0 && a2==0) {v2-=1; a2=1; b2=1;} a=(v1*b1+a1)*b2; b=b1*(v2*b2+a2); if(abs(a)>max_int || b>max_int) { ToNumber(n1,a/b); N[n1].sign*=N[n2].sign; break; } CancelDbl(a,b); N[n1].value=0.0; N[n1].a=a; N[n1].b=b; CancelFrac(n1); N[n1].sign*=N[n2].sign; break; } Free(n2); } bool Exp::SimplyDevide(int node) { bool changed=false; int c,cc,d,dd,nc,nd,n,n0,n1,a,b,tc,td,i,j; QList links; QString e1,e2; c=N[node].links[0]; d=N[node].links[1]; changed|=simplifyN(c); if(ERROR!="") return true; changed|=simplifyN(d); if(ERROR!="") return true; if(changed) return true; int sign=N[node].sign; N[node].sign=1; links=N[node].links; N[node].links.clear(); c=links[0]; sign*=N[c].sign; N[c].sign=1; tc=N[c].type; d=links[1]; sign*=N[d].sign; N[d].sign=1; td=N[d].type; if(N[c].value0 && N[d].links.count()==0) { changed=true; Free(d); d=-1; } if(d!=-1) { if(N[d].type==RBracket) { int d0=N[d].links[0]; if(N[d0].type==Times) { int n=N[d0].links.count(); if(n<2) { if(n==0) ToNumber(d,1.0); if(n==1) Over(d,N[d0].links[0]); changed=true; } } } sign=N[c].sign*N[d].sign*sign; N[c].sign=1; N[d].sign=1; if(N[d].type==Number && N[d].value==1.0 && N[d].a==0) { Over(node,c); Free(d); changed=true; }else { Adopt(node,c); Adopt(node,d); } } else Over(node,c); N[node].sign=sign; return changed; } void Exp::PowEr(int n1,int n2) { int t=0; if(N[n1].type==Frac) t+=2; if(N[n2].type==Frac) t+=1; switch(t) { case NN: N[n1].value= pow(N[n1].value*N[n1].sign, N[n2].value*N[n2].sign); break; case NF: ToNumber(n2,FracToDouble(n2)); N[n1].value= pow(N[n1].value*N[n1].sign, N[n2].value); break; case FN: ToNumber(n1,FracToDouble(n1)); N[n1].value= pow(N[n1].value, N[n2].value*N[n2].sign); break; case FF: ToNumber(n1,FracToDouble(n1)); ToNumber(n2,FracToDouble(n2)); N[n1].value=pow(N[n1].value,N[n2].value); MakeFrac(n1); break; } Free(n2); } bool Exp::SimplyPower(int node) { if(N[node].sign==-1) { N[node].sign=1; InsertRBracket(node,-1); return true; } bool changed=false; int c,cc,d,ct,dt,n; QList links; c=N[node].links[0]; changed|=simplifyN(c); if(ERROR!="") return true; d=N[node].links[1]; changed|=simplifyN(d); if(ERROR!="") return true; if(changed) return true; links=N[node].links; N[node].links.clear(); c=links[0]; ct=N[c].type; d=links[1]; dt=N[d].type; // numeric calculation if((ct==Number || ct==Frac) && (dt==Number || dt==Frac)) { double cv=N[c].value; if(N[c].sign==-1) { Free(c); double dv=N[d].value*N[d].sign; Free(d); int di=(int)dv; if(di!=dv) { double df=dv-di; cv=std::pow(cv,dv); AdoptNumber(node,-1.0); AdoptNumber(node,df); int p=N[node].parent; if(N[p].type!=RBracket) { InsertRBracket(node,1); changed=true; } if(cv!=1.0) { InsertTimes(node,1); AdoptNumber(node,cv); SwapLinks(node,0,1); } return changed; } ToNumber(node,std::pow(-cv,dv)); return true; } PowEr(c,d); if(ERROR!="") return true; Over(node,c); return true; } if(ct==Number || ct==Frac) { // 0^anything if(N[c].value==0.0 && ((ct==Number) || (ct==Frac && N[c].a==0))) { ToNumber(node,0.0); Free(c); Free(d); return true; } // 1^anything if(N[c].value==1.0 && N[c].sign==1 && ((ct==Number) || (ct==Frac && N[c].a==0))) { ToNumber(node,1); Free(c); Free(d); return true; } } if(dt==Number || dt==Frac) { // anything^0 if((dt==Number && N[d].value==0.0) || (dt==Frac && N[d].value==0.0 && N[d].a==0)) { ToNumber(node,1.0); Free(c); Free(d); return true; } // anything^1 if((dt==Number && N[d].value==1.0) || (dt==Frac && N[d].value==1.0 && N[d].a==0)) { if(N[d].sign==1) { Over(node,c); N[node].sign=1; Free(d); return true; } } } // change a^ -b into 1/a^b if(N[d].sign<0) { n=InsertDevide(node,1); AdoptNumber(node,1.0); SwapLinks(node,0,1); Adopt(n,c); N[d].sign=1; Adopt(n,d); return true; } if(N[c].text=="()") { int p=N[c].links[0]; // inside () if(N[p].type==Times) // make (a*b)^c into a^c*b^c { int i,nl=N[p].links.count(); for(i=0; i links=N[node].links; t=N[node].type; nl=N[node].links.count(); #ifdef QT_DEBUG if(nlN[node].max) { ERROR="\""+N[node].text+"\" has a problem"; return false; } #endif switch(t) { case Start: changed|=SimplyStop(node); break; case Number: changed|=SimplyNumber(node); break; case Frac: changed|=SimplyFrac(node); break; case Symbol: changed|=SimplySym(node); break; case Plus: changed|=SimplyPlus(node); break; case Times: changed|=SimplyTimes(node); break; case Devide: changed|=SimplyDevide(node); break; case Power: changed|=SimplyPower(node); break; case RBracket: c=links[0]; changed|=simplifyN(c); changed|=SimplyBracket(node); break; case RCBracket: c=links[0]; changed|=simplifyN(c); changed|=SimplyBracket(node); break; case CBracket: changed|=SimplyBracket(node); break; case CRBracket: d=links[1]; changed|=simplifyN(d); changed|=SimplyBracket(node); break; case CRCBracket: d=links[1]; changed|=simplifyN(d); changed|=SimplyBracket(node); break; case SCBracket: c=links[0]; changed|=simplifyN(c); changed|=SimplyBracket(node); break; case CSBracket: d=links[1]; changed|=simplifyN(d); changed|=SimplyBracket(node); break; case RSBracket: c=links[0]; changed|=simplifyN(c); if(ERROR!="") break; d=links[1]; changed|=simplifyN(d); changed|=SimplyBracket(node); break; case SRBracket: c=links[0]; changed|=simplifyN(c); if(ERROR!="") break; d=links[1]; changed|=simplifyN(d); changed|=SimplyBracket(node); break; case SBracket: c=links[0]; changed|=simplifyN(c); changed|=SimplyBracket(node); break; case Excl: case Not: case Dot: case At: case Tilda: case Question: c=links[0]; if(N[c].sign==-1) { InsertRBracket(c,1); changed=true; } if(N[node].fix==Postfix) { if(N[node].sign==-1) { InsertRBracket(node,-1); N[node].sign=1; changed=true; } } changed|=simplifyN(c); break; case MultiOp: changed|=SimplyMulti(node); break; case MultiEq: case Equal: case Less: case More: case Colon: break; default: changed|=SimplyDefault(node); if(ERROR!="") break; } if(ERROR!="") return true; return changed; } bool Exp::DoCallbacks() { if(ERROR!="") return false; int ni,i,in,t,key,b,c,d; bool changed=false; bool (*opfun)(Exp*,int,bool); int opfuns=OPFuns.count(); bool (*ffun)(Exp*,int,int,NodeType,bool); int rfuns=RFuns.count(); int cfuns=RFuns.count(); int sfuns=RFuns.count(); bool (*fffun)(Exp*,int,int,NodeType,int,NodeType,bool); int rcfuns=RCFuns.count(); int rsfuns=RSFuns.count(); int crfuns=CRFuns.count(); int csfuns=CSFuns.count(); int srfuns=SRFuns.count(); int scfuns=SCFuns.count(); bool (*ffffun)(Exp*,int,int,NodeType,int,NodeType,int,NodeType,bool); int crcfuns=CRCFuns.count(); bool (*ppfun)(Exp*,int,bool,int,NodeType,bool); int ppfuns=PPFuns.count(); ni=FoundNs.count(); for(i=0; i1) { changed=simplifyN(node); if(ERROR!="") { Free(node); while(AN.last()!=MyRoot) AN.takeLast(); an=MyRoot; ERROR.replace("\"+\"","\"+/-\""); int n=NewN(Error,0,0,LLeaf,1,0.0,__LINE__,0,ERROR,Nofix); AddN(n); break; } if(changed) continue; FoundNs.clear(); FindNodes(node); if(FoundNs.count()) changed=DoCallbacks(); if(ERROR!="") break; } } bool Exp::LeafN(NodeType t,QString text,double value,int a,int b) { int n; int s=1; if(value<0.0) s=-1; if(close_bracket && N[an].level!=LBracket) { ERROR="Can not have \""+text+"\" after brackets"; return false; } if(t==Hash && N[last_added].fix==Nofix) { ERROR="\""+text+"\" not allowed after \""+N[last_added].text+"\""; return false; } if(N[last_added].type==Hash) { ERROR="\""+N[last_added].text+"\" not allowed before \""+text+"\""; return false; } n=NewN(t,0,0,LLeaf,s,value,a,b,text,Nofix); if(t==Frac) CancelFrac(n); return(AddN(n)); } bool Exp::PrePostN(int &i,NodeType t, QString text) { bool postfix=false; bool prefix=false; TokenType tt; int n; int j=i-1; while(j>0 && tokens[j].typ==tSpace) j--; tt=tokens[j].typ; switch(tt) { case tWord: case tNumber: case tFrac: case tCRB: case tCCB: case tCSB: postfix=true; default: break; } j=i+1; while(j1) return true; switch(t) { case tCRB: switch(tt) { case tOCB: N[an].type=RCBracket; N[an].min=1; N[an].max=2; N[an].text+="{}"; break; case tOSB: N[an].type=RSBracket; N[an].min=1; N[an].max=2; N[an].text+="[]"; break; default: break; } break; case tCCB: switch(tt) { case tORB: N[an].type=CRBracket; N[an].min=1; N[an].max=2; N[an].text+="()"; break; case tOSB: N[an].type=CSBracket; N[an].min=1; N[an].max=2; N[an].text+="[]"; break; default: break; } break; case tCSB: switch(tt) { case tORB: N[an].type=SRBracket; N[an].min=1; N[an].max=2; N[an].text+="()"; break; case tOCB: N[an].type=SCBracket; N[an].min=1; N[an].max=2; N[an].text+="{}"; break; case tNothing: case tStop: case tError: case tInt: case tNumber: case tFrac: case tQuote: case tPlaceHolder: case tWord: case tMultiOp: case tMultiEq: case tEscape: case tSpace: case tPlus: case tMinus: case tTimes: case tDevide: case tPower: case tExcl: case tLess: case tEqual: case tMore: case tAnd: case tOr: case tBack: case tNot: case tComma: case tDot: case tSemi: case tColon: case tDollar: case tCRB: case tCCB: case tOSB: case tCSB: case tDQuote: case tSQuote: case tAt: case tTilda: case tHash: case tQuestion: break; default: break; } break; default: break; } last_added=an; return true; } bool Exp::InfixN(int i,NodeType t,int maxch,Level level,QString text,double value) { int n,nt=tokens.count(); int s=1; if(value<0.0) s=-1; if(i==nt-1 && t!=Comma && t!=Semi) { ERROR="Trailing \""+text+"\""; return false; } // ignore + after * or ^ / int lt=N[last_added].type; if(text=='+' && (lt==Times || lt==Power || lt==Devide)) return true; n=NewN(t,2,maxch,level,s,value,0,0,text,Infix); return(AddN(n)); } int Exp::BuildTree() { if(tokens.empty()) return YourRoot; int start_uc=UsedNs.count(); int i,n,nt=tokens.count(); TokenType t,tt; double v; QString s; for(i=0; i0) { tt=tokens[i-1].typ; if(tt==tORB || tt==tOCB || tt==tOSB) { n=NewN(PlaceHolder,0,0,LLeaf,1,1.0,0,0,"",Nofix); AddN(n); } if(tt==tCRB || tt==tCCB || tt==tCSB) { while(close_bracket>0 && an!=MyRoot) { close_bracket--; an=AN.last(); while(N[an].level!=LBracket && an!=MyRoot) { AN.takeLast(); an=AN.last(); } AN.takeLast(); an=AN.last(); last_added=an; POS.takeLast(); pos=POS.last(); int ml=N[an].max; int nl=N[an].links.count(); if(ml==1 && nl==0) { int ph=NewN(PlaceHolder,0,0,LLeaf,1,0.0,0,0,"...",Nofix); N[an].links.append(ph); } else if(ml==2 && nl==1) { int ph=NewN(PlaceHolder,0,0,LLeaf,1,0.0,0,0,"...",Nofix); N[an].links.append(ph); } } } } if(i0 && tokens[i-1].typ==tSemi) || i==nt-1) if(!LeafN(PlaceHolder,"",1.0,0,0)) return YourRoot; break; case tComma: if(nt<5) goto ShortError; if(i==0) if(!LeafN(PlaceHolder,"",1.0,0,0)) return YourRoot; if(!InfixN(i,Comma,MAX_LINKS,LComma,tokens[i].s,1.0)) return YourRoot; if((i>0 && tokens[i-1].typ==tComma) || i==nt-1) if(!LeafN(PlaceHolder,"",1.0,0,0)) return YourRoot; break; case tMinus: if(nt<4) goto ShortError; if(IsMinus) IsMinus=false; else IsMinus=true; if(pos==0 && tokens[i+1].typ!=tNothing) break; if(N[last_added].level==LBracket) break; if(N[last_added].level==LEqual) break; if(N[an].level>LPlus && N[last_added].level!=LLeaf && N[last_added].level!=LBracket ) break; case tPlus: if(nt<4) goto ShortError; if(pos==0 && (tokens[i-1].typ==tORB || tokens[i-1].typ==tOSB || tokens[i-1].typ==tOCB || tokens[i-1].typ==tNothing)) break; if(!InfixN(i,Plus,MAX_LINKS,LPlus,"+",1.0)) return YourRoot; break; case tTimes: if(nt<5) goto ShortError; if(!InfixN(i,Times,MAX_LINKS,LTimes,tokens[i].s,1.0)) return YourRoot; break; case tDevide: if(nt<5) goto ShortError; if(!InfixN(i,Devide,2,LDevide,tokens[i].s,1.0)) return YourRoot; break; case tPower: if(nt<5) goto ShortError; if(!InfixN(i,Power,2,LPower,tokens[i].s,1.0)) return YourRoot; break; case tExcl: if(nt==3) goto ShortError; if(!PrePostN(i,Excl,tokens[i].s)) return YourRoot; break; case tNot: if(nt==3) goto ShortError; if(!PrePostN(i,Not,tokens[i].s)) return YourRoot; break; case tDot: if(nt==3) goto ShortError; if(!PrePostN(i,Dot,tokens[i].s)) return YourRoot; break; case tAt: if(nt==3) goto ShortError; if(!PrePostN(i,At,tokens[i].s)) return YourRoot; break; case tTilda: if(nt==3) goto ShortError; if(!PrePostN(i,Tilda,tokens[i].s)) return YourRoot; break; case tQuestion: if(nt==3) goto ShortError; if(!PrePostN(i,Question,tokens[i].s)) return YourRoot; break; case tDQuote: if(!LeafN(DQuote,tokens[i].s,1.0,0,0)) return YourRoot; break; case tAnd: if(nt<5) goto ShortError; if(!InfixN(i,And,MAX_LINKS,LAnd,tokens[i].s,1.0)) return YourRoot; break; case tOr: if(nt<5) goto ShortError; if(!InfixN(i,Or,MAX_LINKS,LOr,tokens[i].s,1.0)) return YourRoot; break; case tBack: if(nt==3) goto ShortError; if(!InfixN(i,Back,MAX_LINKS,LBack,tokens[i].s,1.0)) return YourRoot; break; case tSQuote: if(nt==3) goto ShortError; if(!InfixN(i,SQuote,1,LSQuote,tokens[i].s,1.0)) return YourRoot; break; case tColon: if(nt<5) goto ShortError; if(!InfixN(i,Colon,2,LEqual,tokens[i].s,1.0)) return YourRoot; break; case tLess: if(nt<5) goto ShortError; if(!InfixN(i,Less,2,LEqual,tokens[i].s,1.0)) return YourRoot; break; case tEqual: if(nt<5) goto ShortError; if(!InfixN(i,Equal,2,LEqual,tokens[i].s,1.0)) return YourRoot; break; case tMore: if(nt<5) goto ShortError; if(!InfixN(i,More,2,LEqual,tokens[i].s,1.0)) return YourRoot; break; case tPlaceHolder: if(nt==3) goto ShortError; if(i==0) break; if(!LeafN(PlaceHolder,tokens[i].s,1.0,0,0)) return YourRoot; break; case tMultiOp: if(nt<3) goto ShortError; if(i==0 || (N[last_added].level br; for(int i=0; i toks; Token newt; toks.reserve(nt); TokenType t; QString s; double n,f,e,digits,sign; double d; i=0; bool foundE=true; while(i1) { i++; s=s.right(s.length()-1); for(j=0; j toks; bool equal=false; Token place_holder={"",0.0,tPlaceHolder}; Token multi_op={"",0.0,tMultiOp}; TokenType t; QString s; s=""; bool exempt=false; int start_in=0,start_out=0; while(i1) { if(equal) multi_op.typ=tMultiEq; else multi_op.typ=tMultiOp; equal=false; multi_op.s=s; toks.insert(start_out,multi_op); if(start_in==0 || MultiOps_test(start_in-1)) toks.insert(start_out,place_holder); else if(MultiOps_test(start_in+s.length())) toks.insert(start_out+1,place_holder); } } } toks+=tokens[i]; start_out=toks.length(); s=""; i++; start_in=i; continue; } s+=tokens[i].s; i++; } tokens=toks; return; } void Exp::FindQuotes() { int i=0,tn=tokens.count(); QList toks; Token newt; TokenType t; QString s; repeat: bool inquote=false; while(ieps) { s+=QString::number(abs(v))+"`"; if(a!=0) { s+=QString::number(a); if(b>1) { s+="/"; s+=QString::number(b); } } } else { s+="`"+QString::number(a); if(b>1) { s+="/"; s+=QString::number(b); } } s+=")"; return s; } QString Exp::ExpText(int node) { if(ERROR!="") return ERROR; QString s=exptext(node); if(s.length()) while(s[0]==' ') s.removeFirst(); s.replace("( ","("); s.replace(" )",")"); return s; } QString Exp::exptext(int node) { #ifdef QT_DEBUG if(!VALID_NODE(node)) { ERROR="Invalid Node In ExpText"; return ""; } #endif int n; QString s,text=N[node].text; if(N[node].sign<0) s=" -"; else s=""; switch(N[node].type) { case PlaceHolder: s+=" "; break; case Error: s+=N[node].text; break; case Start: if(N[node].links.isEmpty()) { s+="Empty"; ERROR=s; break; } else s+=exptext(N[node].links[0]); break; case RBracket: case CBracket: case SBracket: s+=N[node].text.first(N[node].text.length()-1); s+=BuildInfixText(node,""); s+=N[node].text.last(1); break; case RCBracket: case RSBracket: case CRBracket: case CSBracket: case SRBracket: case SCBracket: n=N[node].links.count(); s+=N[node].text.first(N[node].text.length()-3); if(n>0) s+=exptext(N[node].links[0]); s+=N[node].text.mid(N[node].text.length()-3,2); if(n>1) s+=exptext(N[node].links[1]); s+=N[node].text.last(1); break; case Symbol: s+=N[node].text; break; case DQuote: s+="\""+N[node].text+"\""; break; case Number: s+=QString::number(abs(N[node].value),'g',10); break; case Frac: s+=BuildFracText(node); break; case Comma: s+=BuildInfixText(node,N[node].text); break; case Semi: s+=BuildInfixText(node,N[node].text); break; case And: s+=BuildInfixText(node,N[node].text); break; case Or: s+=BuildInfixText(node,N[node].text); break; case Back: s+=BuildInfixText(node,N[node].text); break; case Plus: s+=BuildInfixText(node,text); break; case Times: s+=BuildInfixText(node,text); break; case Devide: s+=BuildInfixText(node,text); break; case Power: s+=BuildInfixText(node,text); break; case Equal: s+=BuildInfixText(node,text); break; case More: s+=BuildInfixText(node,text); break; case Less: s+=BuildInfixText(node,text); break; case Colon: s+=BuildInfixText(node,text); break; case MultiOp: case MultiEq: s+=BuildInfixText(node,text); break; case Hash: case Dollar: char n[10]; sprintf_s(n,"%02i",N[node].a); s+=" "+N[node].text+QString(n); break; default: s+=BuildPrePostText(node); } return s; }