Files
mcDandy-more_math/src/more_math/parser.py
T
2025-07-27 11:44:43 +02:00

91 lines
3.0 KiB
Python

class Parser:
def __init__(self, tokens):
self.tokens = tokens # List of (type, value) tuples
self.pos = 0
def peek(self):
return self.tokens[self.pos] if self.pos < len(self.tokens) else ('ENDMARKER', '')
def consume(self):
token = self.peek()
self.pos += 1
return token
def parse_expression(self):
"""Expression: term (PLUS|MINUS term)*"""
left = self.parse_term()
while True:
tok_type, value = self.peek()
if value in ['+', '-']:
op = value
self.consume() # Consume '+' or '-'
right = self.parse_term()
left = ('BINOP', (op, left, right))
else:
break
return left
def parse_term(self):
"""Term: factor (MULT|DIVIDE|POW|MOD factor)*"""
left = self.parse_factor()
while True:
tok_type, value = self.peek()
if value in ['*', '/', '^', '%']:
op = value
self.consume() # Consume '*', '/', '^' nebo '%'
right = self.parse_factor()
left = ('BINOP', (op, left, right))
else:
break
return left
def parse_arguments(self):
"""Parse comma-separated argument list for function calls."""
args = []
if self.peek()[0] == 'OP' and self.peek()[1] == ')':
return args # žádné argumenty
while True:
arg = self.parse_expression()
args.append(arg)
tok_type, value = self.peek()
if tok_type == 'OP' and value == ',':
self.consume() # přeskoč čárku
else:
break
return args
def parse_factor(self):
"""Factor: unary_op factor | variable | function_call | number | parenthesis"""
tok_type, value = self.peek()
# Podpora unárních operátorů + a -
if tok_type == 'OP' and value in ('+', '-'):
op = value
self.consume()
operand = self.parse_factor()
return ('UNARYOP', (op, operand))
if tok_type == 'OP' and value == '(':
self.consume() # Skip '('
expr = self.parse_expression()
assert self.peek()[0] == 'OP' and self.peek()[1] == ')', "Missing closing parenthesis"
self.consume() # Skip ')'
return ('PARENTHESIS', expr)
elif tok_type == 'NAME':
func_name = value
self.consume()
if self.peek()[0] == 'OP' and self.peek()[1] == '(':
self.consume() # Skip '('
args = self.parse_arguments()
assert self.peek()[0] == 'OP' and self.peek()[1] == ')', "Missing closing parenthesis"
self.consume()
return ('FUNCTION', (func_name.upper(), args))
else:
return ('VARIABLE', func_name)
elif tok_type == 'NUMBER':
num = float(value)
self.consume()
return ('LITERAL', num)