123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609 |
- ## 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
|