#! /usr/bin/env python # -*- coding: utf-8 -*- # vim:fenc=utf-8 # # Copyright © 2019 pavle # # Distributed under terms of the BSD-3-Clause license. import math import operator from constants import ( NUMBER, EOF, PLUS, MINUS, MUL, DIV, IDIV, MOD, POW, SQRT, HEX, DEC, BIN, PI, SWAP, POP, ) class Token(): def __init__(self, type, value): self.type = type self.value = value def __repr__(self): return "<{} {}>".format(self.type, self.value) class Lexer(): def __init__(self, text): self.text = text self.pos = 0 self.current_char = self.text[self.pos] def error(self, value=None): if value is None: raise Exception(f'Unexpected character {self.current_char}') else: raise Exception(f'Unexpected token {value}') def advance(self): self.pos += 1 if self.pos > len(self.text) - 1: self.current_char = None else: self.current_char = self.text[self.pos] def number(self): number = '' while self.current_char is not None and (self.current_char.isdigit() or self.current_char == '.'): number += self.current_char self.advance() return float(number) def skip_whitespace(self): while(self.current_char is not None and self.current_char.isspace()): self.advance() def get_next_token(self): while self.current_char is not None: if self.current_char.isspace(): self.skip_whitespace() continue elif self.current_char.isdigit(): return Token(NUMBER, self.number()) elif self.current_char == '+': self.advance() return Token(PLUS, operator.add) elif self.current_char == '-': self.advance() if self.current_char is not None and self.current_char.isdigit(): return Token(NUMBER, -self.number()) return Token(MINUS, operator.sub) elif self.current_char == '*': self.advance() return Token(MUL, operator.mul) elif self.current_char == '/': self.advance() if self.current_char == '/': self.advance() return Token(IDIV, operator.floordiv) return Token(DIV, operator.truediv) elif self.current_char == '%': self.advance() return Token(MOD, operator.mod) elif self.current_char == '^': self.advance() return Token(POW, operator.pow) elif self.current_char and self.current_char.isalpha(): text = '' while self.current_char and (self.current_char.isalpha() or self.current_char.isdigit() or self.current_char == '_'): text += self.current_char self.advance() check = text.lower() if check.lower() == HEX.lower(): return Token(HEX, hex) elif check.lower() == DEC.lower(): return Token(DEC, float) elif check.lower() == BIN.lower(): return Token(BIN, bin) elif check.lower() == SQRT.lower(): return Token(SQRT, math.sqrt) elif check.lower() == PI.lower(): return Token(NUMBER, math.pi) elif check.lower() == SWAP.lower(): return Token(SWAP, text) elif check.lower() == POP.lower(): return Token(POP, text) else: self.error(text) self.error() return Token(EOF, None)