Skip to content

Instantly share code, notes, and snippets.

@fallenflint
Last active July 14, 2016 13:57
Show Gist options
  • Save fallenflint/6c18b176ed1e970ff6056408457288fd to your computer and use it in GitHub Desktop.
Save fallenflint/6c18b176ed1e970ff6056408457288fd to your computer and use it in GitHub Desktop.
Poland Notation Simple evaluator
import unittest
class PolandTestCase(unittest.TestCase):
def test_basic(self):
self.assertEqual(poland_eval('2 4 + 2 *'), 12)
def test_space_agnostic(self):
res1 = poland_eval('2 4+2*')
res2 = poland_eval('2 4 + 2*')
self.assertEqual(res1, 12)
self.assertEqual(res2, 12)
self.assertEqual(res1, res2)
def test_unary(self):
self.assertEqual(poland_eval('2-'), -2)
self.assertEqual(poland_eval('2 +'), 2)
OPERATOR_MAP = {
# format:
# 'operator': ('binary__method', [unary_method]),
'+': ('__add__', '__pos__'),
'-': ('__sub__', '__neg__'),
'/': ('__div__',),
'*': ('__mul__',),
}
OPERATORS = ''.join(OPERATOR_MAP.keys())
def poland_eval(value_string):
# Just insert spaces around operators, for splitting
for operator in OPERATORS:
value_string = value_string.replace(operator, ' %s ' % operator)
stack = []
for item in value_string.split():
if item not in OPERATORS:
stack.append(float(item))
else:
operands = stack[-2:]
if len(operands) == 1:
try:
operator_func = OPERATOR_MAP[item][1] # whether it's unary
result = getattr(operands[0], operator_func)()
except IndexError:
raise ValueError('Unary operator "%s" is not supported!' % item)
elif not operands:
raise ValueError('Expressions is syntactycally wrong, operator without operand!')
else:
operator_func = OPERATOR_MAP[item][0]
result = getattr(operands[0], operator_func)(operands[1])
stack[-2:] = [result]
if len(stack) > 1:
raise ValueError('Expression is syntactycally wrong, unexpected estimate!')
return stack[0]
if __name__ == '__main__':
unittest.main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment