我想了解计算器的工作原理。例如,假设我们输入中缀符号如下:
1 + 2 x 10 - 2
解析器必须遵守数学中的常用规则。在上面的例子中,这意味着:
1 +(2 x 10) - 2 = 19(而不是3 x 10 - 2 = 28)
然后考虑一下:
1 + 2 x((2/9)+ 7) - 2
它是否涉及抽象语法树?二叉树?如何确保操作顺序在数学上是正确的?我必须使用shunting-yard算法将其转换为后缀表示法吗?然后,我将如何用后缀表示法解析它?为什么要先转换?
是否有教程显示如何构建这些相对简单的计算器?或者有人可以解释一下吗?
答案 0 :(得分:22)
评估表达式的一种方法是使用递归下降解析器。 http://en.wikipedia.org/wiki/Recursive_descent_parser
以下是BNF格式的示例语法: http://en.wikipedia.org/wiki/Backus-Naur_form
Expr ::= Term ('+' Term | '-' Term)*
Term ::= Factor ('*' Factor | '/' Factor)*
Factor ::= ['-'] (Number | '(' Expr ')')
Number ::= Digit+
这里*表示前面的元素重复零次或多次,+表示一次或多次重复,方括号表示可选。
语法确保首先收集最高优先级的元素,或者在这种情况下首先计算。 当您访问语法中的每个节点时,不是构建抽象语法树,而是评估当前节点并返回值。
示例代码(不完美,但应该让您了解如何将BNF映射到代码):
def parse_expr():
term = parse_term()
while 1:
if match('+'):
term = term + parse_term()
elif match('-'):
term = term - parse_term()
else: return term
def parse_term():
factor = parse_factor()
while 1:
if match('*'):
factor = factor * parse_factor()
elif match('/'):
factor = factor / parse_factor()
else: return factor
def parse_factor():
if match('-'):
negate = -1
else: negate = 1
if peek_digit():
return negate * parse_number()
if match('('):
expr = parse_expr()
if not match(')'): error...
return negate * expr
error...
def parse_number():
num = 0
while peek_digit():
num = num * 10 + read_digit()
return num
显示1 + 2 * 10 - 2
的示例将如何评估:
call parse_expr stream is 1 + 2 * 10 - 2
call parse term
call parse factor
call parse number which returns 1 stream is now + 2 * 10 - 2
match '+' stream is now 2 * 10 - 2
call parse factor
call parse number which returns 2 stream is now * 10 - 2
match '*' stream is now 10 - 2
call parse number which returns 10 stream is now - 2
computes 2 * 10, return 20
compute 1 + 20 -> 21
match '-' stream is now 2
call parse factor
call parse number which returns 2 stream is empty
compute 21 - 2, return 19
return 19
答案 1 :(得分:3)
尝试查看Antlr。这是我用来构建自定义编译器/解析器的东西......并且很容易与计算器相关,这对于创建来说非常简单。