git @ Cat's Eye Technologies SixtyPical / goto-at-end-of-block doc / SixtyPical.md
goto-at-end-of-block

Tree @goto-at-end-of-block (Download .tar.gz)

SixtyPical.md @goto-at-end-of-block

8ccabdf
f92056d
 
3f0e36a
15072ef
 
 
f92056d
8ccabdf
 
f92056d
4d61f43
 
 
f92056d
 
 
15e1fa5
f92056d
 
 
f2f716d
c98e446
9874b11
f92056d
15e1fa5
0e9a887
d24e9fa
15e1fa5
e2d10d7
15e1fa5
 
 
 
 
 
 
 
 
0e9a887
f92056d
 
 
f2f716d
 
 
f92056d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8ccabdf
 
 
f92056d
 
 
 
 
 
f2f716d
f92056d
 
 
 
 
 
f2f716d
 
22cc7bf
 
f2f716d
22cc7bf
f2f716d
22cc7bf
 
f2f716d
f92056d
 
 
f2f716d
c98e446
f92056d
 
 
6cf8b5f
522c771
c98e446
522c771
6cf8b5f
 
 
7b1ee60
6cf8b5f
f2f716d
 
 
 
f0b8942
15e1fa5
 
 
 
 
f0b8942
0e9a887
 
 
 
 
 
 
 
 
 
 
feb5729
9874b11
 
 
 
 
 
 
 
 
 
 
f92e1f1
9874b11
 
 
 
 
 
 
 
 
 
 
f92056d
 
 
f2f716d
 
 
 
 
 
 
 
 
 
f92056d
 
 
 
 
 
 
 
c79bc56
 
f2f716d
f92056d
2dc4dd9
 
 
f92056d
8ccabdf
 
 
f2f716d
8ccabdf
 
 
 
f2f716d
f92056d
c79bc56
 
 
49d90df
 
 
 
 
 
f92056d
 
 
f2f716d
 
 
 
 
 
 
f92056d
 
41414b0
f92056d
 
 
 
f2f716d
f92056d
 
 
 
f2f716d
8ccabdf
f92056d
41414b0
7f38d04
 
41414b0
f92056d
7f38d04
 
f92056d
f92e1f1
 
ca1c877
f92e1f1
 
 
 
 
 
 
 
 
f92056d
 
41414b0
f92056d
 
 
 
f2f716d
f92056d
 
 
 
 
 
41414b0
7f38d04
 
41414b0
ca1c877
 
 
 
 
 
 
 
 
 
 
 
 
c79bc56
 
 
 
e74c7f2
 
 
c79bc56
 
 
 
 
 
 
 
 
9874b11
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f92056d
 
 
 
 
 
 
 
f2f716d
f92056d
f2f716d
8ccabdf
f92056d
8ccabdf
f92056d
0120a4e
 
 
 
 
 
f92056d
 
8ccabdf
 
 
 
 
 
f2f716d
8ccabdf
f2f716d
8ccabdf
 
f92056d
 
 
 
 
 
8ccabdf
 
f2f716d
8ccabdf
f2f716d
8ccabdf
 
 
f92056d
dcc944d
 
 
f92056d
 
4d61f43
8ccabdf
 
 
 
 
f2f716d
8ccabdf
f2f716d
8ccabdf
 
f92056d
 
 
 
4d61f43
 
94ee042
 
 
f92056d
8ccabdf
 
f2f716d
8ccabdf
f92056d
dcc944d
 
e74c7f2
94ee042
a765a50
 
dcc944d
a765a50
 
4fc38be
f92056d
 
 
4fc38be
f92056d
4fc38be
 
f92056d
4fc38be
 
f2f716d
f92056d
f2f716d
4fc38be
f92056d
4fc38be
f92056d
4fc38be
f92056d
 
4fc38be
f92056d
4fc38be
f92056d
 
4fc38be
 
 
f92056d
 
 
f2f716d
f92056d
f2f716d
4fc38be
 
f92056d
 
2dc4dd9
 
 
 
646ec38
 
f92056d
f2f716d
 
f92056d
 
 
f2f716d
 
 
9874b11
f92056d
646ec38
 
 
 
 
 
 
 
 
 
 
 
 
 
c79bc56
 
646ec38
 
 
f2f716d
 
646ec38
f92056d
 
4d61f43
 
f92056d
4d61f43
f92056d
 
4d61f43
 
 
f92056d
4d61f43
 
 
 
f92056d
feb5729
 
f7eb0d4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c79bc56
c98e446
c79bc56
 
 
 
 
c98e446
c79bc56
c98e446
c79bc56
 
 
 
 
c98e446
d88757c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f92056d
 
 
3f0e36a
 
783d876
3f0e36a
08ec0e4
783d876
 
 
 
08ec0e4
783d876
08ec0e4
783d876
 
f0b8942
783d876
 
 
f92056d
3f0e36a
f92056d
 
3f0e36a
7f38d04
49d90df
3f0e36a
7f38d04
f92056d
4287bf8
 
f92056d
 
 
 
 
 
 
 
 
 
be76b9a
 
7f38d04
f7eb0d4
49e42af
3f0e36a
7f38d04
f7eb0d4
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
SixtyPical
==========

This document describes the SixtyPical programming language version 0.15,
both its static semantics (the capabilities and limits of the static
analyses it defines) and its runtime semantics (with reference to the
semantics of 6502 machine code.)

This document is nominally normative, but the tests in the `tests` directory
are even more normative.

Refer to the bottom of this document for an EBNF grammar of the syntax of
the language.

Types
-----

There are five *primitive types* in SixtyPical:

*   bit (2 possible values)
*   byte (256 possible values)
*   word (65536 possible values)
*   routine (code stored somewhere in memory, read-only)
*   pointer (address of a byte in a buffer)

There are also three *type constructors*:

*   T table[N] (N entries, 1 ≤ N ≤ 256; each entry holds a value
                of type T, where T is `byte`, `word`, or `vector`)
*   buffer[N] (N entries; each entry is a byte; 1 ≤ N ≤ 65536)
*   vector T (address of a value of type T; T must be a routine type)

### User-defined ###

A program may define its own types using the `typedef` feature.  Typedefs
must occur before everything else in the program.  A typedef takes a
type expression and an identifier which has not previously been used in
the program.  It associates that identifer with that type.  This is merely
a type alias; two types with different names will compare as equal.

Memory locations
----------------

A primary concept in SixtyPical is the *memory location*.  At any given point
in time during execution, each memory location is either *uninitialized* or
*initialized*.  At any given point in the program text, too, each memory
location is either uninitialized or initialized.  Where-ever it is one or
the other during execution, it is the same in the corresponding place in
the program text; thus, it is a static property.

There are four general kinds of memory location.  The first three are
pre-defined and built-in.

### Registers ###

Each of these hold a byte.  They are initially uninitialized.

    a
    x
    y

### Flags ###

Each of these hold a bit.  They are initially uninitialized.

    c (carry)
    z (zero)
    v (overflow)
    n (negative)

### Constants ###

It may be strange to think of constants as memory locations, but keep in mind
that a memory location in SixtyPical need not map to a memory location in the
underlying hardware.  All constants are read-only.  Each is initially
initialized with the value that corresponds with its name.

They come in bit and byte types.  There are two bit constants,

    off
    on

two hundred and fifty-six byte constants,

    0
    1
    ...
    255

and sixty-five thousand five hundred and thirty-six word constants,

    word 0
    word 1
    ...
    word 65535

Note that if a word constant is between 256 and 65535, the leading `word`
token can be omitted.

### User-defined ###

There may be any number of user-defined memory locations.  They are defined
by giving the type (which may be any type except `bit` and `routine`) and the
name.

    byte pos

An address in memory may be given explicitly on a user-defined memory location.

    byte table screen @ 1024

Or, a user-defined memory location may be given an initial value.  But in this
case, an explicit address in memory cannot be given.

    byte pos : 0

A user-defined vector memory location is decorated with `inputs`, `outputs`
and `trashes` lists like a routine (see below), and it may only hold addresses
of routines which are compatible.  (Meaning, the routine's inputs (resp. outputs,
trashes) must be a subset of the vector's inputs (resp. outputs, trashes.))

    vector routine
             inputs a, score
             outputs x
             trashes y
      actor_logic @ $c000

Note that in the code of a routine, if a memory location is named by a
user-defined symbol, it is an address in memory, and can be read and written.
But if it is named by a literal integer, either decimal or hexadecimal, it
is a constant and can only be read (and when read always yields that constant
value.  So, for instance, to read the value at `screen` above, in the code,
you would need to reference the symbol `screen`; attempting to read 1024
would not work.

This is actually useful, at least at this point, as you can rely on the fact
that literal integers in the code are always immediate values.  (But this
may change at some point.)

### Buffers and Pointers ###

Roughly speaking, a `buffer` is a table that can be longer than 256 bytes,
and a `pointer` is an address within a buffer.

A `pointer` is implemented as a zero-page memory location, and accessing the
buffer pointed to is implemented with "indirect indexed" addressing, as in

    LDA ($02), Y
    STA ($02), Y

There are extended instruction modes for using these types of memory location.
See `copy` below, but here is some illustrative example code:

    copy ^buf, ptr           // this is the only way to initialize a pointer
    add ptr, 4               // ok, but only if it does not exceed buffer's size
    ld y, 0                  // you must set this to something yourself
    copy [ptr] + y, byt      // read memory through pointer, into byte
    copy 100, [ptr] + y      // write memory through pointer (still trashes a)

where `ptr` is a user-defined storage location of `pointer` type, and the
`+ y` part is mandatory.

Routines
--------

Every routine must list all the memory locations it *reads from*, which we
call its `inputs`, and all the memory locations it *writes to*.  The latter
we divide into two groups: its `outputs` which it intentionally initializes,
and its `trashes`, which it does not care about, and leaves uninitialized.
For example, if it uses a register to temporarily store an intermediate
value used in a multiplication, that register has no meaning outside of
the multiplication, and is one of the routine's `trashes`.

It is common to say that the `trashes` are the memory locations that are
*not preserved* by the routine.

    routine foo
      inputs a, score
      outputs x
      trashes y {
        ...
    }

The union of the `outputs` and `trashes` is sometimes collectively called
"the WRITES" of the routine, for historical reasons and as shorthand.

Routines may call only routines previously defined in the program source.
Thus, directly recursive routines are not allowed.  (However, routines may
also call routines via vectors, which are dynamically assigned.  In this
case, there is, for the time being, no check for recursive calls.)

For a SixtyPical program to be run, there must be one routine called `main`.
This routine is executed when the program is run.

The memory locations given as inputs to a routine are considered to be initialized
at the beginning of the routine.  Various instructions cause memory locations
to be initialized after they are executed.  Calling a routine which trashes
some memory locations causes those memory locations to be uninitialized after
that routine is called.  At the end of a routine, all memory locations listed
as outputs must be initialized.

A literal word can given instead of the body of the routine.  This word is the
absolute address of an "external" routine located in memory but not defined by
the SixtyPical program.

    routine chrout
      inputs a
      trashes a
      @ 65490

Instructions
------------

Instructions are inspired by, and in many cases closely resemble, the 6502
instruction set.  However, in many cases they do not map 1:1 to 6502 instructions.
If a SixtyPical instruction cannot be translated validly to one more more 6502
instructions while retaining all the stated constraints, that's a static error
in a SixtyPical program, and technically any implementation of SixtyPical, even
an interpreter, should flag it up.

### ld ###

    ld <dest-memory-location>, <src-memory-location> [+ <index-memory-location>]

Reads from src and writes to dest.

*   It is illegal if dest is not a register.
*   It is illegal if dest does not occur in the WRITES of the current routine.
*   It is illegal if src is not of same type as dest (i.e., is not a byte.)
*   It is illegal if src is uninitialized.

After execution, dest is considered initialized.  The flags `z` and `n` may be
changed by this instruction; they must be named in the WRITES, and they
are considered initialized after it has executed.

If and only if src is a byte table, the index-memory-location must be given.
In this case, it is illegal if the value of the index-memory-location falls
outside of the range of the table.

Some combinations, such as `ld x, y`, are illegal because they do not map to
underlying opcodes.  (For an instruction which maps more flexibly to underlying
opcodes, see `copy`.)

There is another mode of `ld` which reads into `a` indirectly through a pointer.

    ld a, [<src-memory-location>] + y

The memory location in this syntax must be a pointer.

This syntax copies the contents of memory at the pointer (offset by the `y`
register) into a register (which must be the `a` register.)

In addition to the constraints above, `y` must be initialized before
this mode is used.

### st ###

    st <src-memory-location>, <dest-memory-location> [+ <index-memory-location>]

Reads from src and writes to dest.

*   It is illegal if dest is a register or if dest is read-only.
*   It is illegal if dest does not occur in the WRITES 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.  No flags are
changed by this instruction (unless of course dest is a flag.)

If and only if dest is a byte table, the index-memory-location must be given.
In this case, it is illegal if the value of the index-memory-location falls
outside of the range of the table.

There is another mode of `st` which write `a` into memory, indirectly through
a pointer.

    st a, [<dest-memory-location>] + y

The memory location in this syntax must be a pointer.

This syntax copies the constents of the `a` register into
the contents of memory at the pointer (offset by the `y` register).

In addition to the constraints above, `y` must be initialized before
this mode is used.

### copy ###

    copy <src-memory-location>, <dest-memory-location>

Reads from src and writes to dest.  Differs from `ld` and `st` in that
it is able to copy more general types of data (for example, vectors,)
and it trashes the `z` and `n` flags and the `a` register.

*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES 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, and `z` and `n`, and
`a` are considered uninitialized.

There are two extra modes that this instruction can be used in.  The first is
to load an address into a pointer:

    copy ^<src-memory-location>, <dest-memory-location>

This copies the address of src into dest.  In this case, src must be
of type buffer, and dest must be of type pointer.  src will not be
considered a memory location that is read, since it is only its address
that is being retrieved.

The second is to read or write indirectly through a pointer.

    copy [<src-memory-location>] + y, <dest-memory-location>
    copy <src-memory-location>, [<dest-memory-location>] + y

In both of these, the memory location in the `[]+y` syntax must be
a pointer.

The first copies the contents of memory at the pointer (offset by the `y`
register) into a byte memory location.

The second copies a literal byte, or a byte memory location, into
the contents of memory at the pointer (offset by the `y` register).

In addition to the constraints above, `y` must be initialized before
this mode is used.

### add dest, src ###

    add <dest-memory-location>, <src-memory-location>

Adds the contents of src to dest and stores the result in dest.

*   It is illegal if src OR dest OR c is uninitialized.
*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects n, z, c, and v flags, requiring that they be in the WRITES,
and initializing them afterwards.

dest and src continue to be initialized afterwards.

In addition, if dest is of `word` type, then src must also be of `word`
type, and in this case this instruction trashes the `a` register.

NOTE: If dest is a pointer, the addition does not check if the result of
the pointer arithmetic continues to be valid (within a buffer) or not.

### inc ###

    inc <dest-memory-location>

Increments the value in dest.  Does not honour carry.

*   It is illegal if dest is uninitialized.
*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects n and z flags, requiring that they be in the WRITES,
and initializing them afterwards.

### sub ###

    sub <dest-memory-location>, <src-memory-location>

Subtracts the contents of src from dest and stores the result in dest.

*   It is illegal if src OR dest OR c is uninitialized.
*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects n, z, c, and v flags, requiring that they be in the WRITES,
and initializing them afterwards.

dest and src continue to be initialized afterwards.

In addition, if dest is of `word` type, then src must also be of `word`
type, and in this case this instruction trashes the `a` register.

### dec ###

    dec <dest-memory-location>

Decrements the value in dest.  Does not honour carry.

*   It is illegal if dest is uninitialized.
*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects n and z flags, requiring that they be in the WRITES,
and initializing them afterwards.

### cmp ###

    cmp <dest-memory-location>, <src-memory-location>

Subtracts the contents of src from dest (without considering carry) but
does not store the result anywhere, only sets the resulting flags.
This means that `z` is set if src and dest are equal,
and `c` is set if dest is greater than or equal to src
(`c` is unset if dest is less than src.)

*   It is illegal if src OR dest is uninitialized.

Affects n, z, and c flags, requiring that they be in the WRITES,
and initializing them afterwards.

In addition, if dest is of `word` type, then src must also be of `word`
type, and in this case this instruction trashes the `a` register.

Note that `cmp` is not suitable for making a
signed comparison; this article, which mentions
techniques that a SixtyPical compiler could use to
implement `cmp`, also explains why that is:
[Beyond 8-bit Unsigned Comparisons, by Bruce Clark](http://www.6502.org/tutorials/compare_beyond.html).

### and, or, xor ###

    and <dest-memory-location>, <src-memory-location>
    or <dest-memory-location>, <src-memory-location>
    xor <dest-memory-location>, <src-memory-location>

Applies the given bitwise Boolean operation to src and dest and stores
the result in dest.

*   It is illegal if src OR dest OR is uninitialized.
*   It is illegal if dest is read-only.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects n and z flags, requiring that they be in the WRITES of the
current routine, and sets them as initialized afterwards.

dest and src continue to be initialized afterwards.

### shl, shr ###

    shl <dest-memory-location>
    shr <dest-memory-location>

`shl` shifts the dest left one bit position.  The rightmost position becomes `c`,
and `c` becomes the bit that was shifted off the left.

`shr` shifts the dest right one bit position.  The leftmost position becomes `c`,
and `c` becomes the bit that was shifted off the right.

*   It is illegal if dest is a register besides `a`.
*   It is illegal if dest is read-only.
*   It is illegal if dest OR c is uninitialized.
*   It is illegal if dest does not occur in the WRITES of the current routine.

Affects the c flag, requiring that it be in the WRITES of the
current routine, and it continues to be initialized afterwards.

### call ###

    call <executable-name>

Transfers execution to the given executable, whether that is a previously-
defined routine, or a vector location which contains the address of a routine
which will be called indirectly.  Execution will be transferred back to the
current routine, when execution of the executable is finished.

*   It is illegal if any of the memory locations listed in the called routine's
    `inputs` are uninitialized immediately before the call.

Just after the call,

*   All memory locations listed in the called routine's `trashes` are considered
    to now be uninitialized.
*   All memory locations listed in the called routine's `outputs` are considered
    to now be initialized.

### goto ###

    goto <executable-name>

Unilaterally transfers execution to the given executable.  Execution will not
be transferred back to the current routine when execution of the executable is
finished; rather, it will be transferred back to the caller of the current
routine.

If `goto` is used in a routine, it must be in tail position.  That is, it
must be the final instruction in the routine.

Just before the goto,

*   It is illegal if any of the memory locations in the target routine's
    `inputs` list is uninitialized.

In addition,

*   The target executable's WRITES must not include any locations
    that are not already included in the current routine's WRITES.

### if ###

    if <src-memory-location> {
        <true-branch>
    } else {
        <false-branch>
    }

Executes the true-branch if the value in src is nonzero, otherwise executes
the false-branch.  The false-branch is optional may be omitted; in this case
it is treated like an empty block.

*   It is illegal if src is not z, c, n, or v.
*   It is illegal if src is not initialized.
*   It is illegal if any location initialized at the end of the true-branch
    is not initialized at the end of the false-branch, and vice versa.

The sense of the test can be inverted with `not`.

### repeat ###

    repeat {
        <block>
    } until <src-memory-location>

Executes the block repeatedly until the src (observed at the end of the
execution of the block) is non-zero.  The block is always executed as least
once.

*   It is illegal if any memory location is uninitialized at the exit of
    the loop when that memory location is initialized at the start of
    the loop.

To simulate a "while" loop, use an `if` internal to the block, like

    repeat {
        cmp y, 25
        if z {
        }
    } until z

"until" is optional, but if omitted, must be replaced with "forever":

    repeat {
        cmp y, 25
        if z {
        }
    } forever

The sense of the test can be inverted with `not`.

    repeat {
        cmp y, 25
        if z {
        }
    } until not z

### for ###

    for <dest-memory-location> (up|down) to <literal-byte> {
        <block>
    }

Executes the block repeatedly, incrementing or decrementing the
dest-memory-location at the end of the block, until the value of
the dest-memory-location has gone past the literal-byte.

The block is always executed as least once.

*   It is illegal if any memory location is uninitialized at the exit of
    the loop when that memory location is initialized at the start of
    the loop.

Grammar
-------

    Program ::= {ConstDefn | TypeDefn} {Defn} {Routine}.
    ConstDefn::= "const" Ident<new> Const.
    TypeDefn::= "typedef" Type Ident<new>.
    Defn    ::= Type Ident<new> [Constraints] (":" Const | "@" LitWord).
    Type    ::= TypeTerm ["table" TypeSize].
    TypeExpr::= "byte"
              | "word"
              | "buffer" TypeSize
              | "pointer"
              | "vector" TypeTerm
              | "routine" Constraints
              | "(" Type ")"
              .
    TypeSize::= "[" LitWord "]".
    Constrnt::= ["inputs" LocExprs] ["outputs" LocExprs] ["trashes" LocExprs].
    Routine ::= "define" Ident<new> Type (Block | "@" LitWord).
              | "routine" Ident<new> Constraints (Block | "@" LitWord)
              .
    LocExprs::= LocExpr {"," LocExpr}.
    LocExpr ::= Register | Flag | Const | Ident.
    Register::= "a" | "x" | "y".
    Flag    ::= "c" | "z" | "n" | "v".
    Const   ::= Literal | Ident<const>.
    Literal ::= LitByte | LitWord | LitBit.
    LitByte ::= "0" ... "255".
    LitWord ::= ["word"] "0" ... "65535".
    LitBit  ::= "on" | "off".
    Block   ::= "{" {Instr} "}".
    Instr   ::= "ld" LocExpr "," LocExpr ["+" LocExpr]
              | "st" LocExpr "," LocExpr ["+" LocExpr]
              | "add" LocExpr "," LocExpr
              | "sub" LocExpr "," LocExpr
              | "cmp" LocExpr "," LocExpr
              | "and" LocExpr "," LocExpr
              | "or" LocExpr "," LocExpr
              | "xor" LocExpr "," LocExpr
              | "shl" LocExpr
              | "shr" LocExpr
              | "inc" LocExpr
              | "dec" LocExpr
              | "call" Ident<routine>
              | "goto" Ident<executable>
              | "copy" LocExpr "," LocExpr ["+" LocExpr]
              | "if" ["not"] LocExpr Block ["else" Block]
              | "repeat" Block ("until" ["not"] LocExpr | "forever")
              | "for" LocExpr ("up"|"down") "to" Const Block
              | "with" "interrupts" LitBit Block
              .