1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2025-02-10 08:30:38 +00:00

Refine the AST classes even more.

This commit is contained in:
Chris Pressey 2018-03-06 10:43:23 +00:00
parent 2fdba72959
commit 9ad34ed34f
4 changed files with 64 additions and 63 deletions

View File

@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, BlockOp, IfOp from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, WithInterruptsOff
from sixtypical.model import ( from sixtypical.model import (
TYPE_BYTE, TYPE_WORD, TYPE_BYTE, TYPE_WORD,
TableType, BufferType, PointerType, VectorType, RoutineType, TableType, BufferType, PointerType, VectorType, RoutineType,
@ -313,11 +313,13 @@ class Analyzer(object):
def analyze_instr(self, instr, context): def analyze_instr(self, instr, context):
if isinstance(instr, SingleOp): if isinstance(instr, SingleOp):
return self.analyze_single_op(instr, context) self.analyze_single_op(instr, context)
elif isinstance(instr, BlockOp): elif isinstance(instr, If):
return self.analyze_block_op(instr, context) self.analyze_if(instr, context)
elif isinstance(instr, IfOp): elif isinstance(instr, Repeat):
return self.analyze_if_op(instr, context) self.analyze_repeat(instr, context)
elif isinstance(instr, WithInterruptsOff):
self.analyze_block(instr.block, context)
else: else:
raise NotImplementedError raise NotImplementedError
@ -547,7 +549,7 @@ class Analyzer(object):
else: else:
raise NotImplementedError(opcode) raise NotImplementedError(opcode)
def analyze_if_op(self, instr, context): def analyze_if(self, instr, context):
incoming_meaningful = set(context.each_meaningful()) incoming_meaningful = set(context.each_meaningful())
context1 = context.clone() context1 = context.clone()
@ -586,20 +588,15 @@ class Analyzer(object):
context.set_touched(ref) context.set_touched(ref)
context.set_unmeaningful(ref) context.set_unmeaningful(ref)
def analyze_block_op(self, instr, context): def analyze_repeat(self, instr, context):
if instr.opcode == 'repeat': # it will always be executed at least once, so analyze it having
# it will always be executed at least once, so analyze it having # been executed the first time.
# been executed the first time. self.analyze_block(instr.block, context)
self.analyze_block(instr.block, context) if instr.src is not None: # None indicates 'repeat forever'
if instr.src is not None: # None indicates 'repeat forever' context.assert_meaningful(instr.src)
context.assert_meaningful(instr.src)
# now analyze it having been executed a second time, with the context # now analyze it having been executed a second time, with the context
# of it having already been executed. # of it having already been executed.
self.analyze_block(instr.block, context) self.analyze_block(instr.block, context)
if instr.src is not None: if instr.src is not None:
context.assert_meaningful(instr.src) context.assert_meaningful(instr.src)
elif instr.opcode == 'with-sei':
self.analyze_block(instr.block, context)
else:
raise NotImplementedError(opcode)

View File

@ -72,11 +72,15 @@ class SingleOp(Instr):
value_attrs = ('opcode', 'dest', 'src', 'location',) value_attrs = ('opcode', 'dest', 'src', 'location',)
class BlockOp(Instr): class If(Instr):
value_attrs = ('opcode', 'src', 'inverted') value_attrs = ('src', 'inverted')
child_attrs = ('block1', 'block2',)
class Repeat(Instr):
value_attrs = ('src', 'inverted')
child_attrs = ('block',) child_attrs = ('block',)
class IfOp(Instr): class WithInterruptsOff(Instr):
value_attrs = ('src', 'inverted') child_attrs = ('block',)
child_attrs = ('block1', 'block2',)

View File

@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, BlockOp, IfOp from sixtypical.ast import Program, Routine, Block, Instr, SingleOp, If, Repeat, WithInterruptsOff
from sixtypical.model import ( from sixtypical.model import (
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef, ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
TYPE_BIT, TYPE_BYTE, TYPE_WORD, TYPE_BIT, TYPE_BYTE, TYPE_WORD,
@ -144,10 +144,12 @@ class Compiler(object):
def compile_instr(self, instr): def compile_instr(self, instr):
if isinstance(instr, SingleOp): if isinstance(instr, SingleOp):
return self.compile_single_op(instr) return self.compile_single_op(instr)
elif isinstance(instr, BlockOp): elif isinstance(instr, If):
return self.compile_block_op(instr) return self.compile_if(instr)
elif isinstance(instr, IfOp): elif isinstance(instr, Repeat):
return self.compile_if_op(instr) return self.compile_repeat(instr)
elif isinstance(instr, WithInterruptsOff):
return self.compile_with_interrupts_off(instr)
else: else:
raise NotImplementedError raise NotImplementedError
@ -493,7 +495,7 @@ class Compiler(object):
else: else:
raise NotImplementedError(src.type) raise NotImplementedError(src.type)
def compile_if_op(self, instr): def compile_if(self, instr):
cls = { cls = {
False: { False: {
'c': BCC, 'c': BCC,
@ -518,29 +520,27 @@ class Compiler(object):
else: else:
self.emitter.resolve_label(else_label) self.emitter.resolve_label(else_label)
def compile_block_op(self, instr): def compile_repeat(self, instr):
if instr.opcode == 'repeat': top_label = self.emitter.make_label()
top_label = self.emitter.make_label() self.compile_block(instr.block)
self.compile_block(instr.block) if instr.src is None: # indicates 'repeat forever'
if instr.src is None: # indicates 'repeat forever' self.emitter.emit(JMP(Absolute(top_label)))
self.emitter.emit(JMP(Absolute(top_label)))
else:
cls = {
False: {
'c': BCC,
'z': BNE,
},
True: {
'c': BCS,
'z': BEQ,
},
}[instr.inverted].get(instr.src.name)
if cls is None:
raise UnsupportedOpcodeError(instr)
self.emitter.emit(cls(Relative(top_label)))
elif instr.opcode == 'with-sei':
self.emitter.emit(SEI())
self.compile_block(instr.block)
self.emitter.emit(CLI())
else: else:
raise NotImplementedError(opcode) cls = {
False: {
'c': BCC,
'z': BNE,
},
True: {
'c': BCS,
'z': BEQ,
},
}[instr.inverted].get(instr.src.name)
if cls is None:
raise UnsupportedOpcodeError(instr)
self.emitter.emit(cls(Relative(top_label)))
def compile_with_interrupts_off(self, instr):
self.emitter.emit(SEI())
self.compile_block(instr.block)
self.emitter.emit(CLI())

View File

@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
from sixtypical.ast import Program, Defn, Routine, Block, SingleOp, BlockOp, IfOp from sixtypical.ast import Program, Defn, Routine, Block, SingleOp, If, Repeat, WithInterruptsOff
from sixtypical.model import ( from sixtypical.model import (
TYPE_BIT, TYPE_BYTE, TYPE_WORD, TYPE_BIT, TYPE_BYTE, TYPE_WORD,
RoutineType, VectorType, TableType, BufferType, PointerType, RoutineType, VectorType, TableType, BufferType, PointerType,
@ -355,7 +355,7 @@ class Parser(object):
block2 = None block2 = None
if self.scanner.consume('else'): if self.scanner.consume('else'):
block2 = self.block() block2 = self.block()
return IfOp(src=src, block1=block1, block2=block2, inverted=inverted) return If(src=src, block1=block1, block2=block2, inverted=inverted)
elif self.scanner.consume('repeat'): elif self.scanner.consume('repeat'):
inverted = False inverted = False
src = None src = None
@ -366,7 +366,7 @@ class Parser(object):
src = self.locexpr() src = self.locexpr()
else: else:
self.scanner.expect('forever') self.scanner.expect('forever')
return BlockOp(opcode='repeat', src=src, block=block, inverted=inverted) return Repeat(src=src, block=block, inverted=inverted)
elif self.scanner.token in ("ld",): elif self.scanner.token in ("ld",):
# the same as add, sub, cmp etc below, except supports an indlocexpr for the src # the same as add, sub, cmp etc below, except supports an indlocexpr for the src
opcode = self.scanner.token opcode = self.scanner.token
@ -415,7 +415,7 @@ class Parser(object):
self.scanner.expect("interrupts") self.scanner.expect("interrupts")
self.scanner.expect("off") self.scanner.expect("off")
block = self.block() block = self.block()
return BlockOp(opcode='with-sei', src=None, block=block) return WithInterruptsOff(block=block)
elif self.scanner.consume("trash"): elif self.scanner.consume("trash"):
dest = self.locexpr() dest = self.locexpr()
return SingleOp(opcode='trash', src=None, dest=dest) return SingleOp(opcode='trash', src=None, dest=dest)