-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.py
149 lines (128 loc) · 6.08 KB
/
parser.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
from functools import reduce
from re import VERBOSE
from funcparserlib.lexer import make_tokenizer, Token
from funcparserlib.parser import some, a, skip, with_forward_decls, many, maybe
from ast import Add, Sub, Mul, Div, Lt, Gt, Eq, Or, And, Neq, Not, Le, Ge, Assignment, IfThenElse, While, Print, Declaration, CmdList, Variable, Const, Function, Call, Object, Dot, Pointer, HeapAssign, String, Mod
from env import Env
from functions import Alloc, ReadLine
from programs import diverses, heap_and_string, fibonacci, read_line, prim, iftest
__author__ = 'Donhilion'
def tokenize(string):
"""
Generates a list of tokens from the given string.
"""
specs = [
('Space', (r'[ \t\r\n]+',)),
('Or', ('\|\|',)),
('And', ('&&',)),
('Neq', ('!=',)),
('Not', ('!',)),
('Eq', ('==',)),
('Assign', (':=',)),
('Le', ('<=',)),
('Ge', ('>=',)),
('Dot', ('\.',)),
('Op', (r'[\-+/*=<>%]',)),
('Ident', (r'[A-Za-z][A-Za-z_0-9]*',)),
('Number', (r'(0|([1-9][0-9]*))', VERBOSE)),
('Semicolon', (';',)),
('Comma', (',',)),
('Lb', ('{',)),
('Rb', ('}',)),
('Lp', ('\(',)),
('Rp', ('\)',)),
('String', ('"[^"]*"',)),
]
useless = ['Space']
t = make_tokenizer(specs)
return [x for x in t(string) if x.type not in useless]
def parse(seq):
"""
Parses the list of tokens and generates an AST.
"""
def eval_expr(z, list):
return reduce(lambda s, (f, x): f(s, x), list, z)
unarg = lambda f: lambda x: f(*x)
tokval = lambda x: x.value # returns the value of a token
toktype = lambda t: some(lambda x: x.type == t) >> tokval # checks type of token
const = lambda x: lambda _: x # like ^^^ in Scala
eval_cond = lambda x: x[1](x[0], x[2])
op = lambda s: a(Token('Op', s)) >> tokval # return the value if token is Op
op_ = lambda s: skip(op(s)) # checks if token is Op and ignores it
ident = lambda s: a(Token('Ident', s)) >> tokval # return the value if token is Op
ident_ = lambda s: skip(ident(s)) # checks if token is Op and ignores it
lst = lambda x: [x[0],] + x[1]
makeop = lambda s, f: op(s) >> const(f)
add = makeop('+', Add)
sub = makeop('-', Sub)
mul = makeop('*', Mul)
div = makeop('/', Div)
mod = makeop('%', Mod)
lt = makeop('<', Lt)
gt = makeop('>', Gt)
eq = toktype('Eq') >> const(Eq)
orop = toktype('Or') >> const(Or)
andop = toktype('And') >> const(And)
neq = toktype('Neq') >> const(Neq)
notop = toktype('Not') >> const(Not)
le = toktype('Le') >> const(Le)
ge = toktype('Ge') >> const(Ge)
point_op = mul | div | mod
line_op = add | sub
comp_op = lt | gt | eq | neq | notop | le | ge
combinator = orop | andop
empty_fun = lambda x: ()
heap_assign = with_forward_decls(lambda: pointer + skip(toktype('Assign')) + exp >> unarg(HeapAssign))
assign = with_forward_decls(lambda: toktype('Ident') + skip(toktype('Assign')) + exp >> unarg(Assignment))
ifexp = with_forward_decls(lambda: ident_('if') + cond + cmd + \
maybe(ident_('else') + cmd) >> unarg(IfThenElse))
whileexp = with_forward_decls(lambda: ident_('while') + cond + cmd >> unarg(While))
printexp = with_forward_decls(lambda: ident_('print') + exp >> Print)
vardef = with_forward_decls(lambda: ident_('var') + toktype('Ident') + op_('=') + exp \
>> unarg(Declaration))
arglst = with_forward_decls(lambda: exp + many(skip(toktype('Comma')) + exp) >> lst)
returnexp = with_forward_decls(lambda: ident_('return') + exp)
call = with_forward_decls(lambda: dot + skip(toktype('Lp') + toktype('Rp')) >> Call | \
dot + skip(toktype('Lp')) + arglst + skip(toktype('Rp')) >> unarg(Call))
args = toktype('Ident') + many(skip(toktype('Comma')) + toktype('Ident')) >> lst
decl = with_forward_decls(lambda: toktype('Ident') + op_('=') + exp >> unarg(Declaration))
decls = decl + many(skip(toktype('Semicolon')) + decl) >> lst
cmd = with_forward_decls(lambda: call | returnexp | assign | ifexp | whileexp | printexp | vardef | heap_assign | \
skip(toktype('Lb')) + cmd_list + skip(toktype('Rb')))
cmd_list = (cmd + many(skip(toktype('Semicolon')) + cmd) >> lst) >> CmdList
variable = toktype('Ident') >> Variable
dotop = toktype('Dot') >> const(Dot)
dot = variable + many(dotop + toktype('Ident')) >> unarg(eval_expr)
pointer = with_forward_decls(lambda: op_('*') + exp >> Pointer)
constexp = toktype('Number') >> Const
string = toktype('String') >> String
factor = with_forward_decls(lambda: dot | constexp | pointer | string | \
skip(toktype('Lp')) + exp + skip(toktype('Rp')))
summand = factor + many(point_op + factor) >> unarg(eval_expr)
function = ident_('function') + (skip(toktype('Lp')) + skip(toktype('Rp')) >> empty_fun | \
skip(toktype('Lp')) + args + skip(toktype('Rp'))) + skip(toktype('Lb')) + cmd_list \
+ skip(toktype('Rb')) >> unarg(Function)
objectexp = ident_('object') + skip(toktype('Lb')) + decls + skip(toktype('Rb')) >> Object
exp = with_forward_decls(lambda: objectexp | function | call | \
summand + many(line_op + summand) >> unarg(eval_expr) | cond)
cond = (exp + comp_op + exp >> eval_cond) + many(combinator + (exp + comp_op + exp >> eval_cond)) >> unarg(eval_expr)
return cmd.parse(seq)
def interpret(code, print_ast=False):
ast = parse(tokenize(code))
if print_ast:
print(ast)
env = Env()
env.declare("alloc", Alloc())
env.declare("readline", ReadLine())
env.declare("true", 1)
env.declare("false", 0)
ast.eval(env)
#interpret(diverses)
#
#interpret(heap_and_string, True)
#
#interpret(fibonacci)
#
interpret(prim)
#interpret(iftest)
#interpret(read_line, True)