構文解析!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とかでもっと綺麗になるんじゃないかって。
終わり。