rpn-python/interpreter.py

76 lines
1.9 KiB
Python

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# vim:fenc=utf-8
#
# Copyright © 2019 pavle <pavle.portic@tilda.center>
#
# Distributed under terms of the BSD-3-Clause license.
from constants import (
NUMBER, EOF,
PLUS, MINUS, MUL, DIV, IDIV, MOD, POW, SQRT,
HEX, DEC, BIN,
SWAP, POP,
)
class InterpreterError(Exception):
pass
class Interpreter:
def __init__(self):
self.stack = []
self.mode = DEC
self.mode_func = float
def init_lexer(self, lexer):
self.lexer = lexer
self.current_token = self.lexer.get_next_token()
def evaluate_binary_operator(self, token):
if len(self.stack) < 2:
raise InterpreterError('Needs at least 2 values on the stack')
right = self.stack.pop()
left = self.stack.pop()
self.stack.append(token.value(left, right))
def evaluate_unary_operator(self, token):
if len(self.stack) < 1:
raise InterpreterError('Needs at least 1 value on the stack')
value = self.stack.pop()
self.stack.append(token.value(value))
def set_mode(self, token):
self.mode = token.type
self.mode_func = token.value
def parse(self, lexer):
self.init_lexer(lexer)
while self.current_token.type is not EOF:
if self.current_token.type == NUMBER:
self.stack.append(self.current_token.value)
elif self.current_token.type in (PLUS, MINUS, MUL, DIV, IDIV, MOD, POW):
self.evaluate_binary_operator(self.current_token)
elif self.current_token.type in (SQRT):
self.evaluate_unary_operator(self.current_token)
elif self.current_token.type == SWAP:
a = self.stack.pop()
b = self.stack.pop()
self.stack.append(a)
self.stack.append(b)
elif self.current_token.type == POP:
self.stack.pop()
elif self.current_token.type in (HEX, DEC, BIN):
self.set_mode(self.current_token)
else:
raise InterpreterError('Unexpected token')
self.current_token = self.lexer.get_next_token()
return self.stack