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