git @ Cat's Eye Technologies SixtyPical / 3f0e36a
Add symbolic constants. Chris Pressey 3 years ago
5 changed file(s) with 81 addition(s) and 35 deletion(s). Raw diff Collapse all Expand all
00 History of SixtyPical
11 =====================
2
3 0.15
4 ----
5
6 * Symbolic constants can be defined with the `const` keyword, and can
7 be used in most places where literal values can be used.
28
39 0.14
410 ----
8080 ### And at some point...
8181
8282 * `low` and `high` address operators - to turn `word` type into `byte`.
83 * `const`s that can be used in defining the size of tables, etc.
8483 * Tests, and implementation, ensuring a routine can be assigned to a vector of "wider" type
8584 * Related: can we simply view a (small) part of a buffer as a byte table? If not, why not?
8685 * Related: add constant to buffer to get new buffer. (Or to table, but... well, maybe.)
00 SixtyPical
11 ==========
22
3 This document describes the SixtyPical programming language version 0.14,
3 This document describes the SixtyPical programming language version 0.15,
44 both its static semantics (the capabilities and limits of the static
55 analyses it defines) and its runtime semantics (with reference to the
66 semantics of 6502 machine code.)
554554 Grammar
555555 -------
556556
557 Program ::= {TypeDefn} {Defn} {Routine}.
557 Program ::= {ConstDefn | TypeDefn} {Defn} {Routine}.
558 ConstDefn::= "const" Ident<new> Const.
558559 TypeDefn::= "typedef" Type Ident<new>.
559 Defn ::= Type Ident<new> [Constraints] (":" Literal | "@" LitWord).
560 Defn ::= Type Ident<new> [Constraints] (":" Const | "@" LitWord).
560561 Type ::= TypeTerm ["table" TypeSize].
561562 TypeExpr::= "byte"
562563 | "word"
572573 | "routine" Ident<new> Constraints (Block | "@" LitWord)
573574 .
574575 LocExprs::= LocExpr {"," LocExpr}.
575 LocExpr ::= Register | Flag | Literal | Ident.
576 LocExpr ::= Register | Flag | Const | Ident.
576577 Register::= "a" | "x" | "y".
577578 Flag ::= "c" | "z" | "n" | "v".
579 Const ::= Literal | Ident<const>.
578580 Literal ::= LitByte | LitWord | LitBit.
579581 LitByte ::= "0" ... "255".
580 LitWord ::= "0" ... "65535".
582 LitWord ::= ["word"] "0" ... "65535".
581583 LitBit ::= "on" | "off".
582584 Block ::= "{" {Instr} "}".
583585 Instr ::= "ld" LocExpr "," LocExpr ["+" LocExpr]
597599 | "copy" LocExpr "," LocExpr ["+" LocExpr]
598600 | "if" ["not"] LocExpr Block ["else" Block]
599601 | "repeat" Block ("until" ["not"] LocExpr | "forever")
600 | "for" LocExpr ("up"|"down") "to" Literal Block
602 | "for" LocExpr ("up"|"down") "to" Const Block
601603 | "with" "interrupts" LitBit Block
602604 .
2323 self.symbols = {} # token -> SymEntry
2424 self.current_statics = {} # token -> SymEntry
2525 self.typedefs = {} # token -> Type AST
26 self.consts = {} # token -> Loc
2627 for token in ('a', 'x', 'y'):
2728 self.symbols[token] = SymEntry(None, LocationRef(TYPE_BYTE, token))
2829 for token in ('c', 'z', 'n', 'v'):
5051 def program(self):
5152 defns = []
5253 routines = []
53 while self.scanner.on('typedef'):
54 typedef = self.typedef()
54 while self.scanner.on('typedef', 'const'):
55 if self.scanner.on('typedef'):
56 self.typedef()
57 if self.scanner.on('const'):
58 self.defn_const()
5559 typenames = ['byte', 'word', 'table', 'vector', 'buffer', 'pointer'] # 'routine',
5660 typenames.extend(self.typedefs.keys())
5761 while self.scanner.on(*typenames):
109113 self.typedefs[name] = type_
110114 return type_
111115
116 def defn_const(self):
117 self.scanner.expect('const')
118 name = self.defn_name()
119 if name in self.consts:
120 self.syntax_error('Const "%s" already declared' % name)
121 loc = self.const()
122 self.consts[name] = loc
123 return loc
124
112125 def defn(self):
113126 type_ = self.defn_type()
114127 name = self.defn_name()
117130 if self.scanner.consume(':'):
118131 if isinstance(type_, TableType) and self.scanner.on_type('string literal'):
119132 initial = self.scanner.token
133 self.scanner.scan()
120134 else:
121 self.scanner.check_type('integer literal')
122 initial = int(self.scanner.token)
123 self.scanner.scan()
135 initial = self.const().value
124136
125137 addr = None
126138 if self.scanner.consume('@'):
135147
136148 return Defn(self.scanner.line_number, name=name, addr=addr, initial=initial, location=location)
137149
138 def literal_int(self):
139 self.scanner.check_type('integer literal')
140 c = int(self.scanner.token)
141 self.scanner.scan()
142 return c
143
144 def literal_int_const(self):
145 value = self.literal_int()
146 type_ = TYPE_WORD if value > 255 else TYPE_BYTE
147 loc = ConstantRef(type_, value)
148 return loc
150 def const(self):
151 if self.scanner.token in ('on', 'off'):
152 loc = ConstantRef(TYPE_BIT, 1 if self.scanner.token == 'on' else 0)
153 self.scanner.scan()
154 return loc
155 elif self.scanner.on_type('integer literal'):
156 value = int(self.scanner.token)
157 self.scanner.scan()
158 type_ = TYPE_WORD if value > 255 else TYPE_BYTE
159 loc = ConstantRef(type_, value)
160 return loc
161 elif self.scanner.consume('word'):
162 loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
163 self.scanner.scan()
164 return loc
165 elif self.scanner.token in self.consts:
166 loc = self.consts[self.scanner.token]
167 self.scanner.scan()
168 return loc
169 else:
170 self.syntax_error('bad constant "%s"' % self.scanner.token)
149171
150172 def defn_size(self):
151173 self.scanner.expect('[')
152 size = self.literal_int()
174 size = self.const().value
153175 self.scanner.expect(']')
154176 return size
155177
293315 return accum
294316
295317 def locexpr(self, forward=False):
296 if self.scanner.token in ('on', 'off'):
297 loc = ConstantRef(TYPE_BIT, 1 if self.scanner.token == 'on' else 0)
298 self.scanner.scan()
299 return loc
300 elif self.scanner.on_type('integer literal'):
301 return self.literal_int_const()
302 elif self.scanner.consume('word'):
303 loc = ConstantRef(TYPE_WORD, int(self.scanner.token))
304 self.scanner.scan()
305 return loc
318 if self.scanner.token in ('on', 'off', 'word') or self.scanner.token in self.consts or self.scanner.on_type('integer literal'):
319 return self.const()
306320 elif forward:
307321 name = self.scanner.token
308322 self.scanner.scan()
386400 else:
387401 self.syntax_error('expected "up" or "down", found "%s"' % self.scanner.token)
388402 self.scanner.expect('to')
389 final = self.literal_int_const()
403 final = self.const()
390404 block = self.block()
391405 return For(self.scanner.line_number, dest=dest, direction=direction, final=final, block=block)
392406 elif self.scanner.token in ("ld",):
227227 | }
228228 ? SyntaxError
229229
230 Constants.
231
232 | const lives 3
233 | const days lives
234 | const w1 1000
235 | const w2 word 0
236 |
237 | typedef byte table[days] them
238 |
239 | byte lark: lives
240 |
241 | routine main {
242 | ld a, lives
243 | }
244 = ok
245
246 Can't have two constants with the same name.
247
248 | const w1 1000
249 | const w1 word 0
250 |
251 | routine main {
252 | }
253 ? SyntaxError
254
230255 Explicit memory address.
231256
232257 | byte screen @ 1024