From 6e0ca3838e7d6c1e7008d6bd83c0b5b365021fdd Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Tue, 20 Oct 2015 14:39:32 +0100 Subject: [PATCH] Recast Evaluator as an object. Handle `goto` inside it. --- bin/sixtypical | 4 +- src/sixtypical/evaluator.py | 277 +++++++++++++++++----------------- tests/SixtyPical Execution.md | 18 +++ 3 files changed, 162 insertions(+), 137 deletions(-) diff --git a/bin/sixtypical b/bin/sixtypical index 32cc6df..00645dc 100755 --- a/bin/sixtypical +++ b/bin/sixtypical @@ -18,7 +18,7 @@ import sys import traceback from sixtypical.parser import Parser -from sixtypical.evaluator import eval_program +from sixtypical.evaluator import Evaluator from sixtypical.analyzer import analyze_program from sixtypical.emitter import Emitter, Byte, Word from sixtypical.compiler import Compiler @@ -88,5 +88,5 @@ if __name__ == '__main__': emitter.serialize(fh) if options.execute: - context = eval_program(program) + context = Evaluator().eval_program(program) print str(context) diff --git a/src/sixtypical/evaluator.py b/src/sixtypical/evaluator.py index 53c3b9d..90b9513 100644 --- a/src/sixtypical/evaluator.py +++ b/src/sixtypical/evaluator.py @@ -29,144 +29,151 @@ class Context(object): self._store[ref.name] = value -def eval_program(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 - eval_routine(main, context) - return context +class Evaluator(object): + 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): - assert isinstance(routine, Routine) - eval_block(routine.block, context) + def eval_routine(self, routine, context): + assert isinstance(routine, Routine) + 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): - assert isinstance(block, Block) - for i in block.instrs: - eval_instr(i, context) + def eval_instr(self, instr, context): + assert isinstance(instr, Instr) + opcode = instr.opcode + dest = instr.dest + src = instr.src - -def eval_instr(instr, context): - assert isinstance(instr, Instr) - opcode = instr.opcode - dest = instr.dest - src = instr.src - - if opcode == 'ld': - result = 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 == 'st': - context.set(dest, context.get(src)) - elif opcode == 'add': - carry = context.get(FLAG_C) - val = context.get(src) - now = context.get(dest) - result = now + val + carry - if result > 255: - result &= 255 - context.set(FLAG_C, 1) + if opcode == 'ld': + result = 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 == 'st': + context.set(dest, context.get(src)) + elif opcode == 'add': + carry = context.get(FLAG_C) + val = context.get(src) + now = context.get(dest) + result = now + val + carry + if result > 255: + 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 == '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': + 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: - 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 == '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 + raise NotImplementedError diff --git a/tests/SixtyPical Execution.md b/tests/SixtyPical Execution.md index af3cf1a..1b526d0 100644 --- a/tests/SixtyPical Execution.md +++ b/tests/SixtyPical Execution.md @@ -420,3 +420,21 @@ Indirect call. = x: 200 = y: 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