git @ Cat's Eye Technologies SixtyPical / 6e0ca38
Recast Evaluator as an object. Handle `goto` inside it. Chris Pressey 6 years ago
3 changed file(s) with 162 addition(s) and 137 deletion(s). Raw diff Collapse all Expand all
1717 import traceback
1818
1919 from sixtypical.parser import Parser
20 from sixtypical.evaluator import eval_program
20 from sixtypical.evaluator import Evaluator
2121 from sixtypical.analyzer import analyze_program
2222 from sixtypical.emitter import Emitter, Byte, Word
2323 from sixtypical.compiler import Compiler
8787 emitter.serialize(fh)
8888
8989 if options.execute:
90 context = eval_program(program)
90 context = Evaluator().eval_program(program)
9191 print str(context)
2828 self._store[ref.name] = value
2929
3030
31 def eval_program(program):
32 assert isinstance(program, Program)
33 context = Context()
34 for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C):
35 context.set(ref, 0)
36 main = None
37 for routine in program.routines:
38 context.set(routine.location, routine)
39 if routine.name == 'main':
40 main = routine
41 eval_routine(main, context)
42 return context
31 class Evaluator(object):
4332
33 def eval_program(self, program):
34 assert isinstance(program, Program)
35 context = Context()
36 for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C):
37 context.set(ref, 0)
38 main = None
39 for routine in program.routines:
40 context.set(routine.location, routine)
41 if routine.name == 'main':
42 main = routine
43 self.eval_routine(main, context)
44 return context
4445
45 def eval_routine(routine, context):
46 assert isinstance(routine, Routine)
47 eval_block(routine.block, context)
46 def eval_routine(self, routine, context):
47 assert isinstance(routine, Routine)
48 self.next_routine = routine
49 while self.next_routine:
50 routine = self.next_routine
51 self.next_routine = None
52 self.eval_block(routine.block, context)
4853
54 def eval_block(self, block, context):
55 assert isinstance(block, Block)
56 for i in block.instrs:
57 self.eval_instr(i, context)
58 if self.next_routine:
59 break
4960
50 def eval_block(block, context):
51 assert isinstance(block, Block)
52 for i in block.instrs:
53 eval_instr(i, context)
61 def eval_instr(self, instr, context):
62 assert isinstance(instr, Instr)
63 opcode = instr.opcode
64 dest = instr.dest
65 src = instr.src
5466
55
56 def eval_instr(instr, context):
57 assert isinstance(instr, Instr)
58 opcode = instr.opcode
59 dest = instr.dest
60 src = instr.src
61
62 if opcode == 'ld':
63 result = context.get(src)
64 context.set(FLAG_Z, 1 if result == 0 else 0)
65 context.set(FLAG_N, 1 if result & 128 else 0)
66 context.set(dest, result)
67 elif opcode == 'st':
68 context.set(dest, context.get(src))
69 elif opcode == 'add':
70 carry = context.get(FLAG_C)
71 val = context.get(src)
72 now = context.get(dest)
73 result = now + val + carry
74 if result > 255:
75 result &= 255
76 context.set(FLAG_C, 1)
67 if opcode == 'ld':
68 result = context.get(src)
69 context.set(FLAG_Z, 1 if result == 0 else 0)
70 context.set(FLAG_N, 1 if result & 128 else 0)
71 context.set(dest, result)
72 elif opcode == 'st':
73 context.set(dest, context.get(src))
74 elif opcode == 'add':
75 carry = context.get(FLAG_C)
76 val = context.get(src)
77 now = context.get(dest)
78 result = now + val + carry
79 if result > 255:
80 result &= 255
81 context.set(FLAG_C, 1)
82 else:
83 context.set(FLAG_C, 0)
84 context.set(FLAG_Z, 1 if result == 0 else 0)
85 context.set(FLAG_N, 1 if result & 128 else 0)
86 context.set(dest, result)
87 elif opcode == 'sub':
88 carry = context.get(FLAG_C)
89 val = context.get(src)
90 now = context.get(dest)
91 result = now - val - carry
92 if result < 0:
93 result &= 255
94 context.set(FLAG_C, 1)
95 else:
96 context.set(FLAG_C, 0)
97 context.set(FLAG_Z, 1 if result == 0 else 0)
98 context.set(FLAG_N, 1 if result & 128 else 0)
99 context.set(dest, result)
100 elif opcode == 'inc':
101 val = context.get(dest)
102 result = (val + 1) & 255
103 context.set(FLAG_Z, 1 if result == 0 else 0)
104 context.set(FLAG_N, 1 if result & 128 else 0)
105 context.set(dest, result)
106 elif opcode == 'dec':
107 val = context.get(dest)
108 result = (val - 1) & 255
109 context.set(FLAG_Z, 1 if result == 0 else 0)
110 context.set(FLAG_N, 1 if result & 128 else 0)
111 context.set(dest, result)
112 elif opcode == 'cmp':
113 val = context.get(src)
114 now = context.get(dest)
115 result = now - val
116 context.set(FLAG_Z, 1 if result == 0 else 0)
117 context.set(FLAG_N, 1 if result & 128 else 0)
118 if result < 0:
119 result &= 255
120 context.set(FLAG_C, 1)
121 else:
122 context.set(FLAG_C, 0)
123 elif opcode == 'and':
124 result = context.get(dest) & context.get(src)
125 context.set(FLAG_Z, 1 if result == 0 else 0)
126 context.set(FLAG_N, 1 if result & 128 else 0)
127 context.set(dest, result)
128 elif opcode == 'or':
129 result = context.get(dest) | context.get(src)
130 context.set(FLAG_Z, 1 if result == 0 else 0)
131 context.set(FLAG_N, 1 if result & 128 else 0)
132 context.set(dest, result)
133 elif opcode == 'xor':
134 result = context.get(dest) ^ context.get(src)
135 context.set(FLAG_Z, 1 if result == 0 else 0)
136 context.set(FLAG_N, 1 if result & 128 else 0)
137 context.set(dest, result)
138 elif opcode == 'shl':
139 val = context.get(dest)
140 carry = context.get(FLAG_C)
141 context.set(FLAG_C, 1 if val & 128 else 0)
142 result = ((val << 1) + carry) & 255
143 context.set(FLAG_Z, 1 if result == 0 else 0)
144 context.set(FLAG_N, 1 if result & 128 else 0)
145 context.set(dest, result)
146 elif opcode == 'shr':
147 val = context.get(dest)
148 carry = context.get(FLAG_C)
149 context.set(FLAG_C, 1 if val & 1 else 0)
150 result = (val >> 1) + (carry * 128)
151 context.set(FLAG_Z, 1 if result == 0 else 0)
152 context.set(FLAG_N, 1 if result & 128 else 0)
153 context.set(dest, result)
154 elif opcode == 'call':
155 self.eval_routine(context.get(instr.location), context)
156 elif opcode == 'goto':
157 self.next_routine = context.get(instr.location)
158 elif opcode == 'if':
159 val = context.get(src)
160 test = (val != 0) if not instr.inverted else (val == 0)
161 if test:
162 self.eval_block(instr.block1, context)
163 elif instr.block2:
164 self.eval_block(instr.block2, context)
165 elif opcode == 'repeat':
166 self.eval_block(instr.block, context)
167 while context.get(src) == 0:
168 self.eval_block(instr.block, context)
169 elif opcode == 'copy':
170 context.set(dest, context.get(src))
171 # these are trashed; so could be anything really
172 context.set(REG_A, 0)
173 context.set(FLAG_Z, 0)
174 context.set(FLAG_N, 0)
175 elif opcode == 'with-sei':
176 self.eval_block(instr.block)
77177 else:
78 context.set(FLAG_C, 0)
79 context.set(FLAG_Z, 1 if result == 0 else 0)
80 context.set(FLAG_N, 1 if result & 128 else 0)
81 context.set(dest, result)
82 elif opcode == 'sub':
83 carry = context.get(FLAG_C)
84 val = context.get(src)
85 now = context.get(dest)
86 result = now - val - carry
87 if result < 0:
88 result &= 255
89 context.set(FLAG_C, 1)
90 else:
91 context.set(FLAG_C, 0)
92 context.set(FLAG_Z, 1 if result == 0 else 0)
93 context.set(FLAG_N, 1 if result & 128 else 0)
94 context.set(dest, result)
95 elif opcode == 'inc':
96 val = context.get(dest)
97 result = (val + 1) & 255
98 context.set(FLAG_Z, 1 if result == 0 else 0)
99 context.set(FLAG_N, 1 if result & 128 else 0)
100 context.set(dest, result)
101 elif opcode == 'dec':
102 val = context.get(dest)
103 result = (val - 1) & 255
104 context.set(FLAG_Z, 1 if result == 0 else 0)
105 context.set(FLAG_N, 1 if result & 128 else 0)
106 context.set(dest, result)
107 elif opcode == 'cmp':
108 val = context.get(src)
109 now = context.get(dest)
110 result = now - val
111 context.set(FLAG_Z, 1 if result == 0 else 0)
112 context.set(FLAG_N, 1 if result & 128 else 0)
113 if result < 0:
114 result &= 255
115 context.set(FLAG_C, 1)
116 else:
117 context.set(FLAG_C, 0)
118 elif opcode == 'and':
119 result = context.get(dest) & context.get(src)
120 context.set(FLAG_Z, 1 if result == 0 else 0)
121 context.set(FLAG_N, 1 if result & 128 else 0)
122 context.set(dest, result)
123 elif opcode == 'or':
124 result = context.get(dest) | context.get(src)
125 context.set(FLAG_Z, 1 if result == 0 else 0)
126 context.set(FLAG_N, 1 if result & 128 else 0)
127 context.set(dest, result)
128 elif opcode == 'xor':
129 result = context.get(dest) ^ context.get(src)
130 context.set(FLAG_Z, 1 if result == 0 else 0)
131 context.set(FLAG_N, 1 if result & 128 else 0)
132 context.set(dest, result)
133 elif opcode == 'shl':
134 val = context.get(dest)
135 carry = context.get(FLAG_C)
136 context.set(FLAG_C, 1 if val & 128 else 0)
137 result = ((val << 1) + carry) & 255
138 context.set(FLAG_Z, 1 if result == 0 else 0)
139 context.set(FLAG_N, 1 if result & 128 else 0)
140 context.set(dest, result)
141 elif opcode == 'shr':
142 val = context.get(dest)
143 carry = context.get(FLAG_C)
144 context.set(FLAG_C, 1 if val & 1 else 0)
145 result = (val >> 1) + (carry * 128)
146 context.set(FLAG_Z, 1 if result == 0 else 0)
147 context.set(FLAG_N, 1 if result & 128 else 0)
148 context.set(dest, result)
149 elif opcode == 'call':
150 eval_routine(context.get(instr.location), context)
151 elif opcode == 'if':
152 val = context.get(src)
153 test = (val != 0) if not instr.inverted else (val == 0)
154 if test:
155 eval_block(instr.block1, context)
156 elif instr.block2:
157 eval_block(instr.block2, context)
158 elif opcode == 'repeat':
159 eval_block(instr.block, context)
160 while context.get(src) == 0:
161 eval_block(instr.block, context)
162 elif opcode == 'copy':
163 context.set(dest, context.get(src))
164 # these are trashed; so could be anything really
165 context.set(REG_A, 0)
166 context.set(FLAG_Z, 0)
167 context.set(FLAG_N, 0)
168 elif opcode == 'with-sei':
169 eval_block(instr.block)
170 else:
171 raise NotImplementedError
178 raise NotImplementedError
419419 = x: 200
420420 = y: 0
421421 = z: 0
422
423 goto.
424
425 | routine bar outputs x trashes z, n {
426 | ld x, 200
427 | }
428 |
429 | routine main outputs x trashes a, z, n {
430 | ld y, 200
431 | goto bar
432 | }
433 = a: 0
434 = c: 0
435 = n: 1
436 = v: 0
437 = x: 200
438 = y: 200
439 = z: 0