Files
IMProved/improved/parser.py
2015-07-08 13:07:02 +02:00

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)