From b7b28830d7fe8c119b46145b2a39b8f9f364c4a9 Mon Sep 17 00:00:00 2001 From: Chris Pressey Date: Tue, 12 Dec 2017 14:09:17 +0000 Subject: [PATCH] Introducing a new pseudo-opcode is rarely an elegant solution. --- HISTORY.md | 1 + README.md | 5 ----- src/sixtypical/parser.py | 17 +++++++++++++++++ tests/SixtyPical Syntax.md | 22 ++++++++++++++++++++++ 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/HISTORY.md b/HISTORY.md index f4386fd..f754c66 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -5,6 +5,7 @@ History of SixtyPical ---- * Can `call` and `goto` routines that are defined further down in the source code. +* `assign`, a form of `copy` that can copy (to a vector) a routine that is defined further down. 0.9 --- diff --git a/README.md b/README.md index d0160c8..21dec0f 100644 --- a/README.md +++ b/README.md @@ -46,11 +46,6 @@ Finish the little demo "game" where you can move a block around the screen with the joystick (i.e. bring it up to par with the original demo game that was written for SixtyPical) -### `copy` (to vectors) routines that are defined further down in the source code - -We might have a graph of states that refer to each other and that want to `goto` -each other. Thus we need this. We have it for other things. - ### Allow branches to diverge in what they touch For example, if the routine inputs and outputs `foo`, and one branch of an `if` diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index e27b10b..878d9ec 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -64,6 +64,14 @@ class Parser(object): if not isinstance(self.symbols[name].model.type, ExecutableType): raise SyntaxError('Illegal call of non-executable "%s"' % name) instr.location = self.symbols[name].model + if instr.opcode in ('assign',): + name = instr.src + if name not in self.symbols: + raise SyntaxError('Undefined routine "%s"' % name) + if not isinstance(self.symbols[name].model.type, ExecutableType): + raise SyntaxError('Illegal assign of non-executable "%s"' % name) + instr.src = self.symbols[name].model + instr.opcode = 'copy' return Program(defns=defns, routines=routines) @@ -286,6 +294,15 @@ class Parser(object): self.scanner.expect(',') dest = self.indlocexpr() return Instr(opcode=opcode, dest=dest, src=src) + elif self.scanner.token == 'assign': + opcode = self.scanner.token + self.scanner.scan() + src = self.label() + self.scanner.expect(',') + dest = self.indlocexpr() + instr = Instr(opcode=opcode, dest=dest, src=src) + self.backpatch_instrs.append(instr) + return instr elif self.scanner.consume("with"): self.scanner.expect("interrupts") self.scanner.expect("off") diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index 961997b..91d3913 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -356,6 +356,28 @@ A vector can name itself in its inputs, outputs, and trashes. | } = ok +A routine can be copied into a vector before the routine appears in the program. +*However*, in order to do this currently, one needs to use the special opcode +form `assign`, which is equivalent to `copy` except that the routine need not +have already appeared in the program. + + | vector cinv + | inputs cinv, a + | outputs cinv, x + | trashes a, x, z, n + | @ 788 + | + | routine main { + | with interrupts off { + | assign foo, cinv + | } + | call cinv + | } + | routine foo { + | ld a, 0 + | } + = ok + goto. | routine foo {