py-calc/lexer.py
2026-04-10 16:39:57 +02:00

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))