stage0/stage1/M0-macro.hex2

757 lines
25 KiB
Plaintext

## This file is part of stage0.
##
## stage0 is free software: you an 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
# ;; We will be using R14 for our condition codes
2D2F $stack # LOADUI R15 $stack ; Put stack at end of progra
# ;; Main program
# ;; Reads contents of Tape_01 and applies all Definitions
# ;; Writes results to Tape_02
# ;; Accepts no arguments and HALTS when done
:main
# ;; Prep TAPE_01
2D201100 # LOADUI R0 0x1100
42100000 # FOPEN_READ
0D00002D # FALSE R13 ; Head is NULL
09000510 # MOVE R1 R0 ; Read Tape_01
0D00002E # FALSE R14 ; We haven't yet reached EOF
:main_0
2D0F @Tokenize_Line # CALLI R15 @Tokenize_Line ; Call Tokenize_Line
2C9E @main_0 # JUMP.Z R14 @main_0 ; Until we reach EOF
# ;; Done reading File
2D201100 # LOADUI R0 0x1100 ; Close TAPE_01
42100002 # FCLOSE
0900040D # COPY R0 R13 ; Prepare for function
2D0F @Identify_Macros # CALLI R15 @Identify_Macros ; Tag all nodes that are macros
2D0F @Line_Macro # CALLI R15 @Line_Macro ; Apply macros down nodes
2D0F @Process_String # CALLI R15 @Process_String ; Convert string values to Hex16
2D0F @Eval_Immediates # CALLI R15 @Eval_Immediates ; Convert numbers to hex
2D0F @Preserve_Other # CALLI R15 @Preserve_Other ; Ensure labels/Pointers aren't lost
# ;; Prep TAPE_02
2D201101 # LOADUI R0 0x1101
42100001 # FOPEN_WRITE
2D0F @Print_Hex # CALLI R15 @Print_Hex ; Write Nodes to Tape_02
# ;; Done writing File
2D201101 # LOADUI R0 0x1101 ; Close TAPE_01
42100002 # FCLOSE
FFFFFFFF # HALT ; We are Done
# ;; Primative malloc function
# ;; Recieves number of bytes to allocate in R0
# ;; Returns pointer to block of that size in R0
# ;; Returns to whatever called it
:malloc
# ;; Preserve registers
0902001F # PUSHR R1 R15
# ;; Get current malloc pointer
2E01 @malloc_pointer # LOADR R1 @malloc_pointer
# ;; Deal with special case
A0310000 # CMPSKIPI.NE R1 0 ; If Zero set to our start of heap space
2D214000 # LOADUI R1 0x4000
# ;; update malloc pointer
09000301 # SWAP R0 R1
05000101 # ADD R1 R0 R1
2F01 @malloc_pointer # STORER R1 @malloc_pointer
# ;; Done
# ;; Restore registers
0902801F # POPR R1 R15
0D01001F # RET R15
# ;; Our static value for malloc pointer
:malloc_pointer
00000000 # NOP
# ;; Tokenize_Line function
# ;; Recieves pointer to Head in R0 and desired input in R1
# ;; Alters R14 when EOF Reached
# ;; Returns to whatever called it
:Tokenize_Line
# ;; Preserve registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Initialize
0900044D # COPY R4 R13 ; Get Head pointer out of the way
:Tokenize_Line_0
42100100 # FGETC ; Get a Char
# ;; Deal with lines comments starting with #
A0300023 # CMPSKIPI.NE R0 35
3C00 @Purge_Line_Comment # JUMP @Purge_Line_Comment
# ;; Deal with Line comments starting with ;
A030003b # CMPSKIPI.NE R0 59
3C00 @Purge_Line_Comment # JUMP @Purge_Line_Comment
# ;; Deal with Tab
A0300009 # CMPSKIPI.NE R0 9
3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again
# ;; Deal with New line
A030000a # CMPSKIPI.NE R0 10
3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again
# ;; Deal with space characters
A0300020 # CMPSKIPI.NE R0 32
3C00 @Tokenize_Line_0 # JUMP @Tokenize_Line_0 ; Throw away byte and try again
# ;; Flag if reached EOF
A0100000 # CMPSKIPI.GE R0 0
0D00003E # TRUE R14
# ;; Stop if EOF
A0100000 # CMPSKIPI.GE R0 0
3C00 @Tokenize_Line_Done # JUMP @Tokenize_Line_Done
# ;; Allocate a new Node
09000520 # MOVE R2 R0 ; Get Char out the way
2D200010 # LOADUI R0 16 ; Allocate 16 Bytes
2D0F @malloc # CALLI R15 @malloc ; Get address of new Node
09000320 # SWAP R2 R0 ; Store Pointer in R2
# ;; Deal with Strings wrapped in ""
A0300022 # CMPSKIPI.NE R0 34
3C00 @Store_String # JUMP @Store_String
# ;; Deal with Strings wrapped in '
A0300027 # CMPSKIPI.NE R0 39
3C00 @Store_String # JUMP @Store_String
# ;; Everything else is an atom store it
2D0F @Store_Atom # CALLI R15 @Store_Atom
:Tokenize_Line_Done
09000512 # MOVE R1 R2 ; Put Node pointer we are working on into R1
0900040D # COPY R0 R13 ; Get current HEAD
2D0F @Add_Token # CALLI R15 @Add_Token ; Append new token to Head
# ;; Restore registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
# ;; Return since we are done
0D01001F # RET R15
# ;; Purge_Line_Comment Function
# ;; Recieves 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
A020000a # 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
# ;; Recieves 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
# ;; Preserve registers
0902004F # PUSHR R4 R15
0902005F # PUSHR R5 R15
0902006F # PUSHR R6 R15
# ;; Initialize
09000560 # MOVE R6 R0 ; Get R0 out of the way
2D0F @malloc # CALLI R15 @malloc ; Get where space is free
09000540 # MOVE R4 R0 ; Put pointer someplace safe
0D000025 # FALSE R5 ; Start at index 0
09000406 # COPY R0 R6 ; Copy Char back into R0
# ;; Primary Loop
:Store_String_0
05049045 # STOREX8 R0 R4 R5 ; Store the Byte
42100100 # FGETC ; Get next Byte
0F550001 # ADDUI R5 R5 1 ; Prep for next loop
C306 @Store_String_0 # CMPJUMPI.NE R0 R6 @Store_String_0 ; Loop if matching not found
# ;; Clean up
23420008 # STORE32 R4 R2 8 ; Set Text pointer
0F050004 # ADDUI R0 R5 4 ; Correct Malloc
2D0F @malloc # CALLI R15 @malloc ; To the amount of space used
2D200002 # LOADUI R0 2 ; Using type string
23020004 # STORE32 R0 R2 4 ; Set node type
# ;; Restore Registers
0902806F # POPR R6 R15
0902805F # POPR R5 R15
0902804F # POPR R4 R15
3C00 @Tokenize_Line_Done # JUMP @Tokenize_Line_Done
# ;; Store_Atom function
# ;; Recieves Char in R0, desired input in R1
# ;; And node pointer in R2
# ;; Modifies node Text to point to string
:Store_Atom
# ;; Preserve registers
0902004F # PUSHR R4 R15
0902005F # PUSHR R5 R15
# ;; Initialize
09000550 # MOVE R5 R0 ; Get R0 out of the way
2D0F @malloc # CALLI R15 @malloc ; Get where space is free
09000540 # MOVE R4 R0 ; Put pointer someplace safe
09000505 # MOVE R0 R5 ; Copy Char back and Set index to 0
# ;; Primary Loop
:Store_Atom_0
05049045 # STOREX8 R0 R4 R5 ; Store the Byte
42100100 # FGETC ; Get next Byte
0F550001 # ADDUI R5 R5 1 ; Prep for next loop
A0300009 # CMPSKIPI.NE R0 9 ; If char is Tab
3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done
A030000a # CMPSKIPI.NE R0 10 ; If char is LF
3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done
A0300020 # CMPSKIPI.NE R0 32 ; If char is Space
3C00 @Store_Atom_Done # JUMP @Store_Atom_Done ; Be done
# ;; Otherwise loop
3C00 @Store_Atom_0 # JUMP @Store_Atom_0
:Store_Atom_Done
# ;; Cleanup
23420008 # STORE32 R4 R2 8 ; Set Text pointer
0F050001 # ADDUI R0 R5 1 ; Correct Malloc
2D0F @malloc # CALLI R15 @malloc ; To the amount of space used
# ;; Restore Registers
0902805F # POPR R5 R15
0902804F # POPR R4 R15
0D01001F # RET R15
# ;; Add_Token Function
# ;; Recieves pointers in R0 R1
# ;; Alters R13 if R) is NULL
# ;; Appends nodes together
# ;; Returns to whatever called it
:Add_Token
# ;; Preserve Registers
0902002F # PUSHR R2 R15
0902001F # PUSHR R1 R15
0902000F # PUSHR R0 R15
# ;; Handle if Head is NULL
2CA0 @Add_Token_0 # JUMP.NZ R0 @Add_Token_0
090004D1 # COPY R13 R1 ; Fix head
0902800F # POPR R0 R15 ; Clean up register
0902001F # PUSHR R1 R15 ; And act like we passed the reverse
3C00 @Add_Token_2 # JUMP @Add_Token_2
:Add_Token_0
# ;; Handle if Head->next is NULL
18200000 # LOAD32 R2 R0 0
2CA2 @Add_Token_1 # JUMP.NZ R2 @Add_Token_1
# ;; Set head->next = p
23100000 # STORE32 R1 R0 0
3C00 @Add_Token_2 # JUMP @Add_Token_2
:Add_Token_1
# ;; Handle case of Head->next not being NULL
18000000 # LOAD32 R0 R0 0 ; Move to next node
18200000 # LOAD32 R2 R0 0 ; Get node->next
A0220000 # CMPSKIPI.E R2 0 ; If it is not null
3C00 @Add_Token_1 # JUMP @Add_Token_1 ; Move to the next node and try again
3C00 @Add_Token_0 # JUMP @Add_Token_0 ; Else simply act as if we got this node
# ; in the first place
:Add_Token_2
# ;; Restore registers
0902800F # POPR R0 R15
0902801F # POPR R1 R15
0902802F # POPR R2 R15
0D01001F # RET R15
# ;; strcmp function
# ;; Recieves pointers to null terminated strings
# ;; In R0 and R1
# ;; Returns if they are equal in R0
# ;; Returns to whatever called it
:strcmp
# ;; Preserve registers
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
2D240000 # LOADUI R4 0 ; 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
0F440001 # ADDUI R4 R4 1 ; Prep for next loop
05004101 # CMP R1 R0 R1 ; Compare the bytes
A0200000 # CMPSKIPI.E R0 0 ; Stop if byte is NULL
2C51 @cmpbyte # JUMP.E R1 @cmpbyte ; Loop if bytes are equal
# ;; Done
09000501 # MOVE R0 R1 ; Prepare for return
# ;; Restore registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0D01001F # RET R15
# ;; Identify_Macros Function
# ;; Recieves a pointer to a node in R0
# ;; 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
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
# ;; Main Loop
:Identify_Macros_0
09000520 # MOVE R2 R0
18120008 # LOAD32 R1 R2 8 ; Get Pointer to Text
2D20 $Identify_Macros_string # LOADUI R0 $Identify_Macros_string
2D0F @strcmp # CALLI R15 @strcmp
09000512 # MOVE R1 R2
2C60 @Identify_Macros_1 # JUMP.NE R0 @Identify_Macros_1
# ;; It is a definition
# ;; Set p->Type = macro
2D200001 # LOADUI R0 1 ; The Enum value for macro
23010004 # STORE32 R0 R1 4 ; Set node type
# ;; Set p->Text = p->Next->Text
18210000 # LOAD32 R2 R1 0 ; Get Next
18020008 # LOAD32 R0 R2 8 ; Get Next->Text
23010008 # STORE32 R0 R1 8 ; Set Text = Next->Text
# ;; Set p->Expression = p->next->next->Text
18220000 # LOAD32 R2 R2 0 ; Get Next->Next
18020008 # LOAD32 R0 R2 8 ; Get Next->Next->Text
18320004 # LOAD32 R3 R2 4 ; Get Next->Next->type
A0330002 # CMPSKIPI.NE R3 2 ; If node is a string
0F000001 # ADDUI R0 R0 1 ; Skip first char
2301000c # STORE32 R0 R1 12 ; Set Expression = Next->Next->Text
# ;; Set p->Next = p->Next->Next->Next
18020000 # LOAD32 R0 R2 0 ; Get Next->Next->Next
23010000 # STORE32 R0 R1 0 ; Set Next = Next->Next->Next
:Identify_Macros_1
18010000 # LOAD32 R0 R1 0 ; Get node->next
A0300000 # CMPSKIPI.NE R0 0 ; If node->next is NULL
3C00 @Identify_Macros_Done # JUMP @Identify_Macros_Done ; Be done
# ;; Otherwise keep looping
3C00 @Identify_Macros_0 # JUMP @Identify_Macros_0
:Identify_Macros_Done
# ;; Restore registers
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
:Identify_Macros_string
444546494E450000 # "DEFINE"
# ;; Line_Macro Function
# ;; Recieves a node pointer in R0
# ;; Causes macros to be applied
# ;; Returns to whatever called it
:Line_Macro
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
# ;; Main loop
:Line_Macro_0
18300004 # LOAD32 R3 R0 4 ; Load Node type
1820000c # LOAD32 R2 R0 12 ; Load Expression pointer
18100008 # LOAD32 R1 R0 8 ; Load Text pointer
18000000 # LOAD32 R0 R0 0 ; Load Next pointer
A0330001 # CMPSKIPI.NE R3 1 ; If a macro
2D0F @setExpression # CALLI R15 @setExpression ; Apply to other nodes
A0200000 # CMPSKIPI.E R0 0 ; If Next is Null
3C00 @Line_Macro_0 # JUMP @Line_Macro_0 ; Don't loop
# ;; Clean up
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; setExpression Function
# ;; Recieves 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
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
0902005F # PUSHR R5 R15
# ;; Initialize
09000541 # MOVE R4 R1 ; Put Macro Text in a safe place
09000450 # COPY R5 R0 ; Use R5 for Node pointer
:setExpression_0
18350004 # LOAD32 R3 R5 4 ; Load type into R3
A0330001 # CMPSKIPI.NE R3 1 ; Check if Macro
3C00 @setExpression_1 # JUMP @setExpression_1 ; Move to next if Macro
18050008 # LOAD32 R0 R5 8 ; Load Text pointer into R0 for Comparision
09000414 # COPY R1 R4 ; Put Macro Text for comparision
2D0F @strcmp # CALLI R15 @strcmp ; compare Text and Macro Text
2C60 @setExpression_1 # JUMP.NE R0 @setExpression_1 ; Move to next if not Match
2325000c # STORE32 R2 R5 12 ; Set node->Expression = Exp
:setExpression_1
18550000 # LOAD32 R5 R5 0 ; Load Next
2CA5 @setExpression_0 # JUMP.NZ R5 @setExpression_0 ; Loop if next isn't NULL
:setExpression_Done
# ;; Restore registers
0902805F # POPR R5 R15
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Process_String Function
# ;; Recieves a Node in R0
# ;; Doesn't modify registers
# ;; Returns back to whatever called it
:Process_String
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
:Process_String_0
# ;; Get node type
18100004 # LOAD32 R1 R0 4 ; Load Type
A0210002 # CMPSKIPI.E R1 2 ; If not a string
3C00 @Process_String_Done # JUMP @Process_String_Done ; Just go to next
# ;; Its a string
18100008 # LOAD32 R1 R0 8 ; Get Text pointer
14210000 # LOAD8 R2 R1 0 ; Get first char of Text
# ;; Deal with '
A0220027 # 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
0F110001 # ADDUI R1 R1 1 ; Move Text pointer by 1
2310000c # 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 ""
2D0F @Hexify_String # CALLI R15 @Hexify_String
:Process_String_Done
18000000 # LOAD32 R0 R0 0 ; Load Next
A0200000 # CMPSKIPI.E R0 0 ; If Next isn't NULL
3C00 @Process_String_0 # JUMP @Process_String_0 ; Recurse down list
# ;; Restore registers
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Hexify_String Function
# ;; Recieves 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
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Initialize
09000520 # MOVE R2 R0 ; Move R0 out of the way
2D0F @malloc # CALLI R15 @malloc ; Get address of new Node
09000510 # MOVE R1 R0 ; Prep For Hex32
2312000c # STORE32 R1 R2 12 ; Set node expression pointer
18220008 # LOAD32 R2 R2 8 ; Load Text pointer into R2
0F220001 # ADDUI R2 R2 1 ; SKip leading ""
0D000024 # FALSE R4 ; Set counter for malloc to Zero
# ;; Main Loop
:Hexify_String_0
18020000 # LOAD32 R0 R2 0 ; Load 4 bytes into R0 from Text
B03000ff # ANDI R3 R0 0xFF ; Preserve byte to check for NULL
2D0F @hex32 # CALLI R15 @hex32 ; Convert to hex and store in Expression
0F220004 # ADDUI R2 R2 4 ; Pointer Text pointer to next 4 bytes
0F440008 # ADDUI R4 R4 8 ; Increment storage space required
A0230000 # CMPSKIPI.E R3 0 ; If byte was NULL
3C00 @Hexify_String_0 # JUMP @Hexify_String_0
# ;; Done
0F040001 # ADDUI R0 R4 1 ; Lead space for NULL terminator
2D0F @malloc # CALLI R15 @malloc ; Correct malloc value
# ;; Restore Registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; hex32 functionality
# ;; Accepts 32bit value in R0
# ;; Require R1 to be a pointer to place to store hex16
# ;; WILL ALTER R1 !
# ;; Returns to whatever called it
:hex32
0902000F # PUSHR R0 R15
2D600010 # SR0I R0 16 ; Do high word first
2D0F @hex16 # CALLI R15 @hex16
0902800F # POPR R0 R15
:hex16
0902000F # PUSHR R0 R15
2D600008 # SR0I R0 8 ; Do high byte first
2D0F @hex8 # CALLI R15 @hex8
0902800F # POPR R0 R15
:hex8
0902000F # PUSHR R0 R15
2D600004 # SR0I R0 4 ; Do high nybble first
2D0F @hex4 # CALLI R15 @hex4
0902800F # POPR R0 R15
:hex4
B000000f # ANDI R0 R0 0x000F ; isolate nybble
0F000030 # ADDUI R0 R0 48 ; convert to ascii
A0400039 # CMPSKIPI.LE R0 57 ; If nybble was greater than '9'
0F000007 # ADDUI R0 R0 7 ; Shift it into 'A' range of ascii
21010000 # STORE8 R0 R1 0 ; Store Hex Char
0F110001 # ADDUI R1 R1 1 ; Increment address pointer
0D01001F # RET R15 ; Get next nybble or return if done
# ;; Eval_Immediates function
# ;; Recieves a node in R0
# ;; Converts number into Hex
# ;; And write into Memory and fix pointer
:Eval_Immediates
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
0902005F # PUSHR R5 R15
0902006F # PUSHR R6 R15
# ;; Initialize
0900040D # COPY R0 R13 ; Start with Head
0D000025 # FALSE R5 ; Zero for checking return of numerate_string
# ;; Process Text
:Eval_Immediates_0
09000460 # COPY R6 R0 ; Safely preserve pointer to node
18400000 # LOAD32 R4 R0 0 ; Load Node->Next
18300004 # LOAD32 R3 R0 4 ; Load Node type
1820000c # LOAD32 R2 R0 12 ; Load Expression pointer
18100008 # LOAD32 R1 R0 8 ; Load Text pointer
2CA2 @Eval_Immediates_1 # JUMP.NZ R2 @Eval_Immediates_1 ; Don't do anything if Expression is set
2CA3 @Eval_Immediates_1 # JUMP.NZ R3 @Eval_Immediates_1 ; Don't do anything if Typed
09000401 # COPY R0 R1 ; Put Text pointer into R0
2D0F @numerate_string # CALLI R15 @numerate_string ; Convert to number in R0
14110000 # LOAD8 R1 R1 0 ; Get first char of Text
A0210030 # CMPSKIPI.E R1 48 ; Skip next comparision if '0'
C205 @Eval_Immediates_1 # CMPJUMPI.E R0 R5 @Eval_Immediates_1 ; Don't do anything if string isn't a number
09000510 # MOVE R1 R0 ; Preserve number
2D200005 # LOADUI R0 5 ; Allocate enough space for 4 hex and a null
2D0F @malloc # CALLI R15 @malloc ; Obtain the pointer the newly allocated Expression
2006000c # STORE R0 R6 12 ; Preserve pointer to expression
09000301 # SWAP R0 R1 ; Fix order for call to hex16
2D0F @hex16 # CALLI R15 @hex16 ; Shove our number into expression
# ;; Handle looping
:Eval_Immediates_1
C245 @Eval_Immediates_2 # CMPJUMPI.E R4 R5 @Eval_Immediates_2 ; If null be done
09000504 # MOVE R0 R4 ; Prepare for next loop
3C00 @Eval_Immediates_0 # JUMP @Eval_Immediates_0 ; And loop
# ;; Clean up
:Eval_Immediates_2
# ;; Restore Registers
0902806F # POPR R6 R15
0902805F # POPR R5 R15
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; numerate_string function
# ;; Recieves 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
14010001 # LOAD8 R0 R1 1 ; Get second byte
A0300078 # 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
2D24000a # LOADUI R4 10 ; Multiply by 10
14010000 # LOAD8 R0 R1 0 ; Get a byte
A030002d # CMPSKIPI.NE R0 45 ; If - toggle flag
0D000032 # TRUE R2 ; So that we know to negate
A0220000 # CMPSKIPI.E R2 0 ; If toggled
0F110001 # ADDUI R1 R1 1 ; Move to next
:numerate_string_dec
14010000 # LOAD8 R0 R1 0 ; Get a byte
A0300000 # 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
10000030 # SUBI R0 R0 48 ; Convert ascii to number
A0100000 # CMPSKIPI.GE R0 0 ; If less than a number
3C00 @numerate_string_done # JUMP @numerate_string_done ; Terminate NOW
A050000a # 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
0F110001 # ADDUI R1 R1 1 ; Move onto next byte
3C00 @numerate_string_dec # JUMP @numerate_string_dec
# ;; Deal with Hex input
:numerate_string_hex
14010000 # LOAD8 R0 R1 0 ; Get a byte
A0200030 # CMPSKIPI.E R0 48 ; All hex strings start with 0x
3C00 @numerate_string_done # JUMP @numerate_string_done ; Be done if not a match
0F110002 # ADDUI R1 R1 2 ; Move to after leading 0x
:numerate_string_hex_0
14010000 # LOAD8 R0 R1 0 ; Get a byte
A0300000 # CMPSKIPI.NE R0 0 ; If NULL
3C00 @numerate_string_done # JUMP @numerate_string_done ; Be done
2D530004 # SL0I R3 4 ; Shift counter by 16
10000030 # SUBI R0 R0 48 ; Convert ascii number to number
A050000a # CMPSKIPI.L R0 10 ; If A-F
10000007 # SUBI R0 R0 7 ; Shove into Range
A0500010 # CMPSKIPI.L R0 16 ; If a-f
10000020 # SUBI R0 R0 32 ; Shove into Range
05001330 # ADDU R3 R3 R0 ; Add to the count
0F110001 # ADDUI R1 R1 1 ; Get next Hex
3C00 @numerate_string_hex_0 # JUMP @numerate_string_hex_0
# ;; Clean up
:numerate_string_done
A0220000 # 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
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Initialize
0900040D # COPY R0 R13 ; Start with HEAD
# ;; Process Node
:Preserve_Other_0
18400000 # LOAD32 R4 R0 0 ; Load Node->Next
18300004 # LOAD32 R3 R0 4 ; Load Node type
1820000c # LOAD32 R2 R0 12 ; Load Expression pointer
18100008 # LOAD32 R1 R0 8 ; Load Text pointer
2CA2 @Preserve_Other_1 # JUMP.NZ R2 @Preserve_Other_1 ; Don't do anything if Expression is set
2CA3 @Preserve_Other_1 # JUMP.NZ R3 @Preserve_Other_1 ; Don't do anything if Typed
2310000c # STORE32 R1 R0 12 ; Set Expression pointer to Text pointer
# ;; Loop through nodes
:Preserve_Other_1
09000504 # MOVE R0 R4 ; Prepare for next loop
2CA0 @Preserve_Other_0 # JUMP.NZ R0 @Preserve_Other_0
# ;; Clean up
:Preserve_Other_Done
# ;; Restore Registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Print_Hex Function
# ;; Print all of the expressions
# ;; Starting with HEAD
:Print_Hex
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Initialize
0900040D # COPY R0 R13 ; Start with HEAD
:Print_Hex_0
18200000 # LOAD32 R2 R0 0 ; Load Node->Next
18100004 # LOAD32 R1 R0 4 ; Load Node type
1800000c # LOAD32 R0 R0 12 ; Load Expression pointer
10110001 # SUBI R1 R1 1 ; Check for Macros
2C91 @Print_Hex_1 # JUMP.Z R1 @Print_Hex_1 ; Don't print Macros
2D211101 # LOADUI R1 0x1101 ; Write to Tape_02
2D0F @Print_Line # CALLI R15 @Print_Line ; Print the Expression
# ;; Loop down the nodes
:Print_Hex_1
09000502 # MOVE R0 R2 ; Prepare for next loop
2CA0 @Print_Hex_0 # JUMP.NZ R0 @Print_Hex_0 ; Keep looping if not NULL
# ;; Clean up
:Print_Hex_Done
# ;; Restore Registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
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
# ;; Preserve Registers
0902000F # PUSHR R0 R15
0902001F # PUSHR R1 R15
0902002F # PUSHR R2 R15
0902003F # PUSHR R3 R15
0902004F # PUSHR R4 R15
# ;; Initialize
09000530 # MOVE R3 R0 ; Get Pointer safely out of the way
0D000024 # FALSE R4 ; Start index at 0
:Print_Line_0
0503A034 # LOADXU8 R0 R3 R4 ; Get our first byte
A0300000 # CMPSKIPI.NE R0 0 ; If the loaded byte is NULL
3C00 @Print_Line_Done # JUMP @Print_Line_Done ; Be done
42100200 # FPUTC ; Otherwise print
0F440001 # ADDUI R4 R4 1 ; Increment for next loop
3C00 @Print_Line_0 # JUMP @Print_Line_0 ; And Loop
# ;; Clean up
:Print_Line_Done
2D20000a # LOADUI R0 10 ; Put in Newline char
42100200 # FPUTC ; Write it out
# ;; Restore Registers
0902804F # POPR R4 R15
0902803F # POPR R3 R15
0902802F # POPR R2 R15
0902801F # POPR R1 R15
0902800F # POPR R0 R15
0D01001F # RET R15
# ;; Where we are putting the start of our stack
:stack