デジタル忍者ブログ

デジタル忍者ブログ

2019/05/12

pythonでパーサを作る(#1:簡単な数式)


ユーザが書いたプログラムを機械語に変換する処理をコンパイルと言います。


コンパイルは以下の手順で処理されます。




1) 字句解析

 1文字ずつ走査し、この文字が数値なのか、記号なのかを判定します。


2) 構文解析

 1)の字句解析から、これは数式なのかどうかを判定します。


3) 意味解析

 2)の構文解析より、構文が判定したのでこのように処理することを判断します。


4) 最適化

 解析処理の中で、処理が早い方法が判明した場合は最適化を行います。


5) コード生成

 3),4)の結果を機械語として生成します。




ここでいうパーサとは、コンパイル手順の中でいう1),2)が該当します。


字句解析と構文解析を作る事で、


例えば数式の入力があった場合は、


その計算結果を表示するような事ができます。


数式のみに限らず、日本語の入力があった場合、


その品詞を解析して英語に翻訳して表示する事もできます。




今回は非常に簡単な数式、1桁同士の数式のパーサを作ってみます。


そもそも数式とは<数値><記号><数値>という形で構成されています。


<数値>とは0から9の10種類の中から1つだけ存在している値を指します。


<記号>とは'+','-','*','/'の4種類の中から1つだけ存在している文字を指します。


以上のことから、<数式>は次のように定義できます。




<数式>:=<数値><記号><数値>


<数値>:=[0|1|2|3|4|5|6|7|8|9]


<記号>:=[+|-|*|/]



実際にプログラミングしてみます。


parser1.py

units = []
symbol = ''

def calc():
  if symbol == '+':
    return units[0] + units[1]
  if symbol == '-':
    return units[0] - units[1]
  if symbol == '*':
    return units[0] * units[1]
  if symbol == '/':
    return units[0] / units[1]
  return 'E'

def solve():
  global symbol
  global units
  expression = input()
  for c in expression:
    if c.isdigit():
      units.append(int(c))
    else:
      symbol = c
  print(calc())


if __name__ == '__main__':
  solve()

solve()メソッドで入力した数式に対して字句解析を行なっています。

入力する数式は半角スペースが含まれていないことを前提としています。

文字が数値であればunitsに追加し、記号であればsymbolに格納します。

このプログラムでは<数式>の1パターンしかないため、構文解析の処理はしていません。

calc()メソッドでは、字句解析した結果から、symbolに基づいた計算結果を返します。



実行結果は次の通りとなります。


$ python perser1.py 
5+9
14
$ python perser1.py 
9/3
3.0
$


Comment Form

コメント内容(必須)

Comment

現在、コメントはありません。