summaryrefslogtreecommitdiff
path: root/stage1/M0-macro.hex2
blob: 341d21a8d1e9344bc428cc1b7b5403978e5ef6db (plain)
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
## Copyright (C) 2016 Jeremiah Orians
## This file is part of stage0.
##
## stage0 is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## stage0 is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with stage0.  If not, see <http://www.gnu.org/licenses/>.

:start
# ;; We will be using R13 for storage of Head
E0002D2E 0700	# LOADUI R14 0x700 ; Our malloc pointer (Initialized)
E0002D2F $stack	# LOADUI R15 $stack ; Put stack at end of program

# ;; Main program
# ;; Reads contents of Tape_01 and applies all Definitions
# ;; Writes results to Tape_02
# ;; Accepts no arguments and HALTS when done
:main
E0002D0F @Tokenize_Line	# CALLI R15 @Tokenize_Line ; Call Tokenize_Line
E0002D0F @reverse_list	# CALLI R15 @reverse_list ; Reverse the list of tokens
E0002D0F @Identify_Macros	# CALLI R15 @Identify_Macros ; Tag all nodes that are macros
E0002D0F @Line_Macro	# CALLI R15 @Line_Macro ; Apply macros down nodes
E0002D0F @Process_String	# CALLI R15 @Process_String ; Convert string values to Hex16
E0002D0F @Eval_Immediates	# CALLI R15 @Eval_Immediates ; Convert numbers to hex
E0002D0F @Preserve_Other	# CALLI R15 @Preserve_Other ; Ensure labels/Pointers aren't lost
E0002D0F @Print_Hex	# CALLI R15 @Print_Hex ; Write Nodes to Tape_02
FFFFFFFF	# HALT ; We are Done


# ;; Tokenize_Line function
# ;; Opens tape_01 and reads into a backwards linked list in R13
# ;; Returns to whatever called it
:Tokenize_Line
# ;; Prep TAPE_01
E0002D201100	# LOADUI R0 0x1100
42100000	# FOPEN_READ

0D00002D	# FALSE R13 ; Head is NULL
09000510	# MOVE R1 R0 ; Read Tape_01

:Tokenize_Line_0
42100100	# FGETC ; Get a Char

# ;; Deal with lines comments starting with #
E000A0300023	# CMPSKIPI.NE R0 35
3C00 @Purge_Line_Comment	# JUMP @Purge_Line_Comment

# ;; Deal with Line comments starting with ;
E000A030003B	# CMPSKIPI.NE R0 59
3C00 @Purge_Line_Comment	# JUMP @Purge_Line_Comment

# ;; Deal with Tab
E000A0300009	# CMPSKIPI.NE R0 9
3C00 @Tokenize_Line_0	# JUMP @Tokenize_Line_0 ; Throw away byte and try again

# ;; Deal with New line
E000A030000A	# CMPSKIPI.NE R0 10
3C00 @Tokenize_Line_0	# JUMP @Tokenize_Line_0 ; Throw away byte and try again

# ;; Deal with space characters
E000A0300020	# CMPSKIPI.NE R0 32
3C00 @Tokenize_Line_0	# JUMP @Tokenize_Line_0 ; Throw away byte and try again

# ;; Stop if EOF
E000A0100000	# CMPSKIPI.GE R0 0
3C00 @Tokenize_Line_Done	# JUMP @Tokenize_Line_Done

# ;; Allocate a new Node
0900042E	# COPY R2 R14 ; Get address of new Node
E1000FEE0010	# ADDUI R14 R14 16 ; Allocate 16 Bytes
E10023E20008	# STORE32 R14 R2 8 ; Set Text pointer

# ;; Deal with Strings wrapped in \"
E000A0300022	# CMPSKIPI.NE R0 34
3C00 @Store_String	# JUMP @Store_String

# ;; Deal with Strings wrapped in '
E000A0300027	# CMPSKIPI.NE R0 39
3C00 @Store_String	# JUMP @Store_String

# ;; Everything else is an atom store it
E0002D0F @Store_Atom	# CALLI R15 @Store_Atom

:Tokenize_Line_1
E10023D20000	# STORE32 R13 R2 0 ; Set p->next to head
090005D2	# MOVE R13 R2 ; Set head to p
3C00 @Tokenize_Line_0	# JUMP @Tokenize_Line_0 ; Keep getting tokens

:Tokenize_Line_Done
# ;; Done reading File
E0002D201100	# LOADUI R0 0x1100 ; Close TAPE_01
42100002	# FCLOSE
0D01001F	# RET R15


# ;; reverse_list Function
# ;; Reverses the list given in R13
:reverse_list
# ;; Initialize
0900040D	# COPY R0 R13 ; Using R0 as head
0D000021	# FALSE R1 ; Using R1 as root
	# ; Using R2 as next

:reverse_list_0
E0002C90 @reverse_list_done	# JUMP.Z R0 @reverse_list_done ; Stop if NULL == head
E10013200000	# LOAD R2 R0 0 ; next = head->next
E10020100000	# STORE R1 R0 0 ; head->next = root
09000510	# MOVE R1 R0 ; root = head
09000502	# MOVE R0 R2 ; head = next
3C00 @reverse_list_0	# JUMP @reverse_list_0 ; Keep looping

:reverse_list_done
# ;; Clean up
090005D1	# MOVE R13 R1 ; Set token_list to root
0D01001F	# RET R15


# ;; Purge_Line_Comment Function
# ;; Receives char in R0 and desired input in R1
# ;; Modifies R0
# ;; Returns to Tokenize_Line as if the entire line
# ;; Comment never existed
:Purge_Line_Comment
42100100	# FGETC ; Get another Char
E000A020000a	# CMPSKIPI.E R0 10 ; Stop When LF is reached
3C00 @Purge_Line_Comment	# JUMP @Purge_Line_Comment ; Otherwise keep looping
3C00 @Tokenize_Line_0	# JUMP @Tokenize_Line_0 ; Return as if this never happened


# ;; Store_String function
# ;; Receives Char in R0, desired input in R1
# ;; And node pointer in R2
# ;; Modifies node Text to point to string and sets
# ;; Type to string.
:Store_String
# ;; Initialize
09000430	# COPY R3 R0 ; Copy Char for comparison

:Store_String_0
E100210E0000	# STORE8 R0 R14 0 ; Store the Byte
42100100	# FGETC ; Get next Byte
E1000FEE0001	# ADDUI R14 R14 1 ; Prep for next loop
E100C303 @Store_String_0	# CMPJUMPI.NE R0 R3 @Store_String_0 ; Loop if matching not found

# ;; Clean up
E1000FEE0004	# ADDUI R14 R14 4 ; Correct Malloc
E0002D200002	# LOADUI R0 2 ; Using type string
E10023020004	# STORE32 R0 R2 4 ; Set node type
3C00 @Tokenize_Line_1	# JUMP @Tokenize_Line_1


# ;; Store_Atom function
# ;; Receives Char in R0, desired input in R1
# ;; And node pointer in R2
# ;; Modifies node Text to point to string
:Store_Atom
E100210E0000	# STORE8 R0 R14 0 ; Store the Byte
42100100	# FGETC ; Get next Byte
E1000FEE0001	# ADDUI R14 R14 1 ; Prep for next loop

E000A0300009	# CMPSKIPI.NE R0 9 ; If char is Tab
3C00 @Store_Atom_Done	# JUMP @Store_Atom_Done ; Be done

E000A030000a	# CMPSKIPI.NE R0 10 ; If char is LF
3C00 @Store_Atom_Done	# JUMP @Store_Atom_Done ; Be done

E000A0300020	# CMPSKIPI.NE R0 32 ; If char is Space
3C00 @Store_Atom_Done	# JUMP @Store_Atom_Done ; Be done

# ;; Otherwise loop
3C00 @Store_Atom	# JUMP @Store_Atom

:Store_Atom_Done
# ;; Cleanup
E1000FEE0001	# ADDUI R14 R14 1 ; Correct Malloc
0D01001F	# RET R15


# ;; strcmp function
# ;; Receives pointers to null terminated strings
# ;; In R0 and R1
# ;; Returns if they are equal in R0
# ;; Returns to whatever called it
:strcmp
# ;; Preserve registers
0902001F	# PUSHR R1 R15
0902002F	# PUSHR R2 R15
0902003F	# PUSHR R3 R15
0902004F	# PUSHR R4 R15

# ;; Setup registers
09000520	# MOVE R2 R0 ; Put R0 in a safe place
09000531	# MOVE R3 R1 ; Put R1 in a safe place
0D000024	# FALSE R4 ; Starting at index 0

:cmpbyte
0503A024	# LOADXU8 R0 R2 R4 ; Get a byte of our first string
0503A134	# LOADXU8 R1 R3 R4 ; Get a byte of our second string
E1000F440001	# ADDUI R4 R4 1 ; Prep for next loop
05004001	# CMP R0 R0 R1 ; Compare the bytes
E000A0210000	# CMPSKIPI.E R1 0 ; Stop if byte is NULL
E0002C50 @cmpbyte	# JUMP.E R0 @cmpbyte ; Loop if bytes are equal

# ;; Done
# ;; Restore registers
0902804F	# POPR R4 R15
0902803F	# POPR R3 R15
0902802F	# POPR R2 R15
0902801F	# POPR R1 R15
0D01001F	# RET R15


# ;; Identify_Macros Function
# ;; If the text stored in its Text segment matches
# ;; DEFINE, flag it and Collapse it down to a single Node
# ;; Loop until all nodes are checked
# ;; Return to whatever called it
:Identify_Macros
# ;; Initializ
E0002D21 $Identify_Macros_string	# LOADUI R1 $Identify_Macros_string
0900042D	# COPY R2 R13 ; i = head

# ;; Main Loop
:Identify_Macros_0
E10018020008	# LOAD32 R0 R2 8 ; Get Pointer to Text
E0002D0F @strcmp	# CALLI R15 @strcmp
E0002C60 @Identify_Macros_1	# JUMP.NE R0 @Identify_Macros_1

# ;; It is a definition
# ;; Set i->Type = macro
E0002D200001	# LOADUI R0 1 ; The Enum value for macro
E10023020004	# STORE32 R0 R2 4 ; Set node type

# ;; Set i->Text = i->Next->Text
E10018420000	# LOAD32 R4 R2 0 ; Get Next
E10018040008	# LOAD32 R0 R4 8 ; Get Next->Text
E10023020008	# STORE32 R0 R2 8 ; Set i->Text = Next->Text

# ;; Set i->Expression = i->next->next->Text
E10018440000	# LOAD32 R4 R4 0 ; Get Next->Next
E10018040008	# LOAD32 R0 R4 8 ; Get Next->Next->Text
E10018340004	# LOAD32 R3 R4 4 ; Get Next->Next->type
E000A0330002	# CMPSKIPI.NE R3 2 ; If node is a string
E1000F000001	# ADDUI R0 R0 1 ; Skip first char
E1002302000c	# STORE32 R0 R2 12 ; Set Expression = Next->Next->Text

# ;; Set i->Next = i->Next->Next->Next
E10018440000	# LOAD32 R4 R4 0 ; Get Next->Next->Next
E10023420000	# STORE32 R4 R2 0 ; Set i->Next = Next->Next->Next

:Identify_Macros_1
E10018220000	# LOAD32 R2 R2 0 ; Get node->next
E0002CA2 @Identify_Macros_0	# JUMP.NZ R2 @Identify_Macros_0 ; Loop if i not NULL
0D01001F	# RET R15

:Identify_Macros_string
444546494E450000	# "DEFINE" ;; Line_Macro Function


# ;; Line_Macro Function
# ;; Receives a node pointer in R0
# ;; Causes macros to be applied
# ;; Returns to whatever called it
:Line_Macro
# ;; Initialize
0900040D	# COPY R0 R13 ; Start with Head

# ;; Main loop
:Line_Macro_0
E10018300004	# LOAD32 R3 R0 4 ; Load Node type
E1001820000c	# LOAD32 R2 R0 12 ; Load Expression pointer
E10018100008	# LOAD32 R1 R0 8 ; Load Text pointer
E10018000000	# LOAD32 R0 R0 0 ; Load Next pointer
E000A0330001	# CMPSKIPI.NE R3 1 ; If a macro
E0002D0F @setExpression	# CALLI R15 @setExpression ; Apply to other nodes
E0002CA0 @Line_Macro_0	# JUMP.NZ R0 @Line_Macro_0 ; If Next is Null Don't loop
0D01001F	# RET R15


# ;; setExpression Function
# ;; Receives a node pointer in R0
# ;; A string pointer to compare against in R1
# ;; A string pointer for replacement in R2
# ;; Doesn't modify any registers
# ;; Returns to whatever called it
:setExpression
# ;; Preserve registers
0902000F	# PUSHR R0 R15

# ;; Initialize
09000440	# COPY R4 R0 ; Use R4 for Node pointer

:setExpression_0
E10018340004	# LOAD32 R3 R4 4 ; Load type into R3
E000A0330001	# CMPSKIPI.NE R3 1 ; Check if Macro
3C00 @setExpression_1	# JUMP @setExpression_1 ; Move to next if Macro
E10018040008	# LOAD32 R0 R4 8 ; Load Text pointer into R0 for Comparision
E0002D0F @strcmp	# CALLI R15 @strcmp ; compare Text and Macro Text
E0002C60 @setExpression_1	# JUMP.NE R0 @setExpression_1 ; Move to next if not Match
E1002324000c	# STORE32 R2 R4 12 ; Set node->Expression = Exp

:setExpression_1
E10018440000	# LOAD32 R4 R4 0 ; Load Next
E0002CA4 @setExpression_0	# JUMP.NZ R4 @setExpression_0 ; Loop if next isn't NULL

:setExpression_Done
# ;; Restore registers
0902800F	# POPR R0 R15
0D01001F	# RET R15


# ;; Process_String Function
# ;; Receives a Node in R0
# ;; Doesn't modify registers
# ;; Returns back to whatever called it
:Process_String
# ;; Initialize
0900040D	# COPY R0 R13 ; Start with Head

:Process_String_0
# ;; Get node type
E10018100004	# LOAD32 R1 R0 4 ; Load Type
E000A0210002	# CMPSKIPI.E R1 2 ; If not a string
3C00 @Process_String_Done	# JUMP @Process_String_Done ; Just go to next

# ;; Its a string
E10018100008	# LOAD32 R1 R0 8 ; Get Text pointer
E10014210000	# LOAD8 R2 R1 0 ; Get first char of Text

# ;; Deal with '
E000A0220027	# CMPSKIPI.E R2 39 ; If char is not '
3C00 @Process_String_1	# JUMP @Process_String_1 ; Move to next label

# ;; Simply use Hex strings as is
E1000F110001	# ADDUI R1 R1 1 ; Move Text pointer by 1
E1002310000c	# STORE32 R1 R0 12 ; Set expression to Text + 1
3C00 @Process_String_Done	# JUMP @Process_String_Done ; And move on

:Process_String_1
# ;; Deal with (")
E0002D0F @Hexify_String	# CALLI R15 @Hexify_String

:Process_String_Done
E10018000000	# LOAD32 R0 R0 0 ; Load Next
E0002CA0 @Process_String_0	# JUMP.NZ R0 @Process_String_0 ; If Next isn't NULL Recurse down list
0D01001F	# RET R15


# ;; Hexify_String Function
# ;; Receives a node pointer in R0
# ;; Converts Quoted text to Hex values
# ;; Pads values up to multiple of 4 bytes
# ;; Doesn't modify registers
# ;; Returns to whatever called it
:Hexify_String
# ;; Preserve Registers
0902000F	# PUSHR R0 R15

# ;; Initialize
09000510	# MOVE R1 R0 ; Move R0 out of the way
E10023E1000c	# STORE32 R14 R1 12 ; Set node expression pointer
E10018110008	# LOAD32 R1 R1 8 ; Load Text pointer into R2
E1000F110001	# ADDUI R1 R1 1 ; SKip leading \"

# ;; Main Loop
:Hexify_String_0
E10018010000	# LOAD32 R0 R1 0 ; Load 4 bytes into R0 from Text
E100B02000ff	# ANDI R2 R0 0xFF ; Preserve byte to check for NULL
E0002D0F @hex32	# CALLI R15 @hex32 ; Convert to hex and store in Expression
E1000F110004	# ADDUI R1 R1 4 ; Pointer Text pointer to next 4 bytes
E0002CA2 @Hexify_String_0	# JUMP.NZ R2 @Hexify_String_0

# ;; Done
E1000FEE0001	# ADDUI R14 R14 1 ; Correct malloc value
0902800F	# POPR R0 R15
0D01001F	# RET R15


# ;; hex32 functionality
# ;; Accepts 32bit value in R0
# ;; Require R14 to be the heap pointer
# ;; WILL ALTER R14 !
# ;; Returns to whatever called it
:hex32
0902000F	# PUSHR R0 R15
E0002D600010	# SR0I R0 16 ; Do high word first
E0002D0F @hex16	# CALLI R15 @hex16
0902800F	# POPR R0 R15
:hex16
0902000F	# PUSHR R0 R15
E0002D600008	# SR0I R0 8 ; Do high byte first
E0002D0F @hex8	# CALLI R15 @hex8
0902800F	# POPR R0 R15
:hex8
0902000F	# PUSHR R0 R15
E0002D600004	# SR0I R0 4 ; Do high nybble first
E0002D0F @hex4	# CALLI R15 @hex4
0902800F	# POPR R0 R15
:hex4
E100B000000f	# ANDI R0 R0 0xF ; isolate nybble
E1000F000030	# ADDUI R0 R0 48 ; convert to ascii
E000A0400039	# CMPSKIPI.LE R0 57 ; If nybble was greater than '9'
E1000F000007	# ADDUI R0 R0 7 ; Shift it into 'A' range of ascii
E100210E0000	# STORE8 R0 R14 0 ; Store Hex Char
E1000FEE0001	# ADDUI R14 R14 1 ; Increment address pointer
0D01001F	# RET R15 ; Get next nybble or return if done


# ;; Eval_Immediates function
# ;; Receives a node in R0
# ;; Converts number into Hex
# ;; And write into Memory and fix pointer
:Eval_Immediates
# ;; Initialize
0900043D	# COPY R3 R13 ; Start with Head

# ;; Process Text
:Eval_Immediates_0
E10018230000	# LOAD32 R2 R3 0 ; Load Node->Next
E1001803000c	# LOAD32 R0 R3 12 ; Load Expression pointer
E0002CA0 @Eval_Immediates_1	# JUMP.NZ R0 @Eval_Immediates_1 ; Don't do anything if Expression is set
E10018030004	# LOAD32 R0 R3 4 ; Load Node type
E0002CA0 @Eval_Immediates_1	# JUMP.NZ R0 @Eval_Immediates_1 ; Don't do anything if Typed
E10018030008	# LOAD32 R0 R3 8 ; Load Text pointer
E10014100000	# LOAD8 R1 R0 0 ; Get first char of Text
E0002D0F @numerate_string	# CALLI R15 @numerate_string ; Convert to number in R0
E000A0210030	# CMPSKIPI.E R1 48 ; Skip next comparision if '0'
E0002C90 @Eval_Immediates_1	# JUMP.Z R0 @Eval_Immediates_1 ; Don't do anything if string isn't a number
E10020E3000c	# STORE R14 R3 12 ; Preserve pointer to expression
E0002D0F @hex16	# CALLI R15 @hex16 ; Shove our number into expression
E1000FEE0001	# ADDUI R14 R14 1 ; Allocate enough space for a null

# ;; Handle looping
:Eval_Immediates_1
09000532	# MOVE R3 R2 ; Prepare for next loop
E0002CA3 @Eval_Immediates_0	# JUMP.NZ R3 @Eval_Immediates_0 ; And loop
0D01001F	# RET R15


# ;; numerate_string function
# ;; Receives pointer To string in R0
# ;; Returns number in R0 equal to value of string
# ;; Or Zero in the event of invalid string
:numerate_string
# ;; Preserve Registers
0902001F	# PUSHR R1 R15
0902002F	# PUSHR R2 R15
0902003F	# PUSHR R3 R15
0902004F	# PUSHR R4 R15

# ;; Initialize
09000510	# MOVE R1 R0 ; Get Text pointer out of the way
0D000022	# FALSE R2 ; Set Negative flag to false
0D000023	# FALSE R3 ; Set current count to Zero
E10014010001	# LOAD8 R0 R1 1 ; Get second byte
E000A0300078	# CMPSKIPI.NE R0 120 ; If the second byte is x
3C00 @numerate_string_hex	# JUMP @numerate_string_hex ; treat string like hex

# ;; Deal with Decimal input
E0002D24000a	# LOADUI R4 10 ; Multiply by 10
E10014010000	# LOAD8 R0 R1 0 ; Get a byte
E000A030002d	# CMPSKIPI.NE R0 45 ; If - toggle flag
0D000032	# TRUE R2 ; So that we know to negate
E000A0220000	# CMPSKIPI.E R2 0 ; If toggled
E1000F110001	# ADDUI R1 R1 1 ; Move to next

:numerate_string_dec
E10014010000	# LOAD8 R0 R1 0 ; Get a byte

E000A0300000	# CMPSKIPI.NE R0 0 ; If NULL
3C00 @numerate_string_done	# JUMP @numerate_string_done ; Be done

05006334	# MUL R3 R3 R4 ; Shift counter by 10
E10010000030	# SUBI R0 R0 48 ; Convert ascii to number
E000A0100000	# CMPSKIPI.GE R0 0 ; If less than a number
3C00 @numerate_string_done	# JUMP @numerate_string_done ; Terminate NOW
E000A050000a	# CMPSKIPI.L R0 10 ; If more than a number
3C00 @numerate_string_done	# JUMP @numerate_string_done ; Terminate NOW
05001330	# ADDU R3 R3 R0 ; Don't add to the count

E1000F110001	# ADDUI R1 R1 1 ; Move onto next byte
3C00 @numerate_string_dec	# JUMP @numerate_string_dec

# ;; Deal with Hex input
:numerate_string_hex
E10014010000	# LOAD8 R0 R1 0 ; Get a byte
E000A0200030	# CMPSKIPI.E R0 48 ; All hex strings start with 0x
3C00 @numerate_string_done	# JUMP @numerate_string_done ; Be done if not a match
E1000F110002	# ADDUI R1 R1 2 ; Move to after leading 0x

:numerate_string_hex_0
E10014010000	# LOAD8 R0 R1 0 ; Get a byte
E0002C90 @numerate_string_done	# JUMP.Z R0 @numerate_string_done ; If NULL Be done

E0002D530004	# SL0I R3 4 ; Shift counter by 16
E10010000030	# SUBI R0 R0 48 ; Convert ascii number to number
E000A050000a	# CMPSKIPI.L R0 10 ; If A-F
E10010000007	# SUBI R0 R0 7 ; Shove into Range
E000A0500010	# CMPSKIPI.L R0 16 ; If a-f
E10010000020	# SUBI R0 R0 32 ; Shove into Range
05001330	# ADDU R3 R3 R0 ; Add to the count

E1000F110001	# ADDUI R1 R1 1 ; Get next Hex
3C00 @numerate_string_hex_0	# JUMP @numerate_string_hex_0

# ;; Clean up
:numerate_string_done
E000A0220000	# CMPSKIPI.E R2 0 ; If Negate flag has been set
09000033	# NEG R3 R3 ; Make the number negative
09000503	# MOVE R0 R3 ; Put number in R0

# ;; Restore Registers
0902804F	# POPR R4 R15
0902803F	# POPR R3 R15
0902802F	# POPR R2 R15
0902801F	# POPR R1 R15
0D01001F	# RET R15


# ;; Preserve_Other function
# ;; Sets Expression pointer to Text pointer value
# ;; For all unset nodes
:Preserve_Other
# ;; Initialize
0900040D	# COPY R0 R13 ; Start with HEAD

# ;; Process Node
:Preserve_Other_0
E10018200000	# LOAD32 R2 R0 0 ; Load Node->Next
E10018100004	# LOAD32 R1 R0 4 ; Load Node type
E0002CA1 @Preserve_Other_1	# JUMP.NZ R1 @Preserve_Other_1 ; Don't do anything if Typed
E1001810000c	# LOAD32 R1 R0 12 ; Load Expression pointer
E0002CA1 @Preserve_Other_1	# JUMP.NZ R1 @Preserve_Other_1 ; Don't do anything if Expression is set
E10018100008	# LOAD32 R1 R0 8 ; Load Text pointer
E1002310000c	# STORE32 R1 R0 12 ; Set Expression pointer to Text pointer

# ;; Loop through nodes
:Preserve_Other_1
09000502	# MOVE R0 R2 ; Prepare for next loop
E0002CA0 @Preserve_Other_0	# JUMP.NZ R0 @Preserve_Other_0
0D01001F	# RET R15


# ;; Print_Hex Function
# ;; Print all of the expressions
# ;; Starting with HEAD
:Print_Hex
# ;; Prep TAPE_02
E0002D201101	# LOADUI R0 0x1101
42100001	# FOPEN_WRITE

# ;; Initialize
0900040D	# COPY R0 R13 ; Start with HEAD
E0002D211101	# LOADUI R1 0x1101 ; Write to Tape_02

:Print_Hex_0
E10018200000	# LOAD32 R2 R0 0 ; Load Node->Next
E10018300004	# LOAD32 R3 R0 4 ; Load Node type
E1001800000c	# LOAD32 R0 R0 12 ; Load Expression pointer

E10010330001	# SUBI R3 R3 1 ; Check for Macros
E0002C93 @Print_Hex_1	# JUMP.Z R3 @Print_Hex_1 ; Don't print Macros
E0002D0F @Print_Line	# CALLI R15 @Print_Line ; Print the Expression

# ;; Loop down the nodes
:Print_Hex_1
09000502	# MOVE R0 R2 ; Prepare for next loop
E0002CA0 @Print_Hex_0	# JUMP.NZ R0 @Print_Hex_0 ; Keep looping if not NULL

# ;; Done writing File
E0002D201101	# LOADUI R0 0x1101 ; Close TAPE_01
42100002	# FCLOSE
0D01001F	# RET R15


# ;; Print_Line Function
# ;; Receives a pointer to a string in R0
# ;; And an interface in R1
# ;; Writes all Chars in string
# ;; Then writes a New line character to interface
:Print_Line
# ;; Initialize
09000530	# MOVE R3 R0 ; Get Pointer safely out of the way

:Print_Line_0
E10015030000	# LOADU8 R0 R3 0 ; Get our first byte
E000A0300000	# CMPSKIPI.NE R0 0 ; If the loaded byte is NULL
3C00 @Print_Line_Done	# JUMP @Print_Line_Done ; Be done
42100200	# FPUTC ; Otherwise print
E1000F330001	# ADDUI R3 R3 1 ; Increment for next loop
3C00 @Print_Line_0	# JUMP @Print_Line_0 ; And Loop

# ;; Clean up
:Print_Line_Done
E0002D20000a	# LOADUI R0 10 ; Put in Newline char
42100200	# FPUTC ; Write it out
0D01001F	# RET R15


# ;; Where we are putting the start of our stack
:stack