这一部分,是解析器的具体实现了。
GetLequ将字符串转化为Atom链表
TryLequ是分析运算符、函数、括号、逗号、数字和变量的排布和数量,排除错误算式
AsmLequ则是对Atom链表进行组装,从开始每个链表的节点只包含一个Atom,变成每个节点包含一个算式树,最后可能会有多个节点,也就是返回多个值,如果你使用逗号分隔多个算式的话。构树是采用的后缀表达式法,也就是在翻译为后缀表达式的过程中,直接就构树了,规则十分简单:
两个栈(算式树栈:E、运算符栈:O),一个队列(上面的Atom链表:A)
从A依次获得Atom:
1)如果是变量或者数值,直接入E
2)函数、算符,要入O,在入之前,坚持O中的算符,根据优先级(函数最高,一元算符和函数一样高,二元算符依次是('*' , '/') > ('+' , '-') > ('>' , '>=' , '<' , '<=' , '==' , '!=') > ('&&' , '||'),赋值运算符优先级都相同且低于二元算符,左括号和逗号最小)
1>函数和运算符是左结合,因此要把优先级不低于要入栈函数/算符的O中元素依次出栈入E。
2>赋值运算符是右结合,,因此要把优先级高于要入栈函数/算符的O中元素依次出栈入E。
3)如果是逗号,则从O中出栈到E一直到左括号,但左括号不出栈,逗号不入栈
4)如果是右括号,则从O中出栈到E一直到左括号,左括号出栈,右括号不入栈
5)A中Atom读取结束后,将O中元素依次出栈入E
6)如果要获得后缀表达式,那么在入E时就不需要操作,如果要获得算式树,那么在O中元素入E时,要作:
1>一元函数、一元算符,以E栈顶Atom为算符左子,然后E栈顶出栈,算符入栈
2>二元函数、二元算符、赋值算符,以E栈顶Atom为算符右子,E出栈,新栈顶为算符左子,E再出栈,算符入栈
至于检验算式就很好说了,规则很多,但是很简单,大家看看算式就可以理解了,我的函数也是看着复杂,一堆switch-casr,但其实表达的东西就是那些,只是单纯的堆积代码而已。我事先检验,主要是为了避免搭建时发现错误不太好删除错误算式,但其实也可以在搭建算式时进行验证的。
好了,下面是代码:
Lequ *GetLequ(char *str) { Lequ *sp,rt; int j; sp=&rt; while(1) { while(*str==' ' || *str==' ')str++; if(*str) { sp->nxt=new Lequ; sp->nxt->lst=sp; sp=sp->nxt; sp->equ=new Atom; j=GetAtom(str,sp->equ); if(j==0) { RemoveLequ(rt.nxt); return 0; } str+=j; } else break; } rt.nxt->lst=NULL; return rt.nxt; } bool TryLequ(Lequ *ary) { Lequ *sp,*sq; int i,j; switch(ary->equ->type) { case Is_Rquot: case Is_Comma: case Is_Opr2p: case Is_Setvr: return false; break; default:break; } sp=ary,ary=sp->nxt; while(ary) { switch(ary->equ->type) { case Is_Lquot: switch(sp->equ->type) { case Is_Rquot: case Is_Value: case Is_Param: return false; break; default:break; } sq=ary->nxt; i=1,j=0; while(i && sq) { switch(sq->equ->type) { case Is_Lquot:i++; break; case Is_Comma:j++; break; case Is_Rquot:i--; break; default:break; } sq=sq->nxt; } if(i) { return false; } else { if(ary->lst && ary->lst->equ->type==Is_Fun2p) { if(j!=1)return false; } else { if(j!=0)return false; } } break; case Is_Comma: switch(sp->equ->type) { case Is_Comma: case Is_Fun1p: case Is_Fun2p: case Is_Opr1p: case Is_Opr2p: case Is_Setvr: return false; break; default:break; } break; case Is_Rquot: switch(sp->equ->type) { case Is_Comma: case Is_Fun1p: case Is_Fun2p: case Is_Opr1p: case Is_Opr2p: case Is_Setvr: return false; break; default:break; } i=1,sq=sp; while(i && sq) { switch(sq->equ->type) { case Is_Lquot:i--; break; case Is_Rquot:i++; break; default:break; } sq=sq->lst; } if(i)return false; break; case Is_Value: case Is_Param: case Is_Opr1p: switch(sp->equ->type) { case Is_Rquot: case Is_Value: case Is_Param: case Is_Fun1p: case Is_Fun2p: return false; break; default:break; } break; case Is_Fun1p: case Is_Fun2p: switch(sp->equ->type) { case Is_Rquot: case Is_Value: case Is_Param: case Is_Fun1p: case Is_Fun2p: return false; break; default:break; } if(ary->nxt==NULL || ary->nxt->equ->type!=Is_Lquot)return false; break; case Is_Opr2p: switch(sp->equ->type) { case Is_Lquot: case Is_Comma: case Is_Fun1p: case Is_Fun2p: case Is_Opr1p: case Is_Opr2p: case Is_Setvr: return false; break; default:break; } break; case Is_Setvr: switch(sp->equ->type) { case Is_Lquot: case Is_Comma: case Is_Fun1p: case Is_Fun2p: case Is_Opr1p: case Is_Opr2p: case Is_Setvr: return false; break; default:break; } sq=ary->lst; if(sq==NULL || sq->equ->type!=Is_Param)return false; while(sq && sq->equ->type!=Is_Lquot && sq->equ->type!=Is_Comma) { switch(sq->equ->type) { case Is_Rquot: case Is_Value: case Is_Fun1p: case Is_Fun2p: case Is_Opr1p: case Is_Opr2p: return false; break; default:break; } } break; default:break; } sp=ary,ary=ary->nxt; } switch(sp->equ->type) { case Is_Lquot: case Is_Comma: case Is_Opr2p: case Is_Setvr: case Is_Fun1p: case Is_Fun2p: return false; break; default:break; } return true; } Lequ *AsmLequ(Lequ *ori) { Lequ rt,op,*pe,*po,*sp; int i; if(sp=ori) { pe=&rt; po=&op; while(sp) { switch(sp->equ->type) { case Is_Lquot: po->nxt=sp; sp->lst=po; po=sp; sp=sp->nxt; sp->lst=NULL; po->nxt=NULL; break; case Is_Comma: while(po!=&op && po->equ->type!=Is_Lquot) { switch(po->equ->type) { case Is_Fun1p: case Is_Opr1p: po->equ->Lsun=pe->equ; pe->equ=po->equ; po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Fun2p: case Is_Opr2p: case Is_Setvr: po->equ->Lsun=pe->lst->equ; po->equ->Rsun=pe->equ; pe->lst->equ=po->equ; po=po->lst; pe=pe->lst; delete po->nxt; delete pe->nxt; po->nxt=NULL; pe->nxt=NULL; break; default:break; } } sp=sp->nxt; delete sp->lst; sp->lst=NULL; break; case Is_Rquot: while(po!=&op && po->equ->type!=Is_Lquot) { switch(po->equ->type) { case Is_Fun1p: case Is_Opr1p: po->equ->Lsun=pe->equ; pe->equ=po->equ; po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Fun2p: case Is_Opr2p: case Is_Setvr: po->equ->Lsun=pe->lst->equ; po->equ->Rsun=pe->equ; pe->lst->equ=po->equ; po=po->lst; pe=pe->lst; delete po->nxt; delete pe->nxt; po->nxt=NULL; pe->nxt=NULL; break; default:break; } } if(sp->nxt) { sp=sp->nxt; delete sp->lst; sp->lst=NULL; } else { delete sp; sp=NULL; } po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Value: case Is_Param: pe->nxt=sp; sp->lst=pe; pe=sp; if(sp->nxt) { sp=sp->nxt; sp->lst=NULL; } else { sp=NULL; } pe->nxt=NULL; break; case Is_Fun1p: case Is_Opr1p: case Is_Fun2p: case Is_Opr2p: i=GetRight(sp->equ); while(po!=&op && GetRight(po->equ)>=i) { switch(po->equ->type) { case Is_Fun1p: case Is_Opr1p: po->equ->Lsun=pe->equ; pe->equ=po->equ; po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Fun2p: case Is_Opr2p: case Is_Setvr: po->equ->Lsun=pe->lst->equ; po->equ->Rsun=pe->equ; pe->lst->equ=po->equ; po=po->lst; pe=pe->lst; delete po->nxt; delete pe->nxt; po->nxt=NULL; pe->nxt=NULL; break; default:break; } } po->nxt=sp; sp->lst=po; po=sp; sp=sp->nxt; po->nxt=NULL; sp->lst=NULL; break; case Is_Setvr: i=GetRight(sp->equ); while(po!=&op && GetRight(po->equ)>i) { switch(po->equ->type) { case Is_Fun1p: case Is_Opr1p: po->equ->Lsun=pe->equ; pe->equ=po->equ; po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Fun2p: case Is_Opr2p: case Is_Setvr: po->equ->Lsun=pe->lst->equ; po->equ->Rsun=pe->equ; pe->lst->equ=po->equ; po=po->lst; pe=pe->lst; delete po->nxt; delete pe->nxt; po->nxt=NULL; pe->nxt=NULL; break; default:break; } } po->nxt=sp; sp->lst=po; po=sp; sp=sp->nxt; po->nxt=NULL; sp->lst=NULL; break; default:break; } } while(po!=&op) { switch(po->equ->type) { case Is_Fun1p: case Is_Opr1p: po->equ->Lsun=pe->equ; pe->equ=po->equ; po=po->lst; delete po->nxt; po->nxt=NULL; break; case Is_Fun2p: case Is_Opr2p: case Is_Setvr: po->equ->Lsun=pe->lst->equ; po->equ->Rsun=pe->equ; pe->lst->equ=po->equ; po=po->lst; pe=pe->lst; delete po->nxt; delete pe->nxt; po->nxt=NULL; pe->nxt=NULL; break; default:break; } } rt.nxt->lst=NULL; return rt.nxt; } return NULL; }