Skip to content

Instantly share code, notes, and snippets.

@inaz2
Created November 17, 2012 02:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save inaz2/4092867 to your computer and use it in GitHub Desktop.
Save inaz2/4092867 to your computer and use it in GitHub Desktop.
2012-11-16 g6k.rb #2
#!/usr/bin/env python
import sys
class PolandParser:
"""
EXPR := '(' EXPR ')' | OP TERM TERM
TERM := EXPR | NUM
OP := '+' | '-' | '*' | '/'
NUM := (any integer)
"""
def __init__(self, line):
"""
>>> parser = PolandParser('+ 1 (+ + 1 2 (* 3 4))')
>>> parser.tokens
['+', '1', '(', '+', '+', '1', '2', '(', '*', '3', '4', ')', ')']
"""
line = line.replace('(', ' ( ').replace(')', ' ) ')
self.tokens = line.split()
def run(self):
"""
>>> parser = PolandParser('+ 1 (+ + 1 2 (* 3 4))')
>>> parser.run()
16
>>> parser = PolandParser('(+ (+ 1 1) (+ 1 1))')
>>> parser.run()
4
>>> parser = PolandParser('(+ (+ (- 99 11) (+ 11 11)) -111)')
>>> parser.run()
-1
>>> parser = PolandParser('(+ (+ 1 1) (+ 1 1)')
>>> parser.run()
Traceback (most recent call last):
Exception: tokens are insufficient
"""
try:
return self.parse_expr()
except IndexError:
raise Exception('tokens are insufficient')
def parse_expr(self):
""""
>>> parser = PolandParser('(+ 7 5)')
>>> parser.parse_expr()
12
>>> parser = PolandParser('+ 7 5')
>>> parser.parse_expr()
12
>>> parser = PolandParser('(+ 7 5 ]')
>>> parser.parse_expr()
Traceback (most recent call last):
Exception: unclosed parenthesis: ]
>>> parser = PolandParser('7 5')
>>> parser.parse_expr()
Traceback (most recent call last):
Exception: no operator: 7
"""
token = self.tokens.pop(0)
if token == '(':
value = self.parse_expr()
token2 = self.tokens.pop(0)
if token2 == ')':
return value
else:
raise Exception("unclosed parenthesis: %s" % token2)
elif token == '+':
value1 = self.parse_term()
value2 = self.parse_term()
return value1 + value2
elif token == '-':
value1 = self.parse_term()
value2 = self.parse_term()
return value1 - value2
elif token == '*':
value1 = self.parse_term()
value2 = self.parse_term()
return value1 * value2
elif token == '/':
value1 = self.parse_term()
value2 = self.parse_term()
return value1 / value2
else:
raise Exception("no operator: %s" % token)
def parse_term(self):
""""
>>> parser = PolandParser('7')
>>> parser.parse_term()
7
>>> parser = PolandParser('(+ 7 5)')
>>> parser.parse_term()
12
"""
try:
num = int(self.tokens[0])
self.tokens.pop(0)
return num
except ValueError:
return self.parse_expr()
if __name__ == '__main__':
line = sys.stdin.readline().strip()
parser = PolandParser(line)
print parser.run()
$ python -m doctest -v 01-poland.py
Trying:
parser = PolandParser('+ 1 (+ + 1 2 (* 3 4))')
Expecting nothing
ok
Trying:
parser.tokens
Expecting:
['+', '1', '(', '+', '+', '1', '2', '(', '*', '3', '4', ')', ')']
ok
Trying:
parser = PolandParser('(+ 7 5)')
Expecting nothing
ok
Trying:
parser.parse_expr()
Expecting:
12
ok
Trying:
parser = PolandParser('+ 7 5')
Expecting nothing
ok
Trying:
parser.parse_expr()
Expecting:
12
ok
Trying:
parser = PolandParser('(+ 7 5 ]')
Expecting nothing
ok
Trying:
parser.parse_expr()
Expecting:
Traceback (most recent call last):
Exception: unclosed parenthesis: ]
ok
Trying:
parser = PolandParser('7 5')
Expecting nothing
ok
Trying:
parser.parse_expr()
Expecting:
Traceback (most recent call last):
Exception: no operator: 7
ok
Trying:
parser = PolandParser('7')
Expecting nothing
ok
Trying:
parser.parse_term()
Expecting:
7
ok
Trying:
parser = PolandParser('(+ 7 5)')
Expecting nothing
ok
Trying:
parser.parse_term()
Expecting:
12
ok
Trying:
parser = PolandParser('+ 1 (+ + 1 2 (* 3 4))')
Expecting nothing
ok
Trying:
parser.run()
Expecting:
16
ok
Trying:
parser = PolandParser('(+ (+ 1 1) (+ 1 1))')
Expecting nothing
ok
Trying:
parser.run()
Expecting:
4
ok
Trying:
parser = PolandParser('(+ (+ (- 99 11) (+ 11 11)) -111)')
Expecting nothing
ok
Trying:
parser.run()
Expecting:
-1
ok
Trying:
parser = PolandParser('(+ (+ 1 1) (+ 1 1)')
Expecting nothing
ok
Trying:
parser.run()
Expecting:
Traceback (most recent call last):
Exception: tokens are insufficient
ok
2 items had no tests:
01-poland
01-poland.PolandParser
4 items passed all tests:
2 tests in 01-poland.PolandParser.__init__
8 tests in 01-poland.PolandParser.parse_expr
4 tests in 01-poland.PolandParser.parse_term
8 tests in 01-poland.PolandParser.run
22 tests in 6 items.
22 passed and 0 failed.
Test passed.
@rightgo09
Copy link

if name == 'main': がないと実行されないものなんでしょうか?

@inaz2
Copy link
Author

inaz2 commented Nov 17, 2012

if name == '__main__':がなくても、コードは動きます。
この1行は、このファイルが他のスクリプトから import されたときのためにつけています。

この1行がない場合、他のスクリプトから import されたときにも PolandParser が実際に走ってしまいます。
たいてい import される場合は単にクラスを定義するだけにとどめておきたいので、
この1行をつけることで「直接コードを実行したときのみ、標準入力やコマンドライン引数をもとに走らせる」ことができます。

こうしておけば、他のスクリプトから次のようにPolandParserクラスが再利用できるので便利です。
(ただしこの場合ファイル名を数字から始めることはできないので、poland.pyとして保存したものとします)

#!/usr/bin/env python

import sys
from poland import PolandParser

# 対話的に計算させてみる
while True:
    sys.stdout.write('> ')
    line = sys.stdin.readline().strip()
    print PolandParser(line).run()

@rightgo09
Copy link

理解しました!
丁寧にありがとうございます。
直接でも間接でも使えるようにする配慮なのですね。たまに起動スクリプトがPythonが使われてて、覗くと↑みたいなのが書かれててなんだろうと思っていたのでした。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment