web-dev-qa-db-ja.com

括弧付きの単純な計算機はどのように機能しますか?

電卓のしくみを学びたいです。たとえば、次のような中置記法の入力があるとします。

1 + 2 x 10-2

パーサーは、数学の一般的な規則を尊重する必要があります。上記の例では、これは次のことを意味します。

1 +(2 x 10)-2 = 19(3 x 10-2 = 28ではなく)

そして、これを考慮してください:

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

抽象構文木が含まれていますか?二分木?演算の順序はどのようにして数学的に正しいことが保証されますか?これを後置表記に変換するには、操車場アルゴリズムを使用する必要がありますか?次に、後置記法でどのように解析しますか?そもそもなぜ改宗するのか?

これらの比較的単純な計算機がどのように構築されるかを示すチュートリアルはありますか?または誰かが説明できますか?

22
Proud Member

式を評価する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回以上繰り返されることを意味し、+は1回以上繰り返されることを意味し、角括弧はオプションを意味します。

文法は、最も優先度の高い要素が最初に一緒に収集されるか、この場合は最初に評価されることを保証します。文法の各ノードにアクセスすると、抽象構文ツリーを構築する代わりに、現在のノードを評価して値を返します。

コード例(完全ではありませんが、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
23
bw1024

Antlr を見てみてください。これは、私がカスタムコンパイラ/パーサーを構築するために使用したものです...そして、作成するのが非常に簡単な計算機に簡単に関連付けることができます。

3
pengibot