1
0
mirror of https://github.com/catseye/SixtyPical.git synced 2024-11-25 23:49:17 +00:00

Allow vectors to be decorated with inputs/outputs/trashes; test.

This commit is contained in:
Chris Pressey 2015-10-19 13:04:08 +01:00
parent a12a44eadb
commit f0b8942aa1
5 changed files with 110 additions and 14 deletions

View File

@ -33,10 +33,8 @@ TODO
For 0.6: For 0.6:
* `interrupt` routines. * declared `inputs` `outputs` `trashes` on the `vector` type.
* `goto` (tail call). * `goto` (tail call) a routine or a vector.
* `vector` type... with declared `inputs` `outputs` `trashes`?
* `copy` instruction... that can copy a constant to a user-def mem loc.
* A more involved demo for the C64 — one that sets up an interrupt. * A more involved demo for the C64 — one that sets up an interrupt.
For 0.7: For 0.7:
@ -48,8 +46,10 @@ For 0.7:
At some point... At some point...
* `interrupt` routines.
* add line number (or at least routine name) to error messages. * add line number (or at least routine name) to error messages.
* 6502-mnemonic aliases (`sec`, `clc`) * 6502-mnemonic aliases (`sec`, `clc`)
* other handy aliases (`eq` for `z`, etc.) * 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. * add absolute addressing in shl/shr, absolute-indexed for add, sub, etc.
* check and disallow recursion. * check and disallow recursion.

View File

@ -83,6 +83,17 @@ A location in memory may be given explicitly on a user-defined memory location.
byte table screen @ 1024 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 Routines
-------- --------
@ -350,10 +361,10 @@ Grammar
------- -------
Program ::= {Defn} {Routine}. Program ::= {Defn} {Routine}.
Defn ::= "byte" ["table"] NewIdent ["@" WordConst]. Defn ::= Type NewIdent [Constraints] ["@" WordConst].
Routine ::= "routine" NewIdent Type ::= "byte" ["table"] | "vector"
["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs] Constrnt::= ["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs].
(Block | "@" WordConst). Routine ::= "routine" NewIdent Constraints (Block | "@" WordConst).
LocExprs::= LocExpr {"," LocExpr}. LocExprs::= LocExpr {"," LocExpr}.
LocExpr ::= Register | Flag | LitByte | DefnIdent. LocExpr ::= Register | Flag | LitByte | DefnIdent.
Register::= "a" | "x" | "y". Register::= "a" | "x" | "y".

View File

@ -132,17 +132,20 @@ class Parser(object):
self.scanner.check_type('identifier') self.scanner.check_type('identifier')
name = self.scanner.token name = self.scanner.token
self.scanner.scan() 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 addr = None
if self.scanner.consume('@'): if self.scanner.consume('@'):
self.scanner.check_type('integer literal') self.scanner.check_type('integer literal')
addr = int(self.scanner.token) addr = int(self.scanner.token)
self.scanner.scan() 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): def constraints(self):
self.scanner.expect('routine')
name = self.scanner.token
self.scanner.scan()
inputs = [] inputs = []
outputs = [] outputs = []
trashes = [] trashes = []
@ -152,6 +155,13 @@ class Parser(object):
outputs = self.locexprs() outputs = self.locexprs()
if self.scanner.consume('trashes'): if self.scanner.consume('trashes'):
trashes = self.locexprs() 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('@'): if self.scanner.consume('@'):
self.scanner.check_type('integer literal') self.scanner.check_type('integer literal')
block = None block = None

View File

@ -989,7 +989,7 @@ Can't `copy` from a memory location that isn't initialized.
| } | }
? UninitializedAccessError: x ? 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 | byte lives
| routine main | routine main
@ -1036,3 +1036,62 @@ a, z, and n are trashed, and must not be declared as outputs.
| copy 0, lives | copy 0, lives
| } | }
? UninitializedOutputError: a ? 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

View File

@ -218,6 +218,10 @@ Declaring a byte table memory location.
Declaring a vector. Declaring a vector.
| vector cinv | vector cinv
| inputs a
| outputs x
| trashes a, x, z, n
| @ 788
| |
| routine foo { | routine foo {
| ld a, 0 | ld a, 0
@ -228,3 +232,15 @@ Declaring a vector.
| } | }
| } | }
= ok = 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