diff --git a/README.markdown b/README.markdown index 93e15b5..897d0bd 100644 --- a/README.markdown +++ b/README.markdown @@ -33,10 +33,8 @@ TODO For 0.6: -* `interrupt` routines. -* `goto` (tail call). -* `vector` type... with declared `inputs` `outputs` `trashes`? -* `copy` instruction... that can copy a constant to a user-def mem loc. +* declared `inputs` `outputs` `trashes` on the `vector` type. +* `goto` (tail call) a routine or a vector. * A more involved demo for the C64 — one that sets up an interrupt. For 0.7: @@ -48,8 +46,10 @@ For 0.7: At some point... +* `interrupt` routines. * add line number (or at least routine name) to error messages. * 6502-mnemonic aliases (`sec`, `clc`) * other handy aliases (`eq` for `z`, etc.) +* have `copy` instruction able to copy a constant to a user-def mem loc, etc. * add absolute addressing in shl/shr, absolute-indexed for add, sub, etc. * check and disallow recursion. diff --git a/doc/SixtyPical.md b/doc/SixtyPical.md index 7eaddc5..d41eb4a 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -83,6 +83,17 @@ A location in memory may be given explicitly on a user-defined memory location. byte table screen @ 1024 +A user-defined vector memory location is decorated with READS and WRITES lists +like a routine (see below), and it may only hold addresses of routines which +are compatible. (Meaning, the routine's inputs (resp. outputs, trashes) +must be a subset of the vector's inputs (resp. outputs, trashes.)) + + vector actor_logic + inputs a, score + outputs x + trashes y + @ $c000 + Routines -------- @@ -350,10 +361,10 @@ Grammar ------- Program ::= {Defn} {Routine}. - Defn ::= "byte" ["table"] NewIdent ["@" WordConst]. - Routine ::= "routine" NewIdent - ["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs] - (Block | "@" WordConst). + Defn ::= Type NewIdent [Constraints] ["@" WordConst]. + Type ::= "byte" ["table"] | "vector" + Constrnt::= ["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs]. + Routine ::= "routine" NewIdent Constraints (Block | "@" WordConst). LocExprs::= LocExpr {"," LocExpr}. LocExpr ::= Register | Flag | LitByte | DefnIdent. Register::= "a" | "x" | "y". diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 8b41679..ea26f4d 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -132,17 +132,20 @@ class Parser(object): self.scanner.check_type('identifier') name = self.scanner.token self.scanner.scan() + + (inputs, outputs, trashes) = self.constraints() + if type != TYPE_VECTOR and (inputs or outputs or trashes): + raise SyntaxError("Cannot apply constraints to non-vector type") + addr = None if self.scanner.consume('@'): self.scanner.check_type('integer literal') addr = int(self.scanner.token) self.scanner.scan() - return Defn(name=name, type=type, addr=addr) + return Defn(name=name, type=type, addr=addr, + inputs=inputs, outputs=outputs, trashes=trashes) - def routine(self): - self.scanner.expect('routine') - name = self.scanner.token - self.scanner.scan() + def constraints(self): inputs = [] outputs = [] trashes = [] @@ -152,6 +155,13 @@ class Parser(object): outputs = self.locexprs() if self.scanner.consume('trashes'): trashes = self.locexprs() + return (inputs, outputs, trashes) + + def routine(self): + self.scanner.expect('routine') + name = self.scanner.token + self.scanner.scan() + (inputs, outputs, trashes) = self.constraints() if self.scanner.consume('@'): self.scanner.check_type('integer literal') block = None diff --git a/tests/SixtyPical Analysis.md b/tests/SixtyPical Analysis.md index e0b9db0..f514576 100644 --- a/tests/SixtyPical Analysis.md +++ b/tests/SixtyPical Analysis.md @@ -989,7 +989,7 @@ Can't `copy` from a memory location that isn't initialized. | } ? UninitializedAccessError: x -Can't `st` to a memory location that doesn't appear in (outputs ∪ trashes). +Can't `copy` to a memory location that doesn't appear in (outputs ∪ trashes). | byte lives | routine main @@ -1036,3 +1036,62 @@ a, z, and n are trashed, and must not be declared as outputs. | copy 0, lives | } ? UninitializedOutputError: a + +Unless of course you subsequently initialize them. + + | byte lives + | routine main + | outputs lives, a, z, n + | { + | copy 0, lives + | ld a, 0 + | } + = ok + +You can copy the address of a routine into a vector, if that vector is declared appropriately. + + | vector vec + | inputs x + | outputs x + | trashes z, n + | + | routine foo + | inputs x + | outputs x + | trashes z, n + | { + | inc x + | } + | + | routine main + | inputs foo + | outputs vec + | trashes a, z, n + | { + | copy foo, vec + | } + = ok + +But not if the vector is declared inappropriately. + + | vector vec + | inputs y + | outputs y + | trashes z, n + | + | routine foo + | inputs x + | outputs x + | trashes z, n + | { + | inc x + | } + | + | routine main + | inputs foo + | outputs vec + | trashes a, z, n + | { + | copy foo, vec + | } + ? IllegalWriteError diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index e5d36a5..febf6e2 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -218,6 +218,10 @@ Declaring a byte table memory location. Declaring a vector. | vector cinv + | inputs a + | outputs x + | trashes a, x, z, n + | @ 788 | | routine foo { | ld a, 0 @@ -228,3 +232,15 @@ Declaring a vector. | } | } = ok + +Only vectors can be decorated with constraints like that. + + | byte cinv + | inputs a + | outputs x + | trashes a, x, z, n + | @ 788 + | + | routine main { + | } + ? SyntaxError