#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2019 pavle # # 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