## 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 . :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