一般来说,一个运算符的优先级越高,位置越低。例如表达式3+45中,*的优先级高于+,所以它是+节点的子节点。但是如果把()加到3+4上,即:(3+4)*5,两个符号的优先级就颠倒了。如果我们使用nearley(一种用类BNF文法表示的parsergenerator),有如下代码,可以看到每个不同优先级的算子都对应一条文法规则。当不同优先级的运算符增加时,我们需要写的文法规则也会相应增加:expression->additive{%d=>d[0]%}additive->additive"+"multiple{%d=>d[0]+d[2]%}|加法“-”倍数{%d=>d[0]-d[2]%}|多个{%d=>d[0]%}多个->多个“*”因子{%d=>d[0]*d[2]%}|多个“/”因子{%d=>d[0]/d[2]%}|因子{%d=>d[0]%}因子->"("添加剂")"{%d=>d[1]%}|%number{%d=>Number(d[0])%}这样加一个运算符会给我们的解析器实现带来一定的开销,那么有没有一种通用的方式来处理我们的运算符优先级呢?算子优先级算法就是为此而生。下面是算子优先级算法的代码。为了学习方便,这里我们写的lexer和parser尽量简单,所以我们的parser不允许符号之间有空格,只支持解析个位数(即支持3+4,不支持33+4):classBinaryExpr{构造函数(left,op,right){this.left=leftthis.op=opthis.right=right}}classOpPrecedenceParser{constructor(lexer,precedenceMap){this.lexer=lexerthis.precedenceMap=precedenceMap}expression(){letright=this.factor()letnext;while(next=this.nextOperator()){right=this.doShift(right)}returnright}doShift(left){constop=this.lexer.read()letright=this.factor()letnext;while((next=this.nextOperator())&&this.rightIsExpr(op,next)){right=this.doShift(right)}returnnewBinaryExpr(left,op,right)}nextOperator(){constop=this.lexer.nextToken()if(this.precedenceMap.get(op))returnop返回null}factor(){if(this.lexer.nextToken()==="("){this.token()constexp=this.expression()this.token()returnexp}else{returnthis.lexer.read()}}token(){returnthis.lexer.read()}rightIsExpr(op1,op2){returnthis.precedenceMap.get(op1)
