1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-29 03:51:35 +00:00

Recast Evaluator as an object. Handle goto inside it.

This commit is contained in:
Chris Pressey 2015-10-20 14:39:32 +01:00
parent be76b9a00d
commit 6e0ca3838e
3 changed files with 162 additions and 137 deletions

View File

@ -18,7 +18,7 @@ import sys
import traceback import traceback
from sixtypical.parser import Parser from sixtypical.parser import Parser
from sixtypical.evaluator import eval_program from sixtypical.evaluator import Evaluator
from sixtypical.analyzer import analyze_program from sixtypical.analyzer import analyze_program
from sixtypical.emitter import Emitter, Byte, Word from sixtypical.emitter import Emitter, Byte, Word
from sixtypical.compiler import Compiler from sixtypical.compiler import Compiler
@ -88,5 +88,5 @@ if __name__ == '__main__':
emitter.serialize(fh) emitter.serialize(fh)
if options.execute: if options.execute:
context = eval_program(program) context = Evaluator().eval_program(program)
print str(context) print str(context)

View File

@ -29,144 +29,151 @@ class Context(object):
self._store[ref.name] = value self._store[ref.name] = value
def eval_program(program): class Evaluator(object):
assert isinstance(program, Program)
context = Context()
for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C):
context.set(ref, 0)
main = None
for routine in program.routines:
context.set(routine.location, routine)
if routine.name == 'main':
main = routine
eval_routine(main, context)
return context
def eval_program(self, program):
assert isinstance(program, Program)
context = Context()
for ref in (REG_A, REG_X, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C):
context.set(ref, 0)
main = None
for routine in program.routines:
context.set(routine.location, routine)
if routine.name == 'main':
main = routine
self.eval_routine(main, context)
return context
def eval_routine(routine, context): def eval_routine(self, routine, context):
assert isinstance(routine, Routine) assert isinstance(routine, Routine)
eval_block(routine.block, context) self.next_routine = routine
while self.next_routine:
routine = self.next_routine
self.next_routine = None
self.eval_block(routine.block, context)
def eval_block(self, block, context):
assert isinstance(block, Block)
for i in block.instrs:
self.eval_instr(i, context)
if self.next_routine:
break
def eval_block(block, context): def eval_instr(self, instr, context):
assert isinstance(block, Block) assert isinstance(instr, Instr)
for i in block.instrs: opcode = instr.opcode
eval_instr(i, context) dest = instr.dest
src = instr.src
if opcode == 'ld':
def eval_instr(instr, context): result = context.get(src)
assert isinstance(instr, Instr) context.set(FLAG_Z, 1 if result == 0 else 0)
opcode = instr.opcode context.set(FLAG_N, 1 if result & 128 else 0)
dest = instr.dest context.set(dest, result)
src = instr.src elif opcode == 'st':
context.set(dest, context.get(src))
if opcode == 'ld': elif opcode == 'add':
result = context.get(src) carry = context.get(FLAG_C)
context.set(FLAG_Z, 1 if result == 0 else 0) val = context.get(src)
context.set(FLAG_N, 1 if result & 128 else 0) now = context.get(dest)
context.set(dest, result) result = now + val + carry
elif opcode == 'st': if result > 255:
context.set(dest, context.get(src)) result &= 255
elif opcode == 'add': context.set(FLAG_C, 1)
carry = context.get(FLAG_C) else:
val = context.get(src) context.set(FLAG_C, 0)
now = context.get(dest) context.set(FLAG_Z, 1 if result == 0 else 0)
result = now + val + carry context.set(FLAG_N, 1 if result & 128 else 0)
if result > 255: context.set(dest, result)
result &= 255 elif opcode == 'sub':
context.set(FLAG_C, 1) carry = context.get(FLAG_C)
val = context.get(src)
now = context.get(dest)
result = now - val - carry
if result < 0:
result &= 255
context.set(FLAG_C, 1)
else:
context.set(FLAG_C, 0)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'inc':
val = context.get(dest)
result = (val + 1) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'dec':
val = context.get(dest)
result = (val - 1) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'cmp':
val = context.get(src)
now = context.get(dest)
result = now - val
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
if result < 0:
result &= 255
context.set(FLAG_C, 1)
else:
context.set(FLAG_C, 0)
elif opcode == 'and':
result = context.get(dest) & context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'or':
result = context.get(dest) | context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'xor':
result = context.get(dest) ^ context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'shl':
val = context.get(dest)
carry = context.get(FLAG_C)
context.set(FLAG_C, 1 if val & 128 else 0)
result = ((val << 1) + carry) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'shr':
val = context.get(dest)
carry = context.get(FLAG_C)
context.set(FLAG_C, 1 if val & 1 else 0)
result = (val >> 1) + (carry * 128)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'call':
self.eval_routine(context.get(instr.location), context)
elif opcode == 'goto':
self.next_routine = context.get(instr.location)
elif opcode == 'if':
val = context.get(src)
test = (val != 0) if not instr.inverted else (val == 0)
if test:
self.eval_block(instr.block1, context)
elif instr.block2:
self.eval_block(instr.block2, context)
elif opcode == 'repeat':
self.eval_block(instr.block, context)
while context.get(src) == 0:
self.eval_block(instr.block, context)
elif opcode == 'copy':
context.set(dest, context.get(src))
# these are trashed; so could be anything really
context.set(REG_A, 0)
context.set(FLAG_Z, 0)
context.set(FLAG_N, 0)
elif opcode == 'with-sei':
self.eval_block(instr.block)
else: else:
context.set(FLAG_C, 0) raise NotImplementedError
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'sub':
carry = context.get(FLAG_C)
val = context.get(src)
now = context.get(dest)
result = now - val - carry
if result < 0:
result &= 255
context.set(FLAG_C, 1)
else:
context.set(FLAG_C, 0)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'inc':
val = context.get(dest)
result = (val + 1) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'dec':
val = context.get(dest)
result = (val - 1) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'cmp':
val = context.get(src)
now = context.get(dest)
result = now - val
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
if result < 0:
result &= 255
context.set(FLAG_C, 1)
else:
context.set(FLAG_C, 0)
elif opcode == 'and':
result = context.get(dest) & context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'or':
result = context.get(dest) | context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'xor':
result = context.get(dest) ^ context.get(src)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'shl':
val = context.get(dest)
carry = context.get(FLAG_C)
context.set(FLAG_C, 1 if val & 128 else 0)
result = ((val << 1) + carry) & 255
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'shr':
val = context.get(dest)
carry = context.get(FLAG_C)
context.set(FLAG_C, 1 if val & 1 else 0)
result = (val >> 1) + (carry * 128)
context.set(FLAG_Z, 1 if result == 0 else 0)
context.set(FLAG_N, 1 if result & 128 else 0)
context.set(dest, result)
elif opcode == 'call':
eval_routine(context.get(instr.location), context)
elif opcode == 'if':
val = context.get(src)
test = (val != 0) if not instr.inverted else (val == 0)
if test:
eval_block(instr.block1, context)
elif instr.block2:
eval_block(instr.block2, context)
elif opcode == 'repeat':
eval_block(instr.block, context)
while context.get(src) == 0:
eval_block(instr.block, context)
elif opcode == 'copy':
context.set(dest, context.get(src))
# these are trashed; so could be anything really
context.set(REG_A, 0)
context.set(FLAG_Z, 0)
context.set(FLAG_N, 0)
elif opcode == 'with-sei':
eval_block(instr.block)
else:
raise NotImplementedError

View File

@ -420,3 +420,21 @@ Indirect call.
= x: 200 = x: 200
= y: 0 = y: 0
= z: 0 = z: 0
goto.
| routine bar outputs x trashes z, n {
| ld x, 200
| }
|
| routine main outputs x trashes a, z, n {
| ld y, 200
| goto bar
| }
= a: 0
= c: 0
= n: 1
= v: 0
= x: 200
= y: 200
= z: 0