word types, with syntax and analysis thereof
Chris Pressey
7 years ago
157 | 157 | self.current_routine = None |
158 | 158 | self.has_encountered_goto = False |
159 | 159 | self.routines = {} |
160 | ||
161 | def assert_type(self, type, *locations): | |
162 | for location in locations: | |
163 | if location.type != type: | |
164 | raise TypeMismatchError('%s in %s' % | |
165 | (location.name, self.current_routine.name) | |
166 | ) | |
160 | 167 | |
161 | 168 | def analyze_program(self, program): |
162 | 169 | assert isinstance(program, Program) |
201 | 208 | if src.type == TYPE_BYTE_TABLE and dest.type == TYPE_BYTE: |
202 | 209 | pass |
203 | 210 | else: |
204 | raise TypeMismatchError((src, dest)) | |
211 | raise TypeMismatchError('%s and %s in %s' % | |
212 | (src.name, dest.name, self.current_routine.name) | |
213 | ) | |
205 | 214 | elif src.type != dest.type: |
206 | raise TypeMismatchError((src, dest)) | |
215 | raise TypeMismatchError('%s and %s in %s' % | |
216 | (src.name, dest.name, self.current_routine.name) | |
217 | ) | |
207 | 218 | context.assert_meaningful(src) |
208 | 219 | context.set_written(dest, FLAG_Z, FLAG_N) |
209 | 220 | elif opcode == 'st': |
213 | 224 | else: |
214 | 225 | raise TypeMismatchError((src, dest)) |
215 | 226 | elif src.type != dest.type: |
216 | raise TypeMismatchError((src, dest)) | |
227 | raise TypeMismatchError('%s and %s in %s' % | |
228 | (src.name, dest.name, self.current_routine.name) | |
229 | ) | |
217 | 230 | context.assert_meaningful(src) |
218 | 231 | context.set_written(dest) |
219 | 232 | elif opcode in ('add', 'sub'): |
233 | self.assert_type(TYPE_BYTE, src, dest) | |
220 | 234 | context.assert_meaningful(src, dest, FLAG_C) |
221 | 235 | context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C, FLAG_V) |
222 | 236 | elif opcode in ('inc', 'dec'): |
237 | self.assert_type(TYPE_BYTE, dest) | |
223 | 238 | context.assert_meaningful(dest) |
224 | 239 | context.set_written(dest, FLAG_Z, FLAG_N) |
225 | 240 | elif opcode == 'cmp': |
241 | self.assert_type(TYPE_BYTE, src, dest) | |
226 | 242 | context.assert_meaningful(src, dest) |
227 | 243 | context.set_written(FLAG_Z, FLAG_N, FLAG_C) |
228 | 244 | elif opcode in ('and', 'or', 'xor'): |
245 | self.assert_type(TYPE_BYTE, src, dest) | |
229 | 246 | context.assert_meaningful(src, dest) |
230 | 247 | context.set_written(dest, FLAG_Z, FLAG_N) |
231 | 248 | elif opcode in ('shl', 'shr'): |
249 | self.assert_type(TYPE_BYTE, dest) | |
232 | 250 | context.assert_meaningful(dest, FLAG_C) |
233 | 251 | context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C) |
234 | 252 | elif opcode == 'call': |
16 | 16 | TYPE_BIT = Type('bit') |
17 | 17 | TYPE_BYTE = Type('byte') |
18 | 18 | TYPE_BYTE_TABLE = Type('byte table') |
19 | TYPE_WORD = Type('word') | |
20 | TYPE_WORD_TABLE = Type('word table') | |
19 | 21 | |
20 | 22 | |
21 | 23 | class ExecutableType(Type): |
1 | 1 | |
2 | 2 | from sixtypical.ast import Program, Defn, Routine, Block, Instr |
3 | 3 | from sixtypical.model import ( |
4 | TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, | |
4 | TYPE_BIT, TYPE_BYTE, TYPE_BYTE_TABLE, TYPE_WORD, TYPE_WORD_TABLE, | |
5 | 5 | RoutineType, VectorType, ExecutableType, |
6 | 6 | LocationRef, ConstantRef |
7 | 7 | ) |
31 | 31 | def program(self): |
32 | 32 | defns = [] |
33 | 33 | routines = [] |
34 | while self.scanner.on('byte') or self.scanner.on('vector'): | |
34 | while self.scanner.on('byte', 'word', 'vector'): | |
35 | 35 | defn = self.defn() |
36 | 36 | name = defn.name |
37 | 37 | if name in self.symbols: |
49 | 49 | return Program(defns=defns, routines=routines) |
50 | 50 | |
51 | 51 | def defn(self): |
52 | type = TYPE_BYTE | |
52 | type = None | |
53 | 53 | if self.scanner.consume('byte'): |
54 | 54 | type = TYPE_BYTE |
55 | 55 | if self.scanner.consume('table'): |
56 | 56 | type = TYPE_BYTE_TABLE |
57 | elif self.scanner.consume('word'): | |
58 | type = TYPE_WORD | |
59 | if self.scanner.consume('table'): | |
60 | type = TYPE_WORD_TABLE | |
57 | 61 | else: |
58 | 62 | self.scanner.expect('vector') |
59 | type = 'vector' | |
63 | type = 'vector' # will be resolved to a Type below | |
60 | 64 | self.scanner.check_type('identifier') |
61 | 65 | name = self.scanner.token |
62 | 66 | self.scanner.scan() |
54 | 54 | raise SyntaxError("Expected '%s', but found '%s'" % |
55 | 55 | (token, self.token)) |
56 | 56 | |
57 | def on(self, token): | |
58 | return self.token == token | |
57 | def on(self, *tokens): | |
58 | return self.token in tokens | |
59 | 59 | |
60 | 60 | def on_type(self, type): |
61 | 61 | return self.type == type |
146 | 146 | | ld a, 0 |
147 | 147 | | } |
148 | 148 | ? ForbiddenWriteError: z in main |
149 | ||
150 | Can't `ld` a `word` type. | |
151 | ||
152 | | word foo | |
153 | | | |
154 | | routine main | |
155 | | inputs foo | |
156 | | trashes a, n, z | |
157 | | { | |
158 | | ld a, foo | |
159 | | } | |
160 | ? TypeMismatchError: foo and a in main | |
149 | 161 | |
150 | 162 | ### st ### |
151 | 163 | |
300 | 312 | | } |
301 | 313 | = ok |
302 | 314 | |
315 | Can't `st` a `word` type. | |
316 | ||
317 | | word foo | |
318 | | | |
319 | | routine main | |
320 | | outputs foo | |
321 | | trashes a, n, z | |
322 | | { | |
323 | | ld a, 0 | |
324 | | st a, foo | |
325 | | } | |
326 | ? TypeMismatchError: a and foo in main | |
327 | ||
303 | 328 | ### add ### |
304 | 329 | |
305 | 330 | Can't `add` from or to a memory location that isn't initialized. |
423 | 448 | | } |
424 | 449 | = ok |
425 | 450 | |
451 | Can't `inc` a `word` type. | |
452 | ||
453 | | word foo | |
454 | | | |
455 | | routine main | |
456 | | inputs foo | |
457 | | outputs foo | |
458 | | trashes z, n | |
459 | | { | |
460 | | inc foo | |
461 | | } | |
462 | ? TypeMismatchError: foo in main | |
463 | ||
426 | 464 | ### dec ### |
427 | 465 | |
428 | 466 | Location must be initialized and writeable. |
451 | 489 | | dec x |
452 | 490 | | } |
453 | 491 | = ok |
492 | ||
493 | Can't `dec` a `word` type. | |
494 | ||
495 | | word foo | |
496 | | | |
497 | | routine main | |
498 | | inputs foo | |
499 | | outputs foo | |
500 | | trashes z, n | |
501 | | { | |
502 | | dec foo | |
503 | | } | |
504 | ? TypeMismatchError: foo in main | |
454 | 505 | |
455 | 506 | ### cmp ### |
456 | 507 | |
1047 | 1098 | | } |
1048 | 1099 | = ok |
1049 | 1100 | |
1101 | Can `copy` from a `byte` to a `byte`. | |
1102 | ||
1103 | | byte source : 0 | |
1104 | | byte dest | |
1105 | | | |
1106 | | routine main | |
1107 | | inputs source | |
1108 | | outputs dest | |
1109 | | trashes a, z, n | |
1110 | | { | |
1111 | | copy source, dest | |
1112 | | } | |
1113 | = ok | |
1114 | ||
1115 | Can `copy` from a `word` to a `word`. | |
1116 | ||
1117 | | word source : 0 | |
1118 | | word dest | |
1119 | | | |
1120 | | routine main | |
1121 | | inputs source | |
1122 | | outputs dest | |
1123 | | trashes a, z, n | |
1124 | | { | |
1125 | | copy source, dest | |
1126 | | } | |
1127 | = ok | |
1128 | ||
1129 | Can't `copy` from a `byte` to a `word`. | |
1130 | ||
1131 | | byte source : 0 | |
1132 | | word dest | |
1133 | | | |
1134 | | routine main | |
1135 | | inputs source | |
1136 | | outputs dest | |
1137 | | trashes a, z, n | |
1138 | | { | |
1139 | | copy source, dest | |
1140 | | } | |
1141 | ? TypeMismatchError | |
1142 | ||
1143 | Can't `copy` from a `word` to a `byte`. | |
1144 | ||
1145 | | word source : 0 | |
1146 | | byte dest | |
1147 | | | |
1148 | | routine main | |
1149 | | inputs source | |
1150 | | outputs dest | |
1151 | | trashes a, z, n | |
1152 | | { | |
1153 | | copy source, dest | |
1154 | | } | |
1155 | ? TypeMismatchError | |
1156 | ||
1157 | ### routines ### | |
1158 | ||
1050 | 1159 | Routines are constants. You need not, and in fact cannot, specify a constant |
1051 | 1160 | as an input to, an output of, or as a trashed value of a routine. |
1052 | 1161 |
142 | 142 | | } |
143 | 143 | = ok |
144 | 144 | |
145 | User-defined locations of other types. | |
146 | ||
147 | | byte table screen @ 1024 | |
148 | | word r1 | |
149 | | word r2 @ 60000 | |
150 | | word r3 : 2000 | |
151 | | | |
152 | | routine main { | |
153 | | } | |
154 | = ok | |
155 | ||
156 | Initialized memory locations. | |
157 | ||
158 | | byte lives : 3 | |
159 | | | |
160 | | routine main { | |
161 | | ld a, lives | |
162 | | st a, lives | |
163 | | } | |
164 | = ok | |
165 | ||
145 | 166 | Cannot have both initial value and explicit address. |
146 | 167 | |
147 | 168 | | byte screen : 3 @ 1024 |