原文见:http://liaoweiqiang.info/index.php/2011/01/19/calculator/
1、设计思路
这里只考虑了+-*/()和数字这些符号,实现的是简单的计算器,重点介绍实现思路,更复杂的计算机运算规则可以在这个基础上扩充。
计算器的主要难点在于优先及的处理,目前已经有的主要是使用堆栈的办法,比如:《基于堆栈的计算器实现算法》,另外的就有这种使用文法分析的方法。
本着动手练脑的实践精神,主要介绍后者。使用文法实现优先级相对来说较容易,利用产生式即可达到,满足优先级低的表达式推导出优先级高的即可。
比如下面的方法里面,加减法(addExpr)推导出乘除法(mulExpr),乘除法(mulExpr)推出 括号运算符号(simpleExpr )。
文法验证部分使用到了http://pegjs.majda.cz/online。
start=addExpr
addExpr=a:mulExpr ‘+’ b:addExpr {return a+b;}//推导表达式第一部分不能是自己,避免文化的递归。
/a:mulExpr ‘-’ b:addExpr {return a-b;}
/a:mulExpr {return a;}//mulExpr=>simpleExp,使用mulExpr最高推导项。
mulExpr=a:simpleExpr’*'b:mulExpr {return a*b}
/a:simpleExpr’/'b:mulExpr {return a/b}
/a:simpleExpr {return a}//直接推导出simpleExpr的项,在文法里面只出现一次。
simpleExpr=”(“a:addExpr”)” {return a;}
/integer
integer “integer”
= digits:[0-9]+ { return parseInt(digits.join(“”), 10); }
注意方法设计规则:
- 文法不能出现递归,推导结果表达式如果由多部分组成,第一部分不能为推导值。
- 如果a=>b,那么aR=bR。如果推导结果可能的值,也能由推导结果表达式推出,那么该推导项使用最高推导项。
- 文法应尽量简洁,相同的推导只出现一次。
2、实现DEMO
见:http://liaoweiqiang.info/wp-content/uploads/2011/01/calculator.html
3、实现代码
见:https://www.google.com/notebook/public/06776177474416402618/BDQjwDAoQy5Xm3Nkl