uxn

Varvara Ordinator, written in ANSI C(SDL2)
git clone https://git.eamoncaddigan.net/uxn.git
Log | Files | Refs | README | LICENSE

asma.tal (24710B)


      1 (
      2 	Asma - an in-Uxn assembler
      3 
      4 	This assembler aims to be binary compatible with the output from
      5 	src/uxnasm.c, but unlike that assembler this one can be run inside Uxn
      6 	itself!
      7 
      8 	Asma is designed to be able to be copy-pasted inside another project, so
      9 	all its routines are prefixed with "asma-" to prevent clashes with labels
     10 	used in the incorporating project. The reset vector contains a couple of
     11 	examples of asma's usage and can be discarded.
     12 )
     13 
     14 (
     15 	Asma's public interface.
     16 	These routines are what are expected to be called from programs that bundle
     17 	Asma into bigger projects.
     18 )
     19 
     20 @asma-assemble-file ( src-filename* dest-filename* -- )
     21 	#01 .File/append DEO
     22 	DUP2 .File/name DEO2
     23 	#01 .File/delete DEO
     24 	;asma/dest-filename STA2 ;asma/src-filename STA2
     25 
     26 	;asma-init-first-pass JSR2
     27 	;asma-flush-ignore ;asma/flush-fn STA2
     28 	;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
     29 	;asma/error LDA2 ORA ,&error JCN
     30 
     31 	;asma-init-next-pass JSR2
     32 	;asma-flush-to-file ;asma/flush-fn STA2
     33 	;asma/dest-filename LDA2 ORA ,&filename-present JCN
     34 	;asma-flush-to-console ;asma/flush-fn STA2
     35 	&filename-present
     36 	;asma/src-filename LDA2 ;asma-assemble-file-pass JSR2
     37 	;asma/error LDA2 ORA ,&error JCN
     38 
     39 	( flush output buffer )
     40 	;asma-output/ptr LDA2 ;asma-write-buffer SUB2 ;asma/flush-fn LDA2 JSR2
     41 
     42 	;asma-trees/labels ;asma-print-labels JSR2 ( DEBUG )
     43 	;asma-print-line-count JSR2 ( DEBUG )
     44 	;asma-print-heap-usage JSR2 ( DEBUG )
     45 	JMP2r
     46 
     47 	&error
     48 	;asma-print-error JSR2 ( DEBUG )
     49 	JMP2r
     50 
     51 (
     52 	Debugging routines. These all output extra information to the Console.
     53 	These can be stripped out to save space, once the references to them are
     54 	removed. Look for the word DEBUG above to find these references: the lines
     55 	that contain that word can be deleted to strip out the functionality
     56 	cleanly.
     57 )
     58 
     59 @asma-print-error ( -- )
     60 	.File/name DEI2 ;asma-print-string JSR2
     61 	;&line ;asma-print-string JSR2
     62 	;asma/line LDA2 ;asma-print-short JSR2
     63 	#3a .Console/error DEO
     64 	#20 .Console/error DEO
     65 	;asma/error LDA2 ;asma-print-string JSR2
     66 	#3a .Console/error DEO
     67 	#20 .Console/error DEO
     68 	;asma/orig-token LDA2 ;asma-print-string JSR2
     69 	#2e .Console/error DEO
     70 	#0a .Console/error DEO
     71 	JMP2r
     72 
     73 	&line 20 "line 20 00
     74 
     75 @asma-print-line-count ( -- )
     76 	;asma/log-level LDA #01 AND #00 EQU ,&skip JCN
     77 	;asma/lines LDA2 ;asma-print-short JSR2
     78 	;&lines ;asma-print-string JSR2
     79 	&skip
     80 	JMP2r
     81 
     82 	&lines [ 20 "lines 20 "of 20 "source 20 "code. 0a 00 ]
     83 
     84 @asma-print-heap-usage ( -- )
     85 	;asma/log-level LDA #08 AND #00 EQU ,&skip JCN
     86 	;heap LDA2 ;asma-heap SUB2 ;asma-print-short JSR2
     87 	;&str1 ;asma-print-string JSR2
     88 	;asma-heap/end ;heap LDA2 SUB2 ;asma-print-short JSR2
     89 	;&str2 ;asma-print-string JSR2
     90 	&skip
     91 	JMP2r
     92 
     93 	&str1 [ 20 "bytes 20 "of 20 "heap 20 "used, 20 00 ]
     94 	&str2 [ 20 "bytes 20 "free. 0a 00 ]
     95 
     96 @asma-print-sublabels ( incoming-ptr* -- )
     97 	LDA2
     98 	ORAk ,&valid-incoming-ptr JCN
     99 	POP2 JMP2r
    100 
    101 	&valid-incoming-ptr
    102 	( left node )
    103 	DUP2 ,asma-print-sublabels JSR
    104 	( here )
    105 	#09 .Console/error DEO
    106 	DUP2 #0004 ADD2
    107 	&loop
    108 	DUP2 INC2 SWP2 LDA
    109 	DUP #00 EQU ,&end JCN
    110 	.Console/error DEO
    111 	,&loop JMP
    112 	&end
    113 	POP
    114 	#09 .Console/error DEO
    115 	LDA2 ;asma-print-short JSR2
    116 	#0a .Console/error DEO
    117 
    118 	( right node )
    119 	#0002 ADD2 ,asma-print-sublabels JSR
    120 	JMP2r
    121 
    122 @asma-print-labels ( incoming-ptr* -- )
    123 	;asma/log-level LDA #04 AND #00 EQU ,&skip JCN
    124 	LDA2
    125 	ORAk ,&valid-incoming-ptr JCN
    126 	&skip
    127 	POP2 JMP2r
    128 
    129 	&valid-incoming-ptr
    130 	( left node )
    131 	DUP2 ,asma-print-labels JSR
    132 	( here )
    133 	DUP2 #0004 ADD2
    134 	LDAk LIT "A LTH ,&loop JCN
    135 	LDAk LIT "Z GTH ,&loop JCN
    136 	POP2
    137 	,&skip-device-label JMP
    138 	&loop
    139 	DUP2 INC2 SWP2 LDA
    140 	DUP #00 EQU ,&end JCN
    141 	.Console/error DEO
    142 	,&loop JMP
    143 	&end
    144 	POP
    145 	#09 .Console/error DEO
    146 	LDA2k ;asma-print-short JSR2
    147 	#0a .Console/error DEO
    148 	( subtree )
    149 	#0002 ADD2 ;asma-print-sublabels JSR2
    150 
    151 	&skip-device-label
    152 	( right node )
    153 	#0002 ADD2 ,asma-print-labels JSR
    154 	JMP2r
    155 
    156 @asma-print-string ( ptr* -- )
    157 	LDAk DUP ,&keep-going JCN
    158 	POP POP2 JMP2r
    159 
    160 	&keep-going
    161 	.Console/error DEO
    162 	INC2
    163 	,asma-print-string JMP
    164 
    165 @asma-print-short ( short* -- )
    166 	LIT "0 .Console/error DEO
    167 	LIT "x .Console/error DEO
    168 	OVR #04 SFT ,&hex JSR
    169 	SWP #0f AND ,&hex JSR
    170 	DUP #04 SFT ,&hex JSR
    171 	    #0f AND ,&hex JMP
    172 
    173 	&hex
    174 	#30 ADD DUP #3a LTH ,&not-alpha JCN
    175 	#27 ADD
    176 	&not-alpha
    177 	.Console/error DEO
    178 	JMP2r
    179 
    180 (
    181 	Initialise the assembler state before loading a file or chunk.
    182 )
    183 
    184 @asma-init-first-pass ( -- )
    185 	LIT2 POP2 POP EOR ;asma-parse-opcode/short-flag STA
    186 	LIT2 POPr POP EOR ;asma-parse-opcode/return-flag STA
    187 	LIT2 POPk POP EOR ;asma-parse-opcode/keep-flag STA
    188 	#ff ;asma/pass STA
    189 	#0000 DUP2k
    190 		;asma/error STA2
    191 		;asma-trees/labels STA2
    192 		;asma-trees/macros STA2
    193 	;asma-opcodes/_entry ;asma-trees/opcodes STA2
    194 	( fall through )
    195 
    196 @asma-init-next-pass ( -- )
    197 	;asma/pass LDA INC ;asma/pass STA
    198 	;asma-write-buffer ;asma-output/ptr STA2
    199 	#0100 DUP2 DUP ( 0100 0100 00 )
    200 		;asma/state STA
    201 		;asma/addr STA2
    202 		;asma/written-addr STA2
    203 	;&preamble-end ;&preamble SUB2k ;asma-assemble-chunk JSR2 POP2 POP2
    204 	JMP2r
    205 
    206 	&preamble
    207 	"%BRK 20 "{ 20 "00 20 "} 20
    208 	"%[ 20 "{ 20 "} 20
    209 	"%] 20 "{ 20 "} 20
    210 	"@on-reset 20
    211 	&preamble-end
    212 
    213 (
    214 	Divide a file up into chunks, and pass each chunk to asma-assemble-chunk.
    215 )
    216 
    217 @asma-assemble-file-pass ( filename-ptr* -- )
    218 	;asma-assemble-chunk #0000 ROT2 ( func* line^ filename* )
    219 	;asma-read-buffer DUP2 ;asma-read-buffer/end ROT2 SUB2 ( func* line^ filename* buf* size^ )
    220 	ROT2 ( func* line^ buf* size^ filename* )
    221 	,file-read-chunks JSR
    222 
    223 	;asma/error LDA2 ORA ,&error JCN
    224 
    225 	&error
    226 	POP2 POP2 POP2 POP2 POP2
    227 	JMP2r
    228 
    229 @file-read-chunks ( func* udata* buf* size* filename* -- func* udata'* buf* size* filename* )
    230 
    231 	#0000 DUP2                 ( F* U* B* SZ* FN* OL* OH* / )
    232 	&resume
    233 	ROT2 STH2                  ( F* U* B* SZ* OL* OH*     / FN* )
    234 	ROT2                       ( F* U* B* OL* OH* SZ*     / FN* )
    235 
    236 	&loop
    237 	STH2kr .File/name DEO2     ( F* U* B* OL* OH* SZ*     / FN* )
    238 	STH2k ,ffwd/length STR2    ( F* U* B* OL* OH*         / FN* SZ* )
    239 	STH2                       ( F* U* B* OL*             / FN* SZ* OH* )
    240 	STH2k ,ffwd/offset STR2    ( F* U* B*                 / FN* SZ* OH* OL* )
    241 	DUP2 ,ffwd/addr STR2
    242 	,ffwd JSR
    243 	SWP2                       ( F* B* U*                 / FN* SZ* OH* OL* )
    244 	ROT2k NIP2                 ( F* B* U* B* F*           / FN* SZ* OH* OL* )
    245 	OVR2 .File/read DEO2       ( F* B* U* B* F*           / FN* SZ* OH* OL* )
    246 	.File/success DEI2 SWP2    ( F* B* U* B* length* F*   / FN* SZ* OH* OL* )
    247 	JSR2                       ( F* B* U'* done-up-to*    / FN* SZ* OH* OL* )
    248 	ROT2 SWP2                  ( F* U'* B* done-up-to*    / FN* SZ* OH* OL* )
    249 	SUB2k NIP2                 ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
    250 	ORAk ,&not-end JCN         ( F* U'* B* -done-length*  / FN* SZ* OH* OL* )
    251 
    252 	POP2 POP2r POP2r           ( F* U'* B*                / FN* SZ* )
    253 	STH2r STH2r                ( F* U'* B* SZ* FN*        / )
    254 	JMP2r
    255 
    256 	&not-end
    257 	STH2r SWP2                 ( F* U'* B* OL* -done-length* / FN* SZ* OH* )
    258 	LTH2k JMP INC2r            ( F* U'* B* OL* -done-length* / FN* SZ* OH'* )
    259 	SUB2                       ( F* U'* B* OL'*              / FN* SZ* OH'* )
    260 	STH2r STH2r                ( F* U'* B* OL'* OH'* SZ*     / FN* )
    261 	,&loop JMP
    262 
    263 @ffwd
    264 	LIT2 &length $2
    265 	LIT2 &offset $2
    266 
    267 	&coarse ( length* offset* )
    268 	GTH2k ,&fine JCN
    269 	OVR2 .File/length DEO2
    270 	,&addr LDR2 .File/read DEO2
    271 	OVR2 SUB2
    272 	,&coarse JMP
    273 
    274 	&fine ( length* offset* )
    275 	.File/length DEO2 ( length* )
    276 	,&addr LDR2 .File/read DEO2
    277 	.File/length DEO2 ( )
    278 	JMP2r
    279 
    280 	&addr $2
    281 
    282 
    283 (
    284 	Assemble a chunk of source code, which begins with whitespace or the start
    285 	of a token and is divided up into tokens separated by whitespace. If the
    286 	chunk ends with whitespace, assembled-up-to-ptr* will equal ptr* + len* and
    287 	every token in the chunk will have been assembled. If the chunk ends with a
    288 	non-whitespace character, assembled-up-to-ptr* will point to the beginning
    289 	of the last token in the chunk.
    290 )
    291 
    292 @asma-assemble-chunk ( line^ chunk* len^ -- line^ assembled-up-to-chunk* )
    293 	ROT2 STH2 ( chunk* len^ / line^ )
    294 	OVR2 ADD2 ( chunk* end-chunk* / line^ )
    295 	OVR2 ;asma-read-buffer EQU2 STH
    296 	DUP2 ;asma-read-buffer/end NEQ2
    297 	STHr AND ;asma/eof STA
    298 	SWP2 STH2k ( end-chunk* chunk* / line^ start-of-token* )
    299 
    300 	&loop ( end-chunk* char* / line^ start-of-token* )
    301 	LDAk #21 LTH ,&whitespace JCN
    302 	INC2 ,&loop JMP
    303 
    304 	&whitespace ( end-chunk* ws-char* / line^ start-of-token* )
    305 	GTH2k ,&within-chunk JCN
    306 	;asma/eof LDA ,&eof JCN
    307 
    308 	( reached the end of the chunk, start-of-token* is where we assembled up to )
    309 	POP2 POP2 STH2r STH2r SWP2 JMP2r
    310 
    311 	&within-chunk ( end-chunk* ws-char* / line^ start-of-token* )
    312 	LDAk #0a NEQ ( end-chunk* ws-char* not-newline / line^ start-of-token* )
    313 	#00 OVR2 STA
    314 	STH2r ,asma-assemble-token JSR ( end-chunk* ws-char* not-newline / line^ )
    315 	;asma/error LDA2 ORA ,&error JCN
    316 	,&not-newline JCN
    317 	,asma/lines LDR2 INC2 ,asma/lines STR2
    318 	&not-newline ( end-chunk* ws-char* / line^ )
    319 	;asma/break LDA ,&break JCN
    320 	INC2 STH2k ( end-chunk* start-of-token* / line^ start-of-token* )
    321 	,&loop JMP
    322 
    323 	&break ( end-chunk* ws-char* / line^ )
    324 	( the read buffer has been invalidated, ws-char* plus one is where we assembled up to )
    325 	;asma/break LDA #01 SUB ;asma/break STA
    326 	INC2 NIP2 ( assembled-up-to-ptr* / line^ )
    327 	STH2r SWP2 JMP2r
    328 
    329 	&error ( end-chunk* ws-char* not-newline / line^ )
    330 	( return no progress with assembly to make file-read-chunks exit )
    331 	POP POP2 POP2
    332 	STH2kr ;asma/line STA2
    333 	STH2r ;asma-read-buffer
    334 	JMP2r
    335 
    336 	&eof ( end-chunk* ws-char* / line^ start-of-token* )
    337 	( reached the end of file, end-chunk* is safe to write since the buffer is bigger )
    338 	( return no progress with assembly to make file-read-chunks exit )
    339 	POP2 ( end-chunk* / line^ start-of-token* )
    340 	#00 ROT ROT STA ( / line^ start-of-token* )
    341 	STH2r ,asma-assemble-token JSR ( / line^ )
    342 	STH2r ;asma-read-buffer JMP2r
    343 
    344 @asma [
    345 	&pass $1 &state $1 &line $2 &lines $2 &break $1 &eof $1
    346 	&comment-level $1
    347 	&token $2 &orig-token $2
    348 	&addr $2 &written-addr $2 &flush-fn $2
    349 	&src-filename $2 &dest-filename $2
    350 	&error $2 &log-level $1
    351 ]
    352 @asma-trees [ &labels $2 &macros $2 &opcodes $2 &scope $2 ]
    353 
    354 (
    355 	The main routine to assemble a single token.
    356 	asma/state contains several meaningful bits:
    357 	0x02 we are in a comment,
    358 	0x04 we are in a macro body,
    359 	0x08 we are in a macro body that we are ignoring
    360 	   (because the macro was already defined in a previous pass).
    361 	Since 0x08 never appears without 0x04, the lowest bit set in asma/state is
    362 	always 0x00, 0x02, or 0x04, which is very handy for use with jump tables.
    363 	The lowest bit set can be found easily by #00 (n) SUBk AND.
    364 )
    365 
    366 @asma-assemble-token ( string-ptr* -- )
    367 	DUP2 ;asma/token STA2
    368 	DUP2 ;asma/orig-token STA2
    369 	LDAk ,&not-empty JCN
    370 	POP2
    371 	JMP2r
    372 
    373 	&not-empty ( token* / )
    374 	( truncate to one char long )
    375 	INC2 ( end* / )
    376 	STH2k LDAkr ( end* / end* char )
    377 	STH2k ( end* / end* char end* )
    378 	LITr 00 STH2 ( / end* char end* 00 end* )
    379 	STAr ( / end* char end* )
    380 
    381 	#00 ;asma/state LDA SUBk AND ( tree-offset* / end* )
    382 	DUP2 ;&first-char-trees ADD2 ( tree-offset* incoming-ptr* / end* )
    383 	;asma-traverse-tree JSR2
    384 
    385 	( restore truncated char )
    386 	STAr
    387 
    388 	,&not-found JCN
    389 
    390 	( tree-offset* token-routine-ptr* / end* )
    391 	STH2r ;asma/token STA2
    392 	NIP2 LDA2
    393 	JMP2 ( tail call )
    394 
    395 	&not-found ( tree-offset* dummy* / end* )
    396 	POP2 POP2r
    397 	;&body-routines ADD2 LDA2
    398 	JMP2 ( tail call )
    399 
    400 	&first-char-trees
    401 		:asma-first-char-normal/_entry
    402 		:asma-first-char-comment/_entry
    403 		:asma-first-char-macro/_entry
    404 
    405 	&body-routines
    406 		:asma-normal-body
    407 		:asma-ignore
    408 		:asma-macro-body
    409 
    410 @asma-parse-hex-digit ( charcode -- 00-0f if valid hex
    411                                  OR 10-ff otherwise )
    412 	DUP #3a LTH ,&digit JCN
    413 	DUP #60 GTH ,&letter JCN
    414 	JMP2r
    415 
    416 	&digit
    417 	#30 SUB
    418 	JMP2r
    419 
    420 	&letter
    421 	#57 SUB
    422 	JMP2r
    423 
    424 @asma-parse-hex-string ( strict -- value* 06 if valid hex and (length == 4 or (length == 3 and not strict))
    425                                 OR value* 03 if valid hex and (length == 2 or (length == 1 and not strict))
    426                                 OR 00 otherwise )
    427 	STH
    428 	;asma/token LDA2 DUP2 ,strlen JSR ( token* length^ )
    429 	DUP STHr AND ,&fail2 JCN
    430 	DUP2 #0004 GTH2 ,&fail2 JCN
    431 	ORAk #00 EQU ,&fail2 JCN
    432 	#0002 GTH2 ROT ROT
    433 	LIT2r 0000
    434 
    435 	&loop
    436 	LDAk
    437 	DUP ,&not-end JCN
    438 	POP POP2
    439 	STH2r ROT INC DUPk ADD ADD
    440 	JMP2r
    441 
    442 	&not-end
    443 	,asma-parse-hex-digit JSR
    444 	DUP #f0 AND ,&fail JCN
    445 	LITr 40 SFT2r
    446 	LITr 00 STH ADD2r
    447 	INC2
    448 	,&loop JMP
    449 
    450 	&fail
    451 	POP2r
    452 	&fail2
    453 	POP2 POP2
    454 	#00
    455 	JMP2r
    456 
    457 ~projects/library/string.tal
    458 
    459 @asma-traverse-tree ( incoming-ptr* -- binary-ptr* 00 if key found
    460                                     OR node-incoming-ptr* 01 if key not found )
    461 	;asma/token LDA2
    462 	( fall through to traverse-tree )
    463 
    464 ~projects/library/binary-tree.tal
    465 
    466 @asma-parse-opcode ( -- byte 00 if valid opcode
    467                      OR 01 otherwise )
    468 	;asma/token LDA2
    469 	DUP2 ,strlen JSR #0003 LTH2 ,&too-short JCN
    470 
    471 	( truncate to three chars long )
    472 	#0003 ADD2 ( end* / )
    473 	STH2k LDAkr ( end* / end* char )
    474 	STH2k ( end* / end* char end* )
    475 	LITr 00 STH2 ( / end* char end* 00 end* )
    476 	STAr ( / end* char end* )
    477 
    478 	;asma-trees/opcodes ;asma-traverse-tree JSR2
    479 	STAr
    480 	,&not-found JCN
    481 
    482 	;asma-opcodes/_disasm SUB2 #03 SFT2 ( 00 byte / end* )
    483 	DUP #00 EQU ,&set-keep JCN ( force keep flag for LIT )
    484 	&loop
    485 	LDAkr STHr LIT2r 0001 ADD2r ( 00 byte char / end* )
    486 	DUP ,&not-end JCN
    487 	POP POP2r
    488 	SWP
    489 	JMP2r
    490 
    491 	&not-end
    492 	DUP LIT "2 NEQ ,&not-two JCN
    493 	POP LIT &short-flag $1 ORA ,&loop JMP
    494 
    495 	&not-two
    496 	DUP LIT "r NEQ ,&not-return JCN
    497 	POP LIT &return-flag $1 ORA ,&loop JMP
    498 
    499 	&not-return
    500 	LIT "k NEQ ,&not-keep JCN
    501 	&set-keep LIT &keep-flag $1 ORA ,&loop JMP
    502 
    503 	&not-keep ( 00 byte / end* )
    504 	&not-found ( incoming-ptr* / end* )
    505 	POP2r
    506 	&too-short ( token* / )
    507 	POP2 #01
    508 	JMP2r
    509 
    510 @asma-write-lit ( byte -- )
    511 	LIT LIT ,asma-write-byte JSR
    512 	,asma-write-byte JSR
    513 	JMP2r
    514 
    515 @asma-advance-addr ( delta* -- )
    516 	;asma/addr LDA2k ( delta* ptr* value* )
    517 	ROT2 ADD2 ( ptr* new-value* )
    518 	SWP2 STA2
    519 	JMP2r
    520 
    521 @asma-write-short ( short -- )
    522 	SWP
    523 	,asma-write-byte JSR
    524 	( fall through )
    525 
    526 @asma-write-byte ( byte -- )
    527 	;asma/addr LDA2 ;asma/written-addr LDA2
    528 	LTH2k ,&rewound JCN
    529 	&loop
    530 	EQU2k ,&ready JCN
    531 	#00 ,&write JSR
    532 	INC2
    533 	,&loop JMP
    534 
    535 	&rewound
    536 	;asma-msg-rewound ;asma/error STA2
    537 	POP2 POP2 POP JMP2r
    538 
    539 	&ready
    540 	POP2 INC2
    541 	DUP2 ;asma/addr STA2
    542 	;asma/written-addr STA2
    543 
    544 	&write
    545 	,asma-output/ptr LDR2
    546 	DUP2 ;asma-write-buffer/end EQU2 ,&flush JCN
    547 	&after-flush
    548 	STH2k STA
    549 	STH2r INC2 ,asma-output/ptr STR2
    550 	JMP2r
    551 
    552 	&flush ( ptr* -- start-of-buffer* )
    553 	;asma-write-buffer SUB2k ( ptr* start* len* )
    554 	;asma/flush-fn LDA2 JSR2
    555 	NIP2 ( start* )
    556 	,&after-flush JMP
    557 
    558 @asma-output [ &ptr $2 ]
    559 
    560 @asma-flush-ignore ( len* -- )
    561 	POP2
    562 	JMP2r
    563 
    564 @asma-flush-to-file ( len* -- )
    565 	.File/length DEO2
    566 	;asma/dest-filename LDA2 .File/name DEO2
    567 	;asma-write-buffer .File/write DEO2
    568 	JMP2r
    569 
    570 @asma-flush-to-console ( len* -- )
    571 	ORAk ,&not-empty JCN
    572 	POP2 JMP2r
    573 
    574 	&not-empty
    575 	;asma-write-buffer DUP2 ROT2 ADD2 SWP2 ( end* ptr* )
    576 	&loop ( end* ptr* )
    577 	LDAk .Console/write DEO
    578 	INC2
    579 	GTH2k ,&loop JCN
    580 
    581 	POP2 POP2
    582 	JMP2r
    583 
    584 ~projects/library/heap.tal
    585 
    586 (
    587 	First character routines.
    588 	The following routines (that don't have a FORTH-like signature) are called
    589 	to deal with tokens that begin with particular first letters, or (for
    590 	-body routines) tokens that fail to match any first letter in their tree.
    591 )
    592 
    593 @asma-comment-more
    594 	;asma/token LDA2 ;strlen JSR2 ORA ,asma-ignore JCN
    595 @asma-comment-start
    596 	;asma/comment-level LDAk INC ROT ROT STA
    597 	;asma/state LDA #02 ORA ;asma/state STA
    598 @asma-ignore
    599 	JMP2r
    600 
    601 @asma-comment-less
    602 	;asma/token LDA2 ;strlen JSR2 ORA ,asma-ignore JCN
    603 	;asma/comment-level LDAk #01 SUB DUP SWP2 STA ,asma-ignore JCN
    604 @asma-comment-end
    605 	;asma/state LDA #0c AND ;asma/state STA
    606 	JMP2r
    607 
    608 @asma-macro-define
    609 	;asma/pass LDA ,&ignore-macro JCN
    610 
    611 	;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-exist JCN
    612 	POP2
    613 	;asma-msg-macro ;asma/error STA2
    614 	JMP2r
    615 
    616 	&not-exist ( incoming-ptr* )
    617 	( define macro by creating new node )
    618 	;heap LDA2 SWP2 STA2
    619 	#0000 ;append-heap-short JSR2 ( less-than pointer )
    620 	#0000 ;append-heap-short JSR2 ( greater-than pointer )
    621 	;asma/token LDA2 ;append-heap-string JSR2 ( key )
    622 	;asma/state LDA #04 ORA ;asma/state STA
    623 	JMP2r
    624 
    625 	&ignore-macro
    626 	;asma/state LDA #0c ORA ;asma/state STA
    627 	JMP2r
    628 
    629 @asma-macro-body
    630 	;asma/state LDA #08 AND ,&skip JCN
    631 	;asma/token LDA2 ;append-heap-string JSR2
    632 	&skip
    633 	JMP2r
    634 
    635 @asma-macro-end
    636 	#00 ;append-heap-byte JSR2
    637 	;asma/state LDA #02 AND ;asma/state STA
    638 	JMP2r
    639 
    640 @asma-label-define
    641 	;asma-trees/labels ,asma-label-helper JSR
    642 	,&already-existed JCN
    643 
    644 	#0000 ;append-heap-short JSR2 ( data2: subtree incoming ptr )
    645 
    646 	&already-existed
    647 	#0002 ADD2 ;asma-trees/scope STA2
    648 	JMP2r
    649 
    650 @asma-sublabel-define
    651 	;asma-trees/scope LDA2 ,asma-label-helper JSR
    652 	POP POP2
    653 	JMP2r
    654 
    655 @asma-label-helper ( incoming-ptr* -- binary-ptr* 01 if label existed already
    656                                    OR binary-ptr* 00 if label was created )
    657 	;asma-traverse-tree JSR2
    658 	,&new-label JCN
    659 
    660 	( label already exists )
    661 	LDA2k ;asma/addr LDA2 EQU2 ,&address-match JCN
    662 	;asma-msg-redefined ;asma/error STA2
    663 
    664 	&address-match
    665 	#01 JMP2r
    666 
    667 	&new-label ( incoming-ptr* )
    668 	( define label by creating new node )
    669 	;heap LDA2 SWP2 STA2
    670 	#0000 ;append-heap-short JSR2 ( less-than pointer )
    671 	#0000 ;append-heap-short JSR2 ( greater-than pointer )
    672 	;asma/token LDA2 ;append-heap-string JSR2 ( key )
    673 
    674 	;heap LDA2
    675 
    676 	;asma/addr LDA2 ;append-heap-short JSR2 ( data1: address )
    677 	#00 JMP2r
    678 
    679 @asma-pad-absolute
    680 	#0000 ;asma/addr STA2
    681 	( fall through )
    682 
    683 @asma-pad-relative
    684 	#00 ;asma-parse-hex-string JSR2
    685 	,&valid JCN
    686 
    687 	;asma-msg-hex ;asma/error STA2
    688 	JMP2r
    689 
    690 	&valid
    691 	;asma-advance-addr JMP2 ( tail call )
    692 
    693 @asma-raw-word
    694 	;asma/token LDA2
    695 
    696 	&loop
    697 	LDAk
    698 	DUP ,&not-end JCN
    699 
    700 	POP POP2
    701 	JMP2r
    702 
    703 	&not-end
    704 	;asma-write-byte JSR2
    705 	INC2
    706 	,&loop JMP
    707 
    708 @asma-literal-abs-addr
    709 	LIT LIT2 ;asma-write-byte JSR2
    710 	( fall through )
    711 
    712 @asma-abs-addr
    713 	,asma-addr-helper JSR
    714 	;asma-write-short JMP2 ( tail call )
    715 
    716 @asma-literal-zero-addr
    717 	LIT LIT ;asma-write-byte JSR2
    718 	( fall through )
    719 
    720 @asma-zero-addr
    721 	,asma-addr-helper JSR
    722 	;asma-write-byte JSR2
    723 
    724 	,&not-zero-page JCN
    725 	JMP2r
    726 
    727 	&not-zero-page
    728 	;asma/pass LDA #00 EQU
    729 		;asma/error LDA2 ORA
    730 		ORA ,&ignore-error JCN
    731 	;asma-msg-zero-page ;asma/error STA2
    732 	&ignore-error
    733 	JMP2r
    734 
    735 @asma-jci
    736 	#20 ,asma-jxi JMP ( tail call )
    737 
    738 @asma-jmi
    739 	#40
    740 	( fall through )
    741 
    742 @asma-jxi
    743 	;asma-write-byte JSR2
    744 	,asma-addr-helper JSR
    745 	;asma/addr LDA2 SUB2
    746 	#0002 SUB2
    747 	;asma-write-short JMP2 ( tail call )
    748 
    749 @asma-literal-rel-addr
    750 	LIT LIT ;asma-write-byte JSR2
    751 	( fall through )
    752 
    753 @asma-rel-addr
    754 	,asma-addr-helper JSR
    755 	;asma/addr LDA2 SUB2
    756 	#0002 SUB2
    757 
    758 	DUP2 #0080 LTH2 STH
    759 	DUP2 #ff7f GTH2 STHr ORA ,&in-bounds JCN
    760 
    761 	POP2
    762 	;asma-msg-relative ;asma/error STA2
    763 	JMP2r
    764 
    765 	&in-bounds
    766 	;asma-write-byte JSR2
    767 	POP
    768 	JMP2r
    769 
    770 @asma-addr-helper ( -- addr* )
    771 	;asma/token LDA2 LDAk #26 NEQ ,&not-local JCN
    772 	INC2 ;asma/token STA2
    773 	;asma-trees/scope LDA2
    774 	,&final-lookup JMP
    775 
    776 	&not-local ( token* )
    777 	LDAk
    778 	DUP ,&not-end JCN
    779 	POP POP2
    780 	;asma-trees/labels
    781 	,&final-lookup JMP
    782 
    783 	&not-end ( token* char )
    784 	#2f EQU ,&found-slash JCN
    785 	INC2
    786 	,&not-local JMP
    787 
    788 	&found-slash ( token* )
    789 	DUP2 #00 ROT ROT STA
    790 	;asma-trees/labels ;asma-traverse-tree JSR2 STH
    791 	SWP2 DUP2 #2f ROT ROT STA
    792 	STHr ,&not-found2 JCN
    793 	( token* binary-ptr* )
    794 	INC2 ;asma/token STA2
    795 	#0002 ADD2
    796 
    797 	&final-lookup ( addr-offset* incoming-ptr* )
    798 	;asma-traverse-tree JSR2
    799 	,&not-found JCN
    800 	LDA2
    801 	JMP2r
    802 
    803 	&not-found2 ( dummy* dummy* )
    804 	POP2
    805 	&not-found ( dummy* )
    806 	POP2
    807 
    808 	;asma/pass LDA #00 EQU ,&ignore-error JCN
    809 	;asma-msg-label ;asma/error STA2
    810 	&ignore-error
    811 
    812 	;asma/addr LDA2
    813 	JMP2r
    814 
    815 @asma-literal-hex
    816 	#01 ;asma-parse-hex-string JSR2 JMP
    817 	( hex invalid ) ,&invalid JMP
    818 	( hex byte    ) ,asma-byte-helper JMP
    819 	( hex short   ) ,asma-short-helper JMP
    820 
    821 	&invalid
    822 	;asma-msg-hex ;asma/error STA2
    823 	JMP2r
    824 
    825 @asma-byte-helper ( dummy value -- )
    826 	;asma-write-lit JSR2
    827 	POP
    828 	JMP2r
    829 	&raw
    830 	;asma-write-byte JSR2
    831 	POP
    832 	JMP2r
    833 
    834 @asma-short-helper ( value* -- )
    835 	LIT LIT2 ;asma-write-byte JSR2
    836 	&raw
    837 	;asma-write-short JMP2 ( tail call )
    838 
    839 @asma-normal-body
    840 	;asma-parse-opcode JSR2 ,&not-opcode JCN
    841 	;asma-write-byte JMP2 ( tail call )
    842 
    843 	&not-opcode
    844 	#01 ;asma-parse-hex-string JSR2 JMP
    845 	( hex invalid ) ,&not-hex JMP
    846 	( hex byte    ) ,asma-byte-helper/raw JMP
    847 	( hex short   ) ,asma-short-helper/raw JMP
    848 
    849 	&not-hex
    850 	;asma-trees/macros ;asma-traverse-tree JSR2 ,&not-macro JCN
    851 
    852 	&macro-loop
    853 	LDAk ,&keep-going JCN
    854 	POP2
    855 	JMP2r
    856 
    857 	&keep-going
    858 	DUP2k ;strlen JSR2 INC2 ADD2
    859 	SWP2 ;asma-assemble-token JSR2 ;asma/error LDA2 ORA ,&macro-error JCN
    860 	,&macro-loop JMP
    861 
    862 	&macro-error
    863 	POP2
    864 	JMP2r
    865 
    866 	&not-macro
    867 	POP2
    868 	#60 ;asma-jxi JMP2 ( tail call )
    869 
    870 @asma-include
    871 	;heap LDA2
    872 		;asma/token LDA2 ;append-heap-string JSR2
    873 		;asma-assemble-file-pass JSR2
    874 	;asma/break LDAk INC ROT ROT STA
    875 	JMP2r
    876 
    877 ( Error messages )
    878 
    879 @asma-msg-hex       "Invalid 20 "hexadecimal 00
    880 @asma-msg-zero-page "Address 20 "not 20 "in 20 "zero 20 "page 00
    881 @asma-msg-relative  "Address 20 "outside 20 "range 00
    882 @asma-msg-label     "Label 20 "not 20 "found 00
    883 @asma-msg-macro     "Macro 20 "already 20 "exists 00
    884 @asma-msg-rewound   "Memory 20 "overwrite 00
    885 @asma-msg-redefined "Label 20 "redefined 00
    886 
    887 ( trees )
    888 
    889 ( --- 8< ------- 8< --- cut here --- 8< ------- 8< --- )
    890 (          automatically generated code below          )
    891 (          see etc/asma.moon for instructions          )
    892 
    893 (	label       less       greater      key            binary
    894 	            than       than         string         data )
    895 
    896 @asma-first-char-comment
    897 	&28          $2         $2          "( 00          :asma-comment-more
    898 	&_entry     :&28        $2          ") 00          :asma-comment-less
    899 
    900 @asma-first-char-macro
    901 	&28          $2         $2          "( 00          :asma-comment-start
    902 	&29         :&28        $2          ") 00          :asma-comment-end
    903 	&_entry     :&29       :&7d         "{ 00          :asma-ignore
    904 	&7d          $2         $2          "} 00          :asma-macro-end
    905 
    906 @asma-first-char-normal
    907 	&21          $2         $2          "! 00          :asma-jmi
    908 	&22         :&21        $2          "" 00          :asma-raw-word
    909 	&23         :&22       :&25         "# 00          :asma-literal-hex
    910 	&24          $2         $2          "$ 00          :asma-pad-relative
    911 	&25         :&24        $2          "% 00          :asma-macro-define
    912 	&26         :&23       :&2c         26 00 ( & )    :asma-sublabel-define
    913 	&28          $2         $2          "( 00          :asma-comment-start
    914 	&29         :&28        $2          ") 00          :asma-comment-end
    915 	&2c         :&29       :&2d         ", 00          :asma-literal-rel-addr
    916 	&2d          $2         $2          "- 00          :asma-zero-addr
    917 	&_entry     :&26       :&5f         ". 00          :asma-literal-zero-addr
    918 	&3a          $2         $2          ": 00          :asma-abs-addr
    919 	&3b         :&3a        $2          "; 00          :asma-literal-abs-addr
    920 	&3d         :&3b       :&40         "= 00          :asma-abs-addr
    921 	&3f          $2         $2          "? 00          :asma-jci
    922 	&40         :&3f        $2          "@ 00          :asma-label-define
    923 	&5f         :&3d       :&7d         "_ 00          :asma-rel-addr
    924 	&7b          $2         $2          "{ 00          :asma-ignore
    925 	&7c         :&7b        $2          "| 00          :asma-pad-absolute
    926 	&7d         :&7c       :&7e         "} 00          :asma-ignore
    927 	&7e          $2         $2          "~ 00          :asma-include
    928 
    929 @asma-opcodes
    930 	&_entry     :&GTH      :&ROT &_disasm "LIT 00
    931 	&INC         $2         $2          "INC 00
    932 	&POP         $2         $2          "POP 00
    933 	&NIP        :&MUL      :&OVR        "NIP 00
    934 	&SWP         $2         $2          "SWP 00
    935 	&ROT        :&NIP      :&STR        "ROT 00
    936 	&DUP         $2         $2          "DUP 00
    937 	&OVR        :&ORA      :&POP        "OVR 00
    938 	&EQU         $2         $2          "EQU 00
    939 	&NEQ         $2         $2          "NEQ 00
    940 	&GTH        :&DIV      :&JSR        "GTH 00
    941 	&LTH         $2         $2          "LTH 00
    942 	&JMP         $2         $2          "JMP 00
    943 	&JCN        :&INC      :&JMP        "JCN 00
    944 	&JSR        :&JCN      :&LDR        "JSR 00
    945 	&STH         $2         $2          "STH 00
    946 	&LDZ         $2         $2          "LDZ 00
    947 	&STZ         $2         $2          "STZ 00
    948 	&LDR        :&LDA      :&LDZ        "LDR 00
    949 	&STR        :&STA      :&SUB        "STR 00
    950 	&LDA         $2         $2          "LDA 00
    951 	&STA        :&SFT      :&STH        "STA 00
    952 	&DEI        :&AND      :&DEO        "DEI 00
    953 	&DEO         $2         $2          "DEO 00
    954 	&ADD         $2         $2          "ADD 00
    955 	&SUB        :&STZ      :&SWP        "SUB 00
    956 	&MUL        :&LTH      :&NEQ        "MUL 00
    957 	&DIV        :&DEI      :&EOR        "DIV 00
    958 	&AND        :&ADD       $2          "AND 00
    959 	&ORA         $2         $2          "ORA 00
    960 	&EOR        :&DUP      :&EQU        "EOR 00
    961 	&SFT         $2         $2          "SFT 00
    962