4 | 4 |
|
5 | 5 |
"""
|
6 | 6 |
|
7 | |
from alpaca.ast import AST
|
|
7 |
class Compiler(object):
|
|
8 |
def __init__(self, alpaca, file):
|
|
9 |
"""alpaca is an ALPACA description in AST form. file is a file-like
|
|
10 |
object to which the compiled code will be written.
|
8 | 11 |
|
|
12 |
"""
|
|
13 |
self.alpaca = alpaca
|
|
14 |
self.file = file
|
9 | 15 |
|
10 | |
def compile(alpaca, file):
|
11 | |
"""alpaca is an ALPACA description in AST form. file is a file-like
|
12 | |
object to which the compiled code will be written.
|
13 | |
|
14 | |
"""
|
15 | |
file.write("""
|
|
16 |
def compile(self):
|
|
17 |
self.file.write("""\
|
16 | 18 |
/*
|
17 | 19 |
* This file was AUTOMATICALLY generated from an ALPACA description.
|
18 | 20 |
* EDIT AT YOUR OWN RISK!
|
19 | 21 |
*/
|
20 | 22 |
""")
|
21 | |
defns = alpaca.children[0]
|
22 | |
for defn in defns.children:
|
23 | |
if defn.type == 'StateDefn':
|
24 | |
compile_state_defn(alpaca, defn, file)
|
25 | |
elif defn.type == 'ClassDefn':
|
26 | |
pass
|
27 | |
elif defn.type == 'NbhdDefn':
|
28 | |
pass
|
|
23 |
defns = self.alpaca.children[0]
|
|
24 |
for defn in defns.children:
|
|
25 |
if defn.type == 'StateDefn':
|
|
26 |
self.compile_state_defn(defn)
|
|
27 |
elif defn.type == 'ClassDefn':
|
|
28 |
pass
|
|
29 |
elif defn.type == 'NbhdDefn':
|
|
30 |
pass
|
|
31 |
else:
|
|
32 |
raise NotImplementedError(repr(defn))
|
|
33 |
|
|
34 |
def compile_state_defn(self, defn):
|
|
35 |
char_repr = defn.children[0]
|
|
36 |
repr_decls = defn.children[1]
|
|
37 |
membership = defn.children[2]
|
|
38 |
rules = defn.children[3]
|
|
39 |
self.file.write("function eval_%s(pf, x, y) {\n" % defn.value);
|
|
40 |
for rule in rules.children:
|
|
41 |
dest = rule.children[0]
|
|
42 |
expr = rule.children[1]
|
|
43 |
self.file.write("if (")
|
|
44 |
self.compile_expr(expr)
|
|
45 |
self.file.write(") {\n return ")
|
|
46 |
self.compile_state_ref(dest)
|
|
47 |
self.file.write(";\n}\n" % (dest))
|
|
48 |
self.file.write("return '%s';\n}\n\n" % defn.value)
|
|
49 |
|
|
50 |
def compile_state_ref(self, ref):
|
|
51 |
# compare to eval_state_ref
|
|
52 |
if ref.type == 'StateRefEq':
|
|
53 |
self.file.write("'%s'" % ref.value)
|
|
54 |
elif ref.type == 'StateRefRel':
|
|
55 |
self.file.write("pf.get(x+%d,y+%d)" % (ref.value[0], ref.value[1]))
|
29 | 56 |
else:
|
30 | |
raise NotImplementedError(repr(defn))
|
|
57 |
raise NotImplementedError(repr(expr))
|
31 | 58 |
|
32 | |
|
33 | |
def compile_state_defn(alpaca, defn, file):
|
34 | |
char_repr = defn.children[0]
|
35 | |
repr_decls = defn.children[1]
|
36 | |
membership = defn.children[2]
|
37 | |
rules = defn.children[3]
|
38 | |
file.write("function eval_%s() {\n" % defn.value);
|
39 | |
for rule in rules.children:
|
40 | |
dest = rule.children[0]
|
41 | |
expr = rule.children[1]
|
42 | |
file.write("if (/*%r*/) { state = /*%r*/; }\n" % (expr, dest))
|
43 | |
file.write("}\n\n")
|
|
59 |
def compile_expr(self, expr):
|
|
60 |
if expr.type == 'BoolOp':
|
|
61 |
self.file.write('(')
|
|
62 |
self.compile_expr(expr.children[0])
|
|
63 |
self.file.write({
|
|
64 |
'or': '||',
|
|
65 |
'and': '&&',
|
|
66 |
'xor': '^^', # XXX yes yes I know this does not work
|
|
67 |
}[expr.value])
|
|
68 |
self.compile_expr(expr.children[1])
|
|
69 |
self.file.write(')')
|
|
70 |
elif expr.type == 'Not':
|
|
71 |
self.file.write('!(')
|
|
72 |
self.compile_expr(expr.children[0])
|
|
73 |
self.file.write(')')
|
|
74 |
elif expr.type == 'BoolLit':
|
|
75 |
self.file.write(expr.value)
|
|
76 |
elif expr.type == 'Relational':
|
|
77 |
# XXX todo: class membership
|
|
78 |
self.file.write('(')
|
|
79 |
self.compile_state_ref(expr.children[0])
|
|
80 |
self.file.write('===')
|
|
81 |
self.compile_state_ref(expr.children[1])
|
|
82 |
self.file.write(')')
|
|
83 |
elif expr.type == 'Adjacency':
|
|
84 |
self.file.write('/* ADJACENCY */')
|
|
85 |
else:
|
|
86 |
raise NotImplementedError(repr(expr))
|