91 lines
2.0 KiB
Python
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)
|
|
|