mirror of
https://github.com/catseye/SixtyPical.git
synced 2024-11-29 18:49:22 +00:00
Spec and syntax for vectors and copy instruction.
This commit is contained in:
parent
ab1b5990e7
commit
c98e446583
@ -51,3 +51,4 @@ At some point...
|
|||||||
* 6502-mnemonic aliases (`sec`, `clc`)
|
* 6502-mnemonic aliases (`sec`, `clc`)
|
||||||
* other handy aliases (`eq` for `z`, etc.)
|
* other handy aliases (`eq` for `z`, 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.
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
SixtyPical
|
SixtyPical
|
||||||
==========
|
==========
|
||||||
|
|
||||||
This document describes the SixtyPical programming language version 0.5,
|
This document describes the SixtyPical programming language version 0.6-PRE,
|
||||||
both its execution aspect and its static analysis aspect (even though
|
both its execution aspect and its static analysis aspect (even though
|
||||||
these are, technically speaking, separate concepts.)
|
these are, technically speaking, separate concepts.)
|
||||||
|
|
||||||
@ -14,11 +14,13 @@ the language.
|
|||||||
Types
|
Types
|
||||||
-----
|
-----
|
||||||
|
|
||||||
There are three TYPES in SixtyPical:
|
There are five TYPES in SixtyPical:
|
||||||
|
|
||||||
* bit (2 possible values)
|
* bit (2 possible values)
|
||||||
* byte (256 possible values)
|
* byte (256 possible values)
|
||||||
* byte table (256 entries, each holding a byte)
|
* byte table (256 entries, each holding a byte)
|
||||||
|
* routine (code stored somewhere in memory, read-only)
|
||||||
|
* vector (address of a routine)
|
||||||
|
|
||||||
Memory locations
|
Memory locations
|
||||||
----------------
|
----------------
|
||||||
@ -72,13 +74,14 @@ and two-hundred and fifty-six byte constants,
|
|||||||
### User-defined ###
|
### User-defined ###
|
||||||
|
|
||||||
There may be any number of user-defined memory locations. They are defined
|
There may be any number of user-defined memory locations. They are defined
|
||||||
by giving the type, which must be `byte`, and the name.
|
by giving the type, which must be `byte`, `byte table`, or `vector`, and the
|
||||||
|
name.
|
||||||
|
|
||||||
byte pos
|
byte pos
|
||||||
|
|
||||||
A location in memory may be given explicitly on a user-defined memory location.
|
A location in memory may be given explicitly on a user-defined memory location.
|
||||||
|
|
||||||
byte screen @ 1024
|
byte table screen @ 1024
|
||||||
|
|
||||||
Routines
|
Routines
|
||||||
--------
|
--------
|
||||||
@ -326,6 +329,23 @@ To simulate a "while" loop, use an `if` internal to the block, like
|
|||||||
|
|
||||||
"until" is optional, but if omitted, must be replaced with "forever".
|
"until" is optional, but if omitted, must be replaced with "forever".
|
||||||
|
|
||||||
|
### copy ###
|
||||||
|
|
||||||
|
copy <src-memory-location>, <dest-memory-location>
|
||||||
|
|
||||||
|
Reads from src and writes to dest. Differs from `st` in that is able to
|
||||||
|
copy more general types of data (for example, vectors,) and it sets the
|
||||||
|
`z` and `n` flags and trashes the `a` register.
|
||||||
|
|
||||||
|
* It is illegal if dest is read-only.
|
||||||
|
* It is illegal if dest does not occur in the WRITES lists of the current
|
||||||
|
routine.
|
||||||
|
* It is illegal if src is not of same type as dest.
|
||||||
|
* It is illegal if src is uninitialized.
|
||||||
|
|
||||||
|
After execution, dest is considered initialized, as are `z` and `n`, while
|
||||||
|
`a` is considered uninitialized.
|
||||||
|
|
||||||
Grammar
|
Grammar
|
||||||
-------
|
-------
|
||||||
|
|
||||||
@ -356,4 +376,5 @@ Grammar
|
|||||||
| "call" RoutineIdent
|
| "call" RoutineIdent
|
||||||
| "if" ["not"] LocExpr Block ["else" Block]
|
| "if" ["not"] LocExpr Block ["else" Block]
|
||||||
| "repeat" Block ("until" ["not"] LocExpr | "forever")
|
| "repeat" Block ("until" ["not"] LocExpr | "forever")
|
||||||
|
| "copy" LocExpr "," LocExpr ["+" LocExpr]
|
||||||
.
|
.
|
||||||
|
@ -17,6 +17,8 @@ class Type(object):
|
|||||||
TYPE_BIT = Type('bit')
|
TYPE_BIT = Type('bit')
|
||||||
TYPE_BYTE = Type('byte')
|
TYPE_BYTE = Type('byte')
|
||||||
TYPE_BYTE_TABLE = Type('byte table')
|
TYPE_BYTE_TABLE = Type('byte table')
|
||||||
|
TYPE_ROUTINE = Type('routine')
|
||||||
|
TYPE_VECTOR = Type('vector') # the mem loc contains an address of a routine
|
||||||
|
|
||||||
|
|
||||||
class Ref(object):
|
class Ref(object):
|
||||||
|
@ -4,7 +4,7 @@ import re
|
|||||||
|
|
||||||
from sixtypical.ast import Program, Defn, Routine, Block, Instr
|
from sixtypical.ast import Program, Defn, Routine, Block, Instr
|
||||||
from sixtypical.model import (
|
from sixtypical.model import (
|
||||||
TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE,
|
TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_ROUTINE, TYPE_VECTOR,
|
||||||
LocationRef, ConstantRef
|
LocationRef, ConstantRef
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -103,7 +103,7 @@ class Parser(object):
|
|||||||
def program(self):
|
def program(self):
|
||||||
defns = []
|
defns = []
|
||||||
routines = []
|
routines = []
|
||||||
while self.scanner.on('byte'):
|
while self.scanner.on('byte') or self.scanner.on('vector'):
|
||||||
defn = self.defn()
|
defn = self.defn()
|
||||||
name = defn.name
|
name = defn.name
|
||||||
if name in self.symbols:
|
if name in self.symbols:
|
||||||
@ -115,16 +115,20 @@ class Parser(object):
|
|||||||
name = routine.name
|
name = routine.name
|
||||||
if name in self.symbols:
|
if name in self.symbols:
|
||||||
raise SyntaxError(name)
|
raise SyntaxError(name)
|
||||||
self.symbols[name] = SymEntry(routine, None)
|
self.symbols[name] = SymEntry(routine, LocationRef(TYPE_ROUTINE, name))
|
||||||
routines.append(routine)
|
routines.append(routine)
|
||||||
self.scanner.check_type('EOF')
|
self.scanner.check_type('EOF')
|
||||||
return Program(defns=defns, routines=routines)
|
return Program(defns=defns, routines=routines)
|
||||||
|
|
||||||
def defn(self):
|
def defn(self):
|
||||||
type = TYPE_BYTE
|
type = TYPE_BYTE
|
||||||
self.scanner.expect('byte')
|
if self.scanner.consume('byte'):
|
||||||
if self.scanner.consume('table'):
|
type = TYPE_BYTE
|
||||||
type = TYPE_BYTE_TABLE
|
if self.scanner.consume('table'):
|
||||||
|
type = TYPE_BYTE_TABLE
|
||||||
|
else:
|
||||||
|
self.scanner.expect('vector')
|
||||||
|
type = TYPE_VECTOR
|
||||||
self.scanner.check_type('identifier')
|
self.scanner.check_type('identifier')
|
||||||
name = self.scanner.token
|
name = self.scanner.token
|
||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
@ -246,5 +250,12 @@ class Parser(object):
|
|||||||
self.scanner.scan()
|
self.scanner.scan()
|
||||||
# TODO: check that is has been defined
|
# TODO: check that is has been defined
|
||||||
return Instr(opcode=opcode, name=name, dest=None, src=None)
|
return Instr(opcode=opcode, name=name, dest=None, src=None)
|
||||||
|
elif self.scanner.token in ("copy",):
|
||||||
|
opcode = self.scanner.token
|
||||||
|
self.scanner.scan()
|
||||||
|
src = self.locexpr()
|
||||||
|
self.scanner.expect(',')
|
||||||
|
dest = self.locexpr()
|
||||||
|
return Instr(opcode=opcode, dest=dest, src=src)
|
||||||
else:
|
else:
|
||||||
raise ValueError('bad opcode "%s"' % self.scanner.token)
|
raise ValueError('bad opcode "%s"' % self.scanner.token)
|
||||||
|
@ -196,3 +196,15 @@ Declaring a byte table memory location.
|
|||||||
| st a, tab + y
|
| st a, tab + y
|
||||||
| }
|
| }
|
||||||
= ok
|
= ok
|
||||||
|
|
||||||
|
Declaring a vector.
|
||||||
|
|
||||||
|
| vector cinv
|
||||||
|
|
|
||||||
|
| routine foo {
|
||||||
|
| ld a, 0
|
||||||
|
| }
|
||||||
|
| routine main {
|
||||||
|
| copy foo, cinv
|
||||||
|
| }
|
||||||
|
= ok
|
||||||
|
Loading…
Reference in New Issue
Block a user