131 lines
3.5 KiB
Python
131 lines
3.5 KiB
Python
"""The parser"""
|
|
|
|
from functools import reduce
|
|
|
|
from .ast import *
|
|
from .parser_combinator import *
|
|
from .tokenize import *
|
|
|
|
ARITHMETIC_PRECEDENCE = [
|
|
['*', '/'],
|
|
['+', '-'],
|
|
]
|
|
|
|
BOOLEAN_PRECEDENCE = [
|
|
['and'],
|
|
['or'],
|
|
]
|
|
|
|
#Helper
|
|
def precedence(value_parser, precedence_levels, combine):
|
|
def op_parser(precedence_level):
|
|
return any_op_in_list(precedence_level) ^ combine
|
|
parser = value_parser * op_parser(precedence_levels[0])
|
|
for precedence_level in precedence_levels[1:]:
|
|
parser = parser * op_parser(precedence_level)
|
|
return parser
|
|
|
|
def process_binop(op):
|
|
return lambda l, r: BinArithmeticExp(op, l, r)
|
|
|
|
def process_relop(parsed):
|
|
((left, op), right) = parsed
|
|
return RelationExp(op, left, right)
|
|
|
|
def process_logic(op):
|
|
if op == 'and':
|
|
return lambda l, r: AndExp(l, r)
|
|
elif op == 'or':
|
|
return lambda l, r: OrExp(l, r)
|
|
else:
|
|
raise RuntimeError('unknown logic operator: ' + op)
|
|
|
|
def process_group(parsed):
|
|
((_, p), _) = parsed
|
|
return p
|
|
|
|
def any_op_in_list(ops):
|
|
op_parsers = [keyword(op) for op in ops]
|
|
parser = reduce(lambda l, r: l | r, op_parsers)
|
|
return parser
|
|
|
|
#Parser
|
|
num = Tag(INT) ^ (lambda i: int(i))
|
|
imp_id = Tag(ID)
|
|
|
|
def keyword(kw):
|
|
return Reserved(kw, RESERVED)
|
|
|
|
def arithmetic_group():
|
|
return keyword('(') + Lazy(arithmetic_exp) + keyword(')') ^ process_group
|
|
|
|
def arithmetic_value():
|
|
return ((num ^ (lambda i: IntArithmeticExp(i))) |
|
|
(id ^ (lambda v: VarArithmeticExp(v))))
|
|
|
|
def arithmetic_term():
|
|
return arithmetic_value() | arithmetic_group()
|
|
|
|
def arithmetic_exp():
|
|
return precedence(arithmetic_term(),
|
|
ARITHMETIC_PRECEDENCE,
|
|
process_binop)
|
|
|
|
def boolean_not():
|
|
return keyword('not') + Lazy(boolean_term) ^ (lambda parsed: NotExp(parsed[1]))
|
|
|
|
def boolean_relop():
|
|
relops = ['<', '<=', '>', '>=', '=', '!=']
|
|
return arithmetic_exp() + any_op_in_list(relops) + arithmetic_exp() ^ process_relop
|
|
|
|
def boolean_group():
|
|
return keyword('(') + Lazy(boolean_exp) + keyword(')') ^ process_group
|
|
|
|
def boolean_term():
|
|
return boolean_not() | boolean_relop() | boolean_group()
|
|
|
|
def boolean_exp():
|
|
return precedence(boolean_term(),
|
|
BOOLEAN_PRECEDENCE,
|
|
process_logic)
|
|
|
|
def assign_statement():
|
|
def internal(parsed):
|
|
((name, _), exp) = parsed
|
|
return AssignStatement(name, exp)
|
|
return imp_id + keyword(':=') + arithmetic_exp() ^ internal
|
|
|
|
def if_statement():
|
|
def internal(parsed):
|
|
(((((_, condition), _), on_true), false_parsed), _) = parsed
|
|
if false_parsed:
|
|
(_, on_false) = false_parsed
|
|
else:
|
|
on_false = None
|
|
return IfStatement(condition, on_true, on_false)
|
|
return (keyword('if') + boolean_exp()
|
|
+ keyword('then') + Lazy(statements)
|
|
+ Opt(keyword('else') + Lazy(statements))
|
|
+ keyword('end') ^ internal)
|
|
|
|
def while_statement():
|
|
def internal(parsed):
|
|
((((_, condition), _), body), _) = parsed
|
|
return WhileStatement(condition, body)
|
|
return (keyword('while') + boolean_exp()
|
|
+ keyword('do') + Lazy(statements)
|
|
+ keyword('end') ^ internal)
|
|
|
|
def statement():
|
|
return assign_statement() | if_statement() | while_statement()
|
|
|
|
def statements():
|
|
sep = keyword(';') ^ (lambda x: lambda l, r: CompoundStatement(l, r))
|
|
return Exp(statement(), sep)
|
|
|
|
def parser():
|
|
return Phrase(statements())
|
|
|
|
def imp_parser(tokens):
|
|
return parser()(tokens, 0)
|