带括号的简单计算器如何工作?

Posted

技术标签:

【中文标题】带括号的简单计算器如何工作?【英文标题】:How does a simple calculator with parentheses work? 【发布时间】:2012-04-04 20:18:48 【问题描述】:

我想了解计算器的工作原理。例如,假设我们有这样的中缀符号输入:

1 + 2 x 10 - 2

解析器必须遵守数学中的通用规则。在上面的例子中,这意味着:

1 + (2 x 10) - 2 = 19(而不是 3 x 10 - 2 = 28)

然后考虑一下:

1 + 2 x ((2 / 9) + 7) - 2

它是否涉及抽象语法树?二叉树?如何确保运算顺序在数学上是正确的?我必须使用调车码算法将其转换为后缀表示法吗?然后,我将如何用后缀表示法解析它?为什么首先要转换?

是否有说明这些相对简单的计算器是如何构建的教程?或者谁能​​解释一下?

【问题讨论】:

评估它的方法有很多。这是一个:en.wikipedia.org/wiki/Shunting-yard_algorithm 您喜欢哪种语言?这是 .Net 中使用 Irony.net 的示例。 blog.miraclespain.com/archive/2009/Oct-07.html 【参考方案1】:

评估表达式的一种方法是使用递归下降解析器。 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+

这里*表示前面的元素重复0次或多次,+表示重复一次或多次,方括号表示可选。

语法确保优先级最高的元素首先被收集在一起,或者在这种情况下,首先被评估。 当您访问语法中的每个节点时,您无需构建抽象语法树,而是评估当前节点并返回值。

示例代码(不完美,但应该让您了解如何将 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

【讨论】:

coffeescript 中的工作示例 :) gist.github.com/coderek/a19733e9b48e93e6bdb1 抱歉吹毛求疵,但原始 BNF 仅使用递归,而 Wirth 的 EBNF 增加了重复 x(现代符号:x^*)和可选性 [x](现代:x^0 ,1)【参考方案2】:

尝试查看Antlr。这是我用来构建自定义编译器/解析器的东西......并且可以轻松地与计算器相关联,这将是一件非常简单的事情。

【讨论】:

以上是关于带括号的简单计算器如何工作?的主要内容,如果未能解决你的问题,请参考以下文章

python3简单实现支持括号的加减乘除运算

Python带括号的计算器

c++链表类模板问题(不要用c语言,用c++)

你好,C语言设计一个简单的计算器 你以前在别人那回答的那个是对的么?

Java GUI带括号的计算器(支持小数)

计算器 栈 带括号 2016 10 21