|
| 1 | +#!/usr/bin/env python3 |
| 2 | + |
| 3 | +import sys |
| 4 | +from array import array |
| 5 | +from typing import Mapping, MutableSequence, Callable, Iterable, Sequence, Union, Any |
| 6 | + |
| 7 | + |
| 8 | +OPERATORS: Mapping[str, Callable[[float, float], float]] = { |
| 9 | + '+': lambda a, b: a + b, |
| 10 | + '-': lambda a, b: a - b, |
| 11 | + '*': lambda a, b: a * b, |
| 12 | + '/': lambda a, b: a / b, |
| 13 | + '^': lambda a, b: a ** b, |
| 14 | +} |
| 15 | + |
| 16 | + |
| 17 | +Stack = MutableSequence[float] |
| 18 | + |
| 19 | + |
| 20 | +def parse_token(token: str) -> Union[str, float]: |
| 21 | + try: |
| 22 | + return float(token) |
| 23 | + except ValueError: |
| 24 | + return token |
| 25 | + |
| 26 | + |
| 27 | +def evaluate(tokens: Iterable[str], stack: Stack) -> None: |
| 28 | + for token in tokens: |
| 29 | + atom = parse_token(token) |
| 30 | + if isinstance(atom, float): |
| 31 | + stack.append(atom) |
| 32 | + else: # not float, must be operator |
| 33 | + op = OPERATORS[atom] |
| 34 | + x, y = stack.pop(), stack.pop() |
| 35 | + result = op(y, x) |
| 36 | + stack.append(result) |
| 37 | + |
| 38 | + |
| 39 | +def display(s: Stack) -> str: |
| 40 | + items = (repr(n) for n in s) |
| 41 | + return ' │ '.join(items) + ' →' |
| 42 | + |
| 43 | + |
| 44 | +def repl(input_fn: Callable[[Any], str] = input) -> None: |
| 45 | + """Read-Eval-Print-Loop""" |
| 46 | + |
| 47 | + print('Use CTRL+C to quit.', file=sys.stderr) |
| 48 | + stack: Stack = array('d') |
| 49 | + |
| 50 | + while True: |
| 51 | + try: |
| 52 | + line = input_fn('> ') # Read |
| 53 | + except (EOFError, KeyboardInterrupt): |
| 54 | + break |
| 55 | + try: |
| 56 | + evaluate(line.split(), stack) # Eval |
| 57 | + except IndexError: |
| 58 | + print('*** Not enough arguments.', file=sys.stderr) |
| 59 | + except KeyError as exc: |
| 60 | + print('*** Unknown operator:', exc.args[0], file=sys.stderr) |
| 61 | + print(display(stack)) # Print |
| 62 | + |
| 63 | + print() |
| 64 | + |
| 65 | + |
| 66 | +if __name__ == '__main__': |
| 67 | + repl() |
0 commit comments