added ast definition and parser
This commit is contained in:
130
improved/parser.py
Normal file
130
improved/parser.py
Normal file
@@ -0,0 +1,130 @@
|
||||
"""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)
|
Reference in New Issue
Block a user