diff --git a/README.markdown b/README.markdown index 9409340..667beb2 100644 --- a/README.markdown +++ b/README.markdown @@ -51,3 +51,4 @@ At some point... * 6502-mnemonic aliases (`sec`, `clc`) * other handy aliases (`eq` for `z`, 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 661bae2..5e6fd8b 100644 --- a/doc/SixtyPical.md +++ b/doc/SixtyPical.md @@ -1,7 +1,7 @@ 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 these are, technically speaking, separate concepts.) @@ -14,11 +14,13 @@ the language. Types ----- -There are three TYPES in SixtyPical: +There are five TYPES in SixtyPical: * bit (2 possible values) * byte (256 possible values) * byte table (256 entries, each holding a byte) +* routine (code stored somewhere in memory, read-only) +* vector (address of a routine) Memory locations ---------------- @@ -72,13 +74,14 @@ and two-hundred and fifty-six byte constants, ### User-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 A location in memory may be given explicitly on a user-defined memory location. - byte screen @ 1024 + byte table screen @ 1024 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". +### copy ### + + copy , + +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 ------- @@ -356,4 +376,5 @@ Grammar | "call" RoutineIdent | "if" ["not"] LocExpr Block ["else" Block] | "repeat" Block ("until" ["not"] LocExpr | "forever") + | "copy" LocExpr "," LocExpr ["+" LocExpr] . diff --git a/src/sixtypical/model.py b/src/sixtypical/model.py index 06afbc8..46fe528 100644 --- a/src/sixtypical/model.py +++ b/src/sixtypical/model.py @@ -17,6 +17,8 @@ class Type(object): TYPE_BIT = Type('bit') TYPE_BYTE = Type('byte') 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): diff --git a/src/sixtypical/parser.py b/src/sixtypical/parser.py index 5361484..396a9ed 100644 --- a/src/sixtypical/parser.py +++ b/src/sixtypical/parser.py @@ -4,7 +4,7 @@ import re from sixtypical.ast import Program, Defn, Routine, Block, Instr from sixtypical.model import ( - TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, + TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_ROUTINE, TYPE_VECTOR, LocationRef, ConstantRef ) @@ -103,7 +103,7 @@ class Parser(object): def program(self): defns = [] routines = [] - while self.scanner.on('byte'): + while self.scanner.on('byte') or self.scanner.on('vector'): defn = self.defn() name = defn.name if name in self.symbols: @@ -115,16 +115,20 @@ class Parser(object): name = routine.name if name in self.symbols: raise SyntaxError(name) - self.symbols[name] = SymEntry(routine, None) + self.symbols[name] = SymEntry(routine, LocationRef(TYPE_ROUTINE, name)) routines.append(routine) self.scanner.check_type('EOF') return Program(defns=defns, routines=routines) def defn(self): type = TYPE_BYTE - self.scanner.expect('byte') - if self.scanner.consume('table'): - type = TYPE_BYTE_TABLE + if self.scanner.consume('byte'): + type = TYPE_BYTE + if self.scanner.consume('table'): + type = TYPE_BYTE_TABLE + else: + self.scanner.expect('vector') + type = TYPE_VECTOR self.scanner.check_type('identifier') name = self.scanner.token self.scanner.scan() @@ -246,5 +250,12 @@ class Parser(object): self.scanner.scan() # TODO: check that is has been defined 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: raise ValueError('bad opcode "%s"' % self.scanner.token) diff --git a/tests/SixtyPical Syntax.md b/tests/SixtyPical Syntax.md index 7931771..9d2fa67 100644 --- a/tests/SixtyPical Syntax.md +++ b/tests/SixtyPical Syntax.md @@ -196,3 +196,15 @@ Declaring a byte table memory location. | st a, tab + y | } = ok + +Declaring a vector. + + | vector cinv + | + | routine foo { + | ld a, 0 + | } + | routine main { + | copy foo, cinv + | } + = ok