970 lines
32 KiB
Plaintext
970 lines
32 KiB
Plaintext
|
### Copyright (C) 2019 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/>.
|
||
|
|
||
|
DEFINE ADDI8_to_AL 04
|
||
|
DEFINE ADDI8_to_RAX 4883C0
|
||
|
DEFINE ADDI8_to_RBX 4883C3
|
||
|
DEFINE ADDI8_to_RCX 4883C1
|
||
|
DEFINE ADDI8_to_RDX 4883C2
|
||
|
DEFINE ADD_RAX_to_RDI 4801C7
|
||
|
DEFINE ADD_RCX_to_RAX 4801C8
|
||
|
DEFINE AND_RAX_Immediate8 4883E0
|
||
|
DEFINE CALLI32 E8
|
||
|
DEFINE CMP_AL_Immediate8 3C
|
||
|
DEFINE CMP_RAX_Immediate8 4883F8
|
||
|
DEFINE CMP_RBX_Immediate8 4883FB
|
||
|
DEFINE CMP_RCX_Immediate8 4883F9
|
||
|
DEFINE CMP_RDX_Immediate8 4883FA
|
||
|
DEFINE CMP_RSI_Immediate8 4883FE
|
||
|
DEFINE CMP_RBX_to_RAX 4839D8
|
||
|
DEFINE CMP_RBX_to_RCX 4839D9
|
||
|
DEFINE CMP_RCX_to_RAX 4839C8
|
||
|
DEFINE COPY_R12_to_RAX 4C89E0
|
||
|
DEFINE COPY_R12_to_RDI 4C89E7
|
||
|
DEFINE COPY_R13_to_RAX 4C89E8
|
||
|
DEFINE COPY_R13_to_RBX 4C89EB
|
||
|
DEFINE COPY_R14_to_RDI 4C89F7
|
||
|
DEFINE COPY_R15_to_RDI 4C89FF
|
||
|
DEFINE COPY_RAX_to_R12 4989C4
|
||
|
DEFINE COPY_RAX_to_R13 4989C5
|
||
|
DEFINE COPY_RAX_to_R14 4989C6
|
||
|
DEFINE COPY_RAX_to_R15 4989C7
|
||
|
DEFINE COPY_RAX_to_RBX 4889C3
|
||
|
DEFINE COPY_RAX_to_RCX 4889C1
|
||
|
DEFINE COPY_RAX_to_RDX 4889C2
|
||
|
DEFINE COPY_RBX_to_RAX 4889D8
|
||
|
DEFINE COPY_RBX_to_RCX 4889D9
|
||
|
DEFINE COPY_RBX_to_RDX 4889DA
|
||
|
DEFINE COPY_RCX_to_RAX 4889C8
|
||
|
DEFINE COPY_RCX_to_RBX 4889CB
|
||
|
DEFINE COPY_RDI_to_R12 4989FC
|
||
|
DEFINE COPY_RDX_to_R13 4989D5
|
||
|
DEFINE COPY_RDX_to_RAX 4889D0
|
||
|
DEFINE IMUL_RAX_Immediate8 486BC0
|
||
|
DEFINE JBE8 76
|
||
|
DEFINE JE32 0F84
|
||
|
DEFINE JG32 0F8F
|
||
|
DEFINE JL32 0F8C
|
||
|
DEFINE JMP32 E9
|
||
|
DEFINE JNE32 0F85
|
||
|
DEFINE LEA_RSI 488D3424
|
||
|
DEFINE LOAD8_AL_from_Address_RBX 8A03
|
||
|
DEFINE LOAD8_AL_from_Address_RBX_Index_RCX 8A040B
|
||
|
DEFINE LOAD8_AL_from_Address_RCX 8A01
|
||
|
DEFINE LOAD8_AL_from_Address_RDX 8A02
|
||
|
DEFINE LOAD8_BL_from_Address_RAX 8A18
|
||
|
DEFINE LOAD8_BL_from_Address_RDX 8A1A
|
||
|
DEFINE LOAD8_CL_from_Address_RAX 8A08
|
||
|
DEFINE LOAD8_CL_from_Address_RBX 8A0B
|
||
|
DEFINE LOAD8_CL_from_Address_RBX_Immediate8 8A4B
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RAX 488B00
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RCX 488B01
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RAX_Immediate8 488B40
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RBX_Immediate8 488B43
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RCX_Immediate8 488B41
|
||
|
DEFINE LOAD64_into_RAX_from_Address_RDX_Immediate8 488B42
|
||
|
DEFINE LOAD64_into_RBX_from_Address_RAX_Immediate8 488B58
|
||
|
DEFINE LOAD64_into_RBX_from_Address_RBX 488B1B
|
||
|
DEFINE LOAD64_into_RBX_from_Address_RCX_Immediate8 488B59
|
||
|
DEFINE LOAD64_into_RCX_from_Address_RAX_Immediate8 488B48
|
||
|
DEFINE LOAD64_into_RCX_from_Address_RBX 488B0B
|
||
|
DEFINE LOAD64_into_RCX_from_Address_RCX 488B09
|
||
|
DEFINE LOAD64_into_RDX_from_Address_RDX 488B12
|
||
|
DEFINE LOADI32_RAX 48C7C0
|
||
|
DEFINE LOADI32_RBX BB
|
||
|
DEFINE LOADI32_RCX B9
|
||
|
DEFINE LOADI32_RDI BF
|
||
|
DEFINE LOADI32_RDX BA
|
||
|
DEFINE LOADI32_RSI BE
|
||
|
DEFINE POP_FLAGS 9D
|
||
|
DEFINE POP_R11 415B
|
||
|
DEFINE POP_RAX 58
|
||
|
DEFINE POP_RBX 5B
|
||
|
DEFINE POP_RCX 59
|
||
|
DEFINE POP_RDX 5A
|
||
|
DEFINE POP_RDI 5F
|
||
|
DEFINE POP_RSI 5E
|
||
|
DEFINE PUSH_FLAGS 9C
|
||
|
DEFINE PUSH_R11 4153
|
||
|
DEFINE PUSH_RAX 50
|
||
|
DEFINE PUSH_RBX 53
|
||
|
DEFINE PUSH_RCX 51
|
||
|
DEFINE PUSH_RDX 52
|
||
|
DEFINE PUSH_RSI 56
|
||
|
DEFINE RET C3
|
||
|
DEFINE SHIFT_LEFT_RAX_Immediate8 48C1E0
|
||
|
DEFINE SHIFT_RIGHT_RAX_Immediate8 48C1E8
|
||
|
DEFINE STORE64_R13_into_Address_RDX 4C892A
|
||
|
DEFINE STORE64_RAX_into_Address_RBX 488903
|
||
|
DEFINE STORE64_RAX_into_Address_RCX 488901
|
||
|
DEFINE STORE64_RAX_into_Address_RCX_Immediate8 488941
|
||
|
DEFINE STORE64_RAX_into_Address_RDX_Immediate8 488942
|
||
|
DEFINE STORE64_RBX_into_Address_RAX_Immediate8 488958
|
||
|
DEFINE STORE64_RBX_into_Address_RCX_Immediate8 488959
|
||
|
DEFINE STORE64_RCX_into_Address_RDX_Immediate8 48894A
|
||
|
DEFINE STORE8_AL_into_Address_RBX 8803
|
||
|
DEFINE STORE8_CL_into_Address_RDX 880A
|
||
|
DEFINE SUBI8_RCX 4883E9
|
||
|
DEFINE SWAP_RAX_RBX 4893
|
||
|
DEFINE SYSCALL 0F05
|
||
|
DEFINE ZERO_EXTEND_AL 480FB6C0
|
||
|
DEFINE ZERO_EXTEND_BL 480FB6DB
|
||
|
DEFINE ZERO_EXTEND_CL 480FB6C9
|
||
|
|
||
|
;; Register usage:
|
||
|
;; RAX, RSI, RDI => Temps
|
||
|
;; R12 => MALLOC
|
||
|
;; R13 => HEAD
|
||
|
;; R14 => Output_file
|
||
|
;; R15 => Input_file
|
||
|
|
||
|
;; Struct format: (size 32)
|
||
|
;; NEXT => 0
|
||
|
;; TYPE => 8
|
||
|
;; TEXT => 16
|
||
|
;; EXPRESSION => 24
|
||
|
|
||
|
;; Types
|
||
|
;; None => 0
|
||
|
;; MACRO => 1
|
||
|
;; STRING => 2
|
||
|
|
||
|
; Where the ELF Header is going to hit
|
||
|
; Simply jump to _start
|
||
|
; Our main function
|
||
|
:_start
|
||
|
POP_RAX ;·Get·the·number·of·arguments
|
||
|
POP_RDI ;·Get·the·program·name
|
||
|
POP_RDI ;·Get·the·actual·input name
|
||
|
LOADI32_RSI %0 ;·prepare·read_only
|
||
|
LOADI32_RAX %2 ;·the·syscall·number·for·open()
|
||
|
SYSCALL ; Now open that damn file
|
||
|
COPY_RAX_to_R15 ; Preserve the file pointer we were given
|
||
|
|
||
|
POP_RDI ;·Get·the·actual·output name
|
||
|
LOADI32_RSI %577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC
|
||
|
LOADI32_RDX %384 ; Prepare file as RW for owner only (600 in octal)
|
||
|
LOADI32_RAX %2 ;·the·syscall·number·for·open()
|
||
|
SYSCALL ; Now open that damn file
|
||
|
CMP_RAX_Immediate8 !0 ; Check for missing output
|
||
|
JG32 %_start_out ; Have real input
|
||
|
LOADI32_RAX %1 ; Use stdout
|
||
|
|
||
|
:_start_out
|
||
|
COPY_RAX_to_R14 ; Preserve the file pointer we were given
|
||
|
|
||
|
LOADI32_RAX %0xC ; the Syscall # for SYS_BRK
|
||
|
LOADI32_RDI %0 ; Get current brk
|
||
|
SYSCALL ; Let the kernel do the work
|
||
|
COPY_RAX_to_R12 ; Set our malloc pointer
|
||
|
|
||
|
CALLI32 %Tokenize_Line ; Get all lines
|
||
|
COPY_R13_to_RAX ; prepare for Reverse_List
|
||
|
CALLI32 %Reverse_List ; Correct order
|
||
|
COPY_RAX_to_R13 ; Update HEAD
|
||
|
CALLI32 %Identify_Macros ; Find the DEFINEs
|
||
|
CALLI32 %Line_Macro ; Apply the DEFINEs
|
||
|
CALLI32 %Process_String ; Handle strings
|
||
|
CALLI32 %Eval_Immediates ; Handle Numbers
|
||
|
CALLI32 %Preserve_Other ; Collect the remaining
|
||
|
CALLI32 %Print_Hex ; Output our results
|
||
|
|
||
|
:Done
|
||
|
; program completed Successfully
|
||
|
LOADI32_RDI %0 ; All is well
|
||
|
LOADI32_RAX %0x3C ; put the exit syscall number in eax
|
||
|
SYSCALL ; Call it a good day
|
||
|
|
||
|
|
||
|
;; Tokenize_Line Function
|
||
|
;; Using input file R15 and Head R13
|
||
|
;; Creates a linked list of structs
|
||
|
;; Uses RBX for in_set strings, RCX for Int C and RDX for Struct Token* p
|
||
|
:Tokenize_Line
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
:restart
|
||
|
CALLI32 %fgetc ; Read a char
|
||
|
CMP_RAX_Immediate8 !-4 ; Check for EOF
|
||
|
JE32 %done ; File is collected
|
||
|
|
||
|
ZERO_EXTEND_AL ; We have to zero extend it to use it
|
||
|
COPY_RAX_to_RCX ; Protect C
|
||
|
|
||
|
LOADI32_RBX &comments ; Get pointer to "#;"
|
||
|
CALLI32 %In_Set ; Check for comments
|
||
|
CMP_RAX_Immediate8 !1 ; If comments
|
||
|
JE32 %Purge_LineComment ; try again
|
||
|
|
||
|
COPY_RCX_to_RAX ; put C in place for check
|
||
|
LOADI32_RBX &terminators ; Get pointer to "\n\t "
|
||
|
CALLI32 %In_Set ; Check for terminators
|
||
|
CMP_RAX_Immediate8 !1 ; If terminator
|
||
|
JE32 %restart ; try again
|
||
|
|
||
|
LOADI32_RAX %32 ; Malloc the struct P
|
||
|
CALLI32 %malloc ; Get pointer to P
|
||
|
COPY_RAX_to_RDX ; Protect P
|
||
|
STORE64_R13_into_Address_RDX ; P->NEXT = HEAD
|
||
|
COPY_RDX_to_R13 ; HEAD = P
|
||
|
|
||
|
COPY_RCX_to_RAX ; put C in place for check
|
||
|
LOADI32_RBX &string_char ; Get pointer to "\"'"
|
||
|
CALLI32 %In_Set ; Check for string chars
|
||
|
CMP_RAX_Immediate8 !1 ; If string char
|
||
|
JE32 %Store_String ; Get string
|
||
|
|
||
|
CALLI32 %Store_Atom ; Get whole token
|
||
|
JMP32 %restart
|
||
|
|
||
|
:done
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; fgetc function
|
||
|
;; Recieves FILE* in R15
|
||
|
;; Returns -4 (EOF) or char in RAX
|
||
|
:fgetc
|
||
|
LOADI32_RAX %-4 ; Put EOF in rax
|
||
|
PUSH_RAX ; Assume bad (If nothing read, value will remain EOF)
|
||
|
LEA_RSI ; Get stack address
|
||
|
COPY_R15_to_RDI ; Where are we reading from
|
||
|
LOADI32_RAX %0 ; the syscall number for read
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
LOADI32_RDX %1 ; set the size of chars we want
|
||
|
PUSH_R11 ; Protect r11
|
||
|
SYSCALL ; call the Kernel
|
||
|
POP_R11 ; Restore r11
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RAX ; Get either char or EOF
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Malloc isn't actually required if the program being built fits in the initial memory
|
||
|
;; However, it doesn't take much to add it.
|
||
|
;; Requires R12 to be initialized and RAX to have the number of desired bytes
|
||
|
:malloc
|
||
|
COPY_R12_to_RDI ; Using the current pointer
|
||
|
ADD_RAX_to_RDI ; Request the number of desired bytes
|
||
|
LOADI32_RAX %0xC ; the Syscall # for SYS_BRK
|
||
|
PUSH_RCX ; Protect rcx
|
||
|
PUSH_R11 ; Protect r11
|
||
|
SYSCALL ; call the Kernel
|
||
|
POP_R11 ; Restore r11
|
||
|
POP_RCX ; Restore rcx
|
||
|
COPY_R12_to_RAX ; Return pointer
|
||
|
COPY_RDI_to_R12 ; Update pointer
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Purge_LineComment function
|
||
|
;; Reads chars until LF and jumps to restart
|
||
|
:Purge_LineComment
|
||
|
CALLI32 %fgetc ; Get a char
|
||
|
ZERO_EXTEND_AL ; Zero extend
|
||
|
CMP_RAX_Immediate8 !10 ; While not LF
|
||
|
JNE32 %Purge_LineComment ; Keep reading
|
||
|
JMP32 %restart
|
||
|
|
||
|
|
||
|
;; Store_String Function
|
||
|
;; Recieves C in RCX, HEAD in RDX and Input file in R14
|
||
|
;; Uses RBX for terminator, RCX for C and RDX for string
|
||
|
:Store_String
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
|
||
|
LOADI32_RAX %2 ; Using TYPE STRING
|
||
|
STORE64_RAX_into_Address_RDX_Immediate8 !8 ; HEAD->TYPE = STRING
|
||
|
LOADI32_RAX %256 ; Malloc the string
|
||
|
CALLI32 %malloc ; Get pointer to P
|
||
|
STORE64_RAX_into_Address_RDX_Immediate8 !16 ; HEAD->TEXT = STRING
|
||
|
COPY_RCX_to_RBX ; Protect terminator
|
||
|
COPY_RAX_to_RDX ; Protect string pointer
|
||
|
:Store_String_Loop
|
||
|
STORE8_CL_into_Address_RDX ; write byte
|
||
|
CALLI32 %fgetc ; read next char
|
||
|
ZERO_EXTEND_AL ; Zero extend it
|
||
|
COPY_RAX_to_RCX ; Update C
|
||
|
ADDI8_to_RDX !1 ; STRING = STRING + 1
|
||
|
CMP_RBX_to_RCX ; See if we hit terminator
|
||
|
JNE32 %Store_String_Loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
COPY_RDX_to_RAX ; return HEAD
|
||
|
JMP32 %restart
|
||
|
|
||
|
|
||
|
;; Store_Atom Function
|
||
|
;; Recieves C in RCX, HEAD in RDX and Input file in R15
|
||
|
;; Uses RBX for in_set strings, RCX for C and RDX for string
|
||
|
:Store_Atom
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
|
||
|
LOADI32_RAX %256 ; Malloc the string
|
||
|
CALLI32 %malloc ; Get pointer to P
|
||
|
STORE64_RAX_into_Address_RDX_Immediate8 !16 ; HEAD->TEXT = STRING
|
||
|
LOADI32_RBX &terminators ; Get pointer to "\n\t "
|
||
|
COPY_RAX_to_RDX ; Protect string pointer
|
||
|
:Store_Atom_loop
|
||
|
STORE8_CL_into_Address_RDX ; write byte
|
||
|
CALLI32 %fgetc ; read next char
|
||
|
ZERO_EXTEND_AL ; Zero extend it
|
||
|
COPY_RAX_to_RCX ; Update C
|
||
|
ADDI8_to_RDX !1 ; STRING = STRING + 1
|
||
|
CALLI32 %In_Set ; Check for terminators
|
||
|
CMP_RAX_Immediate8 !0 ; Check for "\n\t "
|
||
|
JE32 %Store_Atom_loop ; Loop otherwise
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
COPY_RDX_to_RAX ; return HEAD
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; In_Set function
|
||
|
;; Recieves Char C in RAX and CHAR* in RBX
|
||
|
;; Returns 1 if true, zero if false in RAX
|
||
|
:In_Set
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
:In_Set_loop
|
||
|
LOAD8_CL_from_Address_RBX ; Read char
|
||
|
ZERO_EXTEND_CL ; Zero extend it
|
||
|
|
||
|
CMP_RCX_to_RAX ; See if they match
|
||
|
JE32 %In_Set_True ; return true
|
||
|
|
||
|
CMP_RCX_Immediate8 !0 ; Check for NULL
|
||
|
JE32 %In_Set_False ; return false
|
||
|
|
||
|
ADDI8_to_RBX !1 ; s = s + 1
|
||
|
JMP32 %In_Set_loop ; Keep looping
|
||
|
|
||
|
:In_Set_True
|
||
|
LOADI32_RAX %1 ; Set True
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
:In_Set_False
|
||
|
LOADI32_RAX %0 ; Set FALSE
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
;; Char sets
|
||
|
:terminators
|
||
|
"
|
||
|
"
|
||
|
|
||
|
:comments
|
||
|
"#;"
|
||
|
|
||
|
:string_char
|
||
|
'22 27 00'
|
||
|
|
||
|
|
||
|
;; Reverse_List function
|
||
|
;; Recieves List in RAX
|
||
|
;; Returns the list reversed in RAX
|
||
|
:Reverse_List
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
COPY_RAX_to_RBX ; Set HEAD
|
||
|
LOADI32_RAX %0 ; ROOT = NULL
|
||
|
:Reverse_List_Loop
|
||
|
CMP_RBX_Immediate8 !0 ; WHILE HEAD != NULL
|
||
|
JE32 %Reverse_List_Done ; Stop otherwise
|
||
|
|
||
|
LOAD64_into_RCX_from_Address_RBX ; NEXT = HEAD->NEXT
|
||
|
STORE64_RAX_into_Address_RBX ; HEAD->NEXT = ROOT
|
||
|
COPY_RBX_to_RAX ; ROOT = HEAD
|
||
|
COPY_RCX_to_RBX ; HEAD = NEXT
|
||
|
JMP32 %Reverse_List_Loop ; Keep Going
|
||
|
|
||
|
:Reverse_List_Done
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Identify_Macros function
|
||
|
;; Recieves List in RAX
|
||
|
;; Updates the list in place; does not modify registers
|
||
|
;; Uses RBX for DEFINE, RCX for I
|
||
|
:Identify_Macros
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
LOADI32_RBX &DEFINE_str ; Setup define string
|
||
|
COPY_RAX_to_RCX ; I = HEAD
|
||
|
:Identify_Macros_Loop
|
||
|
LOAD64_into_RAX_from_Address_RCX_Immediate8 !16 ; I->TEXT
|
||
|
CALLI32 %match ; IF "DEFINE" == I->TEXT
|
||
|
CMP_RAX_Immediate8 !0 ; Check if match
|
||
|
JNE32 %Identify_Macros_Next ; Skip the work
|
||
|
|
||
|
;; Deal with MACRO
|
||
|
LOADI32_RAX %1 ; Using MACRO
|
||
|
STORE64_RAX_into_Address_RCX_Immediate8 !8 ; I->TYPE = MACRO
|
||
|
|
||
|
LOAD64_into_RAX_from_Address_RCX ; I->NEXT
|
||
|
LOAD64_into_RAX_from_Address_RAX_Immediate8 !16 ; I->NEXT->TEXT
|
||
|
STORE64_RAX_into_Address_RCX_Immediate8 !16 ; I->TEXT = I->NEXT->TEXT
|
||
|
|
||
|
LOAD64_into_RAX_from_Address_RCX ; I->NEXT
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT
|
||
|
LOAD64_into_RAX_from_Address_RAX_Immediate8 !16 ; I->NEXT->NEXT->TEXT
|
||
|
STORE64_RAX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = I->NEXT->NEXT->TEXT
|
||
|
|
||
|
LOAD64_into_RAX_from_Address_RCX ; I->NEXT
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I->NEXT->NEXT->NEXT
|
||
|
STORE64_RAX_into_Address_RCX ; I->NEXT = I->NEXT->NEXT->NEXT
|
||
|
|
||
|
:Identify_Macros_Next
|
||
|
LOAD64_into_RCX_from_Address_RCX ; I = I->NEXT
|
||
|
CMP_RCX_Immediate8 !0 ; Check for NULL
|
||
|
JNE32 %Identify_Macros_Loop ; Keep looping otherwise
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
:DEFINE_str
|
||
|
"DEFINE"
|
||
|
|
||
|
|
||
|
;; match function
|
||
|
;; Recieves CHAR* in RAX and CHAR* in RBX
|
||
|
;; Returns 0 (TRUE) or 1 (FALSE) in RAX
|
||
|
:match
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
COPY_RAX_to_RCX ; S1 in place
|
||
|
COPY_RBX_to_RDX ; S2 in place
|
||
|
:match_Loop
|
||
|
LOAD8_AL_from_Address_RCX ; S1[0]
|
||
|
ZERO_EXTEND_AL ; Make it useful
|
||
|
LOAD8_BL_from_Address_RDX ; S2[0]
|
||
|
ZERO_EXTEND_BL ; Make it useful
|
||
|
CMP_RBX_to_RAX ; See if they match
|
||
|
JNE32 %match_False ; If not
|
||
|
|
||
|
ADDI8_to_RCX !1 ; S1 = S1 + 1
|
||
|
ADDI8_to_RDX !1 ; S2 = S2 + 1
|
||
|
CMP_RAX_Immediate8 !0 ; If reached end of string
|
||
|
JE32 %match_Done ; Perfect match
|
||
|
JMP32 %match_Loop ; Otherwise keep looping
|
||
|
|
||
|
:match_False
|
||
|
LOADI32_RAX %1 ; Return false
|
||
|
:match_Done
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Line_Macro function
|
||
|
;; Recieves List in RAX
|
||
|
;; Updates the list in place; does not modify registers
|
||
|
;; Uses RAX for I, RBX for I->TEXT, RCX for I->EXPRESSION
|
||
|
:Line_Macro
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
:Line_Macro_Loop
|
||
|
LOAD64_into_RBX_from_Address_RAX_Immediate8 !8 ; I->TYPE
|
||
|
CMP_RBX_Immediate8 !1 ; IF MACRO == I->TYPE
|
||
|
JNE32 %Line_Macro_Next ; Otherwise move on
|
||
|
|
||
|
;; Is a macro apply
|
||
|
LOAD64_into_RBX_from_Address_RAX_Immediate8 !16 ; I->TEXT
|
||
|
LOAD64_into_RCX_from_Address_RAX_Immediate8 !24 ; I->EXPRESSION
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I->NEXT
|
||
|
CALLI32 %Set_Expression ; Apply it
|
||
|
JMP32 %Line_Macro_Loop ; Move on to next
|
||
|
|
||
|
:Line_Macro_Next
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I->NEXT
|
||
|
CMP_RAX_Immediate8 !0 ; Check for NULL
|
||
|
JNE32 %Line_Macro_Loop ; Keep going
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Set_Expression function
|
||
|
;; Recieves List in RAX, CHAR* in RBX and CHAR* in RCX
|
||
|
;; Updates the list in place; does not modify registers
|
||
|
;; Uses RBX for C, RCX for EXP and RDX for I
|
||
|
:Set_Expression
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
COPY_RAX_to_RDX ; Set I
|
||
|
:Set_Expression_Loop
|
||
|
LOAD64_into_RAX_from_Address_RDX_Immediate8 !8 ; I->TYPE
|
||
|
CMP_RAX_Immediate8 !1 ; IF MACRO == I->TYPE
|
||
|
JE32 %Set_Expression_Next ; Ignore and move on
|
||
|
|
||
|
LOAD64_into_RAX_from_Address_RDX_Immediate8 !16 ; I->TEXT
|
||
|
CALLI32 %match ; Check for match
|
||
|
CMP_RAX_Immediate8 !0 ; If match
|
||
|
JNE32 %Set_Expression_Next ; Otherwise next
|
||
|
|
||
|
;; We have a non-macro match
|
||
|
STORE64_RCX_into_Address_RDX_Immediate8 !24 ; I->EXPRESSION = EXP
|
||
|
|
||
|
:Set_Expression_Next
|
||
|
LOAD64_into_RDX_from_Address_RDX ; I = I->NEXT
|
||
|
CMP_RDX_Immediate8 !0 ; IF NULL == I
|
||
|
JNE32 %Set_Expression_Loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Process_String function
|
||
|
;; Recieves List in RAX
|
||
|
;; Update the list in place; does not modify registers
|
||
|
;; Uses RBX for I->TEXT, RCX for I and RDX for S
|
||
|
:Process_String
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
COPY_RAX_to_RCX ; I = HEAD
|
||
|
:Process_String_loop
|
||
|
LOAD64_into_RAX_from_Address_RCX_Immediate8 !8 ; I->TYPE
|
||
|
CMP_RAX_Immediate8 !2 ; IF STRING == I->TYPE
|
||
|
JNE32 %Process_String_Next ; Skip to next
|
||
|
|
||
|
LOAD64_into_RBX_from_Address_RCX_Immediate8 !16 ; I->TEXT
|
||
|
LOAD8_AL_from_Address_RBX ; I->TEXT[0]
|
||
|
ZERO_EXTEND_AL ; make it useful
|
||
|
CMP_RAX_Immediate8 !39 ; IF '\'' == I->TEXT[0]
|
||
|
JNE32 %Process_String_Raw ; Deal with "\""
|
||
|
|
||
|
;; Deal with '\''
|
||
|
ADDI8_to_RBX !1 ; I->TEXT + 1
|
||
|
STORE64_RBX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = I->TEXT + 1
|
||
|
JMP32 %Process_String_Next ; Move on to next
|
||
|
|
||
|
:Process_String_Raw
|
||
|
COPY_RBX_to_RAX ; Get length of I->TEXT
|
||
|
CALLI32 %string_length ; Do it
|
||
|
SHIFT_RIGHT_RAX_Immediate8 !2 ; LENGTH = LENGTH >> 2
|
||
|
ADDI8_to_RAX !1 ; LENGTH = LENGTH + 1
|
||
|
SHIFT_LEFT_RAX_Immediate8 !3 ; LENGTH = LENGTH << 3
|
||
|
CALLI32 %malloc ; Get string
|
||
|
COPY_RBX_to_RDX ; S = I->TEXT
|
||
|
ADDI8_to_RDX !1 ; S = S + 1
|
||
|
STORE64_RAX_into_Address_RCX_Immediate8 !24 ; I->EXPRESSION = hexify
|
||
|
COPY_RAX_to_RBX ; Put hexify buffer in rbx
|
||
|
|
||
|
:Process_String_Raw_Loop
|
||
|
LOAD8_AL_from_Address_RDX ; Read 1 chars
|
||
|
ZERO_EXTEND_AL ; Make it useful
|
||
|
ADDI8_to_RDX !1 ; S = S + 1
|
||
|
CMP_AL_Immediate8 !0 ; Check for NULL
|
||
|
PUSH_FLAGS ; Protect condition
|
||
|
CALLI32 %hex8 ; write them all
|
||
|
POP_FLAGS ; restore condition
|
||
|
JNE32 %Process_String_Raw_Loop ; Keep looping
|
||
|
|
||
|
:Process_String_Next
|
||
|
LOAD64_into_RCX_from_Address_RCX ; I = I->NEXT
|
||
|
CMP_RCX_Immediate8 !0 ; IF NULL == I
|
||
|
JNE32 %Process_String_loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; string_length function
|
||
|
;; Recieves CHAR* in RAX
|
||
|
;; Returns INT in RAX
|
||
|
;; Uses RAX for CH, RBX for S and RCX for INDEX
|
||
|
:string_length
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
COPY_RAX_to_RBX ; Set S
|
||
|
LOADI32_RCX %0 ; INDEX = 0
|
||
|
:string_length_loop
|
||
|
LOAD8_AL_from_Address_RBX_Index_RCX ; S[0]
|
||
|
ZERO_EXTEND_AL ; make it useful
|
||
|
CMP_RAX_Immediate8 !0 ; IF NULL == S[0]
|
||
|
JE32 %string_length_done ; Stop
|
||
|
|
||
|
ADDI8_to_RCX !1 ; INDEX = INDEX + 1
|
||
|
JMP32 %string_length_loop ; Keep going
|
||
|
|
||
|
:string_length_done
|
||
|
COPY_RCX_to_RAX ; RETURN INDEX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Eval_Immediates function
|
||
|
;; Recieves List in RAX
|
||
|
;; Updates the list in place; does not modify registers
|
||
|
;; Uses RBX for I->TEXT[0], RCX for I->TEXT[1] and RDX for I
|
||
|
:Eval_Immediates
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
COPY_RAX_to_RDX ; I = HEAD
|
||
|
:Eval_Immediates_Loop
|
||
|
;; Check for MACRO
|
||
|
LOAD64_into_RAX_from_Address_RDX_Immediate8 !8 ; I->TYPE
|
||
|
CMP_RAX_Immediate8 !1 ; IF MACRO == I-TYPE
|
||
|
JE32 %Eval_Immediates_Next ; Skip to next
|
||
|
|
||
|
;; Check for NULL EXPRESSION
|
||
|
LOAD64_into_RAX_from_Address_RDX_Immediate8 !24 ; I->EXPRESSION
|
||
|
CMP_RAX_Immediate8 !0 ; IF NULL == I->EXPRESSION
|
||
|
JNE32 %Eval_Immediates_Next ; Skip to next
|
||
|
|
||
|
;; Check if number
|
||
|
LOAD64_into_RAX_from_Address_RDX_Immediate8 !16 ; I->TEXT
|
||
|
LOAD8_BL_from_Address_RAX ; I->TEXT[0]
|
||
|
ZERO_EXTEND_BL ; Extend to use
|
||
|
ADDI8_to_RAX !1 ; I->TEXT + 1
|
||
|
LOAD8_CL_from_Address_RAX ; I->TEXT[1]
|
||
|
ZERO_EXTEND_CL ; Extend to use
|
||
|
CALLI32 %numerate_string ; Convert string to INT
|
||
|
CMP_RAX_Immediate8 !0 ; IF 0 == numerate_number(I->TEXT + 1)
|
||
|
JNE32 %Eval_Immediates_value ; Has a value
|
||
|
|
||
|
;; Last chance for Immediate
|
||
|
CMP_RCX_Immediate8 !48 ; If '0' == I->TEXT[1]
|
||
|
JNE32 %Eval_Immediates_Next ; Skip to next
|
||
|
|
||
|
:Eval_Immediates_value
|
||
|
CALLI32 %express_number ; Convert value to hex string
|
||
|
STORE64_RAX_into_Address_RDX_Immediate8 !24 ; I->EXPRESSION = express_number(value, I-TEXT[0])
|
||
|
|
||
|
:Eval_Immediates_Next
|
||
|
LOAD64_into_RDX_from_Address_RDX ; I = I->NEXT
|
||
|
CMP_RDX_Immediate8 !0 ; IF NULL == I
|
||
|
JNE32 %Eval_Immediates_Loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; numerate_string function
|
||
|
;; Recieves CHAR* in RAX
|
||
|
;; Returns value of CHAR* in RAX
|
||
|
;; Only supports negative decimals and Uppercase Hex (eg 5, -3 and 0xCC)
|
||
|
;; Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE?
|
||
|
:numerate_string
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
PUSH_RSI ; Protect RSI
|
||
|
COPY_RAX_to_RBX ; put S in correct place
|
||
|
LOADI32_RAX %0 ; Initialize to Zero
|
||
|
:numerate_string_loop
|
||
|
LOAD8_CL_from_Address_RBX_Immediate8 !1 ; S[1]
|
||
|
ZERO_EXTEND_CL ; make it useful
|
||
|
CMP_RCX_Immediate8 !120 ; IF 'x' == S[1]
|
||
|
JE32 %numerate_hex ; Deal with hex input
|
||
|
|
||
|
;; Assume decimal input
|
||
|
LOADI32_RSI %0 ; Assume no negation
|
||
|
LOAD8_CL_from_Address_RBX ; S[0]
|
||
|
ZERO_EXTEND_CL ; make it useful
|
||
|
CMP_RCX_Immediate8 !45 ; IF '-' == S[0]
|
||
|
JNE32 %numerate_decimal ; Skip negation
|
||
|
|
||
|
LOADI32_RSI %1 ; Set FLAG
|
||
|
ADDI8_to_RBX !1 ; S = S + 1
|
||
|
|
||
|
:numerate_decimal
|
||
|
LOAD8_CL_from_Address_RBX ; S[0]
|
||
|
ZERO_EXTEND_CL ; make it useful
|
||
|
CMP_RCX_Immediate8 !0 ; IF NULL == S[0]
|
||
|
JE32 %numerate_decimal_done ; We are done
|
||
|
|
||
|
IMUL_RAX_Immediate8 !10 ; VALUE = VALUE * 10
|
||
|
SUBI8_RCX !48 ; CH = CH - '0'
|
||
|
CMP_RCX_Immediate8 !9 ; Check for illegal
|
||
|
JG32 %numerate_string_fail ; If CH > '9'
|
||
|
CMP_RCX_Immediate8 !0 ; Check for illegal
|
||
|
JL32 %numerate_string_fail ; IF CH < 0
|
||
|
ADD_RCX_to_RAX ; VALUE = VALUE + CH
|
||
|
ADDI8_to_RBX !1 ; S = S + 1
|
||
|
JMP32 %numerate_decimal ; Keep looping
|
||
|
|
||
|
:numerate_decimal_done
|
||
|
CMP_RSI_Immediate8 !1 ; Check if need to negate
|
||
|
JNE32 %numerate_string_done ; Nope
|
||
|
|
||
|
IMUL_RAX_Immediate8 !-1 ; VALUE = VALUE * -1
|
||
|
JMP32 %numerate_string_done ; Done
|
||
|
|
||
|
:numerate_hex
|
||
|
ADDI8_to_RBX !2 ; S = S + 2
|
||
|
:numerate_hex_loop
|
||
|
LOAD8_CL_from_Address_RBX ; S[0]
|
||
|
ZERO_EXTEND_CL ; make it useful
|
||
|
CMP_RCX_Immediate8 !0 ; IF NULL == S[0]
|
||
|
JE32 %numerate_string_done ; We are done
|
||
|
|
||
|
SHIFT_LEFT_RAX_Immediate8 !4 ; VALUE = VALUE << 4
|
||
|
SUBI8_RCX !48 ; CH = CH - '0'
|
||
|
CMP_RCX_Immediate8 !10 ; IF 10 >= CH
|
||
|
JL32 %numerate_hex_digit ; NO
|
||
|
SUBI8_RCX !7 ; Push A-F into range
|
||
|
:numerate_hex_digit
|
||
|
CMP_RCX_Immediate8 !15 ; Check for illegal
|
||
|
JG32 %numerate_string_fail ; If CH > 'F'
|
||
|
CMP_RCX_Immediate8 !0 ; Check for illegal
|
||
|
JL32 %numerate_string_fail ; IF CH < 0
|
||
|
ADD_RCX_to_RAX ; VALUE = VALUE + CH
|
||
|
ADDI8_to_RBX !1 ; S = S + 1
|
||
|
JMP32 %numerate_hex_loop ; Keep looping
|
||
|
|
||
|
:numerate_string_fail
|
||
|
LOADI32_RAX %0 ; return ZERO
|
||
|
|
||
|
:numerate_string_done
|
||
|
POP_RSI ; Restore RSI
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; express_number function
|
||
|
;; Recieves INT in RAX and CHAR in RBX
|
||
|
;; Allocates a string and expresses the value in hex
|
||
|
;; Returns string in RAX
|
||
|
;; Uses RAX for VALUE, RBX for S and RCX for CH
|
||
|
:express_number
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
COPY_RBX_to_RCX ; Put CH in right place
|
||
|
COPY_RAX_to_RBX ; Protect VALUE
|
||
|
CMP_RCX_Immediate8 !37 ; IF '%' == CH
|
||
|
JNE32 %express_number2 ; Otherwise try @
|
||
|
|
||
|
LOADI32_RAX %9 ; We need 3bytes
|
||
|
CALLI32 %malloc ; Get S pointer
|
||
|
SWAP_RAX_RBX ; Put S and VALUE in place
|
||
|
PUSH_RBX ; Protect S
|
||
|
CALLI32 %hex32l ; Store 32bits
|
||
|
JMP32 %express_number_done ; done
|
||
|
|
||
|
:express_number2
|
||
|
CMP_RCX_Immediate8 !64 ; IF '@' == CH
|
||
|
JNE32 %express_number1 ; Othrewise try !
|
||
|
|
||
|
LOADI32_RAX %5 ; We need 3bytes
|
||
|
CALLI32 %malloc ; Get S pointer
|
||
|
SWAP_RAX_RBX ; Put S and VALUE in place
|
||
|
PUSH_RBX ; Protect S
|
||
|
CALLI32 %hex16l ; Store 16bits
|
||
|
JMP32 %express_number_done ; done
|
||
|
|
||
|
:express_number1
|
||
|
LOADI32_RAX %3 ; We need 3bytes
|
||
|
CALLI32 %malloc ; Get S pointer
|
||
|
SWAP_RAX_RBX ; Put S and VALUE in place
|
||
|
PUSH_RBX ; Protect S
|
||
|
CALLI32 %hex8 ; Store 8bit
|
||
|
|
||
|
:express_number_done
|
||
|
POP_RAX ; Restore S
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; HEX to ascii routine
|
||
|
;; Recieves INT in RAX and CHAR* in RBX
|
||
|
;; Stores ascii of INT in CHAR*
|
||
|
;; Returns only modifying RAX
|
||
|
:hex64l
|
||
|
PUSH_RAX ; Protect top 32
|
||
|
CALLI32 %hex32l ; Store it
|
||
|
POP_RAX ; do top 32
|
||
|
SHIFT_RIGHT_RAX_Immediate8 !32 ; do bottom 32 first
|
||
|
:hex32l
|
||
|
PUSH_RAX ; Protect top 16
|
||
|
CALLI32 %hex16l ; Store it
|
||
|
POP_RAX ; do top 16
|
||
|
SHIFT_RIGHT_RAX_Immediate8 !16 ; do bottom 16 first
|
||
|
:hex16l
|
||
|
PUSH_RAX ; Protect top byte
|
||
|
CALLI32 %hex8 ; Store it
|
||
|
POP_RAX ; do high byte
|
||
|
SHIFT_RIGHT_RAX_Immediate8 !8 ; do bottom byte first
|
||
|
:hex8
|
||
|
PUSH_RAX ; Protect bottom nibble
|
||
|
SHIFT_RIGHT_RAX_Immediate8 !4 ; do high nibble first
|
||
|
CALLI32 %hex4 ; Store it
|
||
|
POP_RAX ; do low nibble
|
||
|
:hex4
|
||
|
AND_RAX_Immediate8 !0xF ; isolate nibble
|
||
|
ADDI8_to_AL !48 ; convert to ascii
|
||
|
CMP_AL_Immediate8 !57 ; valid digit?
|
||
|
JBE8 !hex1 ; yes
|
||
|
ADDI8_to_AL !7 ; use alpha range
|
||
|
:hex1
|
||
|
STORE8_AL_into_Address_RBX ; store result
|
||
|
ADDI8_to_RBX !1 ; next position
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Preserve_Other function
|
||
|
;; Recieves List in RAX
|
||
|
;; Updates the list in place; does not modify registers
|
||
|
;; Uses RAX for I, RBX for I->TEXT
|
||
|
:Preserve_Other
|
||
|
PUSH_RAX ; Protect RAX
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
:Preserve_Other_Loop
|
||
|
LOAD64_into_RBX_from_Address_RAX_Immediate8 !24 ; I->EXPRESSION
|
||
|
CMP_RBX_Immediate8 !0 ; IF NULL == I->EXPRESSION
|
||
|
JNE32 %Preserve_Other_Next ; Otherwise next
|
||
|
|
||
|
;; Needs preserving
|
||
|
LOAD64_into_RBX_from_Address_RAX_Immediate8 !16 ; I->TEXT
|
||
|
STORE64_RBX_into_Address_RAX_Immediate8 !24 ; I->EXPRESSION = I->TEXT
|
||
|
|
||
|
:Preserve_Other_Next
|
||
|
LOAD64_into_RAX_from_Address_RAX ; I = I->NEXT
|
||
|
CMP_RAX_Immediate8 !0 ; IF NULL == I
|
||
|
JNE32 %Preserve_Other_Loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
POP_RAX ; Restore RAX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; Print_Hex function
|
||
|
;; Recieves list in RAX
|
||
|
;; walks the list and prints the I->EXPRESSION for all nodes followed by newline
|
||
|
;; Uses RBX for I
|
||
|
:Print_Hex
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
COPY_R13_to_RBX ; I = Head
|
||
|
:Print_Hex_Loop
|
||
|
LOAD64_into_RAX_from_Address_RBX_Immediate8 !8 ; I->TYPE
|
||
|
CMP_RAX_Immediate8 !1 ; IF MACRO == I->TYPE
|
||
|
JE32 %Print_Hex_Next ; Skip
|
||
|
|
||
|
LOAD64_into_RAX_from_Address_RBX_Immediate8 !24 ; Using EXPRESSION
|
||
|
CALLI32 %File_Print ; Print it
|
||
|
LOADI32_RAX %10 ; NEWLINE
|
||
|
CALLI32 %fputc ; Append it
|
||
|
|
||
|
:Print_Hex_Next
|
||
|
LOAD64_into_RBX_from_Address_RBX ; Iterate to next Token
|
||
|
CMP_RBX_Immediate8 !0 ; Check for NULL
|
||
|
JNE32 %Print_Hex_Loop ; Otherwise keep looping
|
||
|
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; File_Print function
|
||
|
;; Recieves CHAR* in RAX
|
||
|
;; calls fputc for every non-null char
|
||
|
:File_Print
|
||
|
PUSH_RBX ; Protect RBX
|
||
|
PUSH_RCX ; Protect RCX
|
||
|
COPY_RAX_to_RBX ; Protect S
|
||
|
CMP_RAX_Immediate8 !0 ; Protect against nulls
|
||
|
JE32 %File_Print_Done ; Simply don't try to print them
|
||
|
:File_Print_Loop
|
||
|
LOAD8_AL_from_Address_RBX ; Read byte
|
||
|
ZERO_EXTEND_AL ; zero extend
|
||
|
CMP_RAX_Immediate8 !0 ; Check for NULL
|
||
|
JE32 %File_Print_Done ; Stop at NULL
|
||
|
|
||
|
CALLI32 %fputc ; write it
|
||
|
ADDI8_to_RBX !1 ; S = S + 1
|
||
|
JMP32 %File_Print_Loop ; Keep going
|
||
|
|
||
|
:File_Print_Done
|
||
|
POP_RCX ; Restore RCX
|
||
|
POP_RBX ; Restore RBX
|
||
|
RET
|
||
|
|
||
|
|
||
|
;; fputc function
|
||
|
;; recieves CHAR in RAX and FILE* in R14
|
||
|
;; writes char and returns
|
||
|
:fputc
|
||
|
PUSH_RAX ; We are writing rax
|
||
|
LEA_RSI ; Get stack address
|
||
|
COPY_R14_to_RDI ; Write to target file
|
||
|
LOADI32_RAX %1 ; the syscall number for write
|
||
|
PUSH_RDX ; Protect RDX
|
||
|
LOADI32_RDX %1 ; set the size of chars we want
|
||
|
PUSH_R11 ; Protect HEAD
|
||
|
SYSCALL ; call the Kernel
|
||
|
POP_R11 ; Restore HEAD
|
||
|
POP_RDX ; Restore RDX
|
||
|
POP_RAX ; Restore stack
|
||
|
RET
|
||
|
|
||
|
:ELF_end
|