2019-06-23 22:52:38 +01:00
|
|
|
;; Copyright (C) 2017 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_EAX 83C0
|
|
|
|
DEFINE ADDI8_EBX 83C3
|
|
|
|
DEFINE ADDI8_ECX 83C1
|
|
|
|
DEFINE ADDI8_EDX 83C2
|
|
|
|
DEFINE ADDI8_ESI 83C6
|
|
|
|
DEFINE ADD_eax_into_ebx 01C3
|
|
|
|
DEFINE ADD_ebx_into_eax 01D8
|
|
|
|
DEFINE ADD_ecx_into_eax 01C8
|
|
|
|
DEFINE ADD_edi_into_ecx 01F9
|
|
|
|
DEFINE AND_EAX_EBX 21D8
|
|
|
|
DEFINE ANDI32_EAX 25
|
|
|
|
DEFINE CALL_EAX FFD0
|
|
|
|
DEFINE CALL32 E8
|
|
|
|
DEFINE CMPI8_EAX 83F8
|
|
|
|
DEFINE CMPI8_EBP 83fd
|
|
|
|
DEFINE CMPI8_EBX 83FB
|
|
|
|
DEFINE CMPI8_ECX 83F9
|
|
|
|
DEFINE CMPI8_EDX 83FA
|
|
|
|
DEFINE CMPI8_ESI 83FE
|
|
|
|
DEFINE CMP_EAX_EBX 39D8
|
|
|
|
DEFINE CMP_EAX_ECX 39C8
|
|
|
|
DEFINE CMP_EBX_ECX 39D9
|
|
|
|
DEFINE CMP_ECX_EBX 39CB
|
|
|
|
DEFINE CMP_EDI_ESI 39FE
|
|
|
|
DEFINE CMP_EBX_EDX 39D3
|
|
|
|
DEFINE COPY_EAX_to_EBP 89C5
|
|
|
|
DEFINE COPY_EAX_to_EBX 89C3
|
|
|
|
DEFINE COPY_EAX_to_ECX 89C1
|
|
|
|
DEFINE COPY_EAX_to_EDX 89C2
|
|
|
|
DEFINE COPY_EAX_to_ESI 89C6
|
|
|
|
DEFINE COPY_EBP_to_EAX 89E8
|
|
|
|
DEFINE COPY_EBX_to_EAX 89D8
|
|
|
|
DEFINE COPY_EBX_to_ECX 89D9
|
|
|
|
DEFINE COPY_EBX_to_EDX 89DA
|
|
|
|
DEFINE COPY_ECX_to_EAX 89C8
|
|
|
|
DEFINE COPY_ECX_to_EBX 89CB
|
|
|
|
DEFINE COPY_EDI_to_ESI 89FE
|
|
|
|
DEFINE COPY_EDX_to_EAX 89D0
|
|
|
|
DEFINE COPY_EDX_to_EBP 89D5
|
|
|
|
DEFINE COPY_EDX_to_EBX 89D3
|
|
|
|
DEFINE COPY_ESI_to_EAX 89F0
|
|
|
|
DEFINE COPY_ESI_to_EDI 89F7
|
|
|
|
DEFINE IDIV_EBX F7FB
|
|
|
|
DEFINE IMUL_EAX_by_EBX 0FAFC3
|
|
|
|
DEFINE IMULI8_EAX 6BC0
|
|
|
|
DEFINE IMULI8_EBP 6BED
|
|
|
|
DEFINE INT_80 CD80
|
|
|
|
DEFINE JBE8 76
|
|
|
|
DEFINE JE32 0F84
|
|
|
|
DEFINE JG32 0F8F
|
|
|
|
DEFINE JG8 7F
|
|
|
|
DEFINE JL32 0F8C
|
|
|
|
DEFINE JLE32 0F8E
|
|
|
|
DEFINE JMP32 E9
|
|
|
|
DEFINE JNE32 0F85
|
|
|
|
DEFINE LEA32_ECX_from_esp 8D0C24
|
|
|
|
DEFINE LOAD32_Absolute32_eax A1
|
|
|
|
DEFINE LOAD32_Absolute32_ebx 8B1D
|
|
|
|
DEFINE LOAD32_Absolute32_ecx 8B0D
|
|
|
|
DEFINE LOAD32_EAX_from_EAX 8B00
|
|
|
|
DEFINE LOAD32_EAX_from_EAX_Immediate8 8B40
|
|
|
|
DEFINE LOAD32_EAX_from_EBP_Immediate8 8B45
|
|
|
|
DEFINE LOAD32_EAX_from_EBX 8B03
|
|
|
|
DEFINE LOAD32_EAX_from_EBX_Immediate8 8B43
|
|
|
|
DEFINE LOAD32_EAX_from_ECX_Immediate8 8B41
|
|
|
|
DEFINE LOAD32_EAX_from_EDX_Immediate8 8B42
|
|
|
|
DEFINE LOAD32_EBP_from_EBP 8B6D00
|
|
|
|
DEFINE LOAD32_EBX_from_EAX_Immediate8 8B58
|
|
|
|
DEFINE LOAD32_EBX_from_EBX 8B1B
|
|
|
|
DEFINE LOAD32_EBX_from_EBX_Immediate8 8B5B
|
|
|
|
DEFINE LOAD32_EBX_from_ECX_Immediate8 8B59
|
|
|
|
DEFINE LOAD32_ECX_from_EAX_Immediate8 8B48
|
|
|
|
DEFINE LOAD32_ECX_from_EBX 8B0B
|
|
|
|
DEFINE LOAD32_ECX_from_ECX 8B09
|
|
|
|
DEFINE LOAD32_ECX_from_ECX_Immediate8 8B49
|
|
|
|
DEFINE LOAD32_ECX_from_EDX_Immediate8 8B4A
|
|
|
|
DEFINE LOAD32_EDI_from_EDX_Immediate8 8B7A
|
|
|
|
DEFINE LOAD32_EDX_from_EDX_Immediate8 8B52
|
|
|
|
DEFINE LOAD8_al_from_EAX 8A00
|
|
|
|
DEFINE LOAD8_al_from_EBX 8A03
|
|
|
|
DEFINE LOAD8_al_from_ECX 8A01
|
|
|
|
DEFINE LOAD8_al_from_EDX 8A02
|
|
|
|
DEFINE LOAD8_bl_from_EBX 8A1B
|
|
|
|
DEFINE LOAD8_bl_from_ECX 8A19
|
|
|
|
DEFINE LOAD8_bl_from_EDX 8A1A
|
|
|
|
DEFINE LOAD8_cl_from_EBX 8A0B
|
|
|
|
DEFINE LOAD8_cl_from_EBX_Immediate8 8A4B
|
|
|
|
DEFINE LOADI32_EAX B8
|
|
|
|
DEFINE LOADI32_EBX BB
|
|
|
|
DEFINE LOADI32_ECX B9
|
|
|
|
DEFINE LOADI32_EDI BF
|
|
|
|
DEFINE LOADI32_EDX BA
|
|
|
|
DEFINE LOADI32_ESI BE
|
|
|
|
DEFINE MOVZX_al 0FB6C0
|
|
|
|
DEFINE MOVZX_bl 0FB6DB
|
|
|
|
DEFINE MOVZX_cl 0FB6C9
|
|
|
|
DEFINE NULL 00000000
|
|
|
|
DEFINE POP_EAX 58
|
|
|
|
DEFINE POP_EBP 5D
|
|
|
|
DEFINE POP_EBX 5B
|
|
|
|
DEFINE POP_ECX 59
|
|
|
|
DEFINE POP_EDI 5F
|
|
|
|
DEFINE POP_EDX 5A
|
|
|
|
DEFINE POP_ESI 5E
|
|
|
|
DEFINE PUSH_EAX 50
|
|
|
|
DEFINE PUSH_EBP 55
|
|
|
|
DEFINE PUSH_EBX 53
|
|
|
|
DEFINE PUSH_ECX 51
|
|
|
|
DEFINE PUSH_EDI 57
|
|
|
|
DEFINE PUSH_EDX 52
|
|
|
|
DEFINE PUSH_ESI 56
|
|
|
|
DEFINE RETURN C3
|
|
|
|
DEFINE SALI8_EAX C1E0
|
|
|
|
DEFINE SHRI8_EAX C1E8
|
|
|
|
DEFINE SHRI8_EBX C1EB
|
|
|
|
DEFINE STORE32_Absolute32_eax A3
|
|
|
|
DEFINE STORE32_Absolute32_ebx 891D
|
|
|
|
DEFINE STORE32_Absolute32_ecx 890D
|
|
|
|
DEFINE STORE32_Absolute32_edx 8915
|
|
|
|
DEFINE STORE32_EAX_into_EBP_Immediate8 8945
|
|
|
|
DEFINE STORE32_EAX_into_EBX 8903
|
|
|
|
DEFINE STORE32_EAX_into_ECX_Immediate8 8941
|
|
|
|
DEFINE STORE32_EAX_into_EDX 8902
|
|
|
|
DEFINE STORE32_EAX_into_EDX_Immediate8 8942
|
|
|
|
DEFINE STORE32_EBP_into_EDX_Immediate8 896A
|
|
|
|
DEFINE STORE32_EBX_into_EAX 8918
|
|
|
|
DEFINE STORE32_EBX_into_EAX_Immediate8 8958
|
|
|
|
DEFINE STORE32_EBX_into_EDX_Immediate8 895A
|
|
|
|
DEFINE STORE32_ECX_into_EAX 8908
|
|
|
|
DEFINE STORE32_ECX_into_EAX_Immediate8 8948
|
|
|
|
DEFINE STORE32_ECX_into_EDX_Immediate8 894A
|
|
|
|
DEFINE STORE32_EDX_into_EAX_Immediate8 8950
|
|
|
|
DEFINE STORE32_EDX_into_EBP_Immediate8 8955
|
|
|
|
DEFINE STORE32_ESI_into_EBP_Immedate8 8975
|
|
|
|
DEFINE STORE32_ESI_into_EDX_Immedate8 8972
|
|
|
|
DEFINE STORE8_al_into_Address_EBX 8803
|
|
|
|
DEFINE STORE8_al_into_Address_ECX 8801
|
|
|
|
DEFINE STORE8_al_into_Address_ESI 8806
|
|
|
|
DEFINE STORE8_bl_into_Address_ECX 8819
|
|
|
|
DEFINE SUBI8_EAX 83E8
|
|
|
|
DEFINE SUBI8_ECX 83E9
|
|
|
|
DEFINE SUBI8_ESI 83EE
|
|
|
|
DEFINE SWAP_EAX_EBX 93
|
|
|
|
|
|
|
|
|
|
|
|
;; Register usage:
|
|
|
|
;; EAX => Temps
|
|
|
|
|
|
|
|
;; Struct TYPE format: (size 28)
|
|
|
|
;; NEXT => 0
|
|
|
|
;; SIZE => 4
|
|
|
|
;; OFFSET => 8
|
|
|
|
;; INDIRECT => 12
|
|
|
|
;; MEMBERS => 16
|
|
|
|
;; TYPE => 20
|
|
|
|
;; NAME => 24
|
|
|
|
|
|
|
|
;; Struct TOKEN_LIST format: (size 20)
|
|
|
|
;; NEXT => 0
|
|
|
|
;; LOCALS/PREV => 4
|
|
|
|
;; S => 8
|
|
|
|
;; TYPE => 12
|
|
|
|
;; ARGS/DEPTH => 16
|
|
|
|
|
|
|
|
; Where the ELF Header is going to hit
|
|
|
|
; Simply jump to _start
|
|
|
|
; Our main function
|
|
|
|
:_start
|
|
|
|
POP_EAX ;·Get·the·number·of·arguments
|
|
|
|
POP_EBX ;·Get·the·program·name
|
|
|
|
POP_EBX ;·Get·the·actual·input name
|
|
|
|
LOADI32_ECX %0 ;·prepare·read_only
|
|
|
|
LOADI32_EAX %5 ;·the·syscall·number·for·open()
|
|
|
|
INT_80 ; Now open that damn file
|
|
|
|
STORE32_Absolute32_eax &Input_file ; Preserve the file pointer we were given
|
|
|
|
|
|
|
|
POP_EBX ;·Get·the·actual·output name
|
|
|
|
LOADI32_ECX %577 ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC
|
|
|
|
LOADI32_EDX %384 ; Prepare file as RW for owner only (600 in octal)
|
|
|
|
LOADI32_EAX %5 ;·the·syscall·number·for·open()
|
|
|
|
INT_80 ; Now open that damn file
|
|
|
|
CMPI8_EAX !0 ; Check for missing output
|
|
|
|
JG32 %_start_out ; Have real input
|
|
|
|
LOADI32_EAX %1 ; Use stdout
|
|
|
|
|
|
|
|
:_start_out
|
|
|
|
STORE32_Absolute32_eax &Output_file ; Preserve the file pointer we were given
|
|
|
|
|
|
|
|
LOADI32_EAX %45 ; the Syscall # for SYS_BRK
|
|
|
|
LOADI32_EBX %0 ; Get current brk
|
|
|
|
INT_80 ; Let the kernel do the work
|
|
|
|
STORE32_Absolute32_eax &MALLOC ; Set our malloc pointer
|
|
|
|
LOADI32_EAX %0 ; HEAD = NULL
|
|
|
|
CALL32 %read_all_tokens ; Read all tokens
|
|
|
|
CALL32 %Reverse_List ; Reverse order
|
|
|
|
; CALL32 %debug_list ; Try to figure out what is wrong
|
|
|
|
STORE32_Absolute32_eax &global_token ; Set global_token
|
|
|
|
CALL32 %program ; Convert into program
|
|
|
|
LOADI32_EAX &header_string1 ; Our header string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_Absolute32_eax &output_list ; Our output_list
|
|
|
|
CALL32 %recursive_output ; Print core program
|
|
|
|
; LOADI32_EAX &header_string2 ; Our Enable debug
|
|
|
|
; CALL32 %File_Print ; Print it
|
|
|
|
LOADI32_EAX &header_string3 ; Our second label
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_Absolute32_eax &globals_list ; Our globals
|
|
|
|
CALL32 %recursive_output ; Get them
|
|
|
|
LOADI32_EAX &header_string4 ; Our final header
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_Absolute32_eax &strings_list ; Our strings
|
|
|
|
CALL32 %recursive_output ; Get them
|
|
|
|
LOADI32_EAX &header_string5 ; Make this a bare assembly
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
:Done
|
|
|
|
; program completed Successfully
|
|
|
|
LOADI32_EBX %0 ; All is well
|
|
|
|
LOADI32_EAX %1 ; put the exit syscall number in eax
|
|
|
|
INT_80 ; Call it a good day
|
|
|
|
|
|
|
|
:header_string1 "
|
|
|
|
# Core program
|
|
|
|
"
|
|
|
|
:header_string2 "
|
|
|
|
:ELF_data
|
|
|
|
"
|
|
|
|
:header_string3 "
|
|
|
|
# Program global variables
|
|
|
|
"
|
|
|
|
:header_string4 "
|
|
|
|
# Program strings
|
|
|
|
"
|
|
|
|
:header_string5 "
|
|
|
|
:ELF_end
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; read_all_tokens function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Token_List* in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Tokenizes all input and returns updated list in EAX
|
|
|
|
;; Returns TOKEN in EAX
|
|
|
|
;; Uses EAX for C
|
|
|
|
:read_all_tokens
|
|
|
|
STORE32_Absolute32_eax &Token
|
|
|
|
CALL32 %fgetc
|
|
|
|
:read_all_tokens_loop
|
|
|
|
CMPI8_EAX !-4 ; Check for EOF
|
|
|
|
JE32 %read_all_tokens_done ; Stop if found
|
|
|
|
CALL32 %get_token ; Read all tokens
|
|
|
|
JMP32 %read_all_tokens_loop ; Loop
|
|
|
|
:read_all_tokens_done
|
|
|
|
LOAD32_Absolute32_eax &Token
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; get_token function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Makes a list of TOKEN_LIST
|
|
|
|
;; C and STRING_INDEX are stored in memory, ECX is used for S and EDX is used for current
|
|
|
|
;; Returns C in EAX
|
|
|
|
:get_token
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
|
|
|
|
LOADI32_EAX %20 ; Malloc CURRENT
|
|
|
|
CALL32 %malloc ; Get Pointer
|
|
|
|
COPY_EAX_to_EDX ; Set CURRENT
|
|
|
|
|
|
|
|
LOADI32_EAX %256 ; Malloc the string
|
|
|
|
CALL32 %malloc ; Get pointer to S
|
|
|
|
COPY_EAX_to_ECX ; Set S
|
|
|
|
STORE32_ECX_into_EDX_Immediate8 !8 ; CURRENT->S = S
|
|
|
|
:reset
|
|
|
|
STORE32_Absolute32_ecx &string_index ; S[0]
|
|
|
|
LOAD32_Absolute32_eax &C ; Using C
|
|
|
|
|
|
|
|
CALL32 %clear_white_space ; Clear WhiteSpace
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
|
|
|
|
CMPI8_EAX !-4 ; Check for EOF
|
|
|
|
JE32 %get_token_abort ; if EOF abort
|
|
|
|
|
|
|
|
CMPI8_EAX !35 ; Check for '#'
|
|
|
|
JNE32 %get_token_alpha ; Nope
|
|
|
|
|
|
|
|
;; Deal with # line comments
|
|
|
|
CALL32 %purge_macro ; Let it handle it
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %reset ; Try again
|
|
|
|
|
|
|
|
:get_token_alpha
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
LOADI32_EBX &alphas ; Get alphanumerics
|
|
|
|
CALL32 %In_Set ; See if in set
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %get_token_symbol ; Otherwise
|
|
|
|
|
|
|
|
;; Store keywords
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
CALL32 %preserve_keyword ; Store
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %get_token_done ; Be done with this token
|
|
|
|
|
|
|
|
:get_token_symbol
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
LOADI32_EBX &symbols ; Get symbols
|
|
|
|
CALL32 %In_Set ; See if in set
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %get_token_strings ; Otherwise
|
|
|
|
|
|
|
|
;; Store symbols
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
CALL32 %preserve_symbol ; Store
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %get_token_done ; Be done with this token
|
|
|
|
|
|
|
|
:get_token_strings
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
LOADI32_EBX &strings ; Get symbols
|
|
|
|
CALL32 %In_Set ; See if in set
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %get_token_comment ; Otherwise
|
|
|
|
|
|
|
|
;; Store String
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
CALL32 %consume_word ; Store
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %get_token_done ; Be done with this token
|
|
|
|
|
|
|
|
:get_token_comment
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
CMPI8_EAX !47 ; IF '/' == C
|
|
|
|
JNE32 %get_token_else ; Otherwise
|
|
|
|
|
|
|
|
CALL32 %consume_byte ; Hope it just is '/'
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
|
|
|
|
CMPI8_EAX !42 ; IF '*' we have '/*'
|
|
|
|
JNE32 %get_token_comment_line ; Check for '//'
|
|
|
|
|
|
|
|
;; Deal with /* block comments */
|
|
|
|
CALL32 %fgetc ; get next C
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
:get_token_comment_block_outer
|
|
|
|
LOAD32_Absolute32_eax &C ; Using C
|
|
|
|
CMPI8_EAX !47 ; IF '/' != C
|
|
|
|
JE32 %get_token_comment_block_done ; be done
|
|
|
|
|
|
|
|
:get_token_comment_block_inner
|
|
|
|
LOAD32_Absolute32_eax &C ; Using C
|
|
|
|
CMPI8_EAX !42 ; IF '*' != C
|
|
|
|
JE32 %get_token_comment_block_iter ; jump over
|
|
|
|
|
|
|
|
;; Deal with inner loop
|
|
|
|
CALL32 %fgetc ; get next C
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %get_token_comment_block_inner ; keep going
|
|
|
|
|
|
|
|
:get_token_comment_block_iter
|
|
|
|
CALL32 %fgetc ; get next C
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %get_token_comment_block_outer
|
|
|
|
|
|
|
|
:get_token_comment_block_done
|
|
|
|
CALL32 %fgetc ; get next C
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %reset ; throw away, try again
|
|
|
|
|
|
|
|
:get_token_comment_line
|
|
|
|
CMPI8_EAX !47 ; IF '/' we have //
|
|
|
|
JNE32 %get_token_done ; keep if just '/'
|
|
|
|
|
|
|
|
;; Deal with // line comment
|
|
|
|
CALL32 %fgetc ; drop to match
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
JMP32 %reset ; throw away, try again
|
|
|
|
|
|
|
|
:get_token_else
|
|
|
|
LOAD32_Absolute32_eax &C ; Send C
|
|
|
|
CALL32 %consume_byte
|
|
|
|
STORE32_Absolute32_eax &C ; Set C
|
|
|
|
|
|
|
|
:get_token_done
|
|
|
|
LOAD32_Absolute32_eax &Token ; TOKEN
|
|
|
|
STORE32_EAX_into_EDX_Immediate8 !4 ; CURRENT->PREV = TOKEN
|
|
|
|
STORE32_EAX_into_EDX ; CURRENT->NEXT = TOKEN
|
|
|
|
STORE32_Absolute32_edx &Token ; TOKEN = CURRENT
|
|
|
|
|
|
|
|
:get_token_abort
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
LOAD32_Absolute32_eax &C ; Return C
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; 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 [MALLOC] to be initialized and EAX to have the number of desired bytes
|
|
|
|
:malloc
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
LOAD32_Absolute32_ebx &MALLOC ; Using the current pointer
|
|
|
|
ADD_eax_into_ebx ; Request the number of desired bytes
|
|
|
|
LOADI32_EAX %45 ; the Syscall # for SYS_BRK
|
|
|
|
INT_80 ; call the Kernel
|
|
|
|
LOAD32_Absolute32_eax &MALLOC ; Return pointer
|
|
|
|
STORE32_Absolute32_ebx &MALLOC ; Update pointer
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; clear_white_space function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT C in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns first non-whitespace char in EAX
|
|
|
|
:clear_white_space
|
|
|
|
CMPI8_EAX !32 ; Check for ' '
|
|
|
|
JE32 %clear_white_space_wipe ; wipe it out
|
|
|
|
|
|
|
|
CMPI8_EAX !10 ; Check for '\n'
|
|
|
|
JE32 %clear_white_space_wipe ; wipe it output
|
|
|
|
|
|
|
|
CMPI8_EAX !9 ; Check for '\t'
|
|
|
|
JNE32 %clear_white_space_done ; looks like non-whitespace
|
|
|
|
|
|
|
|
:clear_white_space_wipe
|
|
|
|
CALL32 %fgetc ; Read a new byte
|
|
|
|
CMPI8_EAX !-4 ; Check for EOF
|
|
|
|
JE32 %clear_white_space_done ; Short circuit
|
|
|
|
JMP32 %clear_white_space ; iterate
|
|
|
|
|
|
|
|
:clear_white_space_done
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; In_Set function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Char C in EAX and CHAR* in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns 1 if true, zero if false in EAX
|
|
|
|
:In_Set
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
:In_Set_loop
|
|
|
|
LOAD8_cl_from_EBX ; Read char
|
|
|
|
MOVZX_cl ; Zero extend it
|
|
|
|
|
|
|
|
CMP_EAX_ECX ; See if they match
|
|
|
|
JE32 %In_Set_True ; return true
|
|
|
|
|
|
|
|
CMPI8_ECX !0 ; Check for NULL
|
|
|
|
JE32 %In_Set_False ; return false
|
|
|
|
|
|
|
|
ADDI8_EBX !1 ; s = s + 1
|
|
|
|
JMP32 %In_Set_loop ; Keep looping
|
|
|
|
|
|
|
|
:In_Set_True
|
|
|
|
LOADI32_EAX %1 ; Set True
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:In_Set_False
|
|
|
|
LOADI32_EAX %0 ; Set FALSE
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:alphas "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
|
|
|
|
:symbols "<=>|&!-"
|
|
|
|
:strings '22 27 00'
|
|
|
|
|
|
|
|
|
|
|
|
;; purge_macro function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives CH in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Reads chars until Line feed is read
|
|
|
|
;; returns line feed
|
|
|
|
:purge_macro
|
|
|
|
CALL32 %fgetc ; read next char
|
|
|
|
CMPI8_EAX !10 ; Check for '\n'
|
|
|
|
JNE32 %purge_macro ; Keep going
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; preserve_keyword function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT C in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; collects all chars in keyword
|
|
|
|
;; Returns C in EAX
|
|
|
|
;; Uses ECX for INT C
|
|
|
|
:preserve_keyword
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; Setup C
|
|
|
|
LOADI32_EBX &alphas ; Concerning ourselves with "abc.."
|
|
|
|
:preserve_keyword_loop
|
|
|
|
CALL32 %In_Set ; Check if alphanumerics
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %preserve_keyword_label ; Otherwise check for label
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Pass C
|
|
|
|
CALL32 %consume_byte ; consume that byte
|
|
|
|
COPY_EAX_to_ECX ; Update C
|
|
|
|
JMP32 %preserve_keyword_loop ; keep looping
|
|
|
|
|
|
|
|
:preserve_keyword_label
|
|
|
|
COPY_ECX_to_EAX ; Fix return
|
|
|
|
CMPI8_EAX !58 ; Check for ':'
|
|
|
|
JNE32 %preserve_keyword_done ; be done
|
|
|
|
|
|
|
|
;; Fix our goto label
|
|
|
|
CALL32 %fixup_label ; Fix the label
|
|
|
|
LOADI32_EAX %32 ; Return Whitespace
|
|
|
|
|
|
|
|
:preserve_keyword_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; preserve_symbol function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT C in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; collects all chars in symbol
|
|
|
|
;; Returns C in EAX
|
|
|
|
;; Uses ECX for INT C
|
|
|
|
:preserve_symbol
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; Setup C
|
|
|
|
LOADI32_EBX &symbols ; Concerning ourselves with "<=>.."
|
|
|
|
:preserve_symbol_loop
|
|
|
|
CALL32 %In_Set ; Check if alphanumerics
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %preserve_symbol_done ; Otherwise be done
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Pass C
|
|
|
|
CALL32 %consume_byte ; consume that byte
|
|
|
|
COPY_EAX_to_ECX ; Update C
|
|
|
|
JMP32 %preserve_symbol_loop ; keep looping
|
|
|
|
|
|
|
|
:preserve_symbol_done
|
|
|
|
COPY_ECX_to_EAX ; Fix return
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; consume_word function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; receives INT C in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; returns INT C in EAX
|
|
|
|
;; Uses EAX for C, EBX for FREQ and ECX for ESCAPE
|
|
|
|
:consume_word
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_EBX ; FREQ = C
|
|
|
|
LOADI32_ECX %0 ; ESCAPE = FALSE
|
|
|
|
:consume_word_loop
|
|
|
|
CMPI8_ECX !0 ; IF !ESCAPE
|
|
|
|
JNE32 %consume_word_escape ; Enable escape
|
|
|
|
|
|
|
|
CMPI8_EAX !92 ; if '\\'
|
|
|
|
JNE32 %consume_word_iter ; keep state
|
|
|
|
|
|
|
|
LOADI32_ECX %1 ; ESCAPE = TRUE
|
|
|
|
JMP32 %consume_word_iter ; keep going
|
|
|
|
|
|
|
|
:consume_word_escape
|
|
|
|
LOADI32_ECX %0 ; ESCAPE = FALSE
|
|
|
|
|
|
|
|
:consume_word_iter
|
|
|
|
CALL32 %consume_byte ; read next char
|
|
|
|
|
|
|
|
CMPI8_ECX !0 ; IF ESCAPE
|
|
|
|
JNE32 %consume_word_loop ; keep looping
|
|
|
|
|
|
|
|
CMP_EAX_EBX ; IF C != FREQ
|
|
|
|
JNE32 %consume_word_loop ; keep going
|
|
|
|
|
|
|
|
CALL32 %fgetc ; return next char
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; consume_byte function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT C in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Inserts C into string S, updates String S
|
|
|
|
;; Returns Next char in EAX
|
|
|
|
:consume_byte
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
LOAD32_Absolute32_ebx &string_index ; S[0]
|
|
|
|
STORE8_al_into_Address_EBX ; S[0] = C
|
|
|
|
ADDI8_EBX !1 ; S = S + 1
|
|
|
|
STORE32_Absolute32_ebx &string_index ; Update S
|
|
|
|
CALL32 %fgetc
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; fixup_label function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives S in ECX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; prepends ':' to string and returns registers un changed
|
|
|
|
;; Uses EAX for HOLD, EBX for PREV and ECX for S[0]
|
|
|
|
:fixup_label
|
|
|
|
PUSH_EAX ; Protect EAX
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOADI32_EAX %58 ; HOLD = ':'
|
|
|
|
LOAD32_ECX_from_EDX_Immediate8 !8 ; HOLD_STRING[0]
|
|
|
|
:fixup_label_loop
|
|
|
|
COPY_EAX_to_EBX ; PREV = HOLD
|
|
|
|
LOAD8_al_from_ECX ; HOLD = HOLD_STRING[I]
|
|
|
|
MOVZX_al ; make useful
|
|
|
|
STORE8_bl_into_Address_ECX ; HOLD_STRING[I] = PREV
|
|
|
|
ADDI8_ECX !1 ; I = I + 1
|
|
|
|
CMPI8_EAX !0 ; IF NULL == HOLD
|
|
|
|
JNE32 %fixup_label_loop ; Keep looping
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
POP_EAX ; Restore EAX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; fgetc function
|
|
|
|
;; Loads FILE* from [INPUT_FILE]
|
|
|
|
;; Returns -4 (EOF) or char in EAX
|
|
|
|
:fgetc
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
LOADI32_EAX %-4 ; Put EOF in eax
|
|
|
|
PUSH_EAX ; Assume bad (If nothing read, value will remain EOF)
|
|
|
|
LEA32_ECX_from_esp ; Get stack address
|
|
|
|
LOAD32_Absolute32_ebx &Input_file ; Where are we reading from
|
|
|
|
LOADI32_EAX %3 ; the syscall number for read
|
|
|
|
LOADI32_EDX %1 ; set the size of chars we want
|
|
|
|
INT_80 ; call the Kernel
|
|
|
|
POP_EAX ; Get either char or EOF
|
|
|
|
CMPI8_EAX !-4 ; Check for EOF
|
|
|
|
JE32 %fgetc_done ; Return as is
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
:fgetc_done
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; Reverse_List function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives List in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns the list reversed in EAX
|
|
|
|
:Reverse_List
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_EBX ; Set HEAD
|
|
|
|
LOADI32_EAX %0 ; ROOT = NULL
|
|
|
|
:Reverse_List_Loop
|
|
|
|
CMPI8_EBX !0 ; WHILE HEAD != NULL
|
|
|
|
JE32 %Reverse_List_Done ; Stop otherwise
|
|
|
|
|
|
|
|
LOAD32_ECX_from_EBX ; NEXT = HEAD->NEXT
|
|
|
|
STORE32_EAX_into_EBX ; HEAD->NEXT = ROOT
|
|
|
|
COPY_EBX_to_EAX ; ROOT = HEAD
|
|
|
|
COPY_ECX_to_EBX ; HEAD = NEXT
|
|
|
|
JMP32 %Reverse_List_Loop ; Keep Going
|
|
|
|
|
|
|
|
:Reverse_List_Done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; recursive_output function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives list in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; walks the list and prints the I->S for all nodes backwards
|
|
|
|
;; Uses EBX for I
|
|
|
|
:recursive_output
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CMPI8_EAX !0 ; Check for NULL
|
|
|
|
JE32 %recursive_output_done ; Skip the work
|
|
|
|
COPY_EAX_to_EBX ; I = Head
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX ; Iterate to next Token
|
|
|
|
CALL32 %recursive_output ; Recurse
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; Using S
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
:recursive_output_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; File_Print function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives CHAR* in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; calls fputc for every non-null char
|
|
|
|
:File_Print
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_EBX ; Protect S
|
|
|
|
CMPI8_EAX !0 ; Protect against nulls
|
|
|
|
JE32 %File_Print_Done ; Simply don't try to print them
|
|
|
|
:File_Print_Loop
|
|
|
|
LOAD8_al_from_EBX ; Read byte
|
|
|
|
MOVZX_al ; zero extend
|
|
|
|
CMPI8_EAX !0 ; Check for NULL
|
|
|
|
JE32 %File_Print_Done ; Stop at NULL
|
|
|
|
|
|
|
|
CALL32 %fputc ; write it
|
|
|
|
ADDI8_EBX !1 ; S = S + 1
|
|
|
|
JMP32 %File_Print_Loop ; Keep going
|
|
|
|
|
|
|
|
:File_Print_Done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; fputc function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; receives CHAR in EAX and load FILE* from [OUTPUT_FILE]
|
2019-06-23 22:52:38 +01:00
|
|
|
;; writes char and returns
|
|
|
|
:fputc
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_EAX ; We are writing eax
|
|
|
|
LEA32_ECX_from_esp ; Get stack address
|
|
|
|
LOAD32_Absolute32_ebx &Output_file ; Write to target file
|
|
|
|
LOADI32_EAX %4 ; the syscall number for write
|
|
|
|
LOADI32_EDX %1 ; set the size of chars we want
|
|
|
|
INT_80 ; call the Kernel
|
|
|
|
POP_EAX ; Restore stack
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; program function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; receives nothing, returns nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Uses EAX for type_size
|
|
|
|
:program
|
|
|
|
;; The binary initialized the globals to null, so we can skip those steps
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
|
|
|
|
:new_type
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
CMPI8_EAX !0 ; Check if NULL
|
|
|
|
JE32 %program_done ; Be done if null
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; GLOBAL_TOKEN->S
|
|
|
|
LOADI32_EAX &constant ; "CONSTANT"
|
|
|
|
CALL32 %match ; IF GLOBAL_TOKEN->S == "CONSTANT"
|
|
|
|
CMPI8_EAX !0 ; If true
|
|
|
|
JNE32 %program_else ; Looks like not a constant
|
|
|
|
|
|
|
|
;; Deal with minimal constant case
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EBX %0 ; NULL
|
|
|
|
LOAD32_Absolute32_ecx &global_constant_list ; global_constant_list
|
|
|
|
CALL32 %sym_declare ; Declare that constant
|
|
|
|
STORE32_Absolute32_eax &global_constant_list ; global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next
|
|
|
|
STORE32_EBX_into_EAX_Immediate8 !16 ; global_constant_list->arguments = global_token->next
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next->next
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->next->next
|
|
|
|
JMP32 %new_type ; go around again
|
|
|
|
|
|
|
|
:program_else
|
|
|
|
CALL32 %type_name ; Figure out the type_size
|
|
|
|
CMPI8_EAX !0 ; IF NULL == type_size
|
|
|
|
JE32 %new_type ; it was a new type
|
|
|
|
|
|
|
|
;; Add to global symbol table
|
|
|
|
COPY_EAX_to_EBX ; put type_size in the right spot
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD32_Absolute32_ecx &global_symbol_list ; Using global_symbol_list
|
|
|
|
CALL32 %sym_declare ; Declare symbol
|
|
|
|
STORE32_Absolute32_eax &global_symbol_list ; global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global token
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &semicolon ; ";"
|
|
|
|
CALL32 %match ; if(match(";", global_token->s))
|
|
|
|
CMPI8_EAX !0 ; If true
|
|
|
|
JNE32 %program_function ; looks like not a match
|
|
|
|
|
|
|
|
;; Deal with the global variable
|
|
|
|
LOAD32_Absolute32_ebx &globals_list ; Using globals_list
|
|
|
|
LOADI32_EAX &program_string_0 ; ":GLOBAL_"
|
|
|
|
CALL32 %emit ; Emit it
|
|
|
|
COPY_EAX_to_EBX ; update globals_list
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; global token->prev
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global token->prev->s
|
|
|
|
CALL32 %emit ; Emit it
|
|
|
|
|
|
|
|
COPY_EAX_to_EBX ; update globals_list
|
|
|
|
LOADI32_EAX &program_string_1 ; "\nNOP\n"
|
|
|
|
CALL32 %emit ; Emit it
|
|
|
|
STORE32_Absolute32_eax &globals_list ; update globals_list
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
JMP32 %new_type ; go around again
|
|
|
|
|
|
|
|
:program_function
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_paren ; "("
|
|
|
|
CALL32 %match ; if(match(";", global_token->s))
|
|
|
|
CMPI8_EAX !0 ; If true
|
|
|
|
JNE32 %program_error ; Otherwise deal with error case
|
|
|
|
|
|
|
|
;; Deal with function definition
|
|
|
|
CALL32 %declare_function ; Lets get the parsing rolling
|
|
|
|
JMP32 %new_type ; Keep looping through functions
|
|
|
|
|
|
|
|
:program_error
|
|
|
|
;; Deal with the case of something we don't support
|
|
|
|
;; NOT IMPLEMENTED
|
|
|
|
|
|
|
|
:program_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
;; Strings needed by the program function
|
|
|
|
:program_string_0 ":GLOBAL_"
|
|
|
|
:program_string_1 "
|
|
|
|
NOP
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; declare_function function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing and returns nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Sets current function and adds it to the global function list
|
|
|
|
:declare_function
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOADI32_EAX %0 ; Using NULL
|
|
|
|
STORE32_Absolute32_eax ¤t_count ; current_count = 0
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; global token->prev
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global token->prev->s
|
|
|
|
LOADI32_EBX %0 ; NULL
|
|
|
|
LOAD32_Absolute32_ecx &global_function_list ; global_function_list
|
|
|
|
CALL32 %sym_declare ; sym_declare(global_token->prev->s, NULL, global_function_list);
|
|
|
|
STORE32_Absolute32_eax &function ; function = sym_declare(global_token->prev->s, NULL, global_function_list);
|
|
|
|
STORE32_Absolute32_eax &global_function_list ; global_function_list = function
|
|
|
|
|
|
|
|
CALL32 %collect_arguments ; collect all of the function arguments
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global token->s
|
|
|
|
LOADI32_EBX &semicolon ; ";"
|
|
|
|
CALL32 %match ; IF global token->s == ";"
|
|
|
|
CMPI8_EAX !0 ; If true
|
|
|
|
JNE32 %declare_function_full ; It was a prototype
|
|
|
|
|
|
|
|
;; Deal with prototypes
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX ; global token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global token = global token->next
|
|
|
|
JMP32 %declare_function_done ; Move on
|
|
|
|
|
|
|
|
:declare_function_full
|
|
|
|
;; Deal will full function definitions
|
|
|
|
LOADI32_EAX &declare_function_string_0 ; "# Defining function "
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->s
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &declare_function_string_1 ; "\n:FUNCTION_"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->s
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &declare_function_string_3 ; "\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
CALL32 %statement ; Recursively get the function pieces
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &output_list ; output
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; output->s
|
|
|
|
LOADI32_EBX &declare_function_string_2 ; "RETURN\n"
|
|
|
|
CALL32 %match ; IF output->s == "RETURN\n"
|
|
|
|
CMPI8_EAX !0 ; If true we can skip adding it
|
|
|
|
JE32 %declare_function_done ; otherwise we need to add it
|
|
|
|
|
|
|
|
;; Add the return to the end of a function lacking a return;
|
|
|
|
LOADI32_EAX &declare_function_string_2 ; "RETURN\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
:declare_function_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:declare_function_string_0 "# Defining function "
|
|
|
|
:declare_function_string_1 "
|
|
|
|
:FUNCTION_"
|
|
|
|
:declare_function_string_2 "RETURN
|
|
|
|
"
|
|
|
|
:declare_function_string_3 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; collect_arguments function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Adds arguments to the function definition
|
|
|
|
;; holds struct type* type_size in ECX, then replace with struct token_list* a in ECX when type_size is used
|
|
|
|
:collect_arguments
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
:collect_arguments_loop
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &close_paren ; ")"
|
|
|
|
CALL32 %match ; IF global_token->S == ")"
|
|
|
|
CMPI8_EAX !0 ; we reached the end
|
|
|
|
JE32 %collect_arguments_done ; be done
|
|
|
|
|
|
|
|
;; deal with the case of there are arguments
|
|
|
|
CALL32 %type_name ; Get the type
|
|
|
|
COPY_EAX_to_ECX ; put type_size safely out of the way
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &close_paren ; ")"
|
|
|
|
CALL32 %match ; IF global_token->S == ")"
|
|
|
|
CMPI8_EAX !0 ; is a foo(int, char,void) case
|
|
|
|
JE32 %collect_arguments_common ; deal with commas
|
|
|
|
|
|
|
|
;; Trying second else
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &comma ; ","
|
|
|
|
CALL32 %match ; IF global_token->S == ","
|
|
|
|
CMPI8_EAX !0 ; then deal with the common
|
|
|
|
JE32 %collect_arguments_common ; case of commas between arguments
|
|
|
|
|
|
|
|
;; deal with foo(int a, char b)
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
COPY_ECX_to_EBX ; put type_size in the right place
|
|
|
|
LOAD32_Absolute32_ecx &function ; Using function
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !16 ; function->args
|
|
|
|
CALL32 %sym_declare ; sym_declare(global_token->s, type_size, function->arguments);
|
|
|
|
COPY_EAX_to_ECX ; put a in a safe place
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args
|
|
|
|
CMPI8_EAX !0 ; IF function->args == NULL
|
|
|
|
JNE32 %collect_arguments_another ; otherwise it isn't the first
|
|
|
|
|
|
|
|
;; Deal with the case of first argument in the function
|
|
|
|
LOADI32_EAX %-4 ; -4
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->depth = -4
|
|
|
|
JMP32 %collect_arguments_next ; get to next
|
|
|
|
|
|
|
|
:collect_arguments_another
|
|
|
|
;; deal with the case of non-first arguments
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args->depth
|
|
|
|
SUBI8_EAX !4 ; function->args->depth - 4
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->depth = function->args->depth - 4
|
|
|
|
|
|
|
|
:collect_arguments_next
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
STORE32_ECX_into_EAX_Immediate8 !16 ; function->args = a
|
|
|
|
|
|
|
|
:collect_arguments_common
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &comma ; ","
|
|
|
|
CALL32 %match ; IF global_token->S == ","
|
|
|
|
CMPI8_EAX !0 ; then deal with the comma
|
|
|
|
JNE32 %collect_arguments_loop ; otherwise loop
|
|
|
|
|
|
|
|
;; keep foo(bar(), 1) expressions working
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
JMP32 %collect_arguments_loop ; keep going
|
|
|
|
|
|
|
|
:collect_arguments_done
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; statement function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Walks down global_token recursively to collect the contents of the function
|
|
|
|
:statement
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_curly_brace ; "{"
|
|
|
|
CALL32 %match ; IF global_token->S == "{"
|
|
|
|
JNE32 %statement_label ; otherwise try label
|
|
|
|
|
|
|
|
;; deal with { statement }
|
|
|
|
CALL32 %recursive_statement ; Statements inside of statements for days
|
|
|
|
JMP32 %statement_done ; Be done
|
|
|
|
|
|
|
|
:statement_label
|
|
|
|
LOAD8_al_from_EBX ; global_token->S[0]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
CMPI8_EAX !58 ; IF global_token->S == ':'
|
|
|
|
JNE32 %statement_local ; otherwise try locals
|
|
|
|
|
|
|
|
;; deal with labels
|
|
|
|
COPY_EBX_to_EAX ; put global_token->S in the right spot
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &statement_string_0 ; Using "\t#C goto label\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_local
|
|
|
|
COPY_EBX_to_EAX ; put global_token->S in the right place
|
|
|
|
LOADI32_EBX &prim_types ; pointer to primative types
|
|
|
|
CALL32 %lookup_type ; See if found
|
|
|
|
CMPI8_EAX !0 ; IF NULL == lookup_type(global_token->S, prim_types)
|
|
|
|
JNE32 %statement_local_success ; Sweet a new local
|
|
|
|
|
|
|
|
;; Second chance
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &struct ; "struct"
|
|
|
|
CALL32 %match ; IF global_token->S == "struct"
|
|
|
|
CMPI8_EAX !0 ; then we are a local
|
|
|
|
JNE32 %statement_if ; otherwise try IF
|
|
|
|
|
|
|
|
:statement_local_success
|
|
|
|
CALL32 %collect_local ; Grab those locals
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_if
|
|
|
|
LOADI32_EAX &if_string ; Using "if"
|
|
|
|
CALL32 %match ; IF global_token->S == "if"
|
|
|
|
CMPI8_EAX !0 ; then we have an if statement
|
|
|
|
JNE32 %statement_do ; otherwise try DO
|
|
|
|
|
|
|
|
;; Deal with IF statement
|
|
|
|
CALL32 %process_if ; DO IT
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_do
|
|
|
|
LOADI32_EAX &do_string ; Using "do"
|
|
|
|
CALL32 %match ; IF global_token->S == "do"
|
|
|
|
CMPI8_EAX !0 ; then we have a do statement
|
|
|
|
JNE32 %statement_while ; otherwise try WHILE
|
|
|
|
|
|
|
|
;; Deal with DO statement
|
|
|
|
CALL32 %process_do ; DO IT
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_while
|
|
|
|
LOADI32_EAX &while_string ; Using "while"
|
|
|
|
CALL32 %match ; IF global_token->S == "while"
|
|
|
|
CMPI8_EAX !0 ; then we have a while statement
|
|
|
|
JNE32 %statement_for ; otherwise try FOR
|
|
|
|
|
|
|
|
;; Deal with WHILE statement
|
|
|
|
CALL32 %process_while ; DO IT
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_for
|
|
|
|
LOADI32_EAX &for_string ; Using "for"
|
|
|
|
CALL32 %match ; IF global_token->S == "for"
|
|
|
|
CMPI8_EAX !0 ; then we have a for statement
|
|
|
|
JNE32 %statement_asm ; otherwise try ASM
|
|
|
|
|
|
|
|
;; Deal with FOR statement
|
|
|
|
CALL32 %process_for ; DO IT
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_asm
|
|
|
|
LOADI32_EAX &asm_string ; Using "asm"
|
|
|
|
CALL32 %match ; IF global_token->S == "asm"
|
|
|
|
CMPI8_EAX !0 ; then we have an asm statement
|
|
|
|
JNE32 %statement_goto ; otherwise try GOTO
|
|
|
|
|
|
|
|
;; Deal with ASM statement
|
|
|
|
CALL32 %process_asm ; Hit it
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_goto
|
|
|
|
LOADI32_EAX &goto_string ; Using "goto"
|
|
|
|
CALL32 %match ; IF global_token->S == "goto"
|
|
|
|
CMPI8_EAX !0 ; then we have a goto statement
|
|
|
|
JNE32 %statement_return ; Otherwise try RETURN
|
|
|
|
|
|
|
|
;; Deal with GOTO statement
|
|
|
|
LOADI32_EAX &statement_string_1 ; Using "JUMP %"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &statement_string_2 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOADI32_EAX &statement_string_4 ; Using "ERROR in statement\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure it has the required
|
|
|
|
JMP32 %statement_done ; Be done
|
|
|
|
|
|
|
|
:statement_return
|
|
|
|
LOADI32_EAX &return_string ; Using "return"
|
|
|
|
CALL32 %match ; IF global_token->S == "return"
|
|
|
|
CMPI8_EAX !0 ; then we have a return statement
|
|
|
|
JNE32 %statement_break ; Otherwise try BREAK
|
|
|
|
|
|
|
|
;; Deal with RETURN Statement
|
|
|
|
CALL32 %return_result ; Return anything they want
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_break
|
|
|
|
LOADI32_EAX &break_string ; Using "break"
|
|
|
|
CALL32 %match ; IF global_token->S == "break"
|
|
|
|
CMPI8_EAX !0 ; then we have a break statement
|
|
|
|
JNE32 %statement_continue ; Otherwise try CONTINUE
|
|
|
|
|
|
|
|
;; Deal with BREAK statement
|
|
|
|
CALL32 %process_break ; Lets do some damage
|
|
|
|
JMP32 %statement_done ; be done
|
|
|
|
|
|
|
|
:statement_continue
|
|
|
|
LOADI32_EAX &continue_string ; Using "continue"
|
|
|
|
CALL32 %match ; IF global_token->S == "continue"
|
|
|
|
CMPI8_EAX !0 ; then we have a continue statement
|
|
|
|
JNE32 %statement_else ; Otherwise we are punting to an expression
|
|
|
|
|
|
|
|
;; Deal with CONTINUE statement
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOADI32_EAX &statement_string_3 ; Using "\n#continue statement\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &statement_string_4 ; Using "ERROR in statement\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Don't forget the ";"
|
|
|
|
JMP32 %statement_done ; Be done
|
|
|
|
|
|
|
|
:statement_else
|
|
|
|
CALL32 %expression ; Collect expression
|
|
|
|
LOADI32_EAX &statement_string_4 ; Using "ERROR in statement\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; make sure we have it
|
|
|
|
|
|
|
|
:statement_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:statement_string_0 " #C goto label
|
|
|
|
"
|
|
|
|
:statement_string_1 "JUMP %"
|
|
|
|
:statement_string_2 "
|
|
|
|
"
|
|
|
|
:statement_string_3 "
|
|
|
|
#continue statement
|
|
|
|
"
|
|
|
|
:statement_string_4 "ERROR in statement
|
|
|
|
Missing ;
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; recursive_statement function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Walks the global_token list to build the contents of statements
|
|
|
|
;; Uses struct token_list* frame in ECX
|
|
|
|
:recursive_statement
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ecx &function ; Using function
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !4 ; frame = function->locals
|
|
|
|
|
|
|
|
:recursive_statement_loop
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &close_curly_brace ; Using "}"
|
|
|
|
CALL32 %match ; IF global_token->S == "}"
|
|
|
|
CMPI8_EAX !0 ; Then we are done recuring
|
|
|
|
JE32 %recursive_statement_cleanup ; and then we clean up
|
|
|
|
|
|
|
|
;; Deal with the recursive calls
|
|
|
|
CALL32 %statement ; Deal with another statement
|
|
|
|
JMP32 %recursive_statement_loop ; loop some more
|
|
|
|
|
|
|
|
:recursive_statement_cleanup
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOADI32_EAX &recursive_statement_string_0 ; Using "RETURN\n"
|
|
|
|
LOAD32_Absolute32_ebx &output_list ; Using output
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; output->S
|
|
|
|
CALL32 %match ; IF output->S == "RETURN\n"
|
|
|
|
CMPI8_EAX !0 ; Then we can skip the clean up
|
|
|
|
JE32 %recursive_statement_done ; and be done
|
|
|
|
|
|
|
|
;; Deal with cleanup
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !4 ; i = function->locals
|
|
|
|
LOADI32_EAX &recursive_statement_string_1 ; Using "POP_ebx\t# _recursive_statement_locals\n"
|
|
|
|
|
|
|
|
:recursive_statement_locals
|
|
|
|
CMP_ECX_EBX ; IF frame != i
|
|
|
|
JE32 %recursive_statement_done ; Otherwise be done
|
|
|
|
|
|
|
|
;; Lets emit
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
LOAD32_EBX_from_EBX ; i = i->next
|
|
|
|
JMP32 %recursive_statement_locals ; keep going
|
|
|
|
|
|
|
|
:recursive_statement_done
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
STORE32_ECX_into_EAX_Immediate8 !4 ; function->locals = frame
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:recursive_statement_string_0 "RETURN
|
|
|
|
"
|
|
|
|
:recursive_statement_string_1 "POP_ebx # _recursive_statement_locals
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; return_result function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Cleans up function and generates return
|
|
|
|
;; Also handles returing expressions
|
|
|
|
:return_result
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
CMPI8_EAX !59 ; If global_token->S[0] == ';'
|
|
|
|
JE32 %return_result_cleanup ; Go straight to cleanup
|
|
|
|
|
|
|
|
CALL32 %expression ; get the expression we are returning
|
|
|
|
|
|
|
|
:return_result_cleanup
|
|
|
|
LOADI32_EAX &return_result_string_0 ; Using "ERROR in return_result\nMISSING ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !4 ; function->locals
|
|
|
|
LOADI32_EAX &return_result_string_1 ; Using "POP_ebx\t# _return_result_locals\n"
|
|
|
|
:return_result_locals
|
|
|
|
CMPI8_EBX !0 ; IF NULL == i
|
|
|
|
JE32 %return_result_done ; Be done
|
|
|
|
|
|
|
|
CALL32 %emit_out ; Emit out pop
|
|
|
|
LOAD32_EBX_from_EBX ; i = i->NEXT
|
|
|
|
JMP32 %return_result_locals ; Keep going
|
|
|
|
|
|
|
|
:return_result_done
|
|
|
|
LOADI32_EAX &return_result_string_2 ; Using "RETURN\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:return_result_string_0 "ERROR in return_result
|
|
|
|
MISSING ;
|
|
|
|
"
|
|
|
|
:return_result_string_1 "POP_ebx # _return_result_locals
|
|
|
|
"
|
|
|
|
:return_result_string_2 "RETURN
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; collect_local function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Walks global_token list to create function locals
|
|
|
|
;; Uses ECX for struct token_list* A
|
|
|
|
:collect_local
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %type_name ; Get the local's type
|
|
|
|
|
|
|
|
COPY_EAX_to_EBX ; Put struct type* type_size in the right place
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD32_Absolute32_ecx &function ; Using function
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !4 ; function->locals
|
|
|
|
CALL32 %sym_declare ; Declare it
|
|
|
|
COPY_EAX_to_ECX ; put it away safely
|
|
|
|
|
|
|
|
;; Try for main
|
|
|
|
LOADI32_EAX &main_string ; Using "main"
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %match ; IF match("main", function->s)
|
|
|
|
CMPI8_EAX !0 ; possible
|
|
|
|
JNE32 %collect_local_fresh ; try to see if fresh function
|
|
|
|
|
|
|
|
;; Ok we are in main, now to see if main is fresh
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; function->locals
|
|
|
|
CMPI8_EAX !0 ; IF NULL == function->locals
|
|
|
|
JNE32 %collect_local_fresh ; try to see if fresh function
|
|
|
|
|
|
|
|
;; Sweet we are in a fresh main
|
|
|
|
LOADI32_EAX %-20 ; We start at -20
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->DEPTH = -20
|
|
|
|
JMP32 %collect_local_common ; Go to the commons
|
|
|
|
|
|
|
|
:collect_local_fresh
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args
|
|
|
|
CMPI8_EAX !0 ; IF NULL == function->locals
|
|
|
|
JNE32 %collect_local_first ; Otherwise see if first
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; function->locals
|
|
|
|
CMPI8_EAX !0 ; IF NULL == function->locals
|
|
|
|
JNE32 %collect_local_first ; Otherwise try first
|
|
|
|
|
|
|
|
;; Sweet we are in a fresh function
|
|
|
|
LOADI32_EAX %-8 ; We start at -8
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->DEPTH = -8
|
|
|
|
JMP32 %collect_local_common ; Go to the commons
|
|
|
|
|
|
|
|
:collect_local_first
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; function->locals
|
|
|
|
CMPI8_EAX !0 ; IF NULL == function->locals
|
|
|
|
JNE32 %collect_local_else ; Looks like we are just another local
|
|
|
|
|
|
|
|
;; Ok we are the first local
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->args->depth
|
|
|
|
SUBI8_EAX !8 ; function->arguments->depth - 8
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->DEPTH = function->arguments->depth - 8
|
|
|
|
JMP32 %collect_local_common ; Go to the commons
|
|
|
|
|
|
|
|
:collect_local_else
|
|
|
|
;; Always the last to know
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; function->locals
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !16 ; function->locals->depth
|
|
|
|
SUBI8_EAX !4 ; function->locals->depth - 4
|
|
|
|
STORE32_EAX_into_ECX_Immediate8 !16 ; a->DEPTH = function->locals->depth - 4
|
|
|
|
|
|
|
|
:collect_local_common
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
|
|
|
|
STORE32_ECX_into_EAX_Immediate8 !4 ; function->locals = a
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !8 ; a->S
|
|
|
|
|
|
|
|
LOADI32_EAX &collect_local_string_0 ; Using "# Defining local "
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &collect_local_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; Using "="
|
|
|
|
CALL32 %match ; IF match("=", global_token->s)
|
|
|
|
CMPI8_EAX !0 ; Deal with assignment
|
|
|
|
JNE32 %collect_local_done ; Otherwise finish it
|
|
|
|
|
|
|
|
;; Deal with assignment
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
CALL32 %expression ; Recurse
|
|
|
|
|
|
|
|
:collect_local_done
|
|
|
|
LOADI32_EAX &collect_local_string_2 ; Using "ERROR in collect_local\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &collect_local_string_3 ; Using "PUSH_eax\t#"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; put A->S where it belongs
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &collect_local_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:collect_local_string_0 "# Defining local "
|
|
|
|
:collect_local_string_1 "
|
|
|
|
"
|
|
|
|
:collect_local_string_2 "ERROR in collect_local
|
|
|
|
Missing ;
|
|
|
|
"
|
|
|
|
:collect_local_string_3 "PUSH_eax #"
|
|
|
|
|
|
|
|
|
|
|
|
;; process_asm function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Simply inlines the asm statements
|
|
|
|
;; Uses EBX for global_token temp storage
|
|
|
|
:process_asm
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &process_asm_string_0 ; Using "ERROR in process_asm\nMISSING (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
:process_asm_iter
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !34 ; IF global_token->S[0] == '\"'
|
|
|
|
JNE32 %process_asm_done ; Otherwise be done
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
ADDI8_EAX !1 ; global_token->S + 1
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_asm_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->NEXT
|
|
|
|
JMP32 %process_asm_iter ; keep going
|
|
|
|
|
|
|
|
:process_asm_done
|
|
|
|
LOADI32_EAX &process_asm_string_2 ; Using "ERROR in process_asm\nMISSING )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_asm_string_3 ; Using "ERROR in process_asm\nMISSING ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_asm_string_0 "ERROR in process_asm
|
|
|
|
MISSING (
|
|
|
|
"
|
|
|
|
:process_asm_string_1 "
|
|
|
|
"
|
|
|
|
:process_asm_string_2 "ERROR in process_asm
|
|
|
|
MISSING )
|
|
|
|
"
|
|
|
|
:process_asm_string_3 "ERROR in process_asm
|
|
|
|
MISSING ;
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; process_if function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Increments current_count recurses into expression + statement
|
|
|
|
;; Uses ECX for char* NUMBER_STRING
|
|
|
|
:process_if
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax ¤t_count ; Using current count
|
|
|
|
COPY_EAX_to_EBX ; Preparing for update
|
|
|
|
ADDI8_EBX !1 ; current_count + 1
|
|
|
|
STORE32_Absolute32_ebx ¤t_count ; current_count = current_count + 1
|
|
|
|
CALL32 %numerate_number ; convert to string
|
|
|
|
COPY_EAX_to_ECX ; put NUMBER_STRING in place
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_0 ; Using "# IF_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_1 ; Using "ERROR in process_if\nMISSING (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %expression ; Recurse to get the IF(...) part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_2 ; Using "TEST\nJUMP_EQ %ELSE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_3 ; Using "ERROR in process_if\nMISSING )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %statement ; Recursive to get the IF(){...} part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_4 ; Using "JUMP %_END_IF_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_if_string_5 ; Using ":ELSE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &else_string ; Using "else"
|
|
|
|
CALL32 %match ; IF global_token->S == "else"
|
|
|
|
CMPI8_EAX !0 ; Then we need to collect the else too
|
|
|
|
JNE32 %process_if_done ; Otherwise finish up
|
|
|
|
|
|
|
|
;; deal with else statement
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
CALL32 %statement ; Recurse to get the ELSE {...} part
|
|
|
|
|
|
|
|
:process_if_done
|
|
|
|
LOADI32_EAX &process_if_string_6 ; Using ":_END_IF_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_if_string_0 "# IF_"
|
|
|
|
:process_if_string_1 "ERROR in process_if
|
|
|
|
MISSING (
|
|
|
|
"
|
|
|
|
:process_if_string_2 "TEST
|
|
|
|
JUMP_EQ %ELSE_"
|
|
|
|
:process_if_string_3 "ERROR in process_if
|
|
|
|
MISSING )
|
|
|
|
"
|
|
|
|
:process_if_string_4 "JUMP %_END_IF_"
|
|
|
|
:process_if_string_5 ":ELSE_"
|
|
|
|
:process_if_string_6 ":_END_IF_"
|
|
|
|
|
|
|
|
|
|
|
|
;; save_break_frame microfunction
|
|
|
|
;; Overwrites EAX abd EBX
|
|
|
|
;; Saves break frame on stack
|
|
|
|
;; Returns to caller
|
|
|
|
:save_break_frame
|
|
|
|
POP_EBX ; Save return Address
|
|
|
|
LOAD32_Absolute32_eax &break_frame ; Get break_frame
|
|
|
|
PUSH_EAX ; Store as nested_locals
|
|
|
|
LOAD32_Absolute32_eax &break_target_head ; Get break_target_head
|
|
|
|
PUSH_EAX ; Store as nested_break_head
|
|
|
|
LOAD32_Absolute32_eax &break_target_func ; Get break_target_func
|
|
|
|
PUSH_EAX ; Store as nested_break_func
|
|
|
|
LOAD32_Absolute32_eax &break_target_num ; Get break_target_num
|
|
|
|
PUSH_EAX ; Store as nested_break_num
|
|
|
|
PUSH_EBX ; Put return back in place
|
|
|
|
RETURN ; Return to caller
|
|
|
|
|
|
|
|
|
|
|
|
;; restore_break_frame microfunction
|
|
|
|
;; Overwrites EAX and EBX
|
|
|
|
;; Restores break frame from stack
|
|
|
|
;; Returns to caller
|
|
|
|
:restore_break_frame
|
|
|
|
POP_EBX ; Save return Address
|
|
|
|
POP_EAX ; Get nested_break_num
|
|
|
|
STORE32_Absolute32_eax &break_target_num ; Restore break_target_num
|
|
|
|
POP_EAX ; Get nested_break_func
|
|
|
|
STORE32_Absolute32_eax &break_target_func ; Restore break_target_func
|
|
|
|
POP_EAX ; Get nested_break_head
|
|
|
|
STORE32_Absolute32_eax &break_target_head ; Restore break_target_head
|
|
|
|
POP_EAX ; Get nested_locals
|
|
|
|
STORE32_Absolute32_eax &break_frame ; Restore break_frame
|
|
|
|
PUSH_EBX ; Put return back in place
|
|
|
|
RETURN ; Return to caller
|
|
|
|
|
|
|
|
|
|
|
|
;; set_break_frame microfunction
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* head in EAX and char* num in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Overwrites EAX and EBX
|
|
|
|
;; Returns to calling function
|
|
|
|
:set_break_frame
|
|
|
|
STORE32_Absolute32_eax &break_target_head ; update break_target_head
|
|
|
|
STORE32_Absolute32_ebx &break_target_num ; update break_target_num
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !4 ; function->LOCALS
|
|
|
|
STORE32_Absolute32_eax &break_frame ; break_frame = function->LOCALS
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; function->S
|
|
|
|
STORE32_Absolute32_eax &break_target_func ; break_target_func = function->S
|
|
|
|
RETURN ; Return to sender
|
|
|
|
|
|
|
|
|
|
|
|
;; process_do function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Increments current_count and leverages save/restore_break_frame pieces
|
|
|
|
;; Uses ECX for char* NUMBER_STRING
|
|
|
|
:process_do
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %save_break_frame ; Save the frame
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax ¤t_count ; Using current count
|
|
|
|
COPY_EAX_to_EBX ; Preparing for update
|
|
|
|
ADDI8_EBX !1 ; current_count + 1
|
|
|
|
STORE32_Absolute32_ebx ¤t_count ; current_count = current_count + 1
|
|
|
|
CALL32 %numerate_number ; convert to string
|
|
|
|
COPY_EAX_to_ECX ; put NUMBER_STRING in place
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_0 ; Using "DO_END_"
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %set_break_frame ; Set the frame
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_1 ; Using ":DO_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
CALL32 %statement ; Do the DO {...} part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_2 ; Using "ERROR in process_do\nMISSING while\n"
|
|
|
|
LOADI32_EBX &while_string ; Using "while"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_3 ; Using "ERROR in process_do\nMISSING (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %expression ; Do the WHILE (...) part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_4 ; Using "ERROR in process_do\nMISSING )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_5 ; Using "ERROR in process_do\nMISSING ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_6 ; Using "TEST\nJUMP_NE %DO_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_do_string_7 ; Using ":DO_END_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
CALL32 %restore_break_frame ; Restore the old break frame
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_do_string_0 "DO_END_"
|
|
|
|
:process_do_string_1 ":DO_"
|
|
|
|
:process_do_string_2 "ERROR in process_do
|
|
|
|
MISSING while
|
|
|
|
"
|
|
|
|
:process_do_string_3 "ERROR in process_do
|
|
|
|
MISSING (
|
|
|
|
"
|
|
|
|
:process_do_string_4 "ERROR in process_do
|
|
|
|
MISSING )
|
|
|
|
"
|
|
|
|
:process_do_string_5 "ERROR in process_do
|
|
|
|
MISSING ;
|
|
|
|
"
|
|
|
|
:process_do_string_6 "TEST
|
|
|
|
JUMP_NE %DO_"
|
|
|
|
:process_do_string_7 ":DO_END_"
|
|
|
|
|
|
|
|
|
|
|
|
;; process_while function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Increments current_count and leverages save/restore_break_frame pieces
|
|
|
|
;; Uses ECX for char* NUMBER_STRING
|
|
|
|
:process_while
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %save_break_frame ; Save break_frame
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax ¤t_count ; Using current count
|
|
|
|
COPY_EAX_to_EBX ; Preparing for update
|
|
|
|
ADDI8_EBX !1 ; current_count + 1
|
|
|
|
STORE32_Absolute32_ebx ¤t_count ; current_count = current_count + 1
|
|
|
|
CALL32 %numerate_number ; convert to string
|
|
|
|
COPY_EAX_to_ECX ; put NUMBER_STRING in place
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_0 ; Using "END_WHILE_"
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %set_break_frame ; Set it and forget it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_1 ; Using ":WHILE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_2 ; Using "ERROR in process_while\nMISSING (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %expression ; Deal with the WHILE (...) part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_3 ; Using "TEST\nJUMP_EQ %END_WHILE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_4 ; Using "# THEN_while_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_5 ; Using "ERROR in process_while\nMISSING )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %statement ; Deal with the {....} part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_6 ; Using "JUMP %WHILE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_while_string_7 ; Using ":END_WHILE_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
CALL32 %restore_break_frame ; Restore the old break frame
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_while_string_0 "END_WHILE_"
|
|
|
|
:process_while_string_1 ":WHILE_"
|
|
|
|
:process_while_string_2 "ERROR in process_while
|
|
|
|
MISSING (
|
|
|
|
"
|
|
|
|
:process_while_string_3 "TEST
|
|
|
|
JUMP_EQ %END_WHILE_"
|
|
|
|
:process_while_string_4 "# THEN_while_"
|
|
|
|
:process_while_string_5 "ERROR in process_while
|
|
|
|
MISSING )
|
|
|
|
"
|
|
|
|
:process_while_string_6 "JUMP %WHILE_"
|
|
|
|
:process_while_string_7 ":END_WHILE_"
|
|
|
|
|
|
|
|
|
|
|
|
;; process_for function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Increments current_count and leverages save/restore_break_frame pieces
|
|
|
|
;; Uses ECX for char* NUMBER_STRING
|
|
|
|
:process_for
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %save_break_frame ; Save the frame
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax ¤t_count ; Using current count
|
|
|
|
COPY_EAX_to_EBX ; Preparing for update
|
|
|
|
ADDI8_EBX !1 ; current_count + 1
|
|
|
|
STORE32_Absolute32_ebx ¤t_count ; current_count = current_count + 1
|
|
|
|
CALL32 %numerate_number ; convert to string
|
|
|
|
COPY_EAX_to_ECX ; put NUMBER_STRING in place
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_0 ; Using "FOR_END_"
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %set_break_frame ; Set it and forget it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_1 ; Using "# FOR_initialization_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_2 ; Using "ERROR in process_for\nMISSING (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make Sure we have it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &semicolon ; Using ";"
|
|
|
|
CALL32 %match ; IF global_token->S == ";"
|
|
|
|
CMPI8_EAX !0 ; Then no initializer
|
|
|
|
JE32 %process_for_terminator ; And skip getting the expression
|
|
|
|
|
|
|
|
;; Deal with FOR (...; case
|
|
|
|
CALL32 %expression ; Get the FOR ( ... ; part
|
|
|
|
|
|
|
|
:process_for_terminator
|
|
|
|
LOADI32_EAX &process_for_string_3 ; Using ":FOR_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_4 ; Using "ERROR in process_for\nMISSING ;1\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %expression ; Get the FOR ( ; ... ; Part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_5 ; Using "TEST\nJUMP_EQ %FOR_END_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_6 ; Using "JUMP %FOR_THEN_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_7 ; Using ":FOR_ITER_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_8 ; Using "ERROR in process_for\nMISSING ;2\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %expression ; Get the FOR (;;...) part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_9 ; Using "JUMP %FOR_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_10 ; Using ":FOR_THEN_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_11 ; Using "ERROR in process_for\nMISSING )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %statement ; Get FOR (;;) {...} part
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_12 ; Using "JUMP %FOR_ITER_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Passing NUMBER_STRING
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
LOADI32_EAX &process_for_string_13 ; Using ":FOR_END_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID_out ; uniqueID_out(function->s, number_string)
|
|
|
|
|
|
|
|
CALL32 %restore_break_frame ; Restore the old break frame
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_for_string_0 "FOR_END_"
|
|
|
|
:process_for_string_1 "# FOR_initialization_"
|
|
|
|
:process_for_string_2 "ERROR in process_for
|
|
|
|
MISSING (
|
|
|
|
"
|
|
|
|
:process_for_string_3 ":FOR_"
|
|
|
|
:process_for_string_4 "ERROR in process_for
|
|
|
|
MISSING ;1
|
|
|
|
"
|
|
|
|
:process_for_string_5 "TEST
|
|
|
|
JUMP_EQ %FOR_END_"
|
|
|
|
:process_for_string_6 "JUMP %FOR_THEN_"
|
|
|
|
:process_for_string_7 ":FOR_ITER_"
|
|
|
|
:process_for_string_8 "ERROR in process_for
|
|
|
|
MISSING ;2
|
|
|
|
"
|
|
|
|
:process_for_string_9 "JUMP %FOR_"
|
|
|
|
:process_for_string_10 ":FOR_THEN_"
|
|
|
|
:process_for_string_11 "ERROR in process_for
|
|
|
|
MISSING )
|
|
|
|
"
|
|
|
|
:process_for_string_12 "JUMP %FOR_ITER_"
|
|
|
|
:process_for_string_13 ":FOR_END_"
|
|
|
|
|
|
|
|
|
|
|
|
;; process_break function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Handles the break out of loops case
|
|
|
|
;; Uses EBX for struct token_list* break_frame and ECX for struct token_list* I
|
|
|
|
:process_break
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax &break_target_head ; Catch big error
|
|
|
|
CMPI8_EAX !0 ; IF(NULL == break_target_head)
|
|
|
|
JE32 %process_break_bad ; I'm sorry Mr White but you have stage-3 lung cancer
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_ECX_from_EAX_Immediate8 !4 ; I = function->LOCALS
|
|
|
|
LOAD32_Absolute32_ebx &break_frame ; Put break_frame in the right spot
|
|
|
|
LOADI32_EAX &process_break_string_1 ; Using "POP_ebx\t# break_cleanup_locals\n"
|
|
|
|
|
|
|
|
:process_break_iter
|
|
|
|
CMPI8_ECX !0 ; IF (NULL == I)
|
|
|
|
JE32 %process_break_cleaned ; We are done
|
|
|
|
|
|
|
|
CMP_EBX_ECX ; IF I != break_frame
|
|
|
|
JE32 %process_break_cleaned ; We are done
|
|
|
|
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
LOAD32_ECX_from_ECX ; I = I->NEXT
|
|
|
|
JMP32 %process_break_iter ; Keep looping
|
|
|
|
|
|
|
|
:process_break_cleaned
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &process_break_string_2 ; Using "JUMP %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &break_target_head ; Get what we are in
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &break_target_func ; Get what function we are in
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &underline ; Using "_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &break_target_num ; Get dem digits
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_break_string_3 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_break_string_4 ; Using "ERROR in break statement\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:process_break_bad
|
|
|
|
;; Breaking badly
|
|
|
|
LOADI32_EAX %2 ; Using standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
; CALL32 %line_error ; Write useful debug info
|
|
|
|
COPY_ECX_to_EAX ; put S in the right place
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOADI32_EAX &process_break_string_0 ; Ending string
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
|
|
|
:process_break_string_0 "Not inside of a loop or case statement"
|
|
|
|
:process_break_string_1 "POP_ebx # break_cleanup_locals
|
|
|
|
"
|
|
|
|
:process_break_string_2 "JUMP %"
|
|
|
|
:process_break_string_3 "
|
|
|
|
"
|
|
|
|
:process_break_string_4 "ERROR in break statement
|
|
|
|
Missing ;
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; expression function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Walks global_token and updates output_list
|
|
|
|
;; Uses EAX and EBX for match and ECX for char* store
|
|
|
|
:expression
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %bitwise_expr ; Collect bitwise expressions
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; "="
|
|
|
|
CALL32 %match ; IF global_token->S == "="
|
|
|
|
CMPI8_EAX !0 ; We have to deal with assignment
|
|
|
|
JNE32 %expression_done ; Looks like nope
|
|
|
|
|
|
|
|
;; Deal with possible assignment
|
|
|
|
LOADI32_ECX &expression_string_1 ; Assume "STORE_CHAR\n" by default
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !4 ; global_token->PREV
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->PREV->S
|
|
|
|
LOADI32_EAX &close_bracket ; Using "]"
|
|
|
|
CALL32 %match ; IF global_token->S == "]"
|
|
|
|
CMPI8_EAX !0 ; Then we might have a char
|
|
|
|
JNE32 %expression_int ; Otherwise INT
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx ¤t_target ; Using current_target
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !24 ; current_target->NAME
|
|
|
|
LOADI32_EAX &type_char_indirect_name ; Using "char*"
|
|
|
|
CALL32 %match ; Intensional inefficency because I feel like it
|
|
|
|
CMPI8_EAX !0 ; IF current_target->NAME == "char*"
|
|
|
|
JNE32 %expression_int ; Do char anyway
|
|
|
|
|
|
|
|
JMP32 %expression_common ; Looks like we have to use "STORE_CHAR\n"
|
|
|
|
|
|
|
|
:expression_int
|
|
|
|
LOADI32_ECX &expression_string_0 ; Use "STORE_INTEGER\n"
|
|
|
|
|
|
|
|
:expression_common
|
|
|
|
LOADI32_EAX &expression ; Passing expression
|
|
|
|
CALL32 %common_recursion ; Recurse
|
|
|
|
COPY_ECX_to_EAX ; Using Store
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
LOADI32_EAX %0 ; Using NULL
|
|
|
|
STORE32_Absolute32_eax ¤t_target ; current_target = NULL
|
|
|
|
|
|
|
|
:expression_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:expression_string_0 "STORE_INTEGER
|
|
|
|
"
|
|
|
|
:expression_string_1 "STORE_CHAR
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; bitwise_expr function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Walks global_token list and updates output list
|
|
|
|
;; Just calls other functions
|
|
|
|
:bitwise_expr
|
|
|
|
CALL32 %relational_expr ; Walk up the tree
|
|
|
|
CALL32 %bitwise_expr_stub ; Let general recursion do the work
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; bitwise_expr_stub function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Just calls general_recursion a bunch
|
|
|
|
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
|
|
|
|
:bitwise_expr_stub
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
|
|
|
|
LOADI32_EAX &relational_expr ; Using relational_expr
|
|
|
|
LOADI32_EBX &bitwise_expr_stub_string_0 ; Using "AND_eax_ebx\n"
|
|
|
|
LOADI32_ECX &bitwise_and ; Using "&"
|
|
|
|
LOADI32_EDX &bitwise_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &relational_expr ; Using relational_expr
|
|
|
|
LOADI32_EBX &bitwise_expr_stub_string_0 ; Using "AND_eax_ebx\n"
|
|
|
|
LOADI32_ECX &logical_and ; Using "&&"
|
|
|
|
LOADI32_EDX &bitwise_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &relational_expr ; Using relational_expr
|
|
|
|
LOADI32_EBX &bitwise_expr_stub_string_1 ; Using "OR_eax_ebx\n"
|
|
|
|
LOADI32_ECX &bitwise_or ; Using "|"
|
|
|
|
LOADI32_EDX &bitwise_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &relational_expr ; Using relational_expr
|
|
|
|
LOADI32_EBX &bitwise_expr_stub_string_1 ; Using "OR_eax_ebx\n"
|
|
|
|
LOADI32_ECX &logical_or ; Using "||"
|
|
|
|
LOADI32_EDX &bitwise_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &relational_expr ; Using relational_expr
|
|
|
|
LOADI32_EBX &bitwise_expr_stub_string_2 ; Using "XOR_ebx_eax_into_eax\n"
|
|
|
|
LOADI32_ECX &bitwise_xor ; Using "^"
|
|
|
|
LOADI32_EDX &bitwise_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:bitwise_expr_stub_string_0 "AND_eax_ebx
|
|
|
|
"
|
|
|
|
:bitwise_expr_stub_string_1 "OR_eax_ebx
|
|
|
|
"
|
|
|
|
:bitwise_expr_stub_string_2 "XOR_ebx_eax_into_eax
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; relational_expr function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Walks global_token list and updates output list
|
|
|
|
;; just calls other function
|
|
|
|
:relational_expr
|
|
|
|
CALL32 %additive_expr ; Walk up the tree
|
|
|
|
CALL32 %relational_expr_stub ; Recurse
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; relational_expr_stub function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Just calls general_recursion a bunch
|
|
|
|
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
|
|
|
|
:relational_expr_stub
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_0 ; Using "CMP\nSETL\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX &less_than_string ; Using "<"
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_1 ; Using "CMP\nSETLE\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX &less_than_equal_string ; Using "<="
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_2 ; Using "CMP\nSETGE\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX &greater_than_equal_string ; Using ">="
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_3 ; Using "CMP\nSETG\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX &greater_than_string ; Using ">"
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_4 ; Using "CMP\nSETE\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX &equal_to_string ; Using "=="
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &additive_expr ; Using additive_expr
|
|
|
|
LOADI32_EBX &relational_expr_stub_string_5 ; Using "CMP\nSETNE\nMOVEZBL\n"
|
|
|
|
LOADI32_ECX ¬_equal_string ; Using "!="
|
|
|
|
LOADI32_EDX &relational_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:relational_expr_stub_string_0 "CMP
|
|
|
|
SETL
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
:relational_expr_stub_string_1 "CMP
|
|
|
|
SETLE
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
:relational_expr_stub_string_2 "CMP
|
|
|
|
SETGE
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
:relational_expr_stub_string_3 "CMP
|
|
|
|
SETG
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
:relational_expr_stub_string_4 "CMP
|
|
|
|
SETE
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
:relational_expr_stub_string_5 "CMP
|
|
|
|
SETNE
|
|
|
|
MOVEZBL
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; additive_expr function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Walks global_token list and updates output list
|
|
|
|
;; just calls other function
|
|
|
|
:additive_expr
|
|
|
|
CALL32 %postfix_expr ; Walk up the tree
|
|
|
|
CALL32 %additive_expr_stub ; Recurse
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; additive_expr_stub function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Just calls general_recursion a bunch
|
|
|
|
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
|
|
|
|
:additive_expr_stub
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_0 ; Using "ADD_ebx_to_eax\n"
|
|
|
|
LOADI32_ECX &plus_string ; Using "+"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_1 ; Using "SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n"
|
|
|
|
LOADI32_ECX &minus_string ; Using "-"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_2 ; Using "MULTIPLY_eax_by_ebx_into_eax\n"
|
|
|
|
LOADI32_ECX &multiply_string ; Using "*"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_3 ; Using "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nDIVIDE_eax_by_ebx_into_eax\n"
|
|
|
|
LOADI32_ECX ÷_string ; Using "/"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_4 ; Using "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nMODULUS_eax_from_ebx_into_ebx\nMOVE_edx_to_eax\n"
|
|
|
|
LOADI32_ECX &modulus_string ; Using "%"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_5 ; Using "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAL_eax_cl\n"
|
|
|
|
LOADI32_ECX &left_shift_string ; Using "<<"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Using postfix_expr
|
|
|
|
LOADI32_EBX &additive_expr_stub_string_6 ; Using "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAR_eax_cl\n"
|
|
|
|
LOADI32_ECX &right_shift_string ; Using ">>"
|
|
|
|
LOADI32_EDX &additive_expr_stub ; And recurse
|
|
|
|
CALL32 %general_recursion ; Hit it
|
|
|
|
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:additive_expr_stub_string_0 "ADD_ebx_to_eax
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_1 "SUBTRACT_eax_from_ebx_into_ebx
|
|
|
|
MOVE_ebx_to_eax
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_2 "MULTIPLY_eax_by_ebx_into_eax
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_3 "XCHG_eax_ebx
|
|
|
|
LOAD_IMMEDIATE_edx %0
|
|
|
|
DIVIDE_eax_by_ebx_into_eax
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_4 "XCHG_eax_ebx
|
|
|
|
LOAD_IMMEDIATE_edx %0
|
|
|
|
MODULUS_eax_from_ebx_into_ebx
|
|
|
|
MOVE_edx_to_eax
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_5 "COPY_eax_to_ecx
|
|
|
|
COPY_ebx_to_eax
|
|
|
|
SAL_eax_cl
|
|
|
|
"
|
|
|
|
:additive_expr_stub_string_6 "COPY_eax_to_ecx
|
|
|
|
COPY_ebx_to_eax
|
|
|
|
SAR_eax_cl
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; postfix_expr function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Walks global_token list and updates output list
|
|
|
|
;; just calls other function
|
|
|
|
:postfix_expr
|
|
|
|
CALL32 %primary_expr ; Walk up the tree
|
|
|
|
CALL32 %postfix_expr_stub ; Recurse
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; postfix_expr_stub function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Checks for "[" and "->" and deals with them otherwise does nothing
|
|
|
|
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
|
|
|
|
:postfix_expr_stub
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_bracket ; Using "["
|
|
|
|
CALL32 %match ; IF global_token->S == "["
|
|
|
|
CMPI8_EAX !0 ; then we have an array
|
|
|
|
JNE32 %postfix_expr_stub_arrow ; Otherwise try arrow
|
|
|
|
|
|
|
|
;; Deal with array
|
|
|
|
CALL32 %postfix_expr_array ; Get it
|
|
|
|
CALL32 %postfix_expr_stub ; Recurse
|
|
|
|
|
|
|
|
:postfix_expr_stub_arrow
|
|
|
|
LOADI32_EAX &arrow_string ; Using "->"
|
|
|
|
CALL32 %match ; IF global_token->S == "->"
|
|
|
|
CMPI8_EAX !0 ; Then we need to deal with struct offsets
|
|
|
|
JNE32 %postfix_expr_stub_done ; Otherwise be done
|
|
|
|
|
|
|
|
;; Deal with arrow
|
|
|
|
CALL32 %postfix_expr_arrow ; Get it
|
|
|
|
CALL32 %postfix_expr_stub ; Recurse
|
|
|
|
|
|
|
|
:postfix_expr_stub_done
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; unary_expr_sizeof function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses ECX for A->SIZE
|
|
|
|
:unary_expr_sizeof
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &unary_expr_sizeof_string_0 ; Using "ERROR in unary_expr\nMissing (\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CALL32 %type_name ; Get the type
|
|
|
|
LOAD32_ECX_from_EAX_Immediate8 !4 ; Set A->TYPE
|
|
|
|
|
|
|
|
LOADI32_EAX &unary_expr_sizeof_string_1 ; Using "ERROR in unary_expr\nMissing )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &unary_expr_sizeof_string_2 ; Using "LOAD_IMMEDIATE_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Put A->SIZE in the right place
|
|
|
|
CALL32 %numerate_number ; Turn into string
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &unary_expr_sizeof_string_3 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:unary_expr_sizeof_string_0 "ERROR in unary_expr
|
|
|
|
Missing (
|
|
|
|
"
|
|
|
|
:unary_expr_sizeof_string_1 "ERROR in unary_expr
|
|
|
|
Missing )
|
|
|
|
"
|
|
|
|
:unary_expr_sizeof_string_2 "LOAD_IMMEDIATE_eax %"
|
|
|
|
:unary_expr_sizeof_string_3 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; postfix_expr_array function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives Nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Uses EBX for struct type* ARRAY and ECX for char* ASSIGN
|
|
|
|
:postfix_expr_array
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax ¤t_target ; ARRAY = current_target
|
|
|
|
PUSH_EAX ; Protect it
|
|
|
|
|
|
|
|
LOADI32_EAX &expression ; Using expression
|
|
|
|
CALL32 %common_recursion ; Recurse
|
|
|
|
|
|
|
|
POP_EBX ; Restore array
|
|
|
|
STORE32_Absolute32_ebx ¤t_target ; current_target = ARRAY
|
|
|
|
|
|
|
|
LOADI32_ECX &postfix_expr_array_string_0 ; ASSIGN = "LOAD_INTEGER\n"
|
|
|
|
|
|
|
|
LOADI32_EAX &type_char_indirect_name ; Using "char*"
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !24 ; current_target->NAME
|
|
|
|
CALL32 %match ; IF current_target->NAME == "char*"
|
|
|
|
CMPI8_EAX !0 ; load a byte
|
|
|
|
JNE32 %postfix_expr_array_large ; Otherwise adjust
|
|
|
|
|
|
|
|
;; Deal with loading byte
|
|
|
|
LOADI32_ECX &postfix_expr_array_string_1 ; ASSIGN = "LOAD_BYTE\n"
|
|
|
|
JMP32 %postfix_expr_array_common ; Do the next bit
|
|
|
|
|
|
|
|
:postfix_expr_array_large
|
|
|
|
;; deal with arrays made of things other than chars
|
|
|
|
LOADI32_EAX &postfix_expr_array_string_2 ; Using "SAL_eax_Immediate8 !"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax ¤t_target ; Using current_target
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !12 ; current_target->INDIRECT
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !4 ; current_target->INDIRECT->SIZE
|
|
|
|
CALL32 %ceil_log2 ; ceil_log2(current_target->indirect->size)
|
|
|
|
CALL32 %numerate_number ; numerate_number(ceil_log2(current_target->indirect->size))
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr_array_string_3 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:postfix_expr_array_common
|
|
|
|
LOADI32_EAX &postfix_expr_array_string_4 ; Using "ADD_ebx_to_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr_array_string_5 ; Using "ERROR in postfix_expr\nMissing ]\n"
|
|
|
|
LOADI32_EBX &close_bracket ; Using "]"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; Using "="
|
|
|
|
CALL32 %match ; IF global_token->S == "="
|
|
|
|
CMPI8_EAX !0 ; We need to preserve address
|
|
|
|
JNE32 %postfix_expr_array_done ; Otherwise be done
|
|
|
|
|
|
|
|
;; Clearing out assign
|
|
|
|
LOADI32_ECX &postfix_expr_array_string_6 ; ASSIGN = ""
|
|
|
|
|
|
|
|
:postfix_expr_array_done
|
|
|
|
COPY_ECX_to_EAX ; Using ASSIGN
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:postfix_expr_array_string_0 "LOAD_INTEGER
|
|
|
|
"
|
|
|
|
:postfix_expr_array_string_1 "LOAD_BYTE
|
|
|
|
"
|
|
|
|
:postfix_expr_array_string_2 "SAL_eax_Immediate8 !"
|
|
|
|
:postfix_expr_array_string_3 "
|
|
|
|
"
|
|
|
|
:postfix_expr_array_string_4 "ADD_ebx_to_eax
|
|
|
|
"
|
|
|
|
:postfix_expr_array_string_5 "ERROR in postfix_expr
|
|
|
|
Missing ]
|
|
|
|
"
|
|
|
|
:postfix_expr_array_string_6 ""
|
|
|
|
|
|
|
|
|
|
|
|
;; ceil_log2 function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives int a in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Performs log2 on A and
|
|
|
|
;; Returns result in EAX
|
|
|
|
;; Uses EBX for INT A and ECX for INT RESULT
|
|
|
|
:ceil_log2
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOADI32_ECX %0 ; RESULT = 0
|
|
|
|
|
|
|
|
COPY_EAX_to_EBX ; put A in right place
|
|
|
|
SUBI8_EAX !1 ; (A - 1)
|
|
|
|
AND_EAX_EBX ; A & (A - 1)
|
|
|
|
CMPI8_EAX !0 ; IF 0 == (A & (A - 1))
|
|
|
|
JNE32 %ceil_log2_iter ; Starting from -1
|
|
|
|
|
|
|
|
LOADI32_ECX %-1 ; RESULT = -1
|
|
|
|
|
|
|
|
:ceil_log2_iter
|
|
|
|
CMPI8_EBX !0 ; IF A > 0
|
|
|
|
JLE32 %ceil_log2_done ; Otherwise be done
|
|
|
|
|
|
|
|
ADDI8_ECX !1 ; RESULT = RESULT + 1
|
|
|
|
SHRI8_EBX !1 ; A = A >> 1
|
|
|
|
JMP32 %ceil_log2_iter ; Keep looping
|
|
|
|
|
|
|
|
:ceil_log2_done
|
|
|
|
COPY_ECX_to_EAX ; Return RESULT
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; postfix_expr_arrow function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Emits a bunch and updates current_target
|
|
|
|
;; Uses EBX for struct type* I
|
|
|
|
:postfix_expr_arrow
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
LOADI32_EAX &postfix_expr_arrow_string_0 ; Using "# looking up offset\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; Using global_token->S
|
|
|
|
LOAD32_Absolute32_eax ¤t_target ; Using current_target
|
|
|
|
CALL32 %lookup_member ; lookup_member(current_target, global_token->s)
|
|
|
|
COPY_EAX_to_EBX ; struct type* I = lookup_member(current_target, global_token->s)
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !20 ; I->TYPE
|
|
|
|
STORE32_Absolute32_eax ¤t_target ; current_target = I->TYPE
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; I->OFFSET
|
|
|
|
CMPI8_EAX !0 ; IF 0 != I->OFFSET
|
|
|
|
JE32 %postfix_expr_arrow_first ; Then we don't need to do an offset
|
|
|
|
|
|
|
|
;; Deal with needing an offset
|
|
|
|
LOADI32_EAX &postfix_expr_arrow_string_1 ; Using "# -> offset calculation\nLOAD_IMMEDIATE_ebx %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; I->OFFSET
|
|
|
|
CALL32 %numerate_number ; Convert to string
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr_arrow_string_2 ; Using "\nADD_ebx_to_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:postfix_expr_arrow_first
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !4 ; I->SIZE
|
|
|
|
CMPI8_EAX !4 ; IF I->SIZE >= 4
|
|
|
|
JL32 %postfix_expr_arrow_done ; Otherwise be done
|
|
|
|
|
|
|
|
;; Last chance for load
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; Using "="
|
|
|
|
CALL32 %match ; IF global_token->S == "="
|
|
|
|
CMPI8_EAX !0 ; Then we have assignment and should not load
|
|
|
|
JE32 %postfix_expr_arrow_done ; Be done
|
|
|
|
|
|
|
|
;; Deal with load case
|
|
|
|
LOADI32_EAX &postfix_expr_arrow_string_3 ; Using "LOAD_INTEGER\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:postfix_expr_arrow_done
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:postfix_expr_arrow_string_0 "# looking up offset
|
|
|
|
"
|
|
|
|
:postfix_expr_arrow_string_1 "# -> offset calculation
|
|
|
|
LOAD_IMMEDIATE_ebx %"
|
|
|
|
:postfix_expr_arrow_string_2 "
|
|
|
|
ADD_ebx_to_eax
|
|
|
|
"
|
|
|
|
:postfix_expr_arrow_string_3 "LOAD_INTEGER
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
:primary_expr
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &sizeof_string ; Using "sizeof"
|
|
|
|
CALL32 %match ; See if match
|
|
|
|
CMPI8_EAX !0 ; IF match
|
|
|
|
JNE32 %primary_expr_neg ; Otherwise try negatives
|
|
|
|
|
|
|
|
;; Deal with sizeof
|
|
|
|
CALL32 %unary_expr_sizeof ; Lets do this
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_neg
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !45 ; IF global_token->S[0] == "-"
|
|
|
|
JNE32 %primary_expr_not ; Otherwise try logical NOT
|
|
|
|
|
|
|
|
;; Deal with negative numbers
|
|
|
|
LOADI32_EAX &primary_expr_string_0 ; Using "LOAD_IMMEDIATE_eax %0\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Passing postfix_expr
|
|
|
|
CALL32 %common_recursion ; Get what it is notting
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_string_1 ; Using "SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_not
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !33 ; IF global_token->S[0] == "!"
|
|
|
|
JNE32 %primary_expr_bin ; Otherwise try '~'
|
|
|
|
|
|
|
|
;; Deal with logical not
|
|
|
|
LOADI32_EAX &primary_expr_string_2 ; Using "LOAD_IMMEDIATE_eax %1\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &postfix_expr ; Passing postfix_expr
|
|
|
|
CALL32 %common_recursion ; Get what it is notting
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_string_3 ; Using "XOR_ebx_eax_into_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_bin
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !126 ; IF global_token->S[0] == "~"
|
|
|
|
JNE32 %primary_expr_paren ; Otherwise try paren
|
|
|
|
|
|
|
|
;; Deal with binary NOT
|
|
|
|
LOADI32_EAX &postfix_expr ; Passing postfix_expr
|
|
|
|
CALL32 %common_recursion ; Get what it is notting
|
|
|
|
LOADI32_EAX &primary_expr_string_4 ; Using "NOT_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_paren
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !40 ; IF global_token->S[0] == "("
|
|
|
|
JNE32 %primary_expr_ch ; Otherwise try char
|
|
|
|
|
|
|
|
;; deal with nesting
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
CALL32 %expression ; Lets recurse
|
|
|
|
LOADI32_EAX &primary_expr_string_5 ; Using "Error in Primary expression\nDidn't get )\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_ch
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !39 ; Using "'"
|
|
|
|
JNE32 %primary_expr_str ; Otherwise try string
|
|
|
|
|
|
|
|
;; Deal with chars
|
|
|
|
CALL32 %primary_expr_char ; Handle that char
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_str
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !34 ; Using '\"'
|
|
|
|
JNE32 %primary_expr_var ; Otherwise try a variable
|
|
|
|
|
|
|
|
;; Deal with strings
|
|
|
|
CALL32 %primary_expr_string ; Handle that string
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_var
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
LOADI32_EBX &primary_expr_string_6 ; Using "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
|
|
|
|
CALL32 %In_Set ; See if we have a match
|
|
|
|
CMPI8_EAX !1 ; IF match
|
|
|
|
JNE32 %primary_expr_num ; otherwise try number
|
|
|
|
|
|
|
|
;; Deal with variables
|
|
|
|
CALL32 %primary_expr_variable ; Deal with variable
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_num
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
LOADI32_EBX &primary_expr_string_7 ; Using "0123456789"
|
|
|
|
CALL32 %In_Set ; See if we have a match
|
|
|
|
CMPI8_EAX !1 ; IF match
|
|
|
|
JNE32 %primary_expr_fail ; otherwise we failed hard
|
|
|
|
|
|
|
|
;; Deal with numbers
|
|
|
|
CALL32 %primary_expr_number ; Collect the number
|
|
|
|
JMP32 %primary_expr_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_fail
|
|
|
|
;; looks like we hit bad input
|
|
|
|
;; abort before it gets bad
|
|
|
|
CALL32 %primary_expr_failure ; No match means failure
|
|
|
|
:primary_expr_done
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:primary_expr_string_0 "LOAD_IMMEDIATE_eax %0
|
|
|
|
"
|
|
|
|
:primary_expr_string_1 "SUBTRACT_eax_from_ebx_into_ebx
|
|
|
|
MOVE_ebx_to_eax
|
|
|
|
"
|
|
|
|
:primary_expr_string_2 "LOAD_IMMEDIATE_eax %1
|
|
|
|
"
|
|
|
|
:primary_expr_string_3 "XOR_ebx_eax_into_eax
|
|
|
|
"
|
|
|
|
:primary_expr_string_4 "NOT_eax
|
|
|
|
"
|
|
|
|
:primary_expr_string_5 "Error in Primary expression
|
|
|
|
Didn't get )
|
|
|
|
"
|
|
|
|
:primary_expr_string_6 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
|
|
|
|
:primary_expr_string_7 "0123456789"
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr_variable function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Walks global and updates output
|
|
|
|
;; Uses EAX for struct token_list* a and ECX for char* S
|
|
|
|
:primary_expr_variable
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_ECX_from_EAX_Immediate8 !8 ; S = global_token->S
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
LOAD32_Absolute32_ebx &global_constant_list ; Using global_constant_list
|
|
|
|
CALL32 %sym_lookup ; sym_lookup(s, global_constant_list)
|
|
|
|
CMPI8_EAX !0 ; IF NULL == sym_lookup(s, global_constant_list)
|
|
|
|
JE32 %primary_expr_variable_local ; Try locals next
|
|
|
|
|
|
|
|
;; Deal with constant load
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !16 ; a->ARGS
|
|
|
|
LOADI32_EAX &primary_expr_variable_string_2 ; Using "LOAD_IMMEDIATE_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; a->ARGS->S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_variable_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
JMP32 %primary_expr_variable_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_variable_local
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !4 ; function->locals
|
|
|
|
CALL32 %sym_lookup ; sym_lookup(s, function->locals)
|
|
|
|
CMPI8_EAX !0 ; IF NULL == sym_lookup(s, global_constant_list)
|
|
|
|
JE32 %primary_expr_variable_arguments ; try arguments next
|
|
|
|
|
|
|
|
;; Deal with local load
|
|
|
|
CALL32 %variable_load ; Collect it
|
|
|
|
JMP32 %primary_expr_variable_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_variable_arguments
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
LOAD32_Absolute32_ebx &function ; Using function
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !16 ; function->args
|
|
|
|
CALL32 %sym_lookup ; sym_lookup(s, function->args)
|
|
|
|
CMPI8_EAX !0 ; IF NULL == sym_lookup(s, global_constant_list)
|
|
|
|
JE32 %primary_expr_variable_function ; try functions next
|
|
|
|
|
|
|
|
;; Deal with argument load
|
|
|
|
CALL32 %variable_load ; Collect it
|
|
|
|
JMP32 %primary_expr_variable_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_variable_function
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
LOAD32_Absolute32_ebx &global_function_list ; Using global_function_list
|
|
|
|
CALL32 %sym_lookup ; sym_lookup(s, global_function_list)
|
|
|
|
CMPI8_EAX !0 ; IF NULL == sym_lookup(s, global_function_list)
|
|
|
|
JE32 %primary_expr_variable_global ; try globals next
|
|
|
|
|
|
|
|
;; Deal with functions
|
|
|
|
CALL32 %function_load ; Deal with the function
|
|
|
|
JMP32 %primary_expr_variable_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_variable_global
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
LOAD32_Absolute32_ebx &global_symbol_list ; Using global_symbol_list
|
|
|
|
CALL32 %sym_lookup ; sym_lookup(s, global_symbol_list)
|
|
|
|
CMPI8_EAX !0 ; IF NULL == sym_lookup(s, global_symbol_list)
|
|
|
|
JE32 %primary_expr_variable_error ; Give up
|
|
|
|
|
|
|
|
;; Deal with globals
|
|
|
|
CALL32 %global_load ; Collect that global
|
|
|
|
JMP32 %primary_expr_variable_done ; Be done
|
|
|
|
|
|
|
|
:primary_expr_variable_error
|
|
|
|
LOADI32_EAX %2 ; Using standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
; CALL32 %line_error ; Write useful debug info
|
|
|
|
COPY_ECX_to_EAX ; put S in the right place
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_variable_string_0 ; Ending string
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
|
|
|
:primary_expr_variable_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:primary_expr_variable_string_0 " is not a defined symbol
|
|
|
|
"
|
|
|
|
:primary_expr_variable_string_1 "
|
|
|
|
"
|
|
|
|
:primary_expr_variable_string_2 "LOAD_IMMEDIATE_eax %"
|
|
|
|
|
|
|
|
|
|
|
|
;; function_call function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* S in EAX and int BOOL in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Builds stack frames before and tears them down after function calls
|
|
|
|
;; Uses ECX for char* S, EDX for int BOOL, ESI for PASSED
|
|
|
|
:function_call
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_ESI ; Protect ESI
|
|
|
|
COPY_EAX_to_ECX ; Put S in place
|
|
|
|
COPY_EBX_to_EDX ; Put BOOL in place
|
|
|
|
LOADI32_ESI %0 ; PASSED = 0
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_0 ; Using "ERROR in process_expression_list\nNo ( was found\n"
|
|
|
|
LOADI32_EBX &open_paren ; Using "("
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_1 ; Using "PUSH_edi\t# Prevent overwriting in recursion\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_2 ; Using "PUSH_ebp\t# Protect the old base pointer\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_3 ; Using "COPY_esp_to_edi\t# Copy new base pointer\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !41 ; IF global_token->S[0] == ")"
|
|
|
|
JE32 %function_call_gen_done ; Then no arguments to send
|
|
|
|
|
|
|
|
;; looks like we have arguments to collect
|
|
|
|
CALL32 %expression ; Collect the argument
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_4 ; Using "PUSH_eax\t#_process_expression1\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
LOADI32_ESI %1 ; PASSED = 1
|
|
|
|
|
|
|
|
:function_call_gen_iter
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !44 ; IF global_token->S[0] == ","
|
|
|
|
JNE32 %function_call_gen_done ; Otherwise we are done
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
CALL32 %expression ; Collect the argument
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_5 ; Using "PUSH_eax\t#_process_expression2\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
ADDI8_ESI !1 ; PASSED = PASSED + 1
|
|
|
|
JMP32 %function_call_gen_iter ; Keep trying
|
|
|
|
|
|
|
|
:function_call_gen_done
|
|
|
|
;; All is collected
|
|
|
|
LOADI32_EAX &function_call_string_6 ; Using "ERROR in process_expression_list\nNo ) was found\n"
|
|
|
|
LOADI32_EBX &close_paren ; Using ")"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
CMPI8_EDX !0 ; IF(BOOL == TRUE)
|
|
|
|
JNE32 %function_call_static ; Otherwise it is a static call
|
|
|
|
|
|
|
|
;; Deal with a passed function pointer
|
|
|
|
LOADI32_EAX &function_call_string_7 ; Using "LOAD_BASE_ADDRESS_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_8 ; Using "\nLOAD_INTEGER\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_9 ; Using "COPY_edi_to_ebp\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_10 ; Using "CALL_eax\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_13 ; Using "POP_ebx\t# _process_expression_locals\n"
|
|
|
|
JMP32 %function_call_cleanup ; Clean up
|
|
|
|
|
|
|
|
:function_call_static
|
|
|
|
;; Deal with fixed function name
|
|
|
|
LOADI32_EAX &function_call_string_9 ; Using "COPY_edi_to_ebp\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_11 ; Using "CALL_IMMEDIATE %FUNCTION_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Using S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_12 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_13 ; Using "POP_ebx\t# _process_expression_locals\n"
|
|
|
|
|
|
|
|
:function_call_cleanup
|
|
|
|
CMPI8_ESI !0 ; IF PASSED > 0
|
|
|
|
JLE32 %function_call_done ; Otherwise be done
|
|
|
|
|
|
|
|
;; The desired string is already in EAX
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
SUBI8_ESI !1 ; PASSED = PASSED - 1
|
|
|
|
JMP32 %function_call_cleanup ; Keep going
|
|
|
|
|
|
|
|
:function_call_done
|
|
|
|
LOADI32_EAX &function_call_string_14 ; Using "POP_ebp\t# Restore old base pointer\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_call_string_15 ; Using "POP_edi\t# Prevent overwrite\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
POP_ESI ; Restore ESI
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:function_call_string_0 "ERROR in process_expression_list
|
|
|
|
No ( was found
|
|
|
|
"
|
|
|
|
:function_call_string_1 "PUSH_edi # Prevent overwriting in recursion
|
|
|
|
"
|
|
|
|
:function_call_string_2 "PUSH_ebp # Protect the old base pointer
|
|
|
|
"
|
|
|
|
:function_call_string_3 "COPY_esp_to_edi # Copy new base pointer
|
|
|
|
"
|
|
|
|
:function_call_string_4 "PUSH_eax #_process_expression1
|
|
|
|
"
|
|
|
|
:function_call_string_5 "PUSH_eax #_process_expression2
|
|
|
|
"
|
|
|
|
:function_call_string_6 "ERROR in process_expression_list
|
|
|
|
No ) was found
|
|
|
|
"
|
|
|
|
:function_call_string_7 "LOAD_BASE_ADDRESS_eax %"
|
|
|
|
:function_call_string_8 "
|
|
|
|
LOAD_INTEGER
|
|
|
|
"
|
|
|
|
:function_call_string_9 "COPY_edi_to_ebp
|
|
|
|
"
|
|
|
|
:function_call_string_10 "CALL_eax
|
|
|
|
"
|
|
|
|
:function_call_string_11 "CALL_IMMEDIATE %FUNCTION_"
|
|
|
|
:function_call_string_12 "
|
|
|
|
"
|
|
|
|
:function_call_string_13 "POP_ebx # _process_expression_locals
|
|
|
|
"
|
|
|
|
:function_call_string_14 "POP_ebp # Restore old base pointer
|
|
|
|
"
|
|
|
|
:function_call_string_15 "POP_edi # Prevent overwrite
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; variable_load function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct token_list* A in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Updates output and current_target
|
|
|
|
;; Uses ECX for A
|
|
|
|
:variable_load
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; Protect A
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_paren ; Using "("
|
|
|
|
CALL32 %match ; IF global_token->S == "("
|
|
|
|
CMPI8_EAX !0 ; Then it might be a function
|
|
|
|
JNE32 %variable_load_regular ; Otherwise it is regular
|
|
|
|
|
|
|
|
LOAD32_EBX_from_ECX_Immediate8 !12 ; A->TYPE
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !24 ; A->TYPE->NAME
|
|
|
|
LOADI32_EAX &type_function_name ; Using "FUNCTION"
|
|
|
|
CALL32 %match ; IF A->TYPE->NAME == "FUNCTION"
|
|
|
|
CMPI8_EAX !0 ; Then it must be a function
|
|
|
|
JNE32 %variable_load_regular ; otherwise just another regular
|
|
|
|
|
|
|
|
;; deal with function
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !16 ; A->DEPTH
|
|
|
|
CALL32 %numerate_number ; Convert to string
|
|
|
|
LOADI32_EBX %0 ; pass 0 for true
|
|
|
|
CALL32 %function_call ; Create the function call
|
|
|
|
JMP32 %variable_load_done ; Be done
|
|
|
|
|
|
|
|
:variable_load_regular
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !12 ; A->TYPE
|
|
|
|
STORE32_Absolute32_eax ¤t_target ; current_target = A->TYPE
|
|
|
|
|
|
|
|
LOADI32_EAX &variable_load_string_0 ; Using "LOAD_BASE_ADDRESS_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !16 ; A->DEPTH
|
|
|
|
CALL32 %numerate_number ; Convert to string
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &variable_load_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
;; Check for special case of assignment
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; Using "="
|
|
|
|
CALL32 %match ; IF global_token->S == "="
|
|
|
|
CMPI8_EAX !0 ; Then we skip loading
|
|
|
|
JE32 %variable_load_done ; And be done
|
|
|
|
|
|
|
|
;; Deal with common case
|
|
|
|
LOADI32_EAX &variable_load_string_2 ; Using "LOAD_INTEGER\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:variable_load_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:variable_load_string_0 "LOAD_BASE_ADDRESS_eax %"
|
|
|
|
:variable_load_string_1 "
|
|
|
|
"
|
|
|
|
:variable_load_string_2 "LOAD_INTEGER
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; function_load function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct token_list* a in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses ECX to hold A->S
|
|
|
|
:function_load
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; A->S
|
|
|
|
COPY_EAX_to_ECX ; Protect A->S
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_paren ; Using "("
|
|
|
|
CALL32 %match ; IF global_token->S == "("
|
|
|
|
CMPI8_EAX !0 ; The we need to do a function call
|
|
|
|
JNE32 %function_load_regular ; Otherwise just load it's address
|
|
|
|
|
|
|
|
;; Deal with function call
|
|
|
|
COPY_ECX_to_EAX ; Using A->S
|
|
|
|
LOADI32_EBX %1 ; Using FALSE
|
|
|
|
CALL32 %function_call ; Deal with it
|
|
|
|
JMP32 %function_load_done ; Be done
|
|
|
|
|
|
|
|
:function_load_regular
|
|
|
|
LOADI32_EAX &function_load_string_0 ; Using "LOAD_IMMEDIATE_eax &FUNCTION_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Using A->S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &function_load_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:function_load_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:function_load_string_0 "LOAD_IMMEDIATE_eax &FUNCTION_"
|
|
|
|
:function_load_string_1 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; global_load function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct token_list* A in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses EBX to hold A->S
|
|
|
|
:global_load
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
COPY_EAX_to_EBX ; Set as A
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; Set as A->S
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !12 ; A->TYPE
|
|
|
|
STORE32_Absolute32_eax ¤t_target ; current_target = A->TYPE
|
|
|
|
|
|
|
|
LOADI32_EAX &global_load_string_0 ; Using "LOAD_IMMEDIATE_eax &GLOBAL_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_EBX_to_EAX ; Using A->S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &global_load_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &equal ; "="
|
|
|
|
CALL32 %match ; IF global_token->S == "="
|
|
|
|
CMPI8_EAX !0 ; We need to skip for assignment
|
|
|
|
JE32 %global_load_done ; and be done
|
|
|
|
|
|
|
|
;; Otherwise we are loading the contents
|
|
|
|
LOADI32_EAX &global_load_string_2 ; Using "LOAD_INTEGER\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
:global_load_done
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:global_load_string_0 "LOAD_IMMEDIATE_eax &GLOBAL_"
|
|
|
|
:global_load_string_1 "
|
|
|
|
"
|
|
|
|
:global_load_string_2 "LOAD_INTEGER
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; sym_lookup function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* S in EAX and struct token_list* symbol_list in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Uses I->S in EAX, S in EBX and I in ECX
|
|
|
|
;; Returns match or NULL
|
|
|
|
:sym_lookup
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EBX_to_ECX ; I = symbol_list
|
|
|
|
COPY_EAX_to_EBX ; Put S in the right place
|
|
|
|
:sym_lookup_iter
|
|
|
|
CMPI8_ECX !0 ; IF NULL == I
|
|
|
|
JE32 %sym_lookup_done ; We failed to find match
|
|
|
|
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !8 ; Using I->S
|
|
|
|
CALL32 %match ; IF I->S == S
|
|
|
|
CMPI8_EAX !0 ; then be done
|
|
|
|
JE32 %sym_lookup_done ; Failed
|
|
|
|
|
|
|
|
LOAD32_ECX_from_ECX ; I = I->NEXT
|
|
|
|
JMP32 %sym_lookup_iter ; otherwise keep looping
|
|
|
|
|
|
|
|
:sym_lookup_done
|
|
|
|
COPY_ECX_to_EAX ; Return I
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr_number function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Simply uses current global token to update output and then steps to next global_token
|
|
|
|
:primary_expr_number
|
|
|
|
LOADI32_EAX &primary_expr_number_string_0 ; Using "LOAD_IMMEDIATE_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_number_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:primary_expr_number_string_0 "LOAD_IMMEDIATE_eax %"
|
|
|
|
:primary_expr_number_string_1 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr_string function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; creates entries for string and calls to generate string output
|
|
|
|
;; uses ECX for char* number_string
|
|
|
|
:primary_expr_string
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_ebx ¤t_count ; Using current_count
|
|
|
|
COPY_EBX_to_EAX ; And putting it in the right place
|
|
|
|
CALL32 %numerate_number ; Get the string
|
|
|
|
COPY_EAX_to_ECX ; protect number_string
|
|
|
|
|
|
|
|
ADDI8_EBX !1 ; current_count + 1
|
|
|
|
STORE32_Absolute32_ebx ¤t_count ; current_count = current_count + 1
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_string_string_0 ; Using "LOAD_IMMEDIATE_eax &STRING_"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
COPY_ECX_to_EBX ; Put number_string in the right place
|
|
|
|
CALL32 %uniqueID_out ; Make it unique
|
|
|
|
|
|
|
|
;; Generate the target
|
|
|
|
LOADI32_EAX &primary_expr_string_string_1 ; Using ":STRING_"
|
|
|
|
LOAD32_Absolute32_ebx &strings_list ; Using strings_list
|
|
|
|
CALL32 %emit ; Emit it
|
|
|
|
COPY_EAX_to_EBX ; put new strings_list in place
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &function ; Using function
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; function->S
|
|
|
|
CALL32 %uniqueID ; Make it unique
|
|
|
|
COPY_EAX_to_EBX ; put new strings_list in place
|
|
|
|
|
|
|
|
;; Parse the string
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %parse_string ; convert to useful form
|
|
|
|
CALL32 %emit ; Emit it
|
|
|
|
STORE32_Absolute32_eax &strings_list ; Update Strings _list
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:primary_expr_string_string_0 "LOAD_IMMEDIATE_eax &STRING_"
|
|
|
|
:primary_expr_string_string_1 ":STRING_"
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr_char function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Updates output_list using global_token
|
|
|
|
:primary_expr_char
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOADI32_EAX &primary_expr_char_string_0 ; Using "LOAD_IMMEDIATE_eax %"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
ADDI8_EAX !1 ; global_token->S + 1
|
|
|
|
CALL32 %escape_lookup ; Get the char
|
|
|
|
CALL32 %numerate_number ; Convert to string
|
|
|
|
CALL32 %emit_out ; emit it
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_char_string_1 ; Using "\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:primary_expr_char_string_0 "LOAD_IMMEDIATE_eax %"
|
|
|
|
:primary_expr_char_string_1 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; primary_expr_failure function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Does not return but aborts hard
|
|
|
|
;; Complains about the bad input
|
|
|
|
:primary_expr_failure
|
|
|
|
; CALL32 %line_error ; Get line of issue
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
2019-10-23 20:04:14 +01:00
|
|
|
LOADI32_EAX &primary_expr_failure_string_0 ; Using "Received "
|
2019-06-23 22:52:38 +01:00
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
LOADI32_EAX &primary_expr_failure_string_1 ; Using " in primary_expr\n"
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
2019-10-23 20:04:14 +01:00
|
|
|
:primary_expr_failure_string_0 "Received "
|
2019-06-23 22:52:38 +01:00
|
|
|
:primary_expr_failure_string_1 " in primary_expr
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; general_recursion function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives FUNCTION F in EAX, char* S in EBX, char* name in ECX and FUNCTION iterate in EDX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses ECX for char* S, EDX for FUNCTION iterate and EBP for FUNCTION F
|
|
|
|
;; But generally recurses a shitload
|
|
|
|
:general_recursion
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_EBP ; Protect EBP
|
|
|
|
COPY_EAX_to_EBP ; Protect F
|
|
|
|
COPY_ECX_to_EAX ; Put name in the right place
|
|
|
|
COPY_EBX_to_ECX ; Protect S
|
|
|
|
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %match ; IF match(name, global_token->s)
|
|
|
|
CMPI8_EAX !0 ; If true we do
|
|
|
|
JNE32 %general_recursion_done ; Otherwise skip it
|
|
|
|
|
|
|
|
;; Deal with the recursion
|
|
|
|
COPY_EBP_to_EAX ; Put F in the right place
|
|
|
|
CALL32 %common_recursion ; Recurse
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Put S in the right place
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
COPY_EDX_to_EAX ; Put iterate in the right place
|
|
|
|
CALL_EAX ; Down the rabbit hole
|
|
|
|
|
|
|
|
:general_recursion_done
|
|
|
|
POP_EBP ; Restore EBP
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; promote_type function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct type* a in EAX and struct type* b in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns the most recent type in EAX
|
|
|
|
;; Uses EAX for struct type* I, ECX for struct type* A and EDX for struct type* B
|
|
|
|
:promote_type
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
CMPI8_EBX !0 ; IF NULL == A
|
|
|
|
JE32 %promote_type_done ; Just return A
|
|
|
|
|
|
|
|
COPY_EAX_to_ECX ; Put A in place
|
|
|
|
COPY_EBX_to_EDX ; Put B in place
|
|
|
|
COPY_EBX_to_EAX ; IF NULL == A
|
|
|
|
CMPI8_ECX !0 ; Then we just return B
|
|
|
|
JE32 %promote_type_done ; Be done
|
|
|
|
|
|
|
|
;; Looks like we need to walk the list
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !24 ; A->NAME
|
|
|
|
LOAD32_EDX_from_EDX_Immediate8 !24 ; B->NAME
|
|
|
|
LOAD32_Absolute32_eax &global_types ; I = global_types
|
|
|
|
:promote_type_iter
|
|
|
|
CMPI8_EAX !0 ; IF NULL == I
|
|
|
|
JE32 %promote_type_done ; Just be done
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !24 ; I->NAME
|
|
|
|
CMP_ECX_EBX ; IF(A->NAME == I->NAME)
|
|
|
|
JE32 %promote_type_done ; Be done
|
|
|
|
|
|
|
|
CMP_EBX_EDX ; IF(B->NAME == I->NAME)
|
|
|
|
JE32 %promote_type_done ; Be done
|
|
|
|
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !12 ; I->INDIRECT
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !24 ; I->INDIRECT->NAME
|
|
|
|
|
|
|
|
CMP_ECX_EBX ; IF(A->NAME == I->INDIRECT->NAME)
|
|
|
|
JE32 %promote_type_done ; Be done
|
|
|
|
|
|
|
|
CMP_EBX_EDX ; IF(B->NAME == I->INDIRECT->NAME)
|
|
|
|
JE32 %promote_type_done ; Be done
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX ; I = I->NEXT
|
|
|
|
JMP32 %promote_type_iter ; Keep going
|
|
|
|
|
|
|
|
:promote_type_done
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; common_recursion function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives FUNCTION F in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns Nothing
|
|
|
|
;; Walks global_token list and update output_list
|
|
|
|
;; Updates current_target
|
|
|
|
;; Uses EBX to hold FUNCTION F and struct type* last_type
|
|
|
|
:common_recursion
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
COPY_EAX_to_EBX ; Put FUNCTION F safely out of the way
|
|
|
|
LOADI32_EAX &common_recursion_string_0 ; Using "PUSH_eax\t#_common_recursion\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
COPY_EBX_to_EAX ; Prepare for function call
|
|
|
|
LOAD32_Absolute32_ebx ¤t_target ; Get last type
|
|
|
|
CALL_EAX ; F();
|
|
|
|
LOAD32_Absolute32_eax ¤t_target ; Get current_target
|
|
|
|
CALL32 %promote_type ; get the right type
|
|
|
|
STORE32_Absolute32_eax ¤t_target ; Set new current_target
|
|
|
|
|
|
|
|
LOADI32_EAX &common_recursion_string_1 ; Using "POP_ebx\t# _common_recursion\n"
|
|
|
|
CALL32 %emit_out ; Emit it
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:common_recursion_string_0 "PUSH_eax #_common_recursion
|
|
|
|
"
|
|
|
|
:common_recursion_string_1 "POP_ebx # _common_recursion
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; require_match function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* message in EAX and char* required in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses ECX to hold message and updates global_token
|
|
|
|
:require_match
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; put the message somewhere safe
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %match ; IF required == global_token->S
|
|
|
|
CMPI8_EAX !0 ; we are fine
|
|
|
|
JE32 %require_match_good ; otherwise pain
|
|
|
|
|
|
|
|
;; Deal will bad times
|
|
|
|
; CALL32 %line_error ; Tell user what went wrong
|
|
|
|
LOADI32_EAX %2 ; Using standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
COPY_ECX_to_EAX ; using our message
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
JMP32 %Exit_Failure ; Abort HARD
|
|
|
|
|
|
|
|
:require_match_good
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->next
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->next
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; uniqueID Function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char*S in EAX, struct token_list* l in EBX snd char* num in ECX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns updated struct token_list* L in EAX
|
|
|
|
:uniqueID
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
CALL32 %emit ; emit(s, l)
|
|
|
|
COPY_EAX_to_EBX ; Put L in correct place
|
|
|
|
LOADI32_EAX &underline ; Usinf "_"
|
|
|
|
CALL32 %emit ; emit("_", l)
|
|
|
|
COPY_EAX_to_EBX ; Put L in correct place
|
|
|
|
COPY_ECX_to_EAX ; Put num in correct place
|
|
|
|
CALL32 %emit ; emit(num, l)
|
|
|
|
COPY_EAX_to_EBX ; Put L in correct place
|
|
|
|
LOADI32_EAX &uniqueID_string_0 ; Using "\n"
|
|
|
|
CALL32 %emit ; emit("\n", l)
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:uniqueID_string_0 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; uniqueID_out function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* S in EAX and char* num in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
:uniqueID_out
|
|
|
|
PUSH_EAX ; Protect EAX
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EBX_to_ECX ; Put num in right spot
|
|
|
|
LOAD32_Absolute32_ebx &output_list ; Using output_list
|
|
|
|
CALL32 %uniqueID ; Get updated list
|
|
|
|
STORE32_Absolute32_eax &output_list ; output_list = uniqueID(s, output_list, num)
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
POP_EAX ; Restore EAX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; emit_out function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* S in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Updates output_list
|
|
|
|
;; MUST NOT ALTER REGISTERS
|
|
|
|
:emit_out
|
|
|
|
PUSH_EAX ; Protect EAX
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
LOAD32_Absolute32_ebx &output_list ; Using output_list
|
|
|
|
CALL32 %emit ; emit it
|
|
|
|
STORE32_Absolute32_eax &output_list ; update it
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
POP_EAX ; Restore EAX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; emit function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char *s in EAX and struct token_list* head in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns struct token_list* T in EAX
|
|
|
|
:emit
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; put S out of the way
|
|
|
|
LOADI32_EAX %20 ; sizeof(struct token_list)
|
|
|
|
CALL32 %malloc ; get T
|
|
|
|
STORE32_EBX_into_EAX ; t->next = head;
|
|
|
|
STORE32_ECX_into_EAX_Immediate8 !8 ; t->s = s;
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; escape_lookup function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* c in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns integer value of char in EAX
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Aborts hard if unknown escape is received
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Uses ECX to hold char* C
|
|
|
|
:escape_lookup
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; Put char* C in safe place
|
|
|
|
LOAD8_al_from_ECX ; Load c[0]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
CMPI8_EAX !92 ; If '\\' != c[0]
|
|
|
|
JNE32 %escape_lookup_done ; Be done
|
|
|
|
|
|
|
|
COPY_ECX_to_EBX ; Prepare for walk
|
|
|
|
ADDI8_EBX !1 ; increment
|
|
|
|
LOAD8_bl_from_EBX ; load c[1]
|
|
|
|
MOVZX_bl ; make it useful
|
|
|
|
|
|
|
|
CMPI8_EBX !120 ; Check if \x??
|
|
|
|
JE32 %escape_lookup_hex ; Deal with hex
|
|
|
|
|
|
|
|
;; Deal with \? escapes
|
|
|
|
LOADI32_EAX %10 ; Guess "\n"
|
|
|
|
CMPI8_EBX !110 ; If n
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
|
|
|
|
LOADI32_EAX %9 ; Guess "\t"
|
|
|
|
CMPI8_EBX !116 ; If t
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
|
|
|
|
COPY_EBX_to_EAX ; "\\", "'" and '\"' all encode as themselves
|
|
|
|
CMPI8_EBX !92 ; If "\\"
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
CMPI8_EBX !39 ; IF "'"
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
CMPI8_EBX !34 ; IF '\"'
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
|
|
|
|
LOADI32_EAX %13 ; Guess "\r"
|
|
|
|
CMPI8_EBX !114 ; IF r
|
|
|
|
JE32 %escape_lookup_done ; Be done
|
|
|
|
|
|
|
|
;; Looks like we have no clue what we are doing
|
|
|
|
;; Aborting hard
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
2019-10-23 20:04:14 +01:00
|
|
|
LOADI32_EAX &escape_lookup_string_0 ; Using "Unknown escape received: "
|
2019-06-23 22:52:38 +01:00
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
COPY_ECX_to_EAX ; Using C
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOADI32_EAX &escape_lookup_string_1 ; Using " Unable to process\n"
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
|
|
|
:escape_lookup_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:escape_lookup_hex
|
|
|
|
;; Give up on C and just assume they know what they are doing
|
|
|
|
ADDI8_ECX !2 ; increment
|
|
|
|
LOAD8_al_from_ECX ; c[2]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
ADDI8_ECX !1 ; increment
|
|
|
|
CALL32 %char2hex ; Get the hex value
|
|
|
|
SALI8_EAX !4 ; c << 4
|
|
|
|
LOAD8_bl_from_ECX ; c[3]
|
|
|
|
MOVZX_bl ; make it useful
|
|
|
|
SWAP_EAX_EBX ; protect c << 4
|
|
|
|
CALL32 %char2hex ; Get the hex value
|
|
|
|
ADD_ebx_into_eax ; hex(c[2]) << 4 + hex(c[3])
|
|
|
|
JMP32 %escape_lookup_done ; Be done
|
|
|
|
|
2019-10-23 20:04:14 +01:00
|
|
|
:escape_lookup_string_0 "Unknown escape received: "
|
2019-06-23 22:52:38 +01:00
|
|
|
:escape_lookup_string_1 " Unable to process
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; char2hex function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns hex or aborts hard
|
|
|
|
:char2hex
|
|
|
|
SUBI8_EAX !48 ; Try 0-9
|
|
|
|
CMPI8_EAX !10 ; Otherwise fun times
|
|
|
|
JL32 %char2hex_done ; Be done
|
|
|
|
|
|
|
|
;; Deal with A-F
|
|
|
|
ANDI32_EAX %0xDF ; Unset High bit turning a-f into A-F
|
|
|
|
SUBI8_EAX !7 ; Shift down into position
|
|
|
|
CMPI8_EAX !10 ; Everything below A is bad
|
|
|
|
JL32 %char2hex_fail ; And should fail
|
|
|
|
CMPI8_EAX !16 ; Make sure we are below F
|
|
|
|
JL32 %char2hex_done ; If so be done
|
|
|
|
|
|
|
|
:char2hex_fail
|
|
|
|
;; Time to fail hard
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
LOADI32_EAX &char2hex_string_0 ; Using "Tried to print non-hex number\n"
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
|
|
|
:char2hex_done
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:char2hex_string_0 "Tried to print non-hex number
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; parse_string function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* string in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns cleaned up string
|
|
|
|
;; Protects char* string in EBX
|
|
|
|
:parse_string
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
COPY_EAX_to_EBX ; Protect char* string
|
|
|
|
CALL32 %weird ; Determine if we have a weird string
|
|
|
|
CMPI8_EAX !0 ; If weird
|
|
|
|
JE32 %parse_string_weird ; Deal with it
|
|
|
|
|
|
|
|
;; Dealing with regular string
|
|
|
|
COPY_EBX_to_EAX ; Passing Char* string
|
|
|
|
CALL32 %collect_regular_string ; Collect it
|
|
|
|
JMP32 %parse_string_done ; Be done
|
|
|
|
|
|
|
|
:parse_string_weird
|
|
|
|
COPY_EBX_to_EAX ; Passing Char* string
|
|
|
|
CALL32 %collect_weird_string ; Collect it
|
|
|
|
|
|
|
|
:parse_string_done
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; weird function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* string in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns true(0) or false(1) in EAX
|
|
|
|
;; Uses ECX to hold char* string
|
|
|
|
:weird
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EAX_to_ECX ; Place string in safe place
|
|
|
|
ADDI8_ECX !1 ; increment past the '\"'
|
|
|
|
:weird_reset
|
|
|
|
LOAD8_al_from_ECX ; Load a char
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !0 ; IF NULL == C
|
|
|
|
JE32 %weird_false ; Nothing weird found
|
|
|
|
|
|
|
|
CMPI8_EAX !92 ; IF '\\'
|
|
|
|
JNE32 %weird_escaped ; Deal with escaping
|
|
|
|
|
|
|
|
;; Deal with escape
|
|
|
|
COPY_ECX_to_EAX ; We are passing the string
|
|
|
|
CALL32 %escape_lookup ; to look it up
|
|
|
|
|
|
|
|
ADDI8_ECX !1 ; string = string + 1
|
|
|
|
LOAD8_bl_from_ECX ; get string[1]
|
|
|
|
MOVZX_bl ; make it useful
|
|
|
|
CMPI8_EBX !120 ; IF 'x' == string[1]
|
|
|
|
JNE32 %weird_escaped ; otherwise skip the gap
|
|
|
|
|
|
|
|
ADDI8_ECX !2 ; string = string + 2
|
|
|
|
|
|
|
|
:weird_escaped
|
|
|
|
PUSH_EAX ; Protect C in case we need it
|
|
|
|
LOADI32_EBX &weird_string_0 ; Use "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
|
|
CALL32 %In_Set ; To find if weird
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
POP_EAX ; Restore C
|
|
|
|
JNE32 %weird_true ; Then not weird
|
|
|
|
|
|
|
|
ADDI8_ECX !1 ; string = string + 1
|
|
|
|
|
|
|
|
;; Last chance for weird
|
|
|
|
LOADI32_EBX &weird_string_1 ; Use "\t\n\r "
|
|
|
|
CALL32 %In_Set ; Check for special case
|
|
|
|
CMPI8_EAX !1 ; IF TRUE
|
|
|
|
JNE32 %weird_reset ; Otherwise not in the special case
|
|
|
|
|
|
|
|
;; Deal with possible special case
|
|
|
|
LOAD8_al_from_ECX ; Load string[1]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !58 ; IF string[1] == ":"
|
|
|
|
JE32 %weird_true ; Then we hit the special case
|
|
|
|
JMP32 %weird_reset ; Keep trying
|
|
|
|
|
|
|
|
:weird_done
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:weird_true
|
|
|
|
LOADI32_EAX %0 ; Return true
|
|
|
|
JMP32 %weird_done ; Be done
|
|
|
|
|
|
|
|
:weird_false
|
|
|
|
LOADI32_EAX %1 ; Return false
|
|
|
|
JMP32 %weird_done ; Be done
|
|
|
|
|
|
|
|
:weird_string_0 "
|
|
|
|
!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
|
|
|
:weird_string_1 '09 0A 0D 20' ; "\t\n\r "
|
|
|
|
|
|
|
|
|
|
|
|
;; collect_regular_string function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* string in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Malloc and creates new string to return in EAX
|
|
|
|
;; Uses ECX for return string and EDX for passed string
|
|
|
|
:collect_regular_string
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_EDX ; Protect our passed string
|
|
|
|
LOADI32_EAX %256 ; We need 256bytes of storage
|
|
|
|
CALL32 %malloc ; Get our new pointer
|
|
|
|
COPY_EAX_to_ECX ; put it in place
|
|
|
|
PUSH_EAX ; protect until done
|
|
|
|
:collect_regular_string_reset
|
|
|
|
LOAD8_al_from_EDX ; string[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !0 ; See if we hit the end
|
|
|
|
JE32 %collect_regular_string_done ; And be done
|
|
|
|
|
|
|
|
CMPI8_EAX !92 ; IF string[0] == '\\'
|
|
|
|
JE32 %collect_regular_string_escaped ; Deal with that mess
|
|
|
|
|
|
|
|
;; deal with boring char
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = string[0]
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
JMP32 %collect_regular_string_reset ; And keep going
|
|
|
|
|
|
|
|
:collect_regular_string_escaped
|
|
|
|
COPY_EDX_to_EAX ; Using string
|
|
|
|
CALL32 %escape_lookup ; Get the char
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = escape_lookup(string)
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
LOAD8_al_from_EDX ; string[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
CMPI8_EAX !120 ; IF 'x' == string[1]
|
|
|
|
JNE32 %collect_regular_string_reset ; Otherwise keep going
|
|
|
|
|
|
|
|
ADDI8_EDX !2 ; Increment it
|
|
|
|
JMP32 %collect_regular_string_reset ; Keep going
|
|
|
|
|
|
|
|
:collect_regular_string_done
|
|
|
|
LOADI32_EAX %34 ; Using '\"'
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = '\"'
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
LOADI32_EAX %10 ; Using "\n"
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = '\n'
|
|
|
|
POP_EAX ; Return our new string
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; collect_weird_string function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* string in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Mallocs and returns char* hold in EAX
|
|
|
|
;; Uses ECX for char* hold and EDX for char* string
|
|
|
|
:collect_weird_string
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_EDX ; Protect our passed string
|
|
|
|
LOADI32_EAX %512 ; We need 512bytes of storage
|
|
|
|
CALL32 %malloc ; Get our new pointer
|
|
|
|
COPY_EAX_to_ECX ; put it in place
|
|
|
|
PUSH_EAX ; protect until done
|
|
|
|
|
|
|
|
LOADI32_EAX %39 ; Using "'"
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = "'"
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
:collect_weird_string_reset
|
|
|
|
LOAD8_al_from_EDX ; Read a byte
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !0 ; IF NULL == string[0]
|
|
|
|
JE32 %collect_weird_string_done ; Be done
|
|
|
|
|
|
|
|
LOADI32_EAX %32 ; Using ' '
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = ' '
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
|
|
|
|
COPY_EDX_to_EAX ; Using string
|
|
|
|
CALL32 %escape_lookup ; Get the char
|
|
|
|
CALL32 %hex8 ; Update ECX
|
|
|
|
|
|
|
|
LOAD8_al_from_EDX ; Read a byte
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
CMPI8_EAX !92 ; IF string[0] == '\\'
|
|
|
|
JNE32 %collect_weird_string_reset ; Otherwise keep going
|
|
|
|
|
|
|
|
LOAD8_al_from_EDX ; Read a byte
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
ADDI8_EDX !1 ; Increment it
|
|
|
|
CMPI8_EAX !120 ; IF 'x' == string[1]
|
|
|
|
JNE32 %collect_weird_string_reset ; Otherwise keep going
|
|
|
|
|
|
|
|
ADDI8_EDX !2 ; Increment it
|
|
|
|
JMP32 %collect_weird_string_reset ; Keep going
|
|
|
|
|
|
|
|
:collect_weird_string_done
|
|
|
|
LOADI32_EAX %32 ; Using ' '
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = ' '
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
LOADI32_EAX %48 ; Using '0'
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = '0'
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = '0'
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
LOADI32_EAX %39 ; Using "'"
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = "'"
|
|
|
|
ADDI8_ECX !1 ; Increment it
|
|
|
|
LOADI32_EAX %10 ; Using "\n"
|
|
|
|
STORE8_al_into_Address_ECX ; hold_string[index] = '\n'
|
|
|
|
POP_EAX ; Return our new string
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; HEX to ascii routine
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives INT in EAX and CHAR* in ECX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Stores ascii of INT in CHAR*
|
|
|
|
;; Returns only modifying EAX and ECX
|
|
|
|
:hex8
|
|
|
|
PUSH_EAX ; Protect bottom nibble
|
|
|
|
SHRI8_EAX !4 ; do high nibble first
|
|
|
|
CALL32 %hex4 ; Store it
|
|
|
|
POP_EAX ; do low nibble
|
|
|
|
:hex4
|
|
|
|
ANDI32_EAX %0xF ; isolate nibble
|
|
|
|
ADDI8_EAX !48 ; convert to ascii
|
|
|
|
CMPI8_EAX !57 ; valid digit?
|
|
|
|
JBE8 !hex1 ; yes
|
|
|
|
ADDI8_EAX !7 ; use alpha range
|
|
|
|
:hex1
|
|
|
|
STORE8_al_into_Address_ECX ; store result
|
|
|
|
ADDI8_ECX !1 ; next position
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; type_name function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns type_size in EAX
|
|
|
|
;; Uses ECX for STRUCT TYPE* RET
|
|
|
|
:type_name
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &struct ; Using "struct"
|
|
|
|
CALL32 %match ; IF global_token->S == "struct"
|
|
|
|
COPY_EAX_to_ECX ; Protect structure
|
|
|
|
CMPI8_EAX !0 ; need to skip over "struct"
|
|
|
|
JNE32 %type_name_native ; otherwise keep going
|
|
|
|
|
|
|
|
;; Deal with possible STRUCTs
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->next
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD32_Absolute32_ebx &global_types ; get all known types
|
|
|
|
CALL32 %lookup_type ; Find type if possible
|
|
|
|
COPY_EAX_to_ECX ; Set ret
|
|
|
|
|
|
|
|
CMPI8_EAX !0 ; IF NULL == ret
|
|
|
|
JNE32 %type_name_common ; We have to create struct
|
|
|
|
|
|
|
|
;; Create a struct
|
|
|
|
CALL32 %create_struct ; Create a new struct
|
|
|
|
LOADI32_ECX %0 ; We wish to return NULL
|
|
|
|
JMP32 %type_name_done ; be done
|
|
|
|
|
|
|
|
:type_name_native
|
|
|
|
;; Deal only with native types
|
|
|
|
COPY_EBX_to_EAX ; Put global_token->S in the right place
|
|
|
|
LOAD32_Absolute32_ebx &global_types ; get all known types
|
|
|
|
CALL32 %lookup_type ; Find the type if possible
|
|
|
|
COPY_EAX_to_ECX ; Set ret
|
|
|
|
|
|
|
|
CMPI8_EAX !0 ; IF NULL == ret
|
|
|
|
JNE32 %type_name_common ; We need to abort hard
|
|
|
|
|
|
|
|
;; Aborting hard
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
LOADI32_EAX &type_name_string_0 ; Print header
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
LOADI32_EAX &type_name_string_1 ; Print footer
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
; CALL32 %line_error ; Give details
|
|
|
|
JMP32 %Exit_Failure ; Abort
|
|
|
|
|
|
|
|
:type_name_common
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->next
|
|
|
|
|
|
|
|
:type_name_iter
|
|
|
|
LOAD32_EAX_from_EBX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
CMPI8_EAX !42 ; IF global_token->S[0] == '*'
|
|
|
|
JNE32 %type_name_done ; recurse
|
|
|
|
|
|
|
|
;; Deal with char**
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !12 ; ret = ret->indirect
|
|
|
|
LOAD32_Absolute32_ebx &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EBX ; global_token->next
|
|
|
|
STORE32_Absolute32_ebx &global_token ; global_token = global_token->next
|
|
|
|
JMP32 %type_name_iter ; keep looping
|
|
|
|
|
|
|
|
:type_name_done
|
|
|
|
COPY_ECX_to_EAX ; put ret in the right place
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:type_name_string_0 "Unknown type "
|
|
|
|
:type_name_string_1 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; lookup_type function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char* s in EAX and struct type* start in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns struct type* in EAX
|
|
|
|
;; Uses EBX for S and ECX for I
|
|
|
|
:lookup_type
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
COPY_EBX_to_ECX ; I = Start
|
|
|
|
COPY_EAX_to_EBX ; Put S in place
|
|
|
|
:lookup_type_iter
|
|
|
|
CMPI8_ECX !0 ; Check if I == NULL
|
|
|
|
JE32 %lookup_type_done ; return NULL
|
|
|
|
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !24 ; I->NAME
|
|
|
|
CALL32 %match ; Check if matching
|
|
|
|
CMPI8_EAX !0 ; IF I->NAME == S
|
|
|
|
JE32 %lookup_type_done ; return it
|
|
|
|
|
|
|
|
LOAD32_ECX_from_ECX ; Otherwise I = I->NEXT
|
|
|
|
JMP32 %lookup_type_iter ; And keep looping
|
|
|
|
|
|
|
|
:lookup_type_done
|
|
|
|
COPY_ECX_to_EAX ; return either I or NULL
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; create_struct function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns nothing
|
|
|
|
;; Uses global_token to malloc a struct's definition
|
|
|
|
;; Uses ECX for int OFFSET, EDX for struct type* head, EBP for struct type* I,
|
|
|
|
;; EDI for member_size (Which is passed) and ESI for LAST
|
|
|
|
;; EAX and EBX are used for scratch
|
|
|
|
:create_struct
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_EBP ; Protect EBP
|
|
|
|
PUSH_EDI ; Protect EDI
|
|
|
|
PUSH_ESI ; Protect ESI
|
|
|
|
LOADI32_ECX %0 ; OFFSET = 0
|
|
|
|
LOADI32_EDI %0 ; member_size = 0
|
|
|
|
|
|
|
|
LOADI32_EAX %28 ; sizeof(struct type)
|
|
|
|
CALL32 %malloc ; malloc(sizeof(struct type))
|
|
|
|
COPY_EAX_to_EDX ; Set HEAD
|
|
|
|
|
|
|
|
LOADI32_EAX %28 ; sizeof(struct type)
|
|
|
|
CALL32 %malloc ; malloc(sizeof(struct type))
|
|
|
|
COPY_EAX_to_EBP ; Set I
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
STORE32_EAX_into_EDX_Immediate8 !24 ; HEAD->NAME = global_token->S
|
|
|
|
STORE32_EAX_into_EBP_Immediate8 !24 ; I->NAME = global_token->S
|
|
|
|
|
|
|
|
STORE32_EBP_into_EDX_Immediate8 !12 ; HEAD->INDIRECT = I
|
|
|
|
STORE32_EDX_into_EBP_Immediate8 !12 ; I->INDIRECT = HEAD
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_types ; Using global_types
|
|
|
|
STORE32_EAX_into_EDX ; HEAD->NEXT = global_types
|
|
|
|
STORE32_Absolute32_edx &global_types ; global_types = HEAD
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX %4 ; Using register size
|
|
|
|
STORE32_EAX_into_EBP_Immediate8 !4 ; I->SIZE = register size
|
|
|
|
|
|
|
|
LOADI32_EAX &create_struct_string_0 ; Using "ERROR in create_struct\n Missing {\n"
|
|
|
|
LOADI32_EBX &open_curly_brace ; Using "{"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
LOADI32_ESI %0 ; LAST = NULL
|
|
|
|
|
|
|
|
:create_struct_iter
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
CMPI8_EAX !125 ; IF global_token->S[0] == "}"
|
|
|
|
JE32 %create_struct_done ; be done
|
|
|
|
|
|
|
|
;; Looks like we are adding members
|
|
|
|
;; Lets see if it is a union
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EBX &union ; Using "union"
|
|
|
|
CALL32 %match ; IF match(global_token->s, "union")
|
|
|
|
CMPI8_EAX !0 ; Deal with union
|
|
|
|
JNE32 %create_struct_single ; Otherwise deal with singles
|
|
|
|
|
|
|
|
;; Deal with union
|
|
|
|
COPY_ESI_to_EAX ; Put last in right place
|
|
|
|
COPY_ECX_to_EBX ; put offset in right place
|
|
|
|
CALL32 %build_union ; ASSEMBLE
|
|
|
|
COPY_EAX_to_ESI ; last = build_union(last, offset)
|
|
|
|
ADD_edi_into_ecx ; offset = offset + member_size
|
|
|
|
|
|
|
|
LOADI32_EAX &create_struct_string_1 ; Using "ERROR in create_struct\n Missing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
JMP32 %create_struct_iter ; keep going
|
|
|
|
|
|
|
|
:create_struct_single
|
|
|
|
;; deal with singles
|
|
|
|
COPY_ESI_to_EAX ; Put last in right place
|
|
|
|
COPY_ECX_to_EBX ; put offset in right place
|
|
|
|
CALL32 %build_member ; ASSEMBLE
|
|
|
|
COPY_EAX_to_ESI ; last = build_union(last, offset)
|
|
|
|
ADD_edi_into_ecx ; offset = offset + member_size
|
|
|
|
|
|
|
|
LOADI32_EAX &create_struct_string_1 ; Using "ERROR in create_struct\n Missing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
JMP32 %create_struct_iter ; keep going
|
|
|
|
|
|
|
|
:create_struct_done
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &create_struct_string_1 ; Using "ERROR in create_struct\n Missing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
STORE32_ECX_into_EDX_Immediate8 !4 ; HEAD->SIZE = OFFSET
|
|
|
|
STORE32_ESI_into_EDX_Immedate8 !16 ; HEAD->MEMBERS = LAST
|
|
|
|
STORE32_ESI_into_EBP_Immedate8 !16 ; I->MEMBERS = LAST
|
|
|
|
|
|
|
|
POP_ESI ; Restore ESI
|
|
|
|
POP_EDI ; Restore EDI
|
|
|
|
POP_EBP ; Restore EBP
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:create_struct_string_0 "ERROR in create_struct
|
|
|
|
Missing {
|
|
|
|
"
|
|
|
|
:create_struct_string_1 "ERROR in create_struct
|
|
|
|
Missing ;
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; lookup_member function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct type* parent in EAX and char* name in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns struct type* I in EAX
|
|
|
|
;; Uses char* NAME in EBX, ECX for struct type* I and EDX to hold parent for errors
|
|
|
|
;; Aborts hard if not found
|
|
|
|
:lookup_member
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_EDX ; Protect Parent
|
|
|
|
LOAD32_ECX_from_EAX_Immediate8 !16 ; struct type* I = parent->MEMBERS
|
|
|
|
:lookup_member_iter
|
|
|
|
CMPI8_ECX !0 ; IF I == NULL
|
|
|
|
JE32 %lookup_member_fail ; Abort HARD
|
|
|
|
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !24 ; Using I->NAME
|
|
|
|
CALL32 %match ; IF I->NAME == NAME
|
|
|
|
CMPI8_EAX !0 ; Then we have found the member
|
|
|
|
COPY_ECX_to_EAX ; Prepare for return
|
|
|
|
LOAD32_ECX_from_ECX_Immediate8 !16 ; Prepare for loop I = I->MEMBERS
|
|
|
|
JNE32 %lookup_member_iter ; Looks like we are looping
|
|
|
|
|
|
|
|
;; I is already in EAX
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:lookup_member_fail
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
LOADI32_EAX &lookup_member_string_0 ; Using "ERROR in lookup_member "
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EDX_Immediate8 !24 ; PARENT->NAME
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOADI32_EAX &arrow_string ; Using "->"
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
LOADI32_EAX &lookup_member_string_1 ; Using " does not exist\n"
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
|
|
|
|
; CALL32 %line_error ; Write useful debug info
|
|
|
|
|
|
|
|
LOADI32_EAX &lookup_member_string_2 ; Using "\n"
|
|
|
|
CALL32 %File_Print ; print it
|
|
|
|
JMP32 %Exit_Failure ; Abort Hard
|
|
|
|
|
|
|
|
:lookup_member_string_0 "ERROR in lookup_member "
|
|
|
|
:lookup_member_string_1 " does not exist
|
|
|
|
"
|
|
|
|
:lookup_member_string_2 "
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; build_member function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct type* last in EAX, int offset in EBX and global member_size in EDI
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Updates member_size in EDI and returns struct type* I in EAX
|
|
|
|
;; Uses ECX for struct type* member_type and EDX for struct type* I
|
|
|
|
:build_member
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_EDX ; Put last out of the way
|
|
|
|
LOADI32_EAX %28 ; Allocate type
|
|
|
|
CALL32 %malloc ; Get I
|
|
|
|
STORE32_EDX_into_EAX_Immediate8 !16 ; I->MEMBERS = LAST
|
|
|
|
STORE32_EBX_into_EAX_Immediate8 !8 ; I->OFFSET = OFFSET
|
|
|
|
COPY_EAX_to_EDX ; Put I in place
|
|
|
|
|
|
|
|
CALL32 %type_name ; Get member_type
|
|
|
|
COPY_EAX_to_ECX ; Put in place
|
|
|
|
STORE32_ECX_into_EDX_Immediate8 !20 ; I->TYPE = MEMBER_TYPE
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
STORE32_EBX_into_EDX_Immediate8 !24 ; I->NAME = global_token->S
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
;; Check if we have an array
|
|
|
|
LOAD32_EBX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOADI32_EAX &open_bracket ; Using "["
|
|
|
|
CALL32 %match ; IF global_token->S == "["
|
|
|
|
CMPI8_EAX !0 ; Then we have to deal with arrays in our structs
|
|
|
|
JE32 %build_member_array ; So deal with that pain
|
|
|
|
|
|
|
|
;; Deal with non-array case
|
|
|
|
LOAD32_EAX_from_ECX_Immediate8 !4 ; member_type->SIZE
|
|
|
|
STORE32_EAX_into_EDX_Immediate8 !4 ; I->SIZE = member_type->SIZE
|
|
|
|
JMP32 %build_member_done ; Be done
|
|
|
|
|
|
|
|
:build_member_array
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
CALL32 %numerate_string ; convert number
|
|
|
|
LOAD32_EBX_from_ECX_Immediate8 !20 ; member_type->TYPE
|
|
|
|
LOAD32_EBX_from_EBX_Immediate8 !4 ; member_type->TYPE->SIZE
|
|
|
|
IMUL_EAX_by_EBX ; member_type->type->size * numerate_string(global_token->s)
|
|
|
|
STORE32_EAX_into_EDX_Immediate8 !4 ; I->SIZE = member_type->type->size * numerate_string(global_token->s)
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &build_member_string_0 ; Using "Struct only supports [num] form\n"
|
|
|
|
LOADI32_EBX &close_bracket ; Using "]"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
:build_member_done
|
|
|
|
LOAD32_EDI_from_EDX_Immediate8 !4 ; MEMBER_SIZE = I->SIZE
|
|
|
|
STORE32_ECX_into_EDX_Immediate8 !20 ; I->TYPE = MEMBER_TYPE
|
|
|
|
COPY_EDX_to_EAX ; Return I
|
|
|
|
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:build_member_string_0 "Struct only supports [num] form
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; build_union function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct type* last in EAX, int offset in EBX and global member_size in EDI
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Updates member_size in EDI and returns struct type* LAST in EAX
|
|
|
|
;; Uses ECX for struct type* last, EDX for int offset, ESI for int size and EDI for int member_size
|
|
|
|
:build_union
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_ESI ; Protect ESI
|
|
|
|
COPY_EAX_to_ECX ; Put LAST in right spot
|
|
|
|
COPY_EBX_to_EDX ; Put OFFSET in right spot
|
|
|
|
LOADI32_ESI %0 ; SIZE = 0
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
LOADI32_EAX &build_union_string_0 ; Using "ERROR in build_union\nMissing {\n"
|
|
|
|
LOADI32_EBX &open_curly_brace ; Using "{"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
|
|
|
|
:build_union_iter
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX_Immediate8 !8 ; global_token->S
|
|
|
|
LOAD8_al_from_EAX ; global_token->S[0]
|
|
|
|
MOVZX_al ; make it useful
|
|
|
|
CMPI8_EAX !125 ; IF global_token->S[0] == "}"
|
|
|
|
JE32 %build_union_done ; Be done
|
|
|
|
|
|
|
|
;; Collect union member
|
|
|
|
COPY_ECX_to_EAX ; Passing LAST
|
|
|
|
COPY_EDX_to_EBX ; Passing offset
|
|
|
|
CALL32 %build_member ; build_member(last, offset)
|
|
|
|
COPY_EAX_to_ECX ; last = build_member(last, offset)
|
|
|
|
|
|
|
|
CMP_EDI_ESI ; IF member_size > size
|
|
|
|
JG32 %build_union_size ; Then update size
|
|
|
|
|
|
|
|
;; deal with member_size > size
|
|
|
|
COPY_EDI_to_ESI ; SIZE = MEMBER_SIZE
|
|
|
|
|
|
|
|
:build_union_size
|
|
|
|
LOADI32_EAX &build_union_string_1 ; Using "ERROR in build_union\nMissing ;\n"
|
|
|
|
LOADI32_EBX &semicolon ; Using ";"
|
|
|
|
CALL32 %require_match ; Make sure we have it
|
|
|
|
JMP32 %build_union_iter ; Keep going
|
|
|
|
|
|
|
|
:build_union_done
|
|
|
|
COPY_ESI_to_EDI ; MEMBER_SIZE = SIZE
|
|
|
|
|
|
|
|
LOAD32_Absolute32_eax &global_token ; Using global_token
|
|
|
|
LOAD32_EAX_from_EAX ; global_token->NEXT
|
|
|
|
STORE32_Absolute32_eax &global_token ; global_token = global_token->NEXT
|
|
|
|
|
|
|
|
COPY_ECX_to_EAX ; Return last
|
|
|
|
|
|
|
|
POP_ESI ; Restore ESI
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:build_union_string_0 "ERROR in build_union
|
|
|
|
Missing {
|
|
|
|
"
|
|
|
|
:build_union_string_1 "ERROR in build_union
|
|
|
|
Missing ;
|
|
|
|
"
|
|
|
|
|
|
|
|
|
|
|
|
;; sym_declare function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives char *s in EAX, struct type* t in EBX, and struct token_list* list in ECX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns struct token_list* in EAX
|
|
|
|
;; Uses EAX for A
|
|
|
|
:sym_declare
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_EDX ; Get char *S safely out of the way
|
|
|
|
LOADI32_EAX %20 ; Using sizeof(struct token_list)
|
|
|
|
CALL32 %malloc ; Get pointer to A
|
|
|
|
STORE32_ECX_into_EAX ; A->NEXT = LIST
|
|
|
|
STORE32_EDX_into_EAX_Immediate8 !8 ; A->S = S
|
|
|
|
STORE32_EBX_into_EAX_Immediate8 !12 ; A->TYPE = T
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; match function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives CHAR* in EAX and CHAR* in EBX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns 0 (TRUE) or 1 (FALSE) in EAX
|
|
|
|
:match
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
COPY_EAX_to_ECX ; S1 in place
|
|
|
|
COPY_EBX_to_EDX ; S2 in place
|
|
|
|
:match_Loop
|
|
|
|
LOAD8_al_from_ECX ; S1[0]
|
|
|
|
MOVZX_al ; Make it useful
|
|
|
|
LOAD8_bl_from_EDX ; S2[0]
|
|
|
|
MOVZX_bl ; Make it useful
|
|
|
|
CMP_EAX_EBX ; See if they match
|
|
|
|
JNE32 %match_False ; If not
|
|
|
|
|
|
|
|
ADDI8_ECX !1 ; S1 = S1 + 1
|
|
|
|
ADDI8_EDX !1 ; S2 = S2 + 1
|
|
|
|
CMPI8_EAX !0 ; If reached end of string
|
|
|
|
JE32 %match_Done ; Perfect match
|
|
|
|
JMP32 %match_Loop ; Otherwise keep looping
|
|
|
|
|
|
|
|
:match_False
|
|
|
|
LOADI32_EAX %1 ; Return false
|
|
|
|
:match_Done
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; numerate_number function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives an INT A in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns char* result in EAX
|
|
|
|
;; Allocates 16 bytes of memory
|
|
|
|
;; Behaves badly when given a negative number too large
|
|
|
|
;; Uses EAX for temp, EBX for DIVISOR, EDX for mod/0, ESI for result[i] and EBP for A
|
|
|
|
:numerate_number
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_ESI ; Protect ESI
|
|
|
|
PUSH_EBP ; Protect EBP
|
|
|
|
COPY_EAX_to_EBP ; Protect A
|
|
|
|
|
|
|
|
LOADI32_EAX %16 ; 16bytes
|
|
|
|
CALL32 %malloc ; Get our pointer
|
|
|
|
PUSH_EAX ; Protect our pointer
|
|
|
|
COPY_EAX_to_ESI ; put pointer in right place
|
|
|
|
LOADI32_EBX %0x3B9ACA00 ; Set divisor to largest positive number that fits in 32bits
|
|
|
|
|
|
|
|
CMPI8_EBP !0 ; Deal with 0 case
|
|
|
|
JE32 %numerate_number_ZERO ; If it is
|
|
|
|
JG32 %numerate_number_positive ; If it is positive
|
|
|
|
|
|
|
|
;; Deal with negative case
|
|
|
|
LOADI32_EAX %45 ; Using "-"
|
|
|
|
STORE8_al_into_Address_ESI ; Write it
|
|
|
|
ADDI8_ESI !1 ; increment
|
|
|
|
IMULI8_EBP !-1 ; A = A * -1
|
|
|
|
|
|
|
|
:numerate_number_positive
|
|
|
|
LOADI32_EDX %0 ; Set top to 0
|
|
|
|
COPY_EBP_to_EAX ; Using A as bottom
|
|
|
|
IDIV_EBX ; edx:eax % ebx -> edx + edx:eax / ebx -> eax [Even if we don't want it]
|
|
|
|
CMPI8_EAX !0 ; IF 0 == (a / divisor)
|
|
|
|
JNE32 %numerate_number_iter ; Clean up those leading Zeros
|
|
|
|
|
|
|
|
LOADI32_EDX %0 ; Set top to 0
|
|
|
|
COPY_EBX_to_EAX ; Using Divisor for bottom
|
|
|
|
LOADI32_EBX %10 ; Make this shit work because idiv 10 doesn't work
|
|
|
|
IDIV_EBX ; edx:eax % 10 -> edx + edx:eax / 10 -> eax [Even if we don't want it]
|
|
|
|
COPY_EAX_to_EBX ; Update divisor
|
|
|
|
JMP32 %numerate_number_positive ; Keep collecting
|
|
|
|
|
|
|
|
:numerate_number_iter
|
|
|
|
CMPI8_EBX !0 ; IF DIVISOR < 0
|
|
|
|
JLE32 %numerate_number_done ; Be done
|
|
|
|
|
|
|
|
LOADI32_EDX %0 ; Set top to 0
|
|
|
|
COPY_EBP_to_EAX ; Using A as bottom
|
|
|
|
IDIV_EBX ; edx:eax % ebx -> edx + edx:eax / ebx -> eax [Even if we don't want it]
|
|
|
|
ADDI8_EAX !48 ; ((a / divisor) + 48)
|
|
|
|
STORE8_al_into_Address_ESI ; Write it
|
|
|
|
COPY_EDX_to_EBP ; a = a % divisor
|
|
|
|
|
|
|
|
LOADI32_EDX %0 ; Set top to 0
|
|
|
|
COPY_EBX_to_EAX ; Using Divisor for bottom
|
|
|
|
LOADI32_EBX %10 ; Make this shit work because idiv 10 doesn't work
|
|
|
|
IDIV_EBX ; edx:eax % 10 -> edx + edx:eax / 10 -> eax [Even if we don't want it]
|
|
|
|
COPY_EAX_to_EBX ; Update divisor
|
|
|
|
|
|
|
|
ADDI8_ESI !1 ; increment
|
|
|
|
JMP32 %numerate_number_iter ; Keep going
|
|
|
|
|
|
|
|
:numerate_number_done
|
|
|
|
POP_EAX ; Restore our result
|
|
|
|
POP_EBP ; Restore EBP
|
|
|
|
POP_ESI ; Restore ESI
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
:numerate_number_ZERO
|
|
|
|
LOADI32_EAX %48 ; Using '0'
|
|
|
|
STORE8_al_into_Address_ESI ; Write it
|
|
|
|
ADDI8_ESI !1 ; increment
|
|
|
|
JMP32 %numerate_number_done ; Be done
|
|
|
|
|
|
|
|
|
|
|
|
;; numerate_string function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives CHAR* in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Returns value of CHAR* in EAX
|
|
|
|
;; Uses EAX for VALUE, EBX for S, ECX for CH and ESI for NEGATIVE?
|
|
|
|
:numerate_string
|
|
|
|
PUSH_EBX ; Protect EBX
|
|
|
|
PUSH_ECX ; Protect ECX
|
|
|
|
PUSH_EDX ; Protect EDX
|
|
|
|
PUSH_ESI ; Protect ESI
|
|
|
|
COPY_EAX_to_EBX ; put S in correct place
|
|
|
|
LOADI32_EAX %0 ; Initialize to Zero
|
|
|
|
:numerate_string_loop
|
|
|
|
LOAD8_cl_from_EBX_Immediate8 !1 ; S[1]
|
|
|
|
MOVZX_cl ; make it useful
|
|
|
|
CMPI8_ECX !120 ; IF 'x' == S[1]
|
|
|
|
JE32 %numerate_hex ; Deal with hex input
|
|
|
|
|
|
|
|
;; Assume decimal input
|
|
|
|
LOADI32_ESI %0 ; Assume no negation
|
|
|
|
LOAD8_cl_from_EBX ; S[0]
|
|
|
|
MOVZX_cl ; make it useful
|
|
|
|
CMPI8_ECX !45 ; IF '-' == S[0]
|
|
|
|
JNE32 %numerate_decimal ; Skip negation
|
|
|
|
|
|
|
|
LOADI32_ESI %1 ; Set FLAG
|
|
|
|
ADDI8_EBX !1 ; S = S + 1
|
|
|
|
|
|
|
|
:numerate_decimal
|
|
|
|
LOAD8_cl_from_EBX ; S[0]
|
|
|
|
MOVZX_cl ; make it useful
|
|
|
|
CMPI8_ECX !0 ; IF NULL == S[0]
|
|
|
|
JE32 %numerate_decimal_done ; We are done
|
|
|
|
|
|
|
|
IMULI8_EAX !10 ; VALUE = VALUE * 10
|
|
|
|
SUBI8_ECX !48 ; CH = CH - '0'
|
|
|
|
CMPI8_ECX !9 ; Check for illegal
|
|
|
|
JG32 %numerate_string_fail ; If CH > '9'
|
|
|
|
CMPI8_ECX !0 ; Check for illegal
|
|
|
|
JL32 %numerate_string_fail ; IF CH < 0
|
|
|
|
ADD_ecx_into_eax ; VALUE = VALUE + CH
|
|
|
|
ADDI8_EBX !1 ; S = S + 1
|
|
|
|
JMP32 %numerate_decimal ; Keep looping
|
|
|
|
|
|
|
|
:numerate_decimal_done
|
|
|
|
CMPI8_ESI !1 ; Check if need to negate
|
|
|
|
JNE32 %numerate_string_done ; Nope
|
|
|
|
|
|
|
|
IMULI8_EAX !-1 ; VALUE = VALUE * -1
|
|
|
|
JMP32 %numerate_string_done ; Done
|
|
|
|
|
|
|
|
:numerate_hex
|
|
|
|
ADDI8_EBX !2 ; S = S + 2
|
|
|
|
:numerate_hex_loop
|
|
|
|
LOAD8_cl_from_EBX ; S[0]
|
|
|
|
MOVZX_cl ; make it useful
|
|
|
|
CMPI8_ECX !0 ; IF NULL == S[0]
|
|
|
|
JE32 %numerate_string_done ; We are done
|
|
|
|
|
|
|
|
SALI8_EAX !4 ; VALUE = VALUE << 4
|
|
|
|
SUBI8_ECX !48 ; CH = CH - '0'
|
|
|
|
CMPI8_ECX !10 ; IF 10 >= CH
|
|
|
|
JL32 %numerate_hex_digit ; NO
|
|
|
|
SUBI8_ECX !7 ; Push A-F into range
|
|
|
|
:numerate_hex_digit
|
|
|
|
CMPI8_ECX !15 ; Check for illegal
|
|
|
|
JG32 %numerate_string_fail ; If CH > 'F'
|
|
|
|
CMPI8_ECX !0 ; Check for illegal
|
|
|
|
JL32 %numerate_string_fail ; IF CH < 0
|
|
|
|
ADD_ecx_into_eax ; VALUE = VALUE + CH
|
|
|
|
ADDI8_EBX !1 ; S = S + 1
|
|
|
|
JMP32 %numerate_hex_loop ; Keep looping
|
|
|
|
|
|
|
|
:numerate_string_fail
|
|
|
|
LOADI32_EAX %0 ; return ZERO
|
|
|
|
|
|
|
|
:numerate_string_done
|
|
|
|
POP_ESI ; Restore ESI
|
|
|
|
POP_EDX ; Restore EDX
|
|
|
|
POP_ECX ; Restore ECX
|
|
|
|
POP_EBX ; Restore EBX
|
|
|
|
RETURN
|
|
|
|
|
|
|
|
|
|
|
|
;; Exit_Failure function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives nothing
|
2019-06-23 22:52:38 +01:00
|
|
|
;; And aborts hard
|
|
|
|
;; Does NOT return
|
|
|
|
:Exit_Failure
|
|
|
|
LOADI32_EBX %1 ; All is wrong
|
|
|
|
LOADI32_EAX %1 ; put the exit syscall number in eax
|
|
|
|
INT_80 ; Call it a bad day
|
|
|
|
|
|
|
|
;; Keywords
|
|
|
|
:union "union"
|
|
|
|
:struct "struct"
|
|
|
|
:constant "CONSTANT"
|
|
|
|
:main_string "main"
|
|
|
|
:argc_string "argc"
|
|
|
|
:argv_string "argv"
|
|
|
|
:if_string "if"
|
|
|
|
:else_string "else"
|
|
|
|
:do_string "do"
|
|
|
|
:while_string "while"
|
|
|
|
:for_string "for"
|
|
|
|
:asm_string "asm"
|
|
|
|
:goto_string "goto"
|
|
|
|
:return_string "return"
|
|
|
|
:break_string "break"
|
|
|
|
:continue_string "continue"
|
|
|
|
:sizeof_string "sizeof"
|
|
|
|
:plus_string "+"
|
|
|
|
:minus_string "-"
|
|
|
|
:multiply_string "*"
|
|
|
|
:divide_string "/"
|
|
|
|
:modulus_string "%"
|
|
|
|
:left_shift_string "<<"
|
|
|
|
:right_shift_string ">>"
|
|
|
|
:less_than_string "<"
|
|
|
|
:less_than_equal_string "<="
|
|
|
|
:greater_than_equal_string ">="
|
|
|
|
:greater_than_string ">"
|
|
|
|
:equal_to_string "=="
|
|
|
|
:not_equal_string "!="
|
|
|
|
:bitwise_and "&"
|
|
|
|
:logical_and "&&"
|
|
|
|
:bitwise_or "|"
|
|
|
|
:logical_or "||"
|
|
|
|
:bitwise_xor "^"
|
|
|
|
:arrow_string "->"
|
|
|
|
|
|
|
|
|
|
|
|
;; Frequently Used strings
|
|
|
|
;; Generally used by require_match
|
|
|
|
:open_curly_brace "{"
|
|
|
|
:close_curly_brace "}"
|
|
|
|
:open_paren "("
|
|
|
|
:close_paren ")"
|
|
|
|
:open_bracket "["
|
|
|
|
:close_bracket "]"
|
|
|
|
:comma ","
|
|
|
|
:semicolon ";"
|
|
|
|
:equal "="
|
|
|
|
:percent "%"
|
|
|
|
:newline "\n"
|
|
|
|
:underline "_"
|
|
|
|
|
|
|
|
|
|
|
|
:prim_types
|
|
|
|
:type_void
|
|
|
|
&type_int ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_void ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_void ; TYPE
|
|
|
|
&type_void_name ; NAME
|
|
|
|
:type_void_name "void"
|
|
|
|
|
|
|
|
:type_int
|
|
|
|
&type_char ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_int ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_int ; TYPE
|
|
|
|
&type_int_name ; NAME
|
|
|
|
:type_int_name "int"
|
|
|
|
|
|
|
|
:type_char
|
|
|
|
&type_file ; NEXT
|
|
|
|
%1 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_char_indirect ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_char ; TYPE
|
|
|
|
&type_char_name ; NAME
|
|
|
|
:type_char_name "char"
|
|
|
|
|
|
|
|
:type_char_indirect
|
|
|
|
&type_file ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_char_double_indirect ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_char_indirect ; TYPE
|
|
|
|
&type_char_indirect_name ; NAME
|
|
|
|
:type_char_indirect_name "char*"
|
|
|
|
|
|
|
|
:type_char_double_indirect
|
|
|
|
&type_file ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_char_double_indirect ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_char_indirect ; TYPE
|
|
|
|
&type_char_double_indirect_name ; NAME
|
|
|
|
:type_char_double_indirect_name "char**"
|
|
|
|
|
|
|
|
:type_file
|
|
|
|
&type_function ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_file ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_file ; TYPE
|
|
|
|
&type_file_name ; NAME
|
|
|
|
:type_file_name "FILE"
|
|
|
|
|
|
|
|
:type_function
|
|
|
|
&type_unsigned ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_function ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_function ; TYPE
|
|
|
|
&type_function_name ; NAME
|
|
|
|
:type_function_name "FUNCTION"
|
|
|
|
|
|
|
|
:type_unsigned
|
|
|
|
%0 ; NEXT
|
|
|
|
%4 ; SIZE
|
|
|
|
%0 ; OFFSET
|
|
|
|
&type_unsigned ; INDIRECT
|
|
|
|
%0 ; MEMBERS
|
|
|
|
&type_unsigned ; TYPE
|
|
|
|
&type_unsigned_name ; NAME
|
|
|
|
:type_unsigned_name "unsigned"
|
|
|
|
|
|
|
|
|
|
|
|
;; debug_list function
|
2019-10-23 20:04:14 +01:00
|
|
|
;; Receives struct token_list* in EAX
|
2019-06-23 22:52:38 +01:00
|
|
|
;; Prints contents of list and exits
|
|
|
|
;; Does NOT return
|
|
|
|
:debug_list
|
|
|
|
COPY_EAX_to_EBP ; Protect the list pointer
|
|
|
|
LOADI32_EAX %2 ; Using Standard error
|
|
|
|
STORE32_Absolute32_eax &Output_file ; write to standard error
|
|
|
|
|
|
|
|
:debug_list_iter
|
|
|
|
;; Header
|
|
|
|
LOADI32_EAX &debug_list_string0 ; Using our first string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
COPY_EBP_to_EAX ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; NEXT
|
|
|
|
LOADI32_EAX &debug_list_string1 ; Using our second string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !0 ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; PREV
|
|
|
|
LOADI32_EAX &debug_list_string2 ; Using our third string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !4 ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; S
|
|
|
|
LOADI32_EAX &debug_list_string3 ; Using our fourth string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !8 ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; S Contents
|
|
|
|
LOADI32_EAX &debug_list_string4 ; Using our fifth string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !8 ; Use address of string
|
|
|
|
CMPI8_EAX !0 ; IF NULL Pointer
|
|
|
|
JNE32 %debug_list_null ; otherwise display
|
|
|
|
LOADI32_EAX &debug_list_string_null ; Give meaningful message instead
|
|
|
|
:debug_list_null
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; TYPE
|
|
|
|
LOADI32_EAX &debug_list_string5 ; Using our sixth string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !12 ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
;; ARGS/DEPTH
|
|
|
|
LOADI32_EAX &debug_list_string6 ; Using our third string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
LOAD32_EAX_from_EBP_Immediate8 !16 ; Use address of pointer
|
|
|
|
CALL32 %numerate_number ; Convert it into string
|
|
|
|
CALL32 %File_Print ; Print it
|
|
|
|
|
|
|
|
LOADI32_EAX %10 ; Add "\n"
|
|
|
|
CALL32 %fputc ; print it
|
|
|
|
CALL32 %fputc ; print it
|
|
|
|
|
|
|
|
LOAD32_EBP_from_EBP ; TOKEN = TOKEN->NEXT
|
|
|
|
CMPI8_EBP !0 ; Check if NULL
|
|
|
|
JNE32 %debug_list_iter ; iterate otherwise
|
|
|
|
|
|
|
|
LOADI32_EBX %666 ; All is HELL
|
|
|
|
LOADI32_EAX %1 ; put the exit syscall number in eax
|
|
|
|
INT_80 ; Call it a bad day
|
|
|
|
|
|
|
|
:debug_list_string0 "Token_list node at address: "
|
|
|
|
:debug_list_string1 "
|
|
|
|
NEXT address: "
|
|
|
|
:debug_list_string2 "
|
|
|
|
PREV address: "
|
|
|
|
:debug_list_string3 "
|
|
|
|
S address: "
|
|
|
|
:debug_list_string4 "
|
|
|
|
The contents of S are: "
|
|
|
|
:debug_list_string5 "
|
|
|
|
TYPE address: "
|
|
|
|
:debug_list_string6 "
|
|
|
|
ARGUMENTS address: "
|
|
|
|
:debug_list_string_null ">::<NULL>::<"
|
|
|
|
|
|
|
|
|
|
|
|
:Address_of
|
|
|
|
NULL
|
|
|
|
:C
|
|
|
|
NULL
|
|
|
|
:Input_file
|
|
|
|
NULL
|
|
|
|
:MALLOC
|
|
|
|
NULL
|
|
|
|
:Output_file
|
|
|
|
NULL
|
|
|
|
:Token
|
|
|
|
NULL
|
|
|
|
:break_frame
|
|
|
|
NULL
|
|
|
|
:break_target_func
|
|
|
|
NULL
|
|
|
|
:break_target_head
|
|
|
|
NULL
|
|
|
|
:break_target_num
|
|
|
|
NULL
|
|
|
|
:current_count
|
|
|
|
NULL
|
|
|
|
:current_target
|
|
|
|
NULL
|
|
|
|
:function
|
|
|
|
NULL
|
|
|
|
:global_constant_list
|
|
|
|
NULL
|
|
|
|
:global_function_list
|
|
|
|
NULL
|
|
|
|
:global_symbol_list
|
|
|
|
NULL
|
|
|
|
:global_token
|
|
|
|
NULL
|
|
|
|
:global_types
|
|
|
|
&prim_types
|
|
|
|
:globals_list
|
|
|
|
NULL
|
|
|
|
:output_list
|
|
|
|
NULL
|
|
|
|
:string_index
|
|
|
|
NULL
|
|
|
|
:strings_list
|
|
|
|
NULL
|
|
|
|
|
|
|
|
:ELF_end
|