構文解析!part 2

http://reonreon3reon.hatenablog.com/entry/2012/11/27/020832
↑このときは構文解析じゃあありませんでした。愚直に実装したただの…うん。
(完成度は満足してるんだからいいだろ!いい加減にしろ!)

それから月日は壱年経ちまして、最近「構文解析かけるようになりたいなぁ」って思うようになって
ちゃんと勉強して書きました。

これもC言語を無理やりPythonに直して機能を増やしてる感じなので見た目は悪いです。
もちろん書き直します。

def number(begin):
  global i
  val = 0

  if begin[i] == "(":
    i+=1
    val = expression(begin)
    i+=1

  while begin[i].isdigit():
    val *= 10
    val += int(begin[i])
    i+=1
  return val

def term(begin):

  global i
  val = number(begin)

  while True:
    if begin[i] is "*":
      i += 1
      if begin[i] is "*":
        i += 1
        val **= number(begin)
        continue
      val *= number(begin)
    elif begin[i] is "/":
      i += 1
      val2 = number(begin)
      if val < 0 or val2 < 0:
        val = func1(str(abs2(val,val2)))
      else:
        val /= 1.0*val2
        val = func1(str(val))
    else:
      break

  return val

def expression(begin):

  global i
  val = term(begin)

  while True:
    if begin[i] is "+":
      i += 1
      val += expression(begin)
    elif begin[i] is "-":
      i += 1
      val -= expression(begin)
    else:
      break
  return val

#-3/2 == -2 -> -1.5
abs2 = lambda x,y: int(x*1.0/y)
func1 = lambda x: float(x[0:x.index('.')+3])
def main():
  while True:
    try:
      ex = raw_input()+"="
      global i
      i = 0
      print expression(ex)
    except EOFError:
      break

if __name__ == '__main__':
  main()


Test Case:

1+1
123+321
100-50
100-123
123*3
8/2
100/3
(10+5)*2
(5-10)*3
(100/2)+(100/3)-(11*3)
2**3
(10**3)/1000
-3/2

実行結果:

2
444
50
-23
369
4.0
33.33
30
-15
50.33
8
1.0
-1.5

僕は、小数点は第3桁までを出力するようにしました。
あと、Pythonって -3/2 を -2と出力するらしいです。だからそれも -3/2 = -1.5にするようにしました。

さきほどのテストケースをPythonで出力すると…
実行結果:

>>> 1+1
2
>>> 123+321
444
>>> 100-50
50
>>> 100-123
-23
>>> 123*3
369
>>> 8/2
4
>>> 100/3
33
>>> (10+5)*2
30
>>> (5-10)*3
-15
>>> (100/2)+(100/3)-(11*3)
50
>>> 2**3
8
>>> (10**3)/1000
1
>>> -3/2
-2

僕的に**というn乗できるようにしたのが面白いです。

まとめ:
もっとソース綺麗に書けるようにしたい。
具体的にglobal iをイテレータとしてやればもっと綺麗じゃないかって。
whileとかはyieldとかでもっと綺麗になるんじゃないかって。


終わり。