mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-25 23:49:17 +00:00
Recast Evaluator as an object. Handle goto
inside it.
This commit is contained in:
parent
be76b9a00d
commit
6e0ca3838e
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user