git @ Cat's Eye Technologies SixtyPical / 0be7216
Kind-of not-pretty syntax refactor to support adding typedefs. Chris Pressey 3 years ago
6 changed file(s) with 219 addition(s) and 167 deletion(s). Raw diff Collapse all Expand all
22 from sixtypical.ast import Program, Routine, Block, Instr
33 from sixtypical.model import (
44 TYPE_BYTE, TYPE_WORD,
5 TableType, BufferType, PointerType, VectorType, ExecutableType, RoutineType,
5 TableType, BufferType, PointerType, VectorType, RoutineType,
66 ConstantRef, LocationRef, IndirectRef, IndexedRef, AddressRef,
77 REG_A, REG_Y, FLAG_Z, FLAG_N, FLAG_V, FLAG_C
88 )
302302 context.set_written(dest, FLAG_Z, FLAG_N, FLAG_C)
303303 elif opcode == 'call':
304304 type = instr.location.type
305 if isinstance(type, VectorType):
306 type = type.of_type
305307 for ref in type.inputs:
306308 context.assert_meaningful(ref)
307309 for ref in type.outputs:
365367 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, IndexedRef):
366368 if src.type == TYPE_WORD and TableType.is_a_table_type(dest.ref.type, TYPE_WORD):
367369 pass
368 elif (isinstance(src.type, ExecutableType) and isinstance(dest.ref.type, TableType) and
369 ExecutableType.executable_types_compatible(src.type, dest.ref.type.of_type)):
370 elif (isinstance(src.type, VectorType) and isinstance(dest.ref.type, TableType) and
371 RoutineType.executable_types_compatible(src.type.of_type, dest.ref.type.of_type)):
372 pass
373 elif (isinstance(src.type, RoutineType) and isinstance(dest.ref.type, TableType) and
374 RoutineType.executable_types_compatible(src.type, dest.ref.type.of_type)):
370375 pass
371376 else:
372377 raise TypeMismatchError((src, dest))
375380 if TableType.is_a_table_type(src.ref.type, TYPE_WORD) and dest.type == TYPE_WORD:
376381 pass
377382 elif (isinstance(src.ref.type, TableType) and isinstance(dest.type, VectorType) and
378 ExecutableType.executable_types_compatible(src.ref.type.of_type, dest.type)):
383 RoutineType.executable_types_compatible(src.ref.type.of_type, dest.type.of_type)):
379384 pass
380385 else:
381386 raise TypeMismatchError((src, dest))
383388 elif isinstance(src, (LocationRef, ConstantRef)) and isinstance(dest, LocationRef):
384389 if src.type == dest.type:
385390 pass
386 elif isinstance(src.type, ExecutableType) and isinstance(dest.type, VectorType):
387 self.assert_affected_within('inputs', src.type.inputs, dest.type.inputs)
388 self.assert_affected_within('outputs', src.type.outputs, dest.type.outputs)
389 self.assert_affected_within('trashes', src.type.trashes, dest.type.trashes)
391 elif isinstance(src.type, RoutineType) and isinstance(dest.type, VectorType):
392 self.assert_affected_within('inputs', src.type.inputs, dest.type.of_type.inputs)
393 self.assert_affected_within('outputs', src.type.outputs, dest.type.of_type.outputs)
394 self.assert_affected_within('trashes', src.type.trashes, dest.type.of_type.trashes)
390395 else:
391396 raise TypeMismatchError((src, dest))
392397 else:
433438 location = instr.location
434439 type_ = location.type
435440
436 if not isinstance(type_, ExecutableType):
441 if not isinstance(type_, (RoutineType, VectorType)):
437442 raise TypeMismatchError(location)
438443
439444 # assert that the dest routine's inputs are all initialized
445 if isinstance(type_, VectorType):
446 type_ = type_.of_type
440447 for ref in type_.inputs:
441448 context.assert_meaningful(ref)
442449
1616 def __hash__(self):
1717 return hash(self.name)
1818
19 def backpatch_constraint_labels(self, resolver):
20 if isinstance(self, TableType):
21 self.of_type.backpatch_constraint_labels(resolver)
22 elif isinstance(self, VectorType):
23 self.of_type.backpatch_constraint_labels(resolver)
24 elif isinstance(self, RoutineType):
25 self.inputs = set([resolver(w) for w in self.inputs])
26 self.outputs = set([resolver(w) for w in self.outputs])
27 self.trashes = set([resolver(w) for w in self.trashes])
28
1929
2030 TYPE_BIT = Type('bit')
2131 TYPE_BYTE = Type('byte')
2232 TYPE_WORD = Type('word')
2333
2434
25 class ExecutableType(Type):
26 """Used for routines and vectors."""
27 def __init__(self, name, inputs=None, outputs=None, trashes=None):
28 self.name = name
35
36 class RoutineType(Type):
37 """This memory location contains the code for a routine."""
38 def __init__(self, inputs=None, outputs=None, trashes=None):
39 self.name = 'routine'
2940 self.inputs = inputs or set()
3041 self.outputs = outputs or set()
3142 self.trashes = trashes or set()
3647 )
3748
3849 def __eq__(self, other):
39 return isinstance(other, ExecutableType) and (
50 return isinstance(other, RoutineType) and (
4051 other.name == self.name and
4152 other.inputs == self.inputs and
4253 other.outputs == self.outputs and
4960 @classmethod
5061 def executable_types_compatible(cls_, src, dest):
5162 """Returns True iff a value of type `src` can be assigned to a storage location of type `dest`."""
52 if isinstance(src, ExecutableType) and isinstance(dest, VectorType):
63 if isinstance(src, VectorType):
64 src = src.of_type
65 if isinstance(dest, VectorType):
66 dest = dest.of_type
67 if isinstance(src, RoutineType) and isinstance(dest, RoutineType):
5368 # TODO: I'm sure we can replace some of these with subset-containment, but that requires thought
5469 return (
5570 src.inputs == dest.inputs and
6075 return False
6176
6277
63 class RoutineType(ExecutableType):
64 """This memory location contains the code for a routine."""
65 def __init__(self, **kwargs):
66 super(RoutineType, self).__init__('routine', **kwargs)
67
68
69 class VectorType(ExecutableType):
70 """This memory location contains the address of a routine."""
71 def __init__(self, **kwargs):
72 super(VectorType, self).__init__('vector', **kwargs)
78 class VectorType(Type):
79 """This memory location contains the address of some other type (currently, only RoutineType)."""
80 def __init__(self, of_type):
81 self.name = 'vector'
82 self.of_type = of_type
83
84 def __repr__(self):
85 return '%s(%r)' % (
86 self.__class__.__name__, self.of_type
87 )
88
89 def __eq__(self, other):
90 return self.name == other.name and self.of_type == other.of_type
91
92 def __hash__(self):
93 return hash(self.name) ^ hash(self.of_type)
7394
7495
7596 class TableType(Type):
134155 def is_constant(self):
135156 return isinstance(self.type, RoutineType)
136157
137 def backpatch_vector_labels(self, resolver):
138 if isinstance(self.type, ExecutableType):
139 t = self.type
140 t.inputs = set([resolver(w) for w in t.inputs])
141 t.outputs = set([resolver(w) for w in t.outputs])
142 t.trashes = set([resolver(w) for w in t.trashes])
143 if isinstance(self.type, TableType) and isinstance(self.type.of_type, ExecutableType):
144 t = self.type.of_type
145 t.inputs = set([resolver(w) for w in t.inputs])
146 t.outputs = set([resolver(w) for w in t.outputs])
147 t.trashes = set([resolver(w) for w in t.trashes])
148
149158 @classmethod
150159 def format_set(cls, location_refs):
151160 return '{%s}' % ', '.join([str(loc) for loc in sorted(location_refs)])
22 from sixtypical.ast import Program, Defn, Routine, Block, Instr
33 from sixtypical.model import (
44 TYPE_BIT, TYPE_BYTE, TYPE_WORD,
5 RoutineType, VectorType, ExecutableType, TableType, BufferType, PointerType,
5 RoutineType, VectorType, TableType, BufferType, PointerType,
66 LocationRef, ConstantRef, IndirectRef, IndexedRef, AddressRef,
77 )
88 from sixtypical.scanner import Scanner
3434 def program(self):
3535 defns = []
3636 routines = []
37 while self.scanner.on('byte', 'word', 'vector', 'buffer', 'pointer'):
37 while self.scanner.on('byte', 'word', 'table', 'vector', 'buffer', 'pointer'): # 'routine',
3838 defn = self.defn()
3939 name = defn.name
4040 if name in self.symbols:
4141 raise SyntaxError('Symbol "%s" already declared' % name)
4242 self.symbols[name] = SymEntry(defn, defn.location)
4343 defns.append(defn)
44 while self.scanner.on('routine'):
45 routine = self.routine()
46 name = routine.name
44 while self.scanner.on('define', 'routine'):
45 if self.scanner.consume('define'):
46 name = self.scanner.token
47 self.scanner.scan()
48 else:
49 routine = self.legacy_routine()
50 name = routine.name
4751 if name in self.symbols:
4852 raise SyntaxError('Symbol "%s" already declared' % name)
4953 self.symbols[name] = SymEntry(routine, routine.location)
5256
5357 # now backpatch the executable types.
5458 for defn in defns:
55 defn.location.backpatch_vector_labels(lambda w: self.lookup(w))
59 defn.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
5660 for routine in routines:
57 routine.location.backpatch_vector_labels(lambda w: self.lookup(w))
61 routine.location.type.backpatch_constraint_labels(lambda w: self.lookup(w))
5862 for instr in self.backpatch_instrs:
5963 if instr.opcode in ('call', 'goto'):
6064 name = instr.location
6165 if name not in self.symbols:
6266 raise SyntaxError('Undefined routine "%s"' % name)
63 if not isinstance(self.symbols[name].model.type, ExecutableType):
67 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
6468 raise SyntaxError('Illegal call of non-executable "%s"' % name)
6569 instr.location = self.symbols[name].model
6670 if instr.opcode in ('copy',) and isinstance(instr.src, basestring):
6771 name = instr.src
6872 if name not in self.symbols:
6973 raise SyntaxError('Undefined routine "%s"' % name)
70 if not isinstance(self.symbols[name].model.type, ExecutableType):
74 if not isinstance(self.symbols[name].model.type, (RoutineType, VectorType)):
7175 raise SyntaxError('Illegal copy of non-executable "%s"' % name)
7276 instr.src = self.symbols[name].model
7377
7478 return Program(defns=defns, routines=routines)
7579
7680 def defn(self):
77 type_, name = self.defn_type_and_name()
81 type_ = self.defn_type()
82 name = self.defn_name()
7883
7984 initial = None
8085 if self.scanner.consume(':'):
106111 self.scanner.expect(']')
107112 return size
108113
109 def defn_type_and_name(self):
114 def defn_type(self):
110115 if self.scanner.consume('byte'):
111 type_ = TYPE_BYTE
112 if self.scanner.consume('table'):
113 size = self.defn_size()
114 type_ = TableType(type_, size)
115 name = self.defn_name()
116 return type_, name
116 return TYPE_BYTE
117117 elif self.scanner.consume('word'):
118 type_ = TYPE_WORD
119 if self.scanner.consume('table'):
120 size = self.defn_size()
121 type_ = TableType(type_, size)
122 name = self.defn_name()
123 return type_, name
118 return TYPE_WORD
119 elif self.scanner.consume('table'):
120 size = self.defn_size()
121 type_ = self.defn_type()
122 return TableType(type_, size)
124123 elif self.scanner.consume('vector'):
125 size = None
126 if self.scanner.consume('table'):
127 size = self.defn_size()
128 name = self.defn_name()
124 type_ = self.defn_type()
125 # TODO: assert that it's a routine type
126 return VectorType(type_)
127 elif self.scanner.consume('routine'):
129128 (inputs, outputs, trashes) = self.constraints()
130 type_ = VectorType(inputs=inputs, outputs=outputs, trashes=trashes)
131 if size is not None:
132 type_ = TableType(type_, size)
133 return type_, name
129 return RoutineType(inputs=inputs, outputs=outputs, trashes=trashes)
134130 elif self.scanner.consume('buffer'):
135131 size = self.defn_size()
136 name = self.defn_name()
137 return BufferType(size), name
132 return BufferType(size)
138133 else:
139134 self.scanner.expect('pointer')
140 name = self.defn_name()
141 return PointerType(), name
135 return PointerType()
142136
143137 def defn_name(self):
144138 self.scanner.check_type('identifier')
158152 trashes = set(self.labels())
159153 return (inputs, outputs, trashes)
160154
161 def routine(self):
155 def legacy_routine(self):
162156 self.scanner.expect('routine')
163157 name = self.scanner.token
164158 self.scanner.scan()
165159 (inputs, outputs, trashes) = self.constraints()
160 type_ = RoutineType(inputs=inputs, outputs=outputs, trashes=trashes)
166161 if self.scanner.consume('@'):
167162 self.scanner.check_type('integer literal')
168163 block = None
171166 else:
172167 block = self.block()
173168 addr = None
174 location = LocationRef(
175 RoutineType(inputs=inputs, outputs=outputs, trashes=trashes),
176 name
169 location = LocationRef(type_, name)
170 return Routine(
171 name=name, block=block, addr=addr,
172 location=location
177173 )
174
175 def routine(self):
176 name = self.scanner.token
177 self.scanner.scan()
178 type_ = self.defn_type()
179 # TODO assert that it's a routine
180 if self.scanner.consume('@'):
181 self.scanner.check_type('integer literal')
182 block = None
183 addr = int(self.scanner.token)
184 self.scanner.scan()
185 else:
186 block = self.block()
187 addr = None
188 location = LocationRef(type_, name)
178189 return Routine(
179190 name=name, block=block, addr=addr,
180191 location=location
242242 Storing to a table, you must use an index.
243243
244244 | byte one
245 | byte table[256] many
245 | table[256] byte many
246246 |
247247 | routine main
248248 | outputs one
255255 = ok
256256
257257 | byte one
258 | byte table[256] many
258 | table[256] byte many
259259 |
260260 | routine main
261261 | outputs many
268268 ? TypeMismatchError
269269
270270 | byte one
271 | byte table[256] many
271 | table[256] byte many
272272 |
273273 | routine main
274274 | outputs one
281281 ? TypeMismatchError
282282
283283 | byte one
284 | byte table[256] many
284 | table[256] byte many
285285 |
286286 | routine main
287287 | outputs many
296296 The index must be initialized.
297297
298298 | byte one
299 | byte table[256] many
299 | table[256] byte many
300300 |
301301 | routine main
302302 | outputs many
333333 | }
334334 ? TypeMismatchError
335335
336 | byte table[256] many
336 | table[256] byte many
337337 |
338338 | routine main
339339 | outputs many
346346 | }
347347 ? TypeMismatchError
348348
349 | byte table[256] many
349 | table[256] byte many
350350 |
351351 | routine main
352352 | outputs many
359359 | }
360360 = ok
361361
362 | byte table[256] many
362 | table[256] byte many
363363 |
364364 | routine main
365365 | inputs many
373373
374374 The index must be initialized.
375375
376 | byte table[256] many
376 | table[256] byte many
377377 |
378378 | routine main
379379 | inputs many
387387 Copying to and from a word table.
388388
389389 | word one
390 | word table[256] many
390 | table[256] word many
391391 |
392392 | routine main
393393 | inputs one, many
401401 = ok
402402
403403 | word one
404 | word table[256] many
404 | table[256] word many
405405 |
406406 | routine main
407407 | inputs one, many
414414 ? TypeMismatchError
415415
416416 | word one
417 | word table[256] many
417 | table[256] word many
418418 |
419419 | routine main
420420 | inputs one, many
428428
429429 You can also copy a literal word to a word table.
430430
431 | word table[256] many
431 | table[256] word many
432432 |
433433 | routine main
434434 | inputs many
15921592 Routines are constants. You need not, and in fact cannot, specify a constant
15931593 as an input to, an output of, or as a trashed value of a routine.
15941594
1595 | vector vec
1596 | inputs x
1597 | outputs x
1598 | trashes z, n
1595 | vector routine
1596 | inputs x
1597 | outputs x
1598 | trashes z, n
1599 | vec
15991600 |
16001601 | routine foo
16011602 | inputs x
16141615 | }
16151616 ? ConstantConstraintError: foo in main
16161617
1617 | vector vec
1618 | inputs x
1619 | outputs x
1620 | trashes z, n
1618 | vector routine
1619 | inputs x
1620 | outputs x
1621 | trashes z, n
1622 | vec
16211623 |
16221624 | routine foo
16231625 | inputs x
16351637 | }
16361638 ? ConstantConstraintError: foo in main
16371639
1638 | vector vec
1639 | inputs x
1640 | outputs x
1641 | trashes z, n
1640 | vector routine
1641 | inputs x
1642 | outputs x
1643 | trashes z, n
1644 | vec
16421645 |
16431646 | routine foo
16441647 | inputs x
16591662 You can copy the address of a routine into a vector, if that vector is
16601663 declared appropriately.
16611664
1662 | vector vec
1663 | inputs x
1664 | outputs x
1665 | trashes z, n
1665 | vector routine
1666 | inputs x
1667 | outputs x
1668 | trashes z, n
1669 | vec
16661670 |
16671671 | routine foo
16681672 | inputs x
16821686
16831687 But not if the vector is declared inappropriately.
16841688
1685 | vector vec
1689 | vector routine
16861690 | inputs y
16871691 | outputs y
16881692 | trashes z, n
1693 | vec
16891694 |
16901695 | routine foo
16911696 | inputs x
17061711 "Appropriately" means, if the routine affects no more than what is named
17071712 in the input/output sets of the vector.
17081713
1709 | vector vec
1714 | vector routine
17101715 | inputs a, x
17111716 | outputs x
17121717 | trashes a, z, n
1718 | vec
17131719 |
17141720 | routine foo
17151721 | inputs x
17291735
17301736 Routines are read-only.
17311737
1732 | vector vec
1733 | inputs x
1734 | outputs x
1735 | trashes z, n
1738 | vector routine
1739 | inputs x
1740 | outputs x
1741 | trashes z, n
1742 | vec
17361743 |
17371744 | routine foo
17381745 | inputs x
17521759
17531760 Indirect call.
17541761
1755 | vector foo outputs x trashes z, n
1762 | vector routine
1763 | outputs x trashes z, n
1764 | foo
17561765 |
17571766 | routine bar outputs x trashes z, n {
17581767 | ld x, 200
17661775
17671776 Calling the vector does indeed trash the things the vector says it does.
17681777
1769 | vector foo trashes x, z, n
1778 | vector routine trashes x, z, n foo
17701779 |
17711780 | routine bar trashes x, z, n {
17721781 | ld x, 200
18661875
18671876 Indirect goto.
18681877
1869 | vector foo outputs x trashes a, z, n
1878 | vector routine outputs x trashes a, z, n foo
18701879 |
18711880 | routine bar outputs x trashes a, z, n {
18721881 | ld x, 200
18811890 Jumping through the vector does indeed trash, or output, the things the
18821891 vector says it does.
18831892
1884 | vector foo
1893 | vector routine
18851894 | trashes a, x, z, n
1895 | foo
18861896 |
18871897 | routine bar
18881898 | trashes a, x, z, n {
19041914 | }
19051915 ? UnmeaningfulReadError: x in main
19061916
1907 | vector foo
1908 | outputs x
1909 | trashes a, z, n
1917 | vector routine
1918 | outputs x
1919 | trashes a, z, n foo
19101920 |
19111921 | routine bar
19121922 | outputs x
19341944
19351945 A vector can be copied into a vector table.
19361946
1937 | vector one
1938 | outputs x
1939 | trashes a, z, n
1940 | vector table[256] many
1941 | outputs x
1942 | trashes a, z, n
1947 | vector routine
1948 | outputs x
1949 | trashes a, z, n
1950 | one
1951 | table[256] vector routine
1952 | outputs x
1953 | trashes a, z, n
1954 | many
19431955 |
19441956 | routine bar outputs x trashes a, z, n {
19451957 | ld x, 200
19581970
19591971 A vector can be copied out of a vector table.
19601972
1961 | vector one
1962 | outputs x
1963 | trashes a, z, n
1964 | vector table[256] many
1965 | outputs x
1966 | trashes a, z, n
1973 | vector routine
1974 | outputs x
1975 | trashes a, z, n
1976 | one
1977 | table[256] vector routine
1978 | outputs x
1979 | trashes a, z, n
1980 | many
19671981 |
19681982 | routine bar outputs x trashes a, z, n {
19691983 | ld x, 200
19821996
19831997 A routine can be copied into a vector table.
19841998
1985 | vector table[256] many
1986 | outputs x
1987 | trashes a, z, n
1999 | table[256] vector routine
2000 | outputs x
2001 | trashes a, z, n
2002 | many
19882003 |
19892004 | routine bar outputs x trashes a, z, n {
19902005 | ld x, 200
20022017
20032018 A vector in a vector table cannot be directly called.
20042019
2005 | vector table[256] many
2006 | outputs x
2007 | trashes a, z, n
2020 | table[256] vector routine
2021 | outputs x
2022 | trashes a, z, n
2023 | many
20082024 |
20092025 | routine bar outputs x trashes a, z, n {
20102026 | ld x, 200
138138
139139 Initialized byte table. Bytes allocated, but beyond the string, are 0's.
140140
141 | byte table[8] message : "WHAT?"
141 | table[8] byte message : "WHAT?"
142142 |
143143 | routine main
144144 | inputs message
351351 Indexed access.
352352
353353 | byte one
354 | byte table[256] many
354 | table[256] byte many
355355 |
356356 | routine main
357357 | outputs many
370370
371371 Byte tables take up 256 bytes in memory.
372372
373 | byte table[256] tab1
374 | byte table[256] tab2
373 | table[256] byte tab1
374 | table[256] byte tab2
375375 |
376376 | routine main
377377 | inputs tab1
457457
458458 You can also copy a literal word to a word table.
459459
460 | word table[256] many
460 | table[256] word many
461461 |
462462 | routine main
463463 | inputs many
476476
477477 Copy vector to vector.
478478
479 | vector bar
480 | vector baz
479 | vector routine bar
480 | vector routine baz
481481 |
482482 | routine main
483483 | inputs baz
494494
495495 Copy routine to vector, inside an `interrupts off` block.
496496
497 | vector bar
497 | vector routine bar
498498 |
499499 | routine foo
500500 | inputs x
526526 Copy word to word table and back, with both `x` and `y` as indexes.
527527
528528 | word one
529 | word table[256] many
529 | table[256] word many
530530 |
531531 | routine main
532532 | inputs one, many
567567
568568 Indirect call.
569569
570 | vector foo outputs x trashes z, n
570 | vector routine outputs x trashes z, n foo
571571 |
572572 | routine bar outputs x trashes z, n {
573573 | ld x, 200
607607
608608 Copying to and from a vector table.
609609
610 | vector one
610 | vector routine
611611 | outputs x
612612 | trashes a, z, n
613 | vector table[256] many
613 | one
614 | table[256] vector routine
614615 | outputs x
615616 | trashes a, z, n
617 | many
616618 |
617619 | routine bar outputs x trashes a, z, n {
618620 | ld x, 200
134134
135135 | byte byt
136136 | word wor
137 | vector vec trashes a
138 | byte table[256] tab
139 | word table[256] wtab
140 | vector table[256] vtab trashes a
137 | vector routine trashes a vec
141138 | buffer[2048] buf
142139 | pointer ptr
143140 |
145142 | }
146143 = ok
147144
145 Tables of different types.
146
147 | table[256] byte tab
148 | table[256] word wtab
149 | table[256] vector routine trashes a vtab
150 |
151 | routine main {
152 | }
153 = ok
154
148155 Explicit memory address.
149156
150157 | byte screen @ 1024
177184
178185 User-defined locations of other types.
179186
180 | byte table[256] screen @ 1024
187 | table[256] byte screen @ 1024
181188 | word r1
182189 | word r2 @ 60000
183190 | word r3 : 2000
188195
189196 Initialized byte table.
190197
191 | byte table[28] message : "WHAT DO YOU WANT TO DO NEXT?"
198 | table[28] byte message : "WHAT DO YOU WANT TO DO NEXT?"
192199 |
193200 | routine main {
194201 | }
290297
291298 Declaring byte and word table memory location.
292299
293 | byte table[256] tab
300 | table[256] byte tab
294301 |
295302 | routine main {
296303 | ld x, 0
301308 = ok
302309
303310 | word one
304 | word table[256] many
311 | table[256] word many
305312 |
306313 | routine main {
307314 | ld x, 0
313320
314321 Declaring and calling a vector.
315322
316 | vector cinv
323 | vector routine
317324 | inputs a
318325 | outputs x
319326 | trashes a, x, z, n
320 | @ 788
327 | cinv @ 788
321328 |
322329 | routine foo {
323330 | ld a, 0
344351
345352 Constraints set may only contain labels.
346353
347 | vector cinv
354 | vector routine
348355 | inputs a
349356 | outputs 200
350357 | trashes a, x, z, n
351 | @ 788
358 | cinv @ 788
352359 |
353360 | routine foo {
354361 | ld a, 0
363370
364371 A vector can name itself in its inputs, outputs, and trashes.
365372
366 | vector cinv
373 | vector routine
367374 | inputs cinv, a
368375 | outputs cinv, x
369376 | trashes a, x, z, n
370 | @ 788
377 | cinv @ 788
371378 |
372379 | routine foo {
373380 | ld a, 0
383390 A routine can be copied into a vector before the routine appears in the program,
384391 *however*, it must be marked as such with the keyword `forward`.
385392
386 | vector cinv
393 | vector routine
387394 | inputs cinv, a
388395 | outputs cinv, x
389396 | trashes a, x, z, n
390 | @ 788
397 | cinv @ 788
391398 | routine main {
392399 | with interrupts off {
393400 | copy foo, cinv
399406 | }
400407 ? SyntaxError: Undefined symbol
401408
402 | vector cinv
409 | vector routine
403410 | inputs cinv, a
404411 | outputs cinv, x
405412 | trashes a, x, z, n
406 | @ 788
413 | cinv @ 788
407414 | routine main {
408415 | with interrupts off {
409416 | copy forward foo, cinv
433440 | }
434441 = ok
435442
436 | vector foo
443 | vector routine foo
437444 |
438445 | routine main {
439446 | goto foo