Pythonでスタックマシン風の計算機

タイトルそのまま。

import math

global stack
stack = []

numbers = map(str, range(0,10))

operators = ["+", "-", "/", "*"]


def clear_stack():
    for i in range(len(stack)):
        stack.pop()

def concat(st):
    out = ""
    for i in range(0, len(st)):
        tmp = st.pop()
        if tmp in numbers or isinstance(tmp, float) or tmp == "." :
            out = str(tmp) + out
        else:
            stack.append(tmp)
            return float(out)
    return float(out)

def calc():
    r = stack.pop()
    op = stack.pop()
    l = stack.pop()

    if op == "+":
        return l + r
    if op == "-":
        return l - r
    if op == "/":
        return l / r
    if op == "*":
        return l * r

def solve(token):

    if token == ".":
        if stack[len(stack)-1] != "." or len(stack) != 0:
            stack.append(".")

    if token in numbers:
        print "NUM:" + str(token)
        stack.append(token)

    if token in operators:
        if stack[len(stack)-1] in operators:
            stack.pop()
            stack.append(token)
            return

        print "OP:" + str(token)
        stack.append(concat(stack))
        if len(stack) == 3:
            stack.append(calc())
        stack.append(token)

    if token == "=":
        stack.append(concat(stack))
        if len(stack) == 3:
            stack.append(calc())

    if token == "%" and not stack[len(stack)-1] in operators:
        stack.append(concat(stack))
        per = stack.pop()
        stack.append(stack[0] * (per/100))

    if token == "r":
        stack.append(concat(stack))
        tmp = stack.pop()
        stack.append(math.sqrt(tmp))

    if token == "b":
        stack.pop()

    if token == "i":
        stack.append(concat(stack))
        tmp = stack.pop()
        stack.append(1/tmp)

    if token == "c":
        stack.append(concat(stack))
        if not stack[len(stack)-1] in operators: stack.pop()

    if token == "C":
        clear_stack()

    return

if __name__ == "__main__":
    while 1:
        token = raw_input("> ")
        solve(token)
        print stack


bで一文字削除、rで平方根、iで逆数、cはCE、CはC、ほかはだいたい電卓と同じ。
まだ入力ステートの制御ができていないがそこそこ動く。
ざっくり書いたので非効率なところは多そう。

動作

$ python stack_calc.py 
> 1
NUM:1
['1']
> 2
NUM:2
['1', '2']
> =
[12.0]
> 1
NUM:1
[12.0, '1']
> + 
OP:+
[12.01, '+']
> /
[12.01, '/']
> 10
[12.01, '/']
> 1
NUM:1
[12.01, '/', '1']
> 0
NUM:0
[12.01, '/', '1', '0']
> =
[1.201]
> r
[1.0959014554237987]
> +
OP:+
[1.09590145542, '+']
> 8 
NUM:8
[1.09590145542, '+', '8']
> 4
NUM:4
[1.09590145542, '+', '8', '4']
> %
[1.09590145542, '+', 0.9205572225527999]
> =
[2.016458677973]
> +
OP:+
[2.01645867797, '+']
> 1
NUM:1
[2.01645867797, '+', '1']
> .
[2.01645867797, '+', '1', '.']
> 1
NUM:1
[2.01645867797, '+', '1', '.', '1']
> =
[3.11645867797]