mirror of
https://github.com/catseye/SixtyPical.git
synced 2025-02-09 16:31:42 +00:00
Refine the AST classes even more.
This commit is contained in:
parent
2fdba72959
commit
9ad34ed34f
@ -1,6 +1,6 @@
|
||||
# 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 (
|
||||
TYPE_BYTE, TYPE_WORD,
|
||||
TableType, BufferType, PointerType, VectorType, RoutineType,
|
||||
@ -313,11 +313,13 @@ class Analyzer(object):
|
||||
|
||||
def analyze_instr(self, instr, context):
|
||||
if isinstance(instr, SingleOp):
|
||||
return self.analyze_single_op(instr, context)
|
||||
elif isinstance(instr, BlockOp):
|
||||
return self.analyze_block_op(instr, context)
|
||||
elif isinstance(instr, IfOp):
|
||||
return self.analyze_if_op(instr, context)
|
||||
self.analyze_single_op(instr, context)
|
||||
elif isinstance(instr, If):
|
||||
self.analyze_if(instr, context)
|
||||
elif isinstance(instr, Repeat):
|
||||
self.analyze_repeat(instr, context)
|
||||
elif isinstance(instr, WithInterruptsOff):
|
||||
self.analyze_block(instr.block, context)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
@ -547,7 +549,7 @@ class Analyzer(object):
|
||||
else:
|
||||
raise NotImplementedError(opcode)
|
||||
|
||||
def analyze_if_op(self, instr, context):
|
||||
def analyze_if(self, instr, context):
|
||||
incoming_meaningful = set(context.each_meaningful())
|
||||
|
||||
context1 = context.clone()
|
||||
@ -586,20 +588,15 @@ class Analyzer(object):
|
||||
context.set_touched(ref)
|
||||
context.set_unmeaningful(ref)
|
||||
|
||||
def analyze_block_op(self, instr, context):
|
||||
if instr.opcode == 'repeat':
|
||||
# it will always be executed at least once, so analyze it having
|
||||
# been executed the first time.
|
||||
self.analyze_block(instr.block, context)
|
||||
if instr.src is not None: # None indicates 'repeat forever'
|
||||
context.assert_meaningful(instr.src)
|
||||
def analyze_repeat(self, instr, context):
|
||||
# it will always be executed at least once, so analyze it having
|
||||
# been executed the first time.
|
||||
self.analyze_block(instr.block, context)
|
||||
if instr.src is not None: # None indicates 'repeat forever'
|
||||
context.assert_meaningful(instr.src)
|
||||
|
||||
# now analyze it having been executed a second time, with the context
|
||||
# of it having already been executed.
|
||||
self.analyze_block(instr.block, context)
|
||||
if instr.src is not None:
|
||||
context.assert_meaningful(instr.src)
|
||||
elif instr.opcode == 'with-sei':
|
||||
self.analyze_block(instr.block, context)
|
||||
else:
|
||||
raise NotImplementedError(opcode)
|
||||
# now analyze it having been executed a second time, with the context
|
||||
# of it having already been executed.
|
||||
self.analyze_block(instr.block, context)
|
||||
if instr.src is not None:
|
||||
context.assert_meaningful(instr.src)
|
||||
|
@ -72,11 +72,15 @@ class SingleOp(Instr):
|
||||
value_attrs = ('opcode', 'dest', 'src', 'location',)
|
||||
|
||||
|
||||
class BlockOp(Instr):
|
||||
value_attrs = ('opcode', 'src', 'inverted')
|
||||
class If(Instr):
|
||||
value_attrs = ('src', 'inverted')
|
||||
child_attrs = ('block1', 'block2',)
|
||||
|
||||
|
||||
class Repeat(Instr):
|
||||
value_attrs = ('src', 'inverted')
|
||||
child_attrs = ('block',)
|
||||
|
||||
|
||||
class IfOp(Instr):
|
||||
value_attrs = ('src', 'inverted')
|
||||
child_attrs = ('block1', 'block2',)
|
||||
class WithInterruptsOff(Instr):
|
||||
child_attrs = ('block',)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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 (
|
||||
ConstantRef, LocationRef, IndexedRef, IndirectRef, AddressRef,
|
||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||
@ -144,10 +144,12 @@ class Compiler(object):
|
||||
def compile_instr(self, instr):
|
||||
if isinstance(instr, SingleOp):
|
||||
return self.compile_single_op(instr)
|
||||
elif isinstance(instr, BlockOp):
|
||||
return self.compile_block_op(instr)
|
||||
elif isinstance(instr, IfOp):
|
||||
return self.compile_if_op(instr)
|
||||
elif isinstance(instr, If):
|
||||
return self.compile_if(instr)
|
||||
elif isinstance(instr, Repeat):
|
||||
return self.compile_repeat(instr)
|
||||
elif isinstance(instr, WithInterruptsOff):
|
||||
return self.compile_with_interrupts_off(instr)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
@ -493,7 +495,7 @@ class Compiler(object):
|
||||
else:
|
||||
raise NotImplementedError(src.type)
|
||||
|
||||
def compile_if_op(self, instr):
|
||||
def compile_if(self, instr):
|
||||
cls = {
|
||||
False: {
|
||||
'c': BCC,
|
||||
@ -518,29 +520,27 @@ class Compiler(object):
|
||||
else:
|
||||
self.emitter.resolve_label(else_label)
|
||||
|
||||
def compile_block_op(self, instr):
|
||||
if instr.opcode == 'repeat':
|
||||
top_label = self.emitter.make_label()
|
||||
self.compile_block(instr.block)
|
||||
if instr.src is None: # indicates 'repeat forever'
|
||||
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())
|
||||
def compile_repeat(self, instr):
|
||||
top_label = self.emitter.make_label()
|
||||
self.compile_block(instr.block)
|
||||
if instr.src is None: # indicates 'repeat forever'
|
||||
self.emitter.emit(JMP(Absolute(top_label)))
|
||||
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())
|
||||
|
@ -1,6 +1,6 @@
|
||||
# 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 (
|
||||
TYPE_BIT, TYPE_BYTE, TYPE_WORD,
|
||||
RoutineType, VectorType, TableType, BufferType, PointerType,
|
||||
@ -355,7 +355,7 @@ class Parser(object):
|
||||
block2 = None
|
||||
if self.scanner.consume('else'):
|
||||
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'):
|
||||
inverted = False
|
||||
src = None
|
||||
@ -366,7 +366,7 @@ class Parser(object):
|
||||
src = self.locexpr()
|
||||
else:
|
||||
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",):
|
||||
# the same as add, sub, cmp etc below, except supports an indlocexpr for the src
|
||||
opcode = self.scanner.token
|
||||
@ -415,7 +415,7 @@ class Parser(object):
|
||||
self.scanner.expect("interrupts")
|
||||
self.scanner.expect("off")
|
||||
block = self.block()
|
||||
return BlockOp(opcode='with-sei', src=None, block=block)
|
||||
return WithInterruptsOff(block=block)
|
||||
elif self.scanner.consume("trash"):
|
||||
dest = self.locexpr()
|
||||
return SingleOp(opcode='trash', src=None, dest=dest)
|
||||
|
Loading…
x
Reference in New Issue
Block a user