From 9ad34ed34f09175bdda810941bef903d711cb28a Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Tue, 6 Mar 2018 10:43:23 +0000 Subject: [PATCH] Refine the AST classes even more. --- src/sixtypical/analyzer.py | 43 ++++++++++++-------------- src/sixtypical/ast.py | 14 ++++++--- src/sixtypical/compiler.py | 62 +++++++++++++++++++------------------- src/sixtypical/parser.py | 8 ++--- 4 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/sixtypical/analyzer.py b/src/sixtypical/analyzer.py index 9c9589e..9f07485 100644 --- a/src/sixtypical/analyzer.py +++ b/src/sixtypical/analyzer.py @@ -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) diff --git a/src/sixtypical/ast.py b/src/sixtypical/ast.py index 075742f..d4ab321 100644 --- a/src/sixtypical/ast.py +++ b/src/sixtypical/ast.py @@ -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',) diff --git a/src/sixtypical/compiler.py b/src/sixtypical/compiler.py index 55e64c9..7e160c3 100644 --- a/src/sixtypical/compiler.py +++ b/src/sixtypical/compiler.py @@ -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()) diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index aedab41..6b3ec84 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -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)