86 lines
No EOL
2.1 KiB
Python
86 lines
No EOL
2.1 KiB
Python
from tokens import TokenType, Token
|
|
|
|
|
|
DIGITS = '0123456789'
|
|
|
|
class Lexer:
|
|
|
|
def __init__(self, text):
|
|
self.text = iter(text)
|
|
self.advance()
|
|
|
|
def advance(self):
|
|
try:
|
|
self.current_char = next(self.text)
|
|
except StopIteration:
|
|
self.current_char = None
|
|
|
|
def generate_tokens(self):
|
|
while self.current_char != None:
|
|
if self.current_char == '.' or self.current_char in DIGITS:
|
|
yield self.generate_number()
|
|
elif self.current_char == '+':
|
|
self.advance()
|
|
yield Token(TokenType.PLUS)
|
|
elif self.current_char == '-':
|
|
self.advance()
|
|
yield Token(TokenType.MINUS)
|
|
elif self.current_char == '~':
|
|
self.advance()
|
|
yield Token(TokenType.NEGATE)
|
|
elif self.current_char == '*':
|
|
self.advance()
|
|
yield Token(TokenType.MULTIPLY)
|
|
elif self.current_char == '/':
|
|
self.advance()
|
|
yield Token(TokenType.DIVIDE)
|
|
elif self.current_char == '^':
|
|
self.advance()
|
|
yield Token(TokenType.POWER)
|
|
elif self.current_char == '%':
|
|
self.advance()
|
|
yield Token(TokenType.MODULE)
|
|
elif self.current_char == '!':
|
|
self.advance()
|
|
yield Token(TokenType.FACTORIAL)
|
|
elif self.current_char == '@':
|
|
self.advance()
|
|
yield Token(TokenType.AVERAGE)
|
|
elif self.current_char == '&':
|
|
self.advance()
|
|
yield Token(TokenType.MINIMUM)
|
|
elif self.current_char == '$':
|
|
self.advance()
|
|
yield Token(TokenType.MAXIMUM)
|
|
elif self.current_char == '[':
|
|
self.advance()
|
|
yield Token(TokenType.LBRACKET)
|
|
elif self.current_char == ']':
|
|
self.advance()
|
|
yield Token(TokenType.RBRACKET)
|
|
else:
|
|
raise Exception(f"Illegal character '{self.current_char}'")
|
|
|
|
|
|
def generate_number(self):
|
|
decimal_point_count = 0
|
|
number_str = self.current_char
|
|
self.advance()
|
|
|
|
while self.current_char != None and (self.current_char == '.' or self.current_char in DIGITS):
|
|
|
|
if self.current_char == '.':
|
|
decimal_point_count += 1
|
|
if decimal_point_count > 1:
|
|
break
|
|
|
|
number_str += self.current_char
|
|
self.advance()
|
|
|
|
if number_str.startswith('.'):
|
|
number_str = '0' + number_str
|
|
if number_str.endswith('.'):
|
|
number_str += '0'
|
|
|
|
# Create the token
|
|
return Token(TokenType.NUMBER, float(number_str)) |