rpn-python/lexer.py

91 lines
2.0 KiB
Python

import operator
from token import Token
from constants import (
NUMBER, EOF,
PLUS, MINUS, MUL, DIV, POW,
HEX, DEC, BIN,
)
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()
return Token(MINUS, operator.sub)
elif self.current_char == '*':
self.advance()
return Token(MUL, operator.mul)
elif self.current_char == '/':
self.advance()
return Token(DIV, operator.truediv)
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()
if text.lower() == 'hex':
return Token(HEX, hex)
elif text.lower() == 'dec':
return Token(DEC, float)
elif text.lower() == 'bin':
return Token(BIN, bin)
else:
self.error(text)
self.error()
return Token(EOF, None)