stage0-uefi/amd64/cc_amd64.M1

5773 lines
216 KiB
Plaintext

# Copyright (C) 2017 Jeremiah Orians
# Copyright (C) 2022 Andrius Štikonas
# 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 add_al, 04
DEFINE add_rax, 4805
DEFINE add_rbx, 4881C3
DEFINE add_rcx, 4881C1
DEFINE add_rdx, 4881C2
DEFINE add_rsp, 4881C4
DEFINE add_rsi, 4881C6
DEFINE add_rax,rbx 4801D8
DEFINE add_rax,rcx 4801C8
DEFINE add_rbx,rax 4801C3
DEFINE add_rcx,rdi 4801F9
DEFINE add_rbx,[rdi+BYTE] 48035F
DEFINE and_rax, 4825
DEFINE and_rsp, 4883E4
DEFINE and_rax,rbx 4821D8
DEFINE call E8
DEFINE call_rax FFD0
DEFINE call_[rcx+BYTE] FF51
DEFINE call_[r14+DWORD] 41FF96
DEFINE cmp_al, 3C
DEFINE cmp_rax, 483D
DEFINE cmp_rbx, 4881FB
DEFINE cmp_rcx, 4881F9
DEFINE cmp_rdx, 4881FA
DEFINE cmp_rbp, 4881FD
DEFINE cmp_rsi, 4881FE
DEFINE cmp_r8, 4981F8
DEFINE cmp_r12, 4981FC
DEFINE cmp_r15, 4981FF
DEFINE cmp_rax,rbx 4839D8
DEFINE cmp_rax,rcx 4839C8
DEFINE cmp_rbx,rcx 4839CB
DEFINE cmp_rbx,rdx 4839D3
DEFINE cmp_rsi,rdi 4839FE
DEFINE cmp_rax,[rip+DWORD] 483B05
DEFINE dec_rax 48FFC8
DEFINE jbe 0F86
DEFINE je 0F84
DEFINE jg 0F8F
DEFINE jl 0F8C
DEFINE jle 0F8E
DEFINE jmp E9
DEFINE jne 0F85
DEFINE idiv_rbx 48F7FB
DEFINE imul_rax, 4869C0
DEFINE imul_rbp, 4869ED
DEFINE imul_rax,rbx 480FAFC3
DEFINE lea_rax,[rip+DWORD] 488D05
DEFINE lea_rbx,[rip+DWORD] 488D1D
DEFINE lea_rcx,[rip+DWORD] 488D0D
DEFINE lea_rdx,[rip+DWORD] 488D15
DEFINE mov_rax, 48C7C0
DEFINE mov_rbx, 48C7C3
DEFINE mov_rcx, 48C7C1
DEFINE mov_rdi, 48C7C7
DEFINE mov_rdx, 48C7C2
DEFINE mov_rsi, 48C7C6
DEFINE mov_r9, 49C7C1
DEFINE mov_r15, 49C7C7
DEFINE mov_rax,rbp 4889E8
DEFINE mov_rax,rbx 4889D8
DEFINE mov_rax,rcx 4889C8
DEFINE mov_rax,rdx 4889D0
DEFINE mov_rax,r12 4C89E0
DEFINE mov_rax,rsi 4889F0
DEFINE mov_rbp,rax 4889C5
DEFINE mov_rbp,rdx 4889D5
DEFINE mov_rbp,rsp 4889E5
DEFINE mov_rbx,rax 4889C3
DEFINE mov_rbx,rcx 4889CB
DEFINE mov_rbx,rdx 4889D3
DEFINE mov_rcx,rax 4889C1
DEFINE mov_rcx,rbx 4889D9
DEFINE mov_rcx,r8 4C89C1
DEFINE mov_rcx,r9 4C89C9
DEFINE mov_rdi,rax 4889C7
DEFINE mov_rdi,rsi 4889F7
DEFINE mov_rdx,rax 4889C2
DEFINE mov_rdx,rbx 4889DA
DEFINE mov_rdx,rsp 4889E2
DEFINE mov_rsi,rax 4889C6
DEFINE mov_rsi,rdi 4889FE
DEFINE mov_rsp,rbp 4889EC
DEFINE mov_r8,rsp 4989E0
DEFINE mov_r8,r12 4D89E0
DEFINE mov_r12,rax 4989C4
DEFINE mov_al,[rax] 8A00
DEFINE mov_al,[rbx] 8A03
DEFINE mov_al,[rcx] 8A01
DEFINE mov_al,[rdx] 8A02
DEFINE mov_bl,[rbx] 8A1B
DEFINE mov_bl,[rcx] 8A19
DEFINE mov_bl,[rdx] 8A1A
DEFINE mov_cl,[rbx] 8A0B
DEFINE mov_[rax], C600 # BYTE PTR
DEFINE mov_[rbx], C603 # BYTE PTR
DEFINE mov_rax,[rax] 488B00
DEFINE mov_rax,[rbx] 488B03
DEFINE mov_rax,[r12] 498B0424
DEFINE mov_rax,[r12+BYTE] 498B4424
DEFINE mov_rbx,[rax] 488B18
DEFINE mov_rbx,[rbx] 488B1B
DEFINE mov_rbx,[rbx+BYTE] 488B5B
DEFINE mov_rcx,[rbx] 488B0B
DEFINE mov_rcx,[rcx] 488B09
DEFINE mov_r12,[r12] 4D8B2424
DEFINE mov_[rbx],al 8803
DEFINE mov_[rcx],al 8801
DEFINE mov_[rcx],bl 8819
DEFINE mov_[rsi],al 8806
DEFINE mov_[rax],rbx 488918
DEFINE mov_[rax],rcx 488908
DEFINE mov_[rbx],rax 488903
DEFINE mov_[rdx],rax 488902
DEFINE mov_cl,[rbx+BYTE] 8A4B
DEFINE mov_rax,[rax+BYTE] 488B40
DEFINE mov_rax,[rbx+BYTE] 488B43
DEFINE mov_rax,[rcx+BYTE] 488B41
DEFINE mov_rax,[rdx+BYTE] 488B42
DEFINE mov_rbx,[rax+BYTE] 488B58
DEFINE mov_rbx,[rcx+BYTE] 488B59
DEFINE mov_rbx,[rdi+BYTE] 488B5F
DEFINE mov_rcx,[rax+BYTE] 488B48
DEFINE mov_rcx,[rcx+BYTE] 488B49
DEFINE mov_rcx,[rdi+BYTE] 488B4F
DEFINE mov_rcx,[rdx+BYTE] 488B4A
DEFINE mov_rdi,[rdx+BYTE] 488B7A
DEFINE mov_rdx,[rdx+BYTE] 488B52
DEFINE mov_rsp,[rsp+BYTE] 488B6424
DEFINE mov_r14,[rdx+BYTE] 4C8B72
DEFINE mov_rax,[rax+DWORD] 488B40
DEFINE mov_rbx,[rbx+DWORD] 488B5B
DEFINE mov_rax,[rip+DWORD] 488B05
DEFINE mov_rbx,[rip+DWORD] 488B1D
DEFINE mov_rcx,[rip+DWORD] 488B0D
DEFINE mov_rsp,[rip+DWORD] 488B25
DEFINE mov_r8,[rip+DWORD] 4C8B05
DEFINE mov_r9,[rip+DWORD] 4C8B0D
DEFINE mov_[rax+BYTE],rbx 488958
DEFINE mov_[rax+BYTE],rcx 488948
DEFINE mov_[rax+BYTE],rdx 488950
DEFINE mov_[rbp+BYTE],rax 488945
DEFINE mov_[rbp+BYTE],rdx 488955
DEFINE mov_[rbp+BYTE],rsi 488975
DEFINE mov_[rcx+BYTE],rax 488941
DEFINE mov_[rdx+BYTE],rax 488942
DEFINE mov_[rdx+BYTE],rbx 48895A
DEFINE mov_[rdx+BYTE],rcx 48894A
DEFINE mov_[rdx+BYTE],rbp 48896A
DEFINE mov_[rdx+BYTE],rsi 488972
DEFINE mov_[rip+DWORD],rax 488905
DEFINE mov_[rip+DWORD],rbx 48891D
DEFINE mov_[rip+DWORD],rcx 48890D
DEFINE mov_[rip+DWORD],rdx 488915
DEFINE mov_[rip+DWORD],rsp 488925
DEFINE movzx_rax,al 480FB6C0
DEFINE movzx_rbx,bl 480FB6DB
DEFINE movzx_rcx,cl 480FB6C9
DEFINE popf 9D
DEFINE pop_rax 58
DEFINE pop_rbp 5D
DEFINE pop_rbx 5B
DEFINE pop_rcx 59
DEFINE pop_rdi 5F
DEFINE pop_rdx 5A
DEFINE pop_rsi 5E
DEFINE pop_r8 4158
DEFINE pop_r12 415C
DEFINE pop_r13 415D
DEFINE pop_r14 415E
DEFINE pop_r15 415F
DEFINE push 6A
DEFINE pushf 9C
DEFINE push_rax 50
DEFINE push_rbp 55
DEFINE push_rbx 53
DEFINE push_rcx 51
DEFINE push_rdi 57
DEFINE push_rdx 52
DEFINE push_rsi 56
DEFINE push_rsp 54
DEFINE push_r12 4154
DEFINE push_r13 4155
DEFINE push_r14 4156
DEFINE push_r15 4157
DEFINE push_[rsp] FF3424
DEFINE ret C3
DEFINE ror_r9 49D1C9
DEFINE sal_rax, 48C1E0
DEFINE shl_rax, 48C1E0
DEFINE shr_rax, 48C1E8
DEFINE shr_rbx 48D1EB
DEFINE sub_rax, 482D
DEFINE sub_rbx, 4881EB
DEFINE sub_rcx, 4881E9
DEFINE sub_rsi, 4881EE
DEFINE sub_rsp, 4881EC
DEFINE xchg_rax,rbx 4893
DEFINE NULL 0000000000000000
# Register usage:
# RAX, RSI, RDI => Temps
# R13 => MALLOC
# R15 => stderr flag
# Struct TYPE format: (size 56)
# NEXT => 0
# SIZE => 8
# OFFSET => 16
# INDIRECT => 24
# MEMBERS => 32
# TYPE => 40
# NAME => 48
# Struct TOKEN_LIST format: (size 40)
# NEXT => 0
# LOCALS/PREV => 8
# S => 16
# TYPE => 24
# ARGS/DEPTH => 32
# efi_main(void *image_handle, struct efi_system_table *system)
:_start
# Save non-volatile registers
push_rbp
push_rbx
push_rdi
push_rsi
push_r12
push_r13
push_r14
push_r15
mov_rbp,rsp # save stack pointer
mov_[rip+DWORD],rcx %image_handle # save image_handle
mov_[rip+DWORD],rdx %system # save system
mov_r14,[rdx+BYTE] !96 # system->boot
# Open Loaded Image protocol
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
mov_rcx,r9 # arg1 = image_handle
call %open_protocol # open protocol
mov_rdi,rax # save image
# Get root file system
mov_r9,[rip+DWORD] %image_handle # arg4 = image_handle
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
mov_rcx,[rdi+BYTE] !24 # arg1 = root_device = image->device
mov_[rip+DWORD],rcx %root_device # save root_device
call %open_protocol # open protocol
mov_rcx,rax # get rootfs
# Get root directory
lea_rdx,[rip+DWORD] %rootdir # arg2 = &rootdir
sub_rsp, %40 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir)
add_rsp, %40 # deallocate stack
# Push command line arguments onto stack
mov_rbx,[rdi+BYTE] !56 # options = image->load_options
mov_rdx,rbx # save beginning of load_options
add_rbx,[rdi+BYTE] !48 # go to the end of load_options
push !0 # Save end of arguments (NULL) onto stack
:loop_options
cmp_rbx,rdx # Check if we are done
je %loop_options_done # We are done
sub_rbx, %2 # --options
mov_al,[rbx] # *options
cmp_al, !0x20 # if *options != ' '
jne %loop_options # then continue looping
mov_[rbx], !0 # zero it
add_rbx, %2 # ++options
push_rbx # push another argument onto stack
jmp %loop_options # next argument
:loop_options_done
pop_r8 # arg3 = in
pop_r12 # file out
and_rsp, !-16 # align stack to 16 bytes
# Open file for reading
push !1 # Set exit code in case of failure
cmp_r8, %0 # If NULL
je %failed_input # then exit
lea_rdx,[rip+DWORD] %fin # arg2 = &fin
push !1 # arg5 = EFI_FILE_READ_ONLY
mov_r9, %1 # arg4 = EFI_FILE_MODE_READ
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootdir->open()
cmp_rax, %0 # If failed to open
jne %failed_input # then exit
add_rsp, %48 # deallocate stack
# Open file for writing
mov_r8,r12 # arg3 = out
push !1 # Set exit code in case of failure
cmp_r8, %0 # If NULL
je %failed_output # then exit
lea_rdx,[rip+DWORD] %fout # arg2 = &fout
push !0 # arg5 = 0
mov_r9, %7 # to get 0x8000000000000003 we set the rightmost 3 bits and then do right rotation by 1
ror_r9 # arg4 = EFI_FILE_MODE_CREATE| EFI_FILE_MODE_WRITE | EFI_FILE_MODE_READ
mov_rcx,[rip+DWORD] %rootdir # arg1 = rootdir
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # rootdir->open()
add_rsp, %48 # deallocate stack
# Allocate ourselves 64 MiB of memory
mov_rdx, %0x4000000 # allocate 64 MiB of memory for malloc pool
call %allocate_pool # allocate memory
mov_[rip+DWORD],rax %malloc_pointer # save malloc pointer
mov_[rip+DWORD],rax %malloc_pool # save the beginning of malloc pool
# Zero allocated memory buffer
add_rax, %0x4000000 # end of malloc area
:zero_loop
dec_rax # next byte
mov_[rax], !0 # zero it
cmp_rax,[rip+DWORD] %malloc_pointer # if we are not done yet
jne %zero_loop # then continue looping
# cc_amd64 needs quite a lot of stack space when building M2-Planet
# which is not guaranteed to be available on UEFI (it guarantees at least 128 KiB).
# Therefore we will allocate an extra space on heap and use part of it for user stack
mov_rax, %0x800000 # Allocate 8 MiB for user stack
call %malloc
mov_[rip+DWORD],rax %user_stack # Set user stack
call %exit_uefi_stack # Switch to user stack
mov_r15, %0 # Not writing to stderr yet
call %fix_types # Resolve relative addresses in types struct to absolute
mov_rax, %0 # HEAD = NULL
call %read_all_tokens # Read all tokens
call %Reverse_List # Reverse order
# call %debug_list # Try to figure out what is wrong
mov_[rip+DWORD],rax %global_token # Set global_token
call %program # Convert into program
lea_rax,[rip+DWORD] %header_string1 # Our header string
call %File_Print # Print it
mov_rax,[rip+DWORD] %output_list # Our output_list
call %recursive_output # Print core program
# lea_rax,[rip+DWORD] %header_string2 # Our Enable debug
# call %File_Print # Print it
lea_rax,[rip+DWORD] %header_string3 # Our second label
call %File_Print # Print it
mov_rax,[rip+DWORD] %globals_list # Our globals
call %recursive_output # Get them
lea_rax,[rip+DWORD] %header_string4 # Our final header
call %File_Print # Print it
mov_rax,[rip+DWORD] %strings_list # Our strings
call %recursive_output # Get them
lea_rax,[rip+DWORD] %header_string5 # Our final header
call %File_Print # Print it
:Done
# program completed Successfully
mov_rax, %0 # Set exit code 0
:Done_1
call %enter_uefi_stack # Switch back to UEFI stack
push_rax # save exit code
# Free pool
mov_rcx,[rip+DWORD] %malloc_pool # arg1 = malloc_pool
call %free_pool # system->boot->free_pool(malloc_pool)
mov_rcx,[rip+DWORD] %fout # get fout
call %close_file # close fout
:failed_output
mov_rcx,[rip+DWORD] %fin # get fin
call %close_file # close fin
:failed_input
mov_rcx,[rip+DWORD] %rootdir # get rootdir
call %close_file # close rootdir
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
lea_rdx,[rip+DWORD] %SIMPLE_FS_PROTOCOL # guid = &SIMPLE_FS_PROTOCOL
mov_rcx,[rip+DWORD] %root_device # arg1 = root_device
call %close_protocol # close protocol
mov_r8,[rip+DWORD] %image_handle # arg3 = image_handle
lea_rdx,[rip+DWORD] %LOADED_IMAGE_PROTOCOL # guid = &LOADED_IMAGE_PROTOCOL
mov_rcx,r8 # arg1 = image_handle
call %close_protocol # close protocol
pop_rax # restore exit code
:abort # used for debugging only
# Restore non-volatile registers
mov_rsp,rbp
pop_r15
pop_r14
pop_r13
pop_r12
pop_rsi
pop_rdi
pop_rbx
pop_rbp
ret # return to UEFI
:header_string1
"
# Core program
"
:header_string2
"
:ELF_data
"
:header_string3
"
# Program global variables
"
:header_string4
"
# Program strings
"
:header_string5
"
:ELF_end
"
# Resolve relative addresses in types struct to absolute
# Uses RAX to store current type, RBX for temp
:fix_types
push_rbx # Protect RBX
lea_rax,[rip+DWORD] %prim_types # Get address of prim_types
mov_[rip+DWORD],rax %global_types # Write it to global_types
:fix_type
mov_rbx,[rax+BYTE] !48 # Get offset to NAME
add_rbx,rax # Get NAME
mov_[rax+BYTE],rbx !48 # Store NAME
mov_rbx,[rax+BYTE] !40 # Get offset to TYPE
add_rbx,rax # Get TYPE
mov_[rax+BYTE],rbx !40 # Store TYPE
mov_rbx,[rax+BYTE] !24 # Get offset to INDIRECT
add_rbx,rax # Get INDIRECT
mov_[rax+BYTE],rbx !24 # Store INDIRECT
mov_rbx,[rax] # Get offset to NEXT
cmp_rbx, %0 # If no more types
je %fix_types_done # Then we are done
add_rbx,rax # Get NEXT
mov_[rax],rbx # Store NEXT
add_rax, %56 # Go to next type
jmp %fix_type
:fix_types_done
pop_rbx # Restore RBX
ret
# read_all_tokens function
# Receives Token_List* in RAX
# Tokenizes all input and returns updated list in RAX
# Returns TOKEN in RAX
# Uses RAX for C
:read_all_tokens
mov_[rip+DWORD],rax %Token
call %fgetc
:read_all_tokens_loop
cmp_rax, %-4 # Check for EOF
je %read_all_tokens_done # Stop if found
call %get_token # Read all tokens
jmp %read_all_tokens_loop # Loop
:read_all_tokens_done
mov_rax,[rip+DWORD] %Token
ret
# get_token function
# Receives INT in RAX
# Makes a list of TOKEN_LIST
# C and STRING_INDEX are stored in memory, RCX is used for S and RDX is used for current
# Returns C in RAX
:get_token
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_[rip+DWORD],rax %C # Set C
mov_rax, %40 # Malloc CURRENT
call %malloc # Get Pointer
mov_rdx,rax # Set CURRENT
mov_rax, %256 # Malloc the string
call %malloc # Get pointer to S
mov_rcx,rax # Set S
mov_[rdx+BYTE],rcx !16 # CURRENT->S = S
:reset
mov_[rip+DWORD],rcx %string_index # S[0]
mov_rax,[rip+DWORD] %C # Using C
call %clear_white_space # Clear WhiteSpace
mov_[rip+DWORD],rax %C # Set C
cmp_rax, %-4 # Check for EOF
je %get_token_abort # if EOF abort
cmp_rax, %35 # Check for '#'
jne %get_token_alpha # Nope
# Deal with # line comments
call %purge_macro # Let it handle it
mov_[rip+DWORD],rax %C # Set C
jmp %reset # Try again
:get_token_alpha
mov_rax,[rip+DWORD] %C # Send C
lea_rbx,[rip+DWORD] %alphas # Get alphanumerics
call %In_Set # See if in set
cmp_rax, %1 # IF TRUE
jne %get_token_symbol # Otherwise
# Store keywords
mov_rax,[rip+DWORD] %C # Send C
call %preserve_keyword # Store
mov_[rip+DWORD],rax %C # Set C
jmp %get_token_done # Be done with this token
:get_token_symbol
mov_rax,[rip+DWORD] %C # Send C
lea_rbx,[rip+DWORD] %symbols # Get symbols
call %In_Set # See if in set
cmp_rax, %1 # IF TRUE
jne %get_token_strings # Otherwise
# Store symbols
mov_rax,[rip+DWORD] %C # Send C
call %preserve_symbol # Store
mov_[rip+DWORD],rax %C # Set C
jmp %get_token_done # Be done with this token
:get_token_strings
mov_rax,[rip+DWORD] %C # Send C
lea_rbx,[rip+DWORD] %strings # Get strings
call %In_Set # See if in set
cmp_rax, %1 # IF TRUE
jne %get_token_comment # Otherwise
# Store String
mov_rax,[rip+DWORD] %C # Send C
call %consume_word # Store
mov_[rip+DWORD],rax %C # Set C
jmp %get_token_done # Be done with this token
:get_token_comment
mov_rax,[rip+DWORD] %C # Send C
cmp_rax, %47 # IF '/' == C
jne %get_token_else # Otherwise
call %consume_byte # Hope it just is '/'
mov_[rip+DWORD],rax %C # Set C
cmp_rax, %42 # IF '*' we have '/*'
jne %get_token_comment_line # Check for '//'
# Deal with /* block comments */
call %fgetc # get next C
mov_[rip+DWORD],rax %C # Set C
:get_token_comment_block_outer
mov_rax,[rip+DWORD] %C # Using C
cmp_rax, %47 # IF '/' != C
je %get_token_comment_block_done # be done
:get_token_comment_block_inner
mov_rax,[rip+DWORD] %C # Using C
cmp_rax, %42 # IF '*' != C
je %get_token_comment_block_iter # jump over
# Deal with inner loop
call %fgetc # get next C
mov_[rip+DWORD],rax %C # Set C
jmp %get_token_comment_block_inner # keep going
:get_token_comment_block_iter
call %fgetc # get next C
mov_[rip+DWORD],rax %C # Set C
jmp %get_token_comment_block_outer
:get_token_comment_block_done
call %fgetc # get next C
mov_[rip+DWORD],rax %C # Set C
jmp %reset # throw away, try again
:get_token_comment_line
cmp_rax, %47 # IF '/' we have //
jne %get_token_done # keep if just '/'
# Deal with // line comment
call %fgetc # drop to match
mov_[rip+DWORD],rax %C # Set C
jmp %reset # throw away, try again
:get_token_else
mov_rax,[rip+DWORD] %C # Send C
call %consume_byte
mov_[rip+DWORD],rax %C # Set C
:get_token_done
mov_rax,[rip+DWORD] %Token # TOKEN
mov_[rdx+BYTE],rax !8 # CURRENT->PREV = TOKEN
mov_[rdx],rax # CURRENT->NEXT = TOKEN
mov_[rip+DWORD],rdx %Token # TOKEN = CURRENT
:get_token_abort
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
mov_rax,[rip+DWORD] %C # Return C
ret
# Malloc isn't actually reserving memory here.
# It just updates the pointer in our already reserved storage pool.
:malloc
push_rbx # Protect RBX
mov_rbx,[rip+DWORD] %malloc_pointer # Get malloc pointer
xchg_rax,rbx # Put it in place
add_rbx,rax # Request number of desired bytes
mov_[rip+DWORD],rbx %malloc_pointer # Save malloc_pointer
pop_rbx # Restore RBX
ret
# clear_white_space function
# Receives INT C in RAX and FILE* in R15
# Returns first non-whitespace char in RAX
:clear_white_space
cmp_rax, %32 # Check for ' '
je %clear_white_space_wipe # wipe it out
cmp_rax, %10 # Check for '\n'
je %clear_white_space_wipe # wipe it output
cmp_rax, %9 # Check for '\t'
jne %clear_white_space_done # looks like non-whitespace
:clear_white_space_wipe
call %fgetc # Read a new byte
cmp_rax, %-4 # Check for EOF
je %clear_white_space_done # Short circuit
jmp %clear_white_space # iterate
:clear_white_space_done
ret
# In_Set function
# Receives Char C in RAX and CHAR* in RBX
# Returns 1 if true, zero if false in RAX
:In_Set
push_rbx # Protect RBX
push_rcx # Protect RCX
:In_Set_loop
mov_cl,[rbx] # Read char
movzx_rcx,cl # Zero extend it
cmp_rax,rcx # See if they match
je %In_Set_True # return true
cmp_rcx, %0 # Check for NULL
je %In_Set_False # return false
add_rbx, %1 # s = s + 1
jmp %In_Set_loop # Keep looping
:In_Set_True
mov_rax, %1 # Set True
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:In_Set_False
mov_rax, %0 # Set FALSE
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:alphas
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
:symbols
"<=>|&!-"
:strings
'22 27 00'
# purge_macro function
# Receives CH in RAX
# Reads chars until Line feed is read
# returns line feed
:purge_macro
call %fgetc # read next char
cmp_rax, %10 # Check for '\n'
jne %purge_macro # Keep going
ret
# preserve_keyword function
# Receives INT C in RAX
# collects all chars in keyword
# Returns C in RAX
# Uses RCX for INT C
:preserve_keyword
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # Setup C
lea_rbx,[rip+DWORD] %alphas # Concerning ourselves with "abc.."
:preserve_keyword_loop
call %In_Set # Check if alphanumerics
cmp_rax, %1 # IF TRUE
jne %preserve_keyword_label # Otherwise check for label
mov_rax,rcx # Pass C
call %consume_byte # consume that byte
mov_rcx,rax # Update C
jmp %preserve_keyword_loop # keep looping
:preserve_keyword_label
mov_rax,rcx # Fix return
cmp_rax, %58 # Check for ':'
jne %preserve_keyword_done # be done
# Fix our goto label
call %fixup_label # Fix the label
mov_rax, %32 # Return Whitespace
:preserve_keyword_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# preserve_symbol function
# Receives INT C in RAX
# collects all chars in symbol
# Returns C in RAX
# Uses RCX for INT C
:preserve_symbol
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # Setup C
lea_rbx,[rip+DWORD] %symbols # Concerning ourselves with "<=>.."
:preserve_symbol_loop
call %In_Set # Check if symbol
cmp_rax, %1 # IF TRUE
jne %preserve_symbol_done # Otherwise be done
mov_rax,rcx # Pass C
call %consume_byte # consume that byte
mov_rcx,rax # Update C
jmp %preserve_symbol_loop # keep looping
:preserve_symbol_done
mov_rax,rcx # Fix return
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# consume_word function
# receives INT C in RAX
# returns INT C in RAX
# Uses RAX for C, RBX for FREQ and RCX for ESCAPE
:consume_word
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,rax # FREQ = C
mov_rcx, %0 # ESCAPE = FALSE
:consume_word_loop
cmp_rcx, %0 # IF !ESCAPE
jne %consume_word_escape # Enable escape
cmp_rax, %92 # if '\\'
jne %consume_word_iter # keep state
mov_rcx, %1 # ESCAPE = TRUE
jmp %consume_word_iter # keep going
:consume_word_escape
mov_rcx, %0 # ESCAPE = FALSE
:consume_word_iter
call %consume_byte # read next char
cmp_rcx, %0 # IF ESCAPE
jne %consume_word_loop # keep looping
cmp_rax,rbx # IF C != FREQ
jne %consume_word_loop # keep going
call %fgetc # return next char
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# consume_byte function
# Receives INT C in RAX
# Inserts C into string S, updates String S
# Returns Next char in RAX
:consume_byte
push_rbx # Protect RBX
mov_rbx,[rip+DWORD] %string_index # S[0]
mov_[rbx],al # S[0] = C
add_rbx, %1 # S = S + 1
mov_[rip+DWORD],rbx %string_index # Update S
call %fgetc
pop_rbx # Restore RBX
ret
# fixup_label function
# Receives S in RCX
# prepends ':' to string and returns registers unchanged
# Uses RAX for HOLD, RBX for PREV and RCX for S[0]
:fixup_label
push_rax # Protect RAX
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax, %58 # HOLD = ':'
mov_rcx,[rdx+BYTE] !16 # HOLD_STRING[0]
:fixup_label_loop
mov_rbx,rax # PREV = HOLD
mov_al,[rcx] # HOLD = HOLD_STRING[I]
movzx_rax,al # make useful
mov_[rcx],bl # HOLD_STRING[I] = PREV
add_rcx, %1 # I = I + 1
cmp_rax, %0 # IF NULL == HOLD
jne %fixup_label_loop # Keep looping
pop_rcx # Restore RCX
pop_rbx # Restore RBX
pop_rax # Restore RAX
ret
# fgetc function
# Returns -4 (EOF) or char in RAX
:fgetc
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rcx,[rip+DWORD] %fin # arg1 = fin
push !1 # size = 1
mov_rdx,rsp # arg2 = &size
push !0 # allocate stack
mov_r8,rsp # arg3 = &input
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !32 # fin->read()
mov_rsp,[rsp+BYTE] !40 # deallocate stack
pop_rax # save input to rax
pop_rsi # save size to rsi
# If the file ended (0 bytes read) return EOF
cmp_rsi, %0 # if size == 0
jne %fgetc_1
mov_rax, %-4 # Put EOF in rax
:fgetc_1
pop_rdx # Restore RDX
pop_rcx # Restore RCX
ret # return
# Reverse_List function
# Receives List in RAX
# Returns the list reversed in RAX
:Reverse_List
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,rax # Set HEAD
mov_rax, %0 # ROOT = NULL
:Reverse_List_Loop
cmp_rbx, %0 # WHILE HEAD != NULL
je %Reverse_List_Done # Stop otherwise
mov_rcx,[rbx] # NEXT = HEAD->NEXT
mov_[rbx],rax # HEAD->NEXT = ROOT
mov_rax,rbx # ROOT = HEAD
mov_rbx,rcx # HEAD = NEXT
jmp %Reverse_List_Loop # Keep Going
:Reverse_List_Done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# recursive_output function
# Receives list in RAX
# walks the list and prints the I->S for all nodes backwards
# Uses RBX for I
:recursive_output
push_rbx # Protect RBX
push_rcx # Protect RCX
cmp_rax, %0 # Check for NULL
je %recursive_output_done # Skip the work
mov_rbx,rax # I = Head
mov_rax,[rbx] # Iterate to next Token
call %recursive_output # Recurse
mov_rax,[rbx+BYTE] !16 # Using S
call %File_Print # Print it
:recursive_output_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# File_Print function
# Receives CHAR* in RAX
# calls fputc for every non-null char
:File_Print
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,rax # Protect S
cmp_rax, %0 # Protect against nulls
je %File_Print_Done # Simply don't try to print them
:File_Print_Loop
mov_al,[rbx] # Read byte
movzx_rax,al # zero extend
cmp_rax, %0 # Check for NULL
je %File_Print_Done # Stop at NULL
call %fputc # write it
add_rbx, %1 # S = S + 1
jmp %File_Print_Loop # Keep going
:File_Print_Done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# fputc function
# receives CHAR in RAX
# writes char and returns
:fputc
push_rcx # Protect RCX
push_rdx # Protect RDX
cmp_r15, %2 # Check if printing to system error
jne %fputc_file # Else print to file
# Print to stderr
cmp_rax, %0xA # If we have LF, we need to append CR
pushf # Protect condition
mov_rcx,[rip+DWORD] %system # get system
mov_rcx,[rcx+BYTE] !64 # system->out (system->err doesn't print anything for some reason)
mov_[rip+DWORD],rax %WCHAR # Convert to WCHAR
lea_rdx,[rip+DWORD] %WCHAR # arg3 = *WCHAR
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !8 # system->err->output_string(system->err, WCHAR*)
mov_rsp,[rsp+BYTE] !40 # deallocate stack
popf # Restore condition
jne %fputc_done # We are done if not LF
mov_rax, %0xD # Carriage return
call %fputc # Print it
jmp %fputc_done # We are done
:fputc_file
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
mov_rcx,[rip+DWORD] %fout # arg1 = fout
push !1 # set size
mov_rdx,rsp # arg2 = &size
push_rax # allocate stack
mov_r8,rsp # arg3 = &output
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !40 # fout->write()
mov_rsp,[rsp+BYTE] !56 # deallocate stack
:fputc_done
pop_rdx # Restore RDX
pop_rcx # Restore RCX
ret # return
# program function
# receives nothing, returns nothing
# Uses RAX for type_size
:program
# The binary initialized the globals to null, so we can skip those steps
push_rbx # Protect RBX
push_rcx # Protect RCX
:new_type
mov_rax,[rip+DWORD] %global_token # Using global_token
cmp_rax, %0 # Check if NULL
je %program_done # Be done if null
mov_rbx,[rax+BYTE] !16 # GLOBAL_TOKEN->S
lea_rax,[rip+DWORD] %constant # "CONSTANT"
call %match # IF GLOBAL_TOKEN->S == "CONSTANT"
cmp_rax, %0 # If true
jne %program_else # Looks like not a constant
# Deal with minimal constant case
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
mov_rax,[rax+BYTE] !16 # global_token->S
mov_rbx, %0 # NULL
mov_rcx,[rip+DWORD] %global_constant_list # global_constant_list
call %sym_declare # Declare that constant
mov_[rip+DWORD],rax %global_constant_list # global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx] # global_token->next
mov_[rax+BYTE],rbx !32 # global_constant_list->arguments = global_token->next
mov_rbx,[rbx] # global_token->next->next
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next->next;
jmp %new_type # go around again
:program_else
call %type_name # Figure out the type_size
cmp_rax, %0 # IF NULL == type_size
je %new_type # it was a new type
# Add to global symbol table
mov_rbx,rax # put type_size in the right spot
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_rcx,[rip+DWORD] %global_symbol_list # Using global_symbol_list
call %sym_declare # Declare symbol
mov_[rip+DWORD],rax %global_symbol_list # global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
mov_rbx,[rip+DWORD] %global_token # Using global token
mov_rbx,[rbx] # global_token->next
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
mov_rbx,[rip+DWORD] %global_token # Using global token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %semicolon # ";"
call %match # if(match(";", global_token->s))
cmp_rax, %0 # If true
jne %program_function # looks like not a match
# Deal with the global variable
mov_rbx,[rip+DWORD] %globals_list # Using globals_list
lea_rax,[rip+DWORD] %program_string_0 # ":GLOBAL_"
call %emit # Emit it
mov_rbx,rax # update globals_list
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax+BYTE] !8 # global token->prev
mov_rax,[rax+BYTE] !16 # global token->prev->s
call %emit # Emit it
mov_rbx,rax # update globals_list
lea_rax,[rip+DWORD] %program_string_1 # "\nNULL\n"
call %emit # Emit it
mov_[rip+DWORD],rax %globals_list # update globals_list
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
jmp %new_type # go around again
:program_function
mov_rbx,[rip+DWORD] %global_token # Using global token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_paren # "("
call %match # if(match(";", global_token->s))
cmp_rax, %0 # If true
jne %program_error # Otherwise deal with error case
# Deal with function definition
call %declare_function # Lets get the parsing rolling
jmp %new_type # Keep looping through functions
:program_error
# Deal with the case of something we don't support
:program_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# Strings needed by the program function
:program_string_0
":GLOBAL_"
:program_string_1
"
NULL
"
# declare_function function
# Receives nothing and returns nothing
# Sets current function and adds it to the global function list
:declare_function
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax, %0 # Using NULL
mov_[rip+DWORD],rax %current_count # current_count = 0
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax+BYTE] !8 # global token->prev
mov_rax,[rax+BYTE] !16 # global token->prev->s
mov_rbx, %0 # NULL
mov_rcx,[rip+DWORD] %global_function_list # global_function_list
call %sym_declare # sym_declare(global_token->prev->s, NULL, global_function_list);
mov_[rip+DWORD],rax %function # function = sym_declare(global_token->prev->s, NULL, global_function_list);
mov_[rip+DWORD],rax %global_function_list # global_function_list = function
call %collect_arguments # collect all of the function arguments
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax+BYTE] !16 # global token->s
lea_rbx,[rip+DWORD] %semicolon # ";"
call %match # IF global token->s == ";"
cmp_rax, %0 # If true
jne %declare_function_full # It was a prototype
# Deal with prototypes
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax] # global token->next
mov_[rip+DWORD],rax %global_token # global token = global token->next
jmp %declare_function_done # Move on
:declare_function_full
# Deal with full function definitions
lea_rax,[rip+DWORD] %declare_function_string_0 # "# Defining function "
call %emit_out # emit it
mov_rax,[rip+DWORD] %function # function
mov_rax,[rax+BYTE] !16 # function->s
call %emit_out # emit it
lea_rax,[rip+DWORD] %declare_function_string_1 # "\n:FUNCTION_"
call %emit_out # emit it
mov_rax,[rip+DWORD] %function # function
mov_rax,[rax+BYTE] !16 # function->s
call %emit_out # emit it
lea_rax,[rip+DWORD] %declare_function_string_3 # "\n"
call %emit_out # emit it
call %statement # Recursively get the function pieces
mov_rax,[rip+DWORD] %output_list # output
mov_rax,[rax+BYTE] !16 # output->s
lea_rbx,[rip+DWORD] %declare_function_string_2 # "ret\n"
call %match # IF output->s == "ret\n"
cmp_rax, %0 # If true we can skip adding it
je %declare_function_done # otherwise we need to add it
# Add the return to the end of a function lacking a return;
lea_rax,[rip+DWORD] %declare_function_string_2 # "ret\n"
call %emit_out # emit it
:declare_function_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:declare_function_string_0
"# Defining function "
:declare_function_string_1
"
:FUNCTION_"
:declare_function_string_2
"ret
"
:declare_function_string_3
"
"
# collect_arguments function
# Receives nothing
# Returns Nothing
# Adds arguments to the function definition
# holds struct type* type_size in RCX, then replace with struct token_list* a in RCX when type_size is used
:collect_arguments
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
:collect_arguments_loop
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %close_paren # ")"
call %match # IF global_token->S == ")"
cmp_rax, %0 # we reached the end
je %collect_arguments_done # be done
# deal with the case of there are arguments
call %type_name # Get the type
mov_rcx,rax # put type_size safely out of the way
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %close_paren # ")"
call %match # IF global_token->S == ")"
cmp_rax, %0 # is a foo(int, char,void) case
je %collect_arguments_common # deal with commas
# Trying second else
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %comma # ","
call %match # IF global_token->S == ","
cmp_rax, %0 # then deal with the common
je %collect_arguments_common # case of commas between arguments
# deal with foo(int a, char b)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+DWORD] !16 # global_token->S
mov_rbx,rcx # put type_size in the right place
mov_rcx,[rip+DWORD] %function # Using function
mov_rcx,[rcx+BYTE] !32 # function->args
call %sym_declare # sym_declare(global_token->s, type_size, function->arguments);
mov_rcx,rax # put a in a safe place
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !32 # function->args
cmp_rax, %0 # IF function->args == NULL
jne %collect_arguments_another # otherwise it isn't the first
# Deal with the case of first argument in the function
mov_rax, %-8 # -8
mov_[rcx+BYTE],rax !32 # a->depth = -8
jmp %collect_arguments_next # get to next
:collect_arguments_another
# deal with the case of non-first arguments
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !32 # function->args
mov_rax,[rax+BYTE] !32 # function->args->depth
sub_rax, %8 # function->args->depth - 8
mov_[rcx+BYTE],rax !32 # a->depth = function->args->depth - 8
:collect_arguments_next
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
mov_rax,[rip+DWORD] %function # Using function
mov_[rax+BYTE],rcx !32 # function->args = a
:collect_arguments_common
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+DWORD] !16 # global_token->S
lea_rax,[rip+DWORD] %comma # ","
call %match # IF global_token->S == ","
cmp_rax, %0 # then deal with the comma
jne %collect_arguments_loop # otherwise loop
# keep foo(bar(), 1) expressions working
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
jmp %collect_arguments_loop # keep going
:collect_arguments_done
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# statement function
# Receives nothing
# Returns nothing
# Walks down global_token recursively to collect the contents of the function
:statement
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_curly_brace # "{"
call %match # IF global_token->S == "{"
jne %statement_label # otherwise try label
# deal with { statement }
call %recursive_statement # Statements inside of statements for days
jmp %statement_done # Be done
:statement_label
mov_al,[rbx] # global_token->S[0]
movzx_rax,al # make it useful
cmp_rax, %58 # IF global_token->S == ':'
jne %statement_local # otherwise try locals
# deal with labels
mov_rax,rbx # put global_token->S in the right spot
call %emit_out # emit it
lea_rax,[rip+DWORD] %statement_string_0 # Using "\t#C goto label\n"
call %emit_out # emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
jmp %statement_done # be done
:statement_local
mov_rax,rbx # put global_token->S in the right place
lea_rbx,[rip+DWORD] %prim_types # pointer to primative types
call %lookup_type # See if found
cmp_rax, %0 # IF NULL == lookup_type(global_token->S, prim_types)
jne %statement_local_success # Sweet a new local
# Second chance
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %struct # "struct"
call %match # IF global_token->S == "struct"
cmp_rax, %0 # then we are a local
jne %statement_if # otherwise try IF
:statement_local_success
call %collect_local # Grab those locals
jmp %statement_done # be done
:statement_if
lea_rax,[rip+DWORD] %if_string # Using "if"
call %match # IF global_token->S == "if"
cmp_rax, %0 # then we have an if statement
jne %statement_do # otherwise try DO
# Deal with IF statement
call %process_if # DO IT
jmp %statement_done # be done
:statement_do
lea_rax,[rip+DWORD] %do_string # Using "do"
call %match # IF global_token->S == "do"
cmp_rax, %0 # then we have a do statement
jne %statement_while # otherwise try WHILE
# Deal with DO statement
call %process_do # DO IT
jmp %statement_done # be done
:statement_while
lea_rax,[rip+DWORD] %while_string # Using "while"
call %match # IF global_token->S == "while"
cmp_rax, %0 # then we have a while statement
jne %statement_for # otherwise try FOR
# Deal with WHILE statement
call %process_while # DO IT
jmp %statement_done # be done
:statement_for
lea_rax,[rip+DWORD] %for_string # Using "for"
call %match # IF global_token->S == "for"
cmp_rax, %0 # then we have a for statement
jne %statement_asm # otherwise try ASM
# Deal with FOR statement
call %process_for # DO IT
jmp %statement_done # be done
:statement_asm
lea_rax,[rip+DWORD] %asm_string # Using "asm"
call %match # IF global_token->S == "asm"
cmp_rax, %0 # then we have an asm statement
jne %statement_goto # otherwise try GOTO
# Deal with ASM statement
call %process_asm # Hit it
jmp %statement_done # be done
:statement_goto
lea_rax,[rip+DWORD] %goto_string # Using "goto"
call %match # IF global_token->S == "goto"
cmp_rax, %0 # then we have a goto statement
jne %statement_return # Otherwise try RETURN
# Deal with GOTO statement
lea_rax,[rip+DWORD] %statement_string_1 # Using "jmp %"
call %emit_out # emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
mov_rax,[rax+BYTE] !16 # global_token->S
call %emit_out # emit it
lea_rax,[rip+DWORD] %statement_string_2 # Using "\n"
call %emit_out # emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure it has the required
jmp %statement_done # Be done
:statement_return
lea_rax,[rip+DWORD] %return_string # Using "return"
call %match # IF global_token->S == "return"
cmp_rax, %0 # then we have a return statement
jne %statement_break # Otherwise try BREAK
# Deal with RETURN Statement
call %return_result # Return anything they want
jmp %statement_done # be done
:statement_break
lea_rax,[rip+DWORD] %break_string # Using "break"
call %match # IF global_token->S == "break"
cmp_rax, %0 # then we have a break statement
jne %statement_continue # Otherwise try CONTINUE
# Deal with BREAK statement
call %process_break # Lets do some damage
jmp %statement_done # be done
:statement_continue
lea_rax,[rip+DWORD] %continue_string # Using "continue"
call %match # IF global_token->S == "continue"
cmp_rax, %0 # then we have a continue statement
jne %statement_else # Otherwise we are punting to an expression
# Deal with CONTINUE statement
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
lea_rax,[rip+DWORD] %statement_string_3 # Using "\n#continue statement\n"
call %emit_out # emit it
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Don't forget the ";"
jmp %statement_done # Be done
:statement_else
call %expression # Collect expression
lea_rax,[rip+DWORD] %statement_string_4 # Using "ERROR in statement\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # make sure we have it
:statement_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:statement_string_0
" #C goto label
"
:statement_string_1
"jmp %"
:statement_string_2
"
"
:statement_string_3
"
#continue statement
"
:statement_string_4
"ERROR in statement
Missing ;
"
# recursive_statement function
# Receives nothing
# Returns nothing
# Walks the global_token list to build the contents of statements
# Uses struct token_list* frame in RCX
:recursive_statement
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
mov_rcx,[rip+DWORD] %function # Using function
mov_rcx,[rcx+BYTE] !8 # frame = function->locals
:recursive_statement_loop
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %close_curly_brace # Using "}"
call %match # IF global_token->S == "}"
cmp_rax, %0 # Then we are done recursing
je %recursive_statement_cleanup # and then we clean up
# Deal with the recursive calls
call %statement # Deal with another statement
jmp %recursive_statement_loop # loop some more
:recursive_statement_cleanup
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
lea_rax,[rip+DWORD] %recursive_statement_string_0 # Using "ret\n"
mov_rbx,[rip+DWORD] %output_list # Using output
mov_rbx,[rbx+BYTE] !16 # output->S
call %match # IF output->S == "ret\n"
cmp_rax, %0 # Then we can skip the clean up
je %recursive_statement_done # and be done
# Deal with cleanup
mov_rbx,[rip+DWORD] %function # Using function
mov_rbx,[rbx+BYTE] !8 # i = function->locals
lea_rax,[rip+DWORD] %recursive_statement_string_1 # Using "pop_rbx\t# _recursive_statement_locals\n"
:recursive_statement_locals
cmp_rbx,rcx # IF frame != i
je %recursive_statement_done # Otherwise be done
# Lets emit
call %emit_out # emit it
mov_rbx,[rbx] # i = i->next
jmp %recursive_statement_locals # keep going
:recursive_statement_done
mov_rax,[rip+DWORD] %function # Using function
mov_[rax+BYTE],rcx !8 # function->locals = frame
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:recursive_statement_string_0
"ret
"
:recursive_statement_string_1
"pop_rbx # _recursive_statement_locals
"
# return_result function
# Receives nothing
# Returns nothing
# Cleans up function and generates return
# Also handles returning expressions
:return_result
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # make it useful
cmp_rax, %59 # If global_token->S[0] == ';'
je %return_result_cleanup # Go straight to cleanup
call %expression # get the expression we are returning
:return_result_cleanup
lea_rax,[rip+DWORD] %return_result_string_0 # Using "ERROR in return_result\nMISSING ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
mov_rbx,[rip+DWORD] %function # Using function
mov_rbx,[rbx+BYTE] !8 # function->locals
lea_rax,[rip+DWORD] %return_result_string_1 # Using "pop_rbx\t# _return_result_locals\n"
:return_result_locals
cmp_rbx, %0 # IF NULL == i
je %return_result_done # Be done
call %emit_out # Emit out pop
mov_rbx,[rbx] # i = i->NEXT
jmp %return_result_locals # Keep going
:return_result_done
lea_rax,[rip+DWORD] %return_result_string_2 # Using "ret\n"
call %emit_out # Emit it
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:return_result_string_0
"ERROR in return_result
MISSING ;
"
:return_result_string_1
"pop_rbx # _return_result_locals
"
:return_result_string_2
"ret
"
# collect_local function
# Receives nothing
# Returns nothing
# Walks global_token list to create function locals
# Uses RCX for struct token_list* A
:collect_local
push_rbx # Protect RBX
push_rcx # Protect RCX
call %type_name # Get the local's type
mov_rbx,rax # Put struct type* type_size in the right place
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_rcx,[rip+DWORD] %function # Using function
mov_rcx,[rcx+BYTE] !8 # function->locals
call %sym_declare # Declare it
mov_rcx,rax # put it away safely
# Try for main
lea_rax,[rip+DWORD] %main_string # Using "main"
mov_rbx,[rip+DWORD] %function # Using function
mov_rbx,[rbx+BYTE] !16 # function->S
call %match # IF match("main", function->s)
cmp_rax, %0 # possible
jne %collect_local_fresh # try to see if fresh function
# Ok we are in main, now to see if main is fresh
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !8 # function->locals
cmp_rax, %0 # IF NULL == function->locals
jne %collect_local_fresh # try to see if fresh function
# Sweet we are in a fresh main
mov_rax, %-40 # We start at -40
mov_[rcx+BYTE],rax !32 # a->DEPTH = -40
jmp %collect_local_common # Go to the commons
:collect_local_fresh
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !32 # function->args
cmp_rax, %0 # IF NULL == function->args
jne %collect_local_first # Otherwise see if first
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !8 # function->locals
cmp_rax, %0 # IF NULL == function->locals
jne %collect_local_first # Otherwise try first
# Sweet we are in a fresh function
mov_rax, %-16 # We start at -16
mov_[rcx+BYTE],rax !32 # a->DEPTH = -16
jmp %collect_local_common # Go to the commons
:collect_local_first
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !8 # function->locals
cmp_rax, %0 # IF NULL == function->locals
jne %collect_local_else # Looks like we are just another local
# Ok we are the first local
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !32 # function->args
mov_rax,[rax+BYTE] !32 # function->args->depth
sub_rax, %16 # function->arguments->depth - 16
mov_[rcx+BYTE],rax !32 # a->DEPTH = function->arguments->depth - 16
jmp %collect_local_common # Go to the commons
:collect_local_else
# Always the last to know
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !8 # function->locals
mov_rax,[rax+BYTE] !32 # function->locals->depth
sub_rax, %8 # function->locals->depth - 8
mov_[rcx+BYTE],rax !32 # a->DEPTH = function->locals->depth - 8
:collect_local_common
mov_rax,[rip+DWORD] %function # Using function
mov_[rax+BYTE],rcx !8 # function->locals = a
mov_rcx,[rcx+BYTE] !16 # a->S
lea_rax,[rip+DWORD] %collect_local_string_0 # Using "# Defining local "
call %emit_out # emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %emit_out # emit it
lea_rax,[rip+DWORD] %collect_local_string_1 # Using "\n"
call %emit_out # emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rbx,[rax+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # Using "="
call %match # IF match("=", global_token->s)
cmp_rax, %0 # Deal with assignment
jne %collect_local_done # Otherwise finish it
# Deal with assignment
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
call %expression # Recurse
:collect_local_done
lea_rax,[rip+DWORD] %collect_local_string_2 # Using "ERROR in collect_local\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %collect_local_string_3 # Using "push_rax\t#"
call %emit_out # emit it
mov_rax,rcx # put A->S where it belongs
call %emit_out # emit it
lea_rax,[rip+DWORD] %collect_local_string_1 # Using "\n"
call %emit_out # emit it
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:collect_local_string_0
"# Defining local "
:collect_local_string_1
"
"
:collect_local_string_2
"ERROR in collect_local
Missing ;
"
:collect_local_string_3
"push_rax #"
# process_asm function
# Receives nothing
# Returns nothing
# Simply inlines the asm statements
# Uses RBX for global_token temp storage
:process_asm
push_rbx # Protect RBX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %process_asm_string_0 # Using "ERROR in process_asm\nMISSING (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
mov_rbx,[rip+DWORD] %global_token # Using global_token
:process_asm_iter
mov_rax,[rbx+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %34 # IF global_token->S[0] == '"'
jne %process_asm_done # Otherwise be done
mov_rax,[rbx+BYTE] !16 # global_token->S
add_rax, %1 # global_token->S + 1
call %emit_out # Emit it
lea_rax,[rip+DWORD] %process_asm_string_1 # Using "\n"
call %emit_out # Emit it
mov_rbx,[rbx] # global_token->NEXT
mov_[rip+DWORD],rbx %global_token # global_token = global_token->NEXT
jmp %process_asm_iter # keep going
:process_asm_done
lea_rax,[rip+DWORD] %process_asm_string_2 # Using "ERROR in process_asm\nMISSING )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %process_asm_string_3 # Using "ERROR in process_asm\nMISSING ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
pop_rbx # Restore RBX
ret
: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
# Receives nothing
# Returns Nothing
# Increments current_count recurses into expression + statement
# Uses RCX for char* NUMBER_STRING
:process_if
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %current_count # Using current count
mov_rbx,rax # Preparing for update
add_rbx, %1 # current_count + 1
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
call %numerate_number # convert to string
mov_rcx,rax # put NUMBER_STRING in place
lea_rax,[rip+DWORD] %process_if_string_0 # Using "# IF_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %process_if_string_1 # Using "ERROR in process_if\nMISSING (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
call %expression # Recurse to get the IF(...) part
lea_rax,[rip+DWORD] %process_if_string_2 # Using "test_rax,rax\nje %ELSE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_if_string_3 # Using "ERROR in process_if\nMISSING )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
call %statement # Recursive to get the IF(){...} part
lea_rax,[rip+DWORD] %process_if_string_4 # Using "jmp %_END_IF_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_if_string_5 # Using ":ELSE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %else_string # Using "else"
call %match # IF global_token->S == "else"
cmp_rax, %0 # Then we need to collect the else too
jne %process_if_done # Otherwise finish up
# deal with else statement
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
call %statement # Recurse to get the ELSE {...} part
:process_if_done
lea_rax,[rip+DWORD] %process_if_string_6 # Using ":_END_IF_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:process_if_string_0
"# IF_"
:process_if_string_1
"ERROR in process_if
MISSING (
"
:process_if_string_2
"test_rax,rax
je %ELSE_"
:process_if_string_3
"ERROR in process_if
MISSING )
"
:process_if_string_4
"jmp %_END_IF_"
:process_if_string_5
":ELSE_"
:process_if_string_6
":_END_IF_"
# save_break_frame microfunction
# Overwrites RAX and RBX
# Saves break frame on stack
# Returns to caller
:save_break_frame
pop_rbx # Save return Address
mov_rax,[rip+DWORD] %break_frame # Get break_frame
push_rax # Store as nested_locals
mov_rax,[rip+DWORD] %break_target_head # Get break_target_head
push_rax # Store as nested_break_head
mov_rax,[rip+DWORD] %break_target_func # Get break_target_func
push_rax # Store as nested_break_func
mov_rax,[rip+DWORD] %break_target_num # Get break_target_num
push_rax # Store as nested_break_num
push_rbx # Put return back in place
ret # Return to caller
# restore_break_frame microfunction
# Overwrites RAX and RBX
# Restores break frame from stack
# Returns to caller
:restore_break_frame
pop_rbx # Save return Address
pop_rax # Get nested_break_num
mov_[rip+DWORD],rax %break_target_num # Restore break_target_num
pop_rax # Get nested_break_func
mov_[rip+DWORD],rax %break_target_func # Restore break_target_func
pop_rax # Get nested_break_head
mov_[rip+DWORD],rax %break_target_head # Restore break_target_head
pop_rax # Get nested_locals
mov_[rip+DWORD],rax %break_frame # Restore break_frame
push_rbx # Put return back in place
ret # Return to caller
# set_break_frame microfunction
# Receives char* head in RAX and char* num in RBX
# Overwrites RAX and RBX
# Returns to calling function
:set_break_frame
mov_[rip+DWORD],rax %break_target_head # update break_target_head
mov_[rip+DWORD],rbx %break_target_num # update break_target_num
mov_rbx,[rip+DWORD] %function # Using function
mov_rax,[rbx+BYTE] !8 # function->LOCALS
mov_[rip+DWORD],rax %break_frame # break_frame = function->LOCALS
mov_rax,[rbx+BYTE] !16 # function->S
mov_[rip+DWORD],rax %break_target_func # break_target_func = function->S
ret # Return to sender
# process_do function
# Receives Nothing
# Returns Nothing
# Increments current_count and leverages save/restore_break_frame pieces
# Uses RCX for char* NUMBER_STRING
:process_do
push_rbx # Protect RBX
push_rcx # Protect RCX
call %save_break_frame # Save the frame
mov_rax,[rip+DWORD] %current_count # Using current count
mov_rbx,rax # Preparing for update
add_rbx, %1 # current_count + 1
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
call %numerate_number # convert to string
mov_rcx,rax # put NUMBER_STRING in place
lea_rax,[rip+DWORD] %process_do_string_0 # Using "DO_END_"
mov_rbx,rcx # Passing NUMBER_STRING
call %set_break_frame # Set the frame
lea_rax,[rip+DWORD] %process_do_string_1 # Using ":DO_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
call %statement # Do the DO {...} part
lea_rax,[rip+DWORD] %process_do_string_2 # Using "ERROR in process_do\nMISSING while\n"
lea_rbx,[rip+DWORD] %while_string # Using "while"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %process_do_string_3 # Using "ERROR in process_do\nMISSING (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
call %expression # Do the WHILE (...) part
lea_rax,[rip+DWORD] %process_do_string_4 # Using "ERROR in process_do\nMISSING )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %process_do_string_5 # Using "ERROR in process_do\nMISSING ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %process_do_string_6 # Using "test_rax,rax\njne %DO_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_do_string_7 # Using ":DO_END_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
call %restore_break_frame # Restore the old break frame
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
: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_rax,rax
jne %DO_"
:process_do_string_7
":DO_END_"
# process_while function
# Receives nothing
# Returns nothing
# Increments current_count and leverages save/restore_break_frame pieces
# Uses RCX for char* NUMBER_STRING
:process_while
push_rbx # Protect RBX
push_rcx # Protect RCX
call %save_break_frame # Save break_frame
mov_rax,[rip+DWORD] %current_count # Using current count
mov_rbx,rax # Preparing for update
add_rbx, %1 # current_count + 1
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
call %numerate_number # convert to string
mov_rcx,rax # put NUMBER_STRING in place
lea_rax,[rip+DWORD] %process_while_string_0 # Using "END_WHILE_"
mov_rbx,rcx # Passing NUMBER_STRING
call %set_break_frame # Set it and forget it
lea_rax,[rip+DWORD] %process_while_string_1 # Using ":WHILE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %process_while_string_2 # Using "ERROR in process_while\nMISSING (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
call %expression # Deal with the WHILE (...) part
lea_rax,[rip+DWORD] %process_while_string_3 # Using "test_rax,rax\nje %END_WHILE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_while_string_4 # Using "# THEN_while_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_while_string_5 # Using "ERROR in process_while\nMISSING )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
call %statement # Deal with the {....} part
lea_rax,[rip+DWORD] %process_while_string_6 # Using "jmp %WHILE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_while_string_7 # Using ":END_WHILE_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
call %restore_break_frame # Restore the old break frame
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
: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_rax,rax
je %END_WHILE_"
:process_while_string_4
"# THEN_while_"
:process_while_string_5
"ERROR in process_while
MISSING )
"
:process_while_string_6
"jmp %WHILE_"
:process_while_string_7
":END_WHILE_"
# process_for function
# Receives Nothing
# Returns Nothing
# Increments current_count and leverages save/restore_break_frame pieces
# Uses RCX for char* NUMBER_STRING
:process_for
push_rbx # Protect RBX
push_rcx # Protect RCX
call %save_break_frame # Save the frame
mov_rax,[rip+DWORD] %current_count # Using current count
mov_rbx,rax # Preparing for update
add_rbx, %1 # current_count + 1
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
call %numerate_number # convert to string
mov_rcx,rax # put NUMBER_STRING in place
lea_rax,[rip+DWORD] %process_for_string_0 # Using "FOR_END_"
mov_rbx,rcx # Passing NUMBER_STRING
call %set_break_frame # Set it and forget it
lea_rax,[rip+DWORD] %process_for_string_1 # Using "# FOR_initialization_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %process_for_string_2 # Using "ERROR in process_for\nMISSING (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make Sure we have it
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %semicolon # Using ";"
call %match # IF global_token->S == ";"
cmp_rax, %0 # Then no initializer
je %process_for_terminator # And skip getting the expression
# Deal with FOR (...; case
call %expression # Get the FOR ( ... ; part
:process_for_terminator
lea_rax,[rip+DWORD] %process_for_string_3 # Using ":FOR_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_4 # Using "ERROR in process_for\nMISSING ;1\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
call %expression # Get the FOR ( ; ... ; Part
lea_rax,[rip+DWORD] %process_for_string_5 # Using "test_rax,rax\nje %FOR_END_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_6 # Using "jmp %FOR_THEN_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_7 # Using ":FOR_ITER_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_8 # Using "ERROR in process_for\nMISSING ;2\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
call %expression # Get the FOR (;;...) part
lea_rax,[rip+DWORD] %process_for_string_9 # Using "jmp %FOR_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_10 # Using ":FOR_THEN_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_11 # Using "ERROR in process_for\nMISSING )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
call %statement # Get FOR (;;) {...} part
lea_rax,[rip+DWORD] %process_for_string_12 # Using "jmp %FOR_ITER_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Passing NUMBER_STRING
call %uniqueID_out # uniqueID_out(function->s, number_string)
lea_rax,[rip+DWORD] %process_for_string_13 # Using ":FOR_END_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID_out # uniqueID_out(function->s, number_string)
call %restore_break_frame # Restore the old break frame
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
: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_rax,rax
je %FOR_END_"
:process_for_string_6
"jmp %FOR_THEN_"
:process_for_string_7
":FOR_ITER_"
:process_for_string_8
"ERROR in process_for
MISSING ;2
"
:process_for_string_9
"jmp %FOR_"
:process_for_string_10
":FOR_THEN_"
:process_for_string_11
"ERROR in process_for
MISSING )
"
:process_for_string_12
"jmp %FOR_ITER_"
:process_for_string_13
":FOR_END_"
# process_break function
# Receives nothing
# Returns nothing
# Handles the break out of loops case
# Uses RBX for struct token_list* break_frame and RCX for struct token_list* I
:process_break
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %break_target_head # Catch big error
cmp_rax, %0 # IF(NULL == break_target_head)
je %process_break_bad # I'm sorry Mr White but you have stage-3 lung cancer
mov_rax,[rip+DWORD] %function # Using function
mov_rcx,[rax+BYTE] !8 # I = function->LOCALS
mov_rbx,[rip+DWORD] %break_frame # Put break_frame in the right spot
lea_rax,[rip+DWORD] %process_break_string_1 # Using "pop_rbx\t# break_cleanup_locals\n"
:process_break_iter
cmp_rcx, %0 # IF (NULL == I)
je %process_break_cleaned # We are done
cmp_rbx,rcx # IF I != break_frame
je %process_break_cleaned # We are done
call %emit_out # Emit it
mov_rcx,[rcx] # I = I->NEXT
jmp %process_break_iter # Keep looping
:process_break_cleaned
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %process_break_string_2 # Using "jmp %"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %break_target_head # Get what we are in
call %emit_out # Emit it
mov_rax,[rip+DWORD] %break_target_func # Get what function we are in
call %emit_out # Emit it
lea_rax,[rip+DWORD] %underline # Using "_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %break_target_num # Get dem digits
call %emit_out # Emit it
lea_rax,[rip+DWORD] %process_break_string_3 # Using "\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %process_break_string_4 # Using "ERROR in break statement\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:process_break_bad
# Breaking badly
mov_r15, %2 # write to standard error
# call %line_error # Write useful debug info
mov_rax,rcx # put S in the right place
call %File_Print # print it
lea_rax,[rip+DWORD] %process_break_string_0 # Ending string
call %File_Print # print it
jmp %Exit_Failure # Abort Hard
:process_break_string_0
"Not inside of a loop or case statement"
:process_break_string_1
"pop_rbx # break_cleanup_locals
"
:process_break_string_2
"jmp %"
:process_break_string_3
"
"
:process_break_string_4
"ERROR in break statement
Missing ;
"
# expression function
# Receives Nothing
# Returns Nothing
# Walks global_token and updates output_list
# Uses RAX and RBX for match and RCX for char* store
:expression
push_rbx # Protect RBX
push_rcx # Protect RCX
call %bitwise_expr # Collect bitwise expressions
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # "="
call %match # IF global_token->S == "="
cmp_rax, %0 # We have to deal with assignment
jne %expression_done # Looks like nope
# Deal with possible assignment
lea_rcx,[rip+DWORD] %expression_string_1 # Assume "mov_[rbx],al\n" by default
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !8 # global_token->PREV
mov_rbx,[rbx+BYTE] !16 # global_token->PREV->S
lea_rax,[rip+DWORD] %close_bracket # Using "]"
call %match # IF global_token->S == "]"
cmp_rax, %0 # Then we might have a char
jne %expression_int # Otherwise INT
mov_rbx,[rip+DWORD] %current_target # Using current_target
mov_rbx,[rbx+BYTE] !48 # current_target->NAME
lea_rax,[rip+DWORD] %type_char_indirect_name # Using "char*"
call %match # Intentional inefficiency because I feel like it
cmp_rax, %0 # IF current_target->NAME == "char*"
jne %expression_int # Do char anyway
jmp %expression_common # Looks like we have to use "mov_[rbx],al\n"
:expression_int
lea_rcx,[rip+DWORD] %expression_string_0 # Use "mov_[rbx],rax\n"
:expression_common
lea_rax,[rip+DWORD] %expression # Passing expression
call %common_recursion # Recurse
mov_rax,rcx # Using Store
call %emit_out # Emit it
mov_rax, %0 # Using NULL
mov_[rip+DWORD],rax %current_target # current_target = NULL
:expression_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:expression_string_0
"mov_[rbx],rax
"
:expression_string_1
"mov_[rbx],al
"
# bitwise_expr function
# Receives nothing
# Returns nothing
# Walks global_token list and updates output list
# Just calls other functions
:bitwise_expr
call %relational_expr # Walk up the tree
call %bitwise_expr_stub # Let general recursion do the work
ret
# bitwise_expr_stub function
# Receives nothing
# Returns Nothing
# Just calls general_recursion a bunch
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
:bitwise_expr_stub
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_0 # Using "and_rax,rbx\n"
lea_rcx,[rip+DWORD] %bitwise_and # Using "&"
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_0 # Using "and_rax,rbx\n"
lea_rcx,[rip+DWORD] %logical_and # Using "&&"
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_1 # Using "or_rax,rbx\n"
lea_rcx,[rip+DWORD] %bitwise_or # Using "|"
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_1 # Using "or_rax,rbx\n"
lea_rcx,[rip+DWORD] %logical_or # Using "||"
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %relational_expr # Using relational_expr
lea_rbx,[rip+DWORD] %bitwise_expr_stub_string_2 # Using "xor_rax,rbx\n"
lea_rcx,[rip+DWORD] %bitwise_xor # Using "^"
lea_rdx,[rip+DWORD] %bitwise_expr_stub # And recurse
call %general_recursion # Hit it
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:bitwise_expr_stub_string_0
"and_rax,rbx
"
:bitwise_expr_stub_string_1
"or_rax,rbx
"
:bitwise_expr_stub_string_2
"xor_rax,rbx
"
# relational_expr function
# Receives nothing
# Returns Nothing
# Walks global_token list and updates output list
# just calls other function
:relational_expr
call %additive_expr # Walk up the tree
call %relational_expr_stub # Recurse
ret
# relational_expr_stub function
# Receives nothing
# Returns Nothing
# Just calls general_recursion a bunch
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
:relational_expr_stub
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_0 # Using "cmp_rbx,rax\nsetl_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %less_than_string # Using "<"
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_1 # Using "cmp_rbx,rax\nsetle_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %less_than_equal_string # Using "<="
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_2 # Using "cmp_rbx,rax\nsetge_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %greater_than_equal_string # Using ">="
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_3 # Using "cmp_rbx,rax\nsetg_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %greater_than_string # Using ">"
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_4 # Using "cmp_rbx,rax\nsete_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %equal_to_string # Using "=="
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %additive_expr # Using additive_expr
lea_rbx,[rip+DWORD] %relational_expr_stub_string_5 # Using "cmp_rbx,rax\nsetne_al\nmovzx_rax,al\n"
lea_rcx,[rip+DWORD] %not_equal_string # Using "!="
lea_rdx,[rip+DWORD] %relational_expr_stub # And recurse
call %general_recursion # Hit it
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:relational_expr_stub_string_0
"cmp_rbx,rax
setl_al
movzx_rax,al
"
:relational_expr_stub_string_1
"cmp_rbx,rax
setle_al
movzx_rax,al
"
:relational_expr_stub_string_2
"cmp_rbx,rax
setge_al
movzx_rax,al
"
:relational_expr_stub_string_3
"cmp_rbx,rax
setg_al
movzx_rax,al
"
:relational_expr_stub_string_4
"cmp_rbx,rax
sete_al
movzx_rax,al
"
:relational_expr_stub_string_5
"cmp_rbx,rax
setne_al
movzx_rax,al
"
# additive_expr function
# Receives nothing
# Returns Nothing
# Walks global_token list and updates output list
# just calls other function
:additive_expr
call %postfix_expr # Walk up the tree
call %additive_expr_stub # Recurse
ret
# additive_expr_stub function
# Receives nothing
# Returns Nothing
# Just calls general_recursion a bunch
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
:additive_expr_stub
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_0 # Using "add_rax,rbx\n"
lea_rcx,[rip+DWORD] %plus_string # Using "+"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_1 # Using "sub_rbx,rax\nmov_rax,rbx\n"
lea_rcx,[rip+DWORD] %minus_string # Using "-"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_2 # Using "mul_rbx\n"
lea_rcx,[rip+DWORD] %multiply_string # Using "*"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_3 # Using "xchg_rbx,rax\nmov_rdx, %0\ndiv_rbx\n"
lea_rcx,[rip+DWORD] %divide_string # Using "/"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_4 # Using "xchg_rbx,rax\nmov_rdx, %0\ndiv_rbx\nmov_rax,rdx\n"
lea_rcx,[rip+DWORD] %modulus_string # Using "%"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_5 # Using "mov_rcx,rax\nmov_rax,rbx\nsal_rax,cl\n"
lea_rcx,[rip+DWORD] %left_shift_string # Using "<<"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
lea_rax,[rip+DWORD] %postfix_expr # Using postfix_expr
lea_rbx,[rip+DWORD] %additive_expr_stub_string_6 # Using "mov_rcx,rax\nmov_rax,rbx\nsar_rax,cl\n"
lea_rcx,[rip+DWORD] %right_shift_string # Using ">>"
lea_rdx,[rip+DWORD] %additive_expr_stub # And recurse
call %general_recursion # Hit it
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:additive_expr_stub_string_0
"add_rax,rbx
"
:additive_expr_stub_string_1
"sub_rbx,rax
mov_rax,rbx
"
:additive_expr_stub_string_2
"mul_rbx
"
:additive_expr_stub_string_3
"xchg_rbx,rax
mov_rdx, %0
div_rbx
"
:additive_expr_stub_string_4
"xchg_rbx,rax
mov_rdx, %0
div_rbx
mov_rax,rdx
"
:additive_expr_stub_string_5
"mov_rcx,rax
mov_rax,rbx
sal_rax,cl
"
:additive_expr_stub_string_6
"mov_rcx,rax
mov_rax,rbx
sar_rax,cl
"
# postfix_expr function
# Receives nothing
# Returns Nothing
# Walks global_token list and updates output list
# just calls other function
:postfix_expr
call %primary_expr # Walk up the tree
call %postfix_expr_stub # Recurse
ret
# postfix_expr_stub function
# Receives nothing
# Returns Nothing
# Checks for "[" and "->" and deals with them otherwise does nothing
# Uses RAX, RBX, RCX and RDX for passing constants to general recursion
:postfix_expr_stub
push_rbx # Protect RBX
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_bracket # Using "["
call %match # IF global_token->S == "["
cmp_rax, %0 # then we have an array
jne %postfix_expr_stub_arrow # Otherwise try arrow
# Deal with array
call %postfix_expr_array # Get it
call %postfix_expr_stub # Recurse
:postfix_expr_stub_arrow
lea_rax,[rip+DWORD] %arrow_string # Using "->"
call %match # IF global_token->S == "->"
cmp_rax, %0 # Then we need to deal with struct offsets
jne %postfix_expr_stub_done # Otherwise be done
# Deal with arrow
call %postfix_expr_arrow # Get it
call %postfix_expr_stub # Recurse
:postfix_expr_stub_done
pop_rbx # Restore RBX
ret
# unary_expr_sizeof function
# Receives nothing
# Returns nothing
# Uses RCX for A->SIZE
:unary_expr_sizeof
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_0 # Using "ERROR in unary_expr\nMissing (\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
call %type_name # Get the type
mov_rcx,[rax+BYTE] !8 # Set A->TYPE
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_1 # Using "ERROR in unary_expr\nMissing )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_2 # Using "mov_rax, %"
call %emit_out # Emit it
mov_rax,rcx # Put A->SIZE in the right place
call %numerate_number # Turn into string
call %emit_out # Emit it
lea_rax,[rip+DWORD] %unary_expr_sizeof_string_3 # Using "\n"
call %emit_out # Emit it
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
: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
"mov_rax, %"
:unary_expr_sizeof_string_3
"
"
# postfix_expr_array function
# Receives Nothing
# Returns Nothing
# Uses RBX for struct type* ARRAY and RCX for char* ASSIGN
:postfix_expr_array
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %current_target # ARRAY = current_target
push_rax # Protect it
lea_rax,[rip+DWORD] %expression # Using expression
call %common_recursion # Recurse
pop_rbx # Restore array
mov_[rip+DWORD],rbx %current_target # current_target = ARRAY
lea_rcx,[rip+DWORD] %postfix_expr_array_string_0 # ASSIGN = "mov_rax,[rax]\n"
lea_rax,[rip+DWORD] %type_char_indirect_name # Using "char*"
mov_rbx,[rbx+BYTE] !48 # current_target->NAME
call %match # IF current_target->NAME == "char*"
cmp_rax, %0 # load a byte
jne %postfix_expr_array_large # Otherwise adjust
# Deal with loading byte
lea_rcx,[rip+DWORD] %postfix_expr_array_string_1 # ASSIGN = "movsx_rax,BYTE_PTR_[rax]\n"
jmp %postfix_expr_array_common # Do the next bit
:postfix_expr_array_large
# deal with arrays made of things other than chars
lea_rax,[rip+DWORD] %postfix_expr_array_string_2 # Using "sal_rax, !"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %current_target # Using current_target
mov_rax,[rax+BYTE] !24 # current_target->INDIRECT
mov_rax,[rax+BYTE] !8 # current_target->INDIRECT->SIZE
call %ceil_log2 # ceil_log2(current_target->indirect->size)
call %numerate_number # numerate_number(ceil_log2(current_target->indirect->size))
call %emit_out # Emit it
lea_rax,[rip+DWORD] %postfix_expr_array_string_3 # Using "\n"
call %emit_out # Emit it
:postfix_expr_array_common
lea_rax,[rip+DWORD] %postfix_expr_array_string_4 # Using "add_rax,rbx\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %postfix_expr_array_string_5 # Using "ERROR in postfix_expr\nMissing ]\n"
lea_rbx,[rip+DWORD] %close_bracket # Using "]"
call %require_match # Make sure we have it
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # Using "="
call %match # IF global_token->S == "="
cmp_rax, %0 # We need to preserve address
jne %postfix_expr_array_done # Otherwise be done
# Clearing out assign
lea_rcx,[rip+DWORD] %postfix_expr_array_string_6 # ASSIGN = ""
:postfix_expr_array_done
mov_rax,rcx # Using ASSIGN
call %emit_out # Emit it
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:postfix_expr_array_string_0
"mov_rax,[rax]
"
:postfix_expr_array_string_1
"movsx_rax,BYTE_PTR_[rax]
"
:postfix_expr_array_string_2
"sal_rax, !"
:postfix_expr_array_string_3
"
"
:postfix_expr_array_string_4
"add_rax,rbx
"
:postfix_expr_array_string_5
"ERROR in postfix_expr
Missing ]
"
:postfix_expr_array_string_6
'00'
# ceil_log2 function
# Receives int a in RAX
# Performs log2 on A and
# Returns result in RAX
# Uses RBX for INT A and RCX for INT RESULT
:ceil_log2
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx, %0 # RESULT = 0
mov_rbx,rax # put A in right place
sub_rax, %1 # (A - 1)
and_rax,rbx # A & (A - 1)
cmp_rax, %0 # IF 0 == (A & (A - 1))
jne %ceil_log2_iter # Starting from -1
mov_rcx, %-1 # RESULT = -1
:ceil_log2_iter
cmp_rbx, %0 # IF A > 0
jle %ceil_log2_done # Otherwise be done
add_rcx, %1 # RESULT = RESULT + 1
shr_rbx # A = A >> 1
jmp %ceil_log2_iter # Keep looping
:ceil_log2_done
mov_rax,rcx # Return RESULT
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# postfix_expr_arrow function
# Receives nothing
# Returns nothing
# Emits a bunch and updates current_target
# Uses RBX for struct type* I
:postfix_expr_arrow
push_rbx # Protect RBX
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_0 # Using "# looking up offset\n"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rbx,[rax+BYTE] !16 # Using global_token->S
mov_rax,[rip+DWORD] %current_target # Using current_target
call %lookup_member # lookup_member(current_target, global_token->s)
mov_rbx,rax # struct type* I = lookup_member(current_target, global_token->s)
mov_rax,[rax+BYTE] !40 # I->TYPE
mov_[rip+DWORD],rax %current_target # current_target = I->TYPE
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax,[rbx+BYTE] !16 # I->OFFSET
cmp_rax, %0 # IF 0 != I->OFFSET
je %postfix_expr_arrow_first # Then we don't need to do an offset
# Deal with needing an offset
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_1 # Using "# -> offset calculation\nmov_rbx, %"
call %emit_out # Emit it
mov_rax,[rbx+BYTE] !16 # I->OFFSET
call %numerate_number # Convert to string
call %emit_out # Emit it
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_2 # Using "\nadd_rax,rbx\n"
call %emit_out # Emit it
:postfix_expr_arrow_first
mov_rax,[rbx+BYTE] !8 # I->SIZE
cmp_rax, %4 # IF I->SIZE >= 4
jl %postfix_expr_arrow_done # Otherwise be done
# Last chance for load
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rax+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # Using "="
call %match # IF global_token->S == "="
cmp_rax, %0 # Then we have assignment and should not load
je %postfix_expr_arrow_done # Be done
# Deal with load case
lea_rax,[rip+DWORD] %postfix_expr_arrow_string_3 # Using "mov_rax,[rax]\n"
call %emit_out # Emit it
:postfix_expr_arrow_done
pop_rbx # Restore RBX
ret
:postfix_expr_arrow_string_0
"# looking up offset
"
:postfix_expr_arrow_string_1
"# -> offset calculation
mov_rbx, %"
:postfix_expr_arrow_string_2
"
add_rax,rbx
"
:postfix_expr_arrow_string_3
"mov_rax,[rax]
"
# primary_expr function
# Receives nothing
# Returns nothing
:primary_expr
push_rbx # Protect RBX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rax+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %sizeof_string # Using "sizeof"
call %match # See if match
cmp_rax, %0 # IF match
jne %primary_expr_neg # Otherwise try negatives
# Deal with sizeof
call %unary_expr_sizeof # Lets do this
jmp %primary_expr_done # Be done
:primary_expr_neg
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %45 # IF global_token->S[0] == "-"
jne %primary_expr_not # Otherwise try logical NOT
# Deal with negative numbers
lea_rax,[rip+DWORD] %primary_expr_string_0 # Using "mov_rax, %0\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
call %common_recursion # Get what it is notting
lea_rax,[rip+DWORD] %primary_expr_string_1 # Using "sub_rbx,rax\nmov_rax,rbx\n"
call %emit_out # Emit it
jmp %primary_expr_done # Be done
:primary_expr_not
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %33 # IF global_token->S[0] == "!"
jne %primary_expr_bin # Otherwise try '~'
# Deal with logical not
lea_rax,[rip+DWORD] %primary_expr_string_2 # Using "mov_rax, %1\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
call %common_recursion # Get what it is notting
lea_rax,[rip+DWORD] %primary_expr_string_3 # Using "xor_rax,rbx\n"
call %emit_out # Emit it
jmp %primary_expr_done # Be done
:primary_expr_bin
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %126 # IF global_token->S[0] == "~"
jne %primary_expr_paren # Otherwise try paren
# Deal with binary NOT
lea_rax,[rip+DWORD] %postfix_expr # Passing postfix_expr
call %common_recursion # Get what it is notting
lea_rax,[rip+DWORD] %primary_expr_string_4 # Using "not_rax\n"
call %emit_out # Emit it
jmp %primary_expr_done # Be done
:primary_expr_paren
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %40 # IF global_token->S[0] == "("
jne %primary_expr_ch # Otherwise try char
# deal with nesting
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
call %expression # Lets recurse
lea_rax,[rip+DWORD] %primary_expr_string_5 # Using "Error in Primary expression\nDidn't get )\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
jmp %primary_expr_done # Be done
:primary_expr_ch
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %39 # Using "'"
jne %primary_expr_str # Otherwise try string
# Deal with chars
call %primary_expr_char # Handle that char
jmp %primary_expr_done # Be done
:primary_expr_str
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %34 # Using '"'
jne %primary_expr_var # Otherwise try a variable
# Deal with strings
call %primary_expr_string # Handle that string
jmp %primary_expr_done # Be done
:primary_expr_var
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
lea_rbx,[rip+DWORD] %primary_expr_string_6 # Using "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
call %In_Set # See if we have a match
cmp_rax, %1 # IF match
jne %primary_expr_num # otherwise try number
# Deal with variables
call %primary_expr_variable # Deal with variable
jmp %primary_expr_done # Be done
:primary_expr_num
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
lea_rbx,[rip+DWORD] %primary_expr_string_7 # Using "0123456789"
call %In_Set # See if we have a match
cmp_rax, %1 # IF match
jne %primary_expr_fail # otherwise we failed hard
# Deal with numbers
call %primary_expr_number # Collect the number
jmp %primary_expr_done # Be done
:primary_expr_fail
# looks like we hit bad input
# abort before it gets bad
call %primary_expr_failure # No match means failure
:primary_expr_done
pop_rbx # Restore RBX
ret
:primary_expr_string_0
"mov_rax, %0
"
:primary_expr_string_1
"sub_rbx,rax
mov_rax,rbx
"
:primary_expr_string_2
"mov_rax, %1
"
:primary_expr_string_3
"xor_rax,rbx
"
:primary_expr_string_4
"not_rax
"
: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
# Receives nothing
# Returns nothing
# Walks global and updates output
# Uses RAX for struct token_list* a and RCX for char* S
:primary_expr_variable
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rcx,[rax+BYTE] !16 # S = global_token->S
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax,rcx # Using S
mov_rbx,[rip+DWORD] %global_constant_list # Using global_constant_list
call %sym_lookup # sym_lookup(s, global_constant_list)
cmp_rax, %0 # IF NULL == sym_lookup(s, global_constant_list)
je %primary_expr_variable_local # Try locals next
# Deal with constant load
mov_rbx,[rax+BYTE] !32 # a->ARGS
lea_rax,[rip+DWORD] %primary_expr_variable_string_2 # Using "mov_rax, %"
call %emit_out # Emit it
mov_rax,[rbx+BYTE] !16 # a->ARGS->S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %primary_expr_variable_string_1 # Using "\n"
call %emit_out # Emit it
jmp %primary_expr_variable_done # Be done
:primary_expr_variable_local
mov_rax,rcx # Using S
mov_rbx,[rip+DWORD] %function # Using function
mov_rbx,[rbx+BYTE] !8 # function->locals
call %sym_lookup # sym_lookup(s, function->locals)
cmp_rax, %0 # IF NULL == sym_lookup(s, function->locals)
je %primary_expr_variable_arguments # try arguments next
# Deal with local load
call %variable_load # Collect it
jmp %primary_expr_variable_done # Be done
:primary_expr_variable_arguments
mov_rax,rcx # Using S
mov_rbx,[rip+DWORD] %function # Using function
mov_rbx,[rbx+BYTE] !32 # function->args
call %sym_lookup # sym_lookup(s, function->args)
cmp_rax, %0 # IF NULL == sym_lookup(s, function->args)
je %primary_expr_variable_function # try functions next
# Deal with argument load
call %variable_load # Collect it
jmp %primary_expr_variable_done # Be done
:primary_expr_variable_function
mov_rax,rcx # Using S
mov_rbx,[rip+DWORD] %global_function_list # Using global_function_list
call %sym_lookup # sym_lookup(s, global_function_list)
cmp_rax, %0 # IF NULL == sym_lookup(s, global_function_list)
je %primary_expr_variable_global # try globals next
# Deal with functions
call %function_load # Deal with the function
jmp %primary_expr_variable_done # Be done
:primary_expr_variable_global
mov_rax,rcx # Using S
mov_rbx,[rip+DWORD] %global_symbol_list # Using global_symbol_list
call %sym_lookup # sym_lookup(s, global_symbol_list)
cmp_rax, %0 # IF NULL == sym_lookup(s, global_symbol_list)
je %primary_expr_variable_error # Give up
# Deal with globals
call %global_load # Collect that global
jmp %primary_expr_variable_done # Be done
:primary_expr_variable_error
mov_r15, %2 # write to standard error
# call %line_error # Write useful debug info
mov_rax,rcx # put S in the right place
call %File_Print # print it
lea_rax,[rip+DWORD] %primary_expr_variable_string_0 # Ending string
call %File_Print # print it
jmp %Exit_Failure # Abort Hard
:primary_expr_variable_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:primary_expr_variable_string_0
" is not a defined symbol
"
:primary_expr_variable_string_1
"
"
:primary_expr_variable_string_2
"mov_rax, %"
# function_call function
# Receives char* S in RAX and int BOOL in RBX
# Builds stack frames before and tears them down after function calls
# Uses RCX for char* S, RDX for int BOOL, RSI for PASSED
:function_call
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rsi # Protect RSI
mov_rcx,rax # Put S in place
mov_rdx,rbx # Put BOOL in place
mov_rsi, %0 # PASSED = 0
lea_rax,[rip+DWORD] %function_call_string_0 # Using "ERROR in process_expression_list\nNo ( was found\n"
lea_rbx,[rip+DWORD] %open_paren # Using "("
call %require_match # Make sure we have it
lea_rax,[rip+DWORD] %function_call_string_1 # Using "push_rdi\t# Prevent overwriting in recursion\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_2 # Using "push_rbp\t# Protect the old base pointer\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_3 # Using "mov_rdi,rsp\t# Copy new base pointer\n"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %41 # IF global_token->S[0] == ")"
je %function_call_gen_done # Then no arguments to send
# looks like we have arguments to collect
call %expression # Collect the argument
lea_rax,[rip+DWORD] %function_call_string_4 # Using "push_rax\t#_process_expression1\n"
call %emit_out # Emit it
mov_rsi, %1 # PASSED = 1
:function_call_gen_iter
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %44 # IF global_token->S[0] == ","
jne %function_call_gen_done # Otherwise we are done
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
call %expression # Collect the argument
lea_rax,[rip+DWORD] %function_call_string_5 # Using "push_rax\t#_process_expression2\n"
call %emit_out # Emit it
add_rsi, %1 # PASSED = PASSED + 1
jmp %function_call_gen_iter # Keep trying
:function_call_gen_done
# All is collected
lea_rax,[rip+DWORD] %function_call_string_6 # Using "ERROR in process_expression_list\nNo ) was found\n"
lea_rbx,[rip+DWORD] %close_paren # Using ")"
call %require_match # Make sure we have it
cmp_rdx, %0 # IF(BOOL == TRUE)
jne %function_call_static # Otherwise it is a static call
# Deal with a passed function pointer
lea_rax,[rip+DWORD] %function_call_string_7 # Using "lea_rax,[rbp+DWORD] %"
call %emit_out # Emit it
mov_rax,rcx # Using S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_8 # Using "\nmov_rax,[rax]\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_9 # Using "mov_rbp,rdi\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_10 # Using "call_rax\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_13 # Using "pop_rbx\t# _process_expression_locals\n"
jmp %function_call_cleanup # Clean up
:function_call_static
# Deal with fixed function name
lea_rax,[rip+DWORD] %function_call_string_9 # Using "mov_rbp,rdi\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_11 # Using "call %FUNCTION_"
call %emit_out # Emit it
mov_rax,rcx # Using S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_12 # Using "\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_13 # Using "pop_rbx\t# _process_expression_locals\n"
:function_call_cleanup
cmp_rsi, %0 # IF PASSED > 0
jle %function_call_done # Otherwise be done
# The desired string is already in RAX
call %emit_out # Emit it
sub_rsi, %1 # PASSED = PASSED - 1
jmp %function_call_cleanup # Keep going
:function_call_done
lea_rax,[rip+DWORD] %function_call_string_14 # Using "POP_rbp\t# Restore old base pointer\n"
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_call_string_15 # Using "POP_rdi\t# Prevent overwrite\n"
call %emit_out # Emit it
pop_rsi # Restore RSI
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:function_call_string_0
"ERROR in process_expression_list
No ( was found
"
:function_call_string_1
"push_rdi # Prevent overwriting in recursion
"
:function_call_string_2
"push_rbp # Protect the old base pointer
"
:function_call_string_3
"mov_rdi,rsp # Copy new base pointer
"
:function_call_string_4
"push_rax #_process_expression1
"
:function_call_string_5
"push_rax #_process_expression2
"
:function_call_string_6
"ERROR in process_expression_list
No ) was found
"
:function_call_string_7
"lea_rax,[rbp+DWORD] %"
:function_call_string_8
"
mov_rax,[rax]
"
:function_call_string_9
"mov_rbp,rdi
"
:function_call_string_10
"call_rax
"
:function_call_string_11
"call %FUNCTION_"
:function_call_string_12
"
"
:function_call_string_13
"pop_rbx # _process_expression_locals
"
:function_call_string_14
"pop_rbp # Restore old base pointer
"
:function_call_string_15
"pop_rdi # Prevent overwrite
"
# variable_load function
# Receives struct token_list* A in RAX
# Returns nothing
# Updates output and current_target
# Uses RCX for A
:variable_load
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # Protect A
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_paren # Using "("
call %match # IF global_token->S == "("
cmp_rax, %0 # Then it might be a function
jne %variable_load_regular # Otherwise it is regular
mov_rbx,[rcx+BYTE] !24 # A->TYPE
mov_rbx,[rbx+BYTE] !48 # A->TYPE->NAME
lea_rax,[rip+DWORD] %type_function_name # Using "FUNCTION"
call %match # IF A->TYPE->NAME == "FUNCTION"
cmp_rax, %0 # Then it must be a function
jne %variable_load_regular # otherwise just another regular
# deal with function
mov_rax,[rcx+BYTE] !32 # A->DEPTH
call %numerate_number # Convert to string
mov_rbx, %0 # pass 0 for true
call %function_call # Create the function call
jmp %variable_load_done # Be done
:variable_load_regular
mov_rax,[rcx+BYTE] !24 # A->TYPE
mov_[rip+DWORD],rax %current_target # current_target = A->TYPE
lea_rax,[rip+DWORD] %variable_load_string_0 # Using "lea_rax,[rbp+DWORD] %"
call %emit_out # Emit it
mov_rax,[rcx+BYTE] !32 # A->DEPTH
call %numerate_number # Convert to string
call %emit_out # Emit it
lea_rax,[rip+DWORD] %variable_load_string_1 # Using "\n"
call %emit_out # Emit it
# Check for special case of assignment
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # Using "="
call %match # IF global_token->S == "="
cmp_rax, %0 # Then we skip loading
je %variable_load_done # And be done
# Deal with common case
lea_rax,[rip+DWORD] %variable_load_string_2 # Using "mov_rax,[rax]\n"
call %emit_out # Emit it
:variable_load_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:variable_load_string_0
"lea_rax,[rbp+DWORD] %"
:variable_load_string_1
"
"
:variable_load_string_2
"mov_rax,[rax]
"
# function_load function
# Receives struct token_list* a in RAX
# Returns nothing
# Uses RCX to hold A->S
:function_load
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rax,[rax+BYTE] !16 # A->S
mov_rcx,rax # Protect A->S
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_paren # Using "("
call %match # IF global_token->S == "("
cmp_rax, %0 # The we need to do a function call
jne %function_load_regular # Otherwise just load it's address
# Deal with function call
mov_rax,rcx # Using A->S
mov_rbx, %1 # Using FALSE
call %function_call # Deal with it
jmp %function_load_done # Be done
:function_load_regular
lea_rax,[rip+DWORD] %function_load_string_0 # Using "lea_rax,[rip+DWORD] %FUNCTION_"
call %emit_out # Emit it
mov_rax,rcx # Using A->S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %function_load_string_1 # Using "\n"
call %emit_out # Emit it
:function_load_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:function_load_string_0
"lea_rax,[rip+DWORD] %FUNCTION_"
:function_load_string_1
"
"
# global_load function
# Receives struct token_list* A in RAX
# Returns nothing
# Uses RBX to hold A->S
:global_load
push_rbx # Protect RBX
mov_rbx,rax # Set as A
mov_rbx,[rbx+BYTE] !16 # Set as A->S
mov_rax,[rax+BYTE] !24 # A->TYPE
mov_[rip+DWORD],rax %current_target # current_target = A->TYPE
lea_rax,[rip+DWORD] %global_load_string_0 # Using "lea_rax,[rip+DWORD] %GLOBAL_"
call %emit_out # Emit it
mov_rax,rbx # Using A->S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %global_load_string_1 # Using "\n"
call %emit_out # Emit it
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %equal # "="
call %match # IF global_token->S == "="
cmp_rax, %0 # We need to skip for assignment
je %global_load_done # and be done
# Otherwise we are loading the contents
lea_rax,[rip+DWORD] %global_load_string_2 # Using "mov_rax,[rax]\n"
call %emit_out # Emit it
:global_load_done
pop_rbx # Restore RBX
ret
:global_load_string_0
"lea_rax,[rip+DWORD] %GLOBAL_"
:global_load_string_1
"
"
:global_load_string_2
"mov_rax,[rax]
"
# sym_lookup function
# Receives char* S in RAX and struct token_list* symbol_list in RBX
# Uses I->S in RAX, S in RBX and I in RCX
# Returns match or NULL
:sym_lookup
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rbx # I = symbol_list
mov_rbx,rax # Put S in the right place
:sym_lookup_iter
cmp_rcx, %0 # IF NULL == I
je %sym_lookup_done # We failed to find match
mov_rax,[rcx+BYTE] !16 # Using I->S
call %match # IF I->S == S
cmp_rax, %0 # then be done
je %sym_lookup_done # Failed
mov_rcx,[rcx] # I = I->NEXT
jmp %sym_lookup_iter # otherwise keep looping
:sym_lookup_done
mov_rax,rcx # Return I
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# primary_expr_number function
# Receives nothing
# Returns nothing
# Simply uses current global token to update output and then steps to next global_token
:primary_expr_number
lea_rax,[rip+DWORD] %primary_expr_number_string_0 # Using "mov_rax, %"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %emit_out # Emit it
lea_rax,[rip+DWORD] %primary_expr_number_string_1 # Using "\n"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
ret
:primary_expr_number_string_0
"mov_rax, %"
:primary_expr_number_string_1
"
"
# primary_expr_string function
# receives nothing
# Returns nothing
# creates entries for string and calls to generate string output
# uses RCX for char* number_string
:primary_expr_string
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,[rip+DWORD] %current_count # Using current_count
mov_rax,rbx # And putting it in the right place
call %numerate_number # Get the string
mov_rcx,rax # protect number_string
add_rbx, %1 # current_count + 1
mov_[rip+DWORD],rbx %current_count # current_count = current_count + 1
lea_rax,[rip+DWORD] %primary_expr_string_string_0 # Using "lea_rax,[rip+DWORD] %STRING_"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
mov_rbx,rcx # Put number_string in the right place
call %uniqueID_out # Make it unique
# Generate the target
lea_rax,[rip+DWORD] %primary_expr_string_string_1 # Using ":STRING_"
mov_rbx,[rip+DWORD] %strings_list # Using strings_list
call %emit # Emit it
mov_rbx,rax # put new strings_list in place
mov_rax,[rip+DWORD] %function # Using function
mov_rax,[rax+BYTE] !16 # function->S
call %uniqueID # Make it unique
mov_rbx,rax # put new strings_list in place
# Parse the string
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %parse_string # convert to useful form
call %emit # Emit it
mov_[rip+DWORD],rax %strings_list # Update Strings _list
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:primary_expr_string_string_0
"lea_rax,[rip+DWORD] %STRING_"
:primary_expr_string_string_1
":STRING_"
# primary_expr_char function
# Receives nothing
# Returns nothing
# Updates output_list using global_token
:primary_expr_char
push_rbx # Protect RBX
push_rcx # Protect RCX
lea_rax,[rip+DWORD] %primary_expr_char_string_0 # Using "mov_rax, %"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
add_rax, %1 # global_token->S + 1
call %escape_lookup # Get the char
call %numerate_number # Convert to string
call %emit_out # emit it
lea_rax,[rip+DWORD] %primary_expr_char_string_1 # Using "\n"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:primary_expr_char_string_0
"mov_rax, %"
:primary_expr_char_string_1
"
"
# primary_expr_failure function
# Receives nothing
# Does not return but aborts hard
# Complains about the bad input
:primary_expr_failure
# call %line_error # Get line of issue
mov_r15, %2 # write to standard error
lea_rax,[rip+DWORD] %primary_expr_failure_string_0 # Using "Received "
call %File_Print # Print it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %File_Print # Print it
lea_rax,[rip+DWORD] %primary_expr_failure_string_1 # Using " in primary_expr\n"
call %File_Print # Print it
jmp %Exit_Failure # Abort Hard
:primary_expr_failure_string_0
"Received "
:primary_expr_failure_string_1
" in primary_expr
"
# general_recursion function
# Receives FUNCTION F in RAX, char* S in RBX, char* name in RCX and FUNCTION iterate in RDX
# Returns nothing
# Uses RCX for char* S, RDX for FUNCTION iterate and RBP for FUNCTION F
# But generally recurses a shitload
:general_recursion
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rbp # Protect RBP
mov_rbp,rax # Protect F
mov_rax,rcx # Put name in the right place
mov_rcx,rbx # Protect S
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
call %match # IF match(name, global_token->s)
cmp_rax, %0 # If true we do
jne %general_recursion_done # Otherwise skip it
# Deal with the recursion
mov_rax,rbp # Put F in the right place
call %common_recursion # Recurse
mov_rax,rcx # Put S in the right place
call %emit_out # Emit it
mov_rax,rdx # Put iterate in the right place
call_rax # Down the rabbit hole
:general_recursion_done
pop_rbp # Restore RBP
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# promote_type function
# Receives struct type* a in RAX and struct type* b in RBX
# Returns the most recent type in RAX
# Uses RAX for struct type* I, RCX for struct type* A and RDX for struct type* B
:promote_type
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
cmp_rbx, %0 # IF NULL == B
je %promote_type_done # Just return A
mov_rcx,rax # Put A in place
mov_rdx,rbx # Put B in place
mov_rax,rbx # IF NULL == A
cmp_rcx, %0 # Then we just return B
je %promote_type_done # Be done
# Looks like we need to walk the list
mov_rcx,[rcx+BYTE] !48 # A->NAME
mov_rdx,[rdx+BYTE] !48 # B->NAME
mov_rax,[rip+DWORD] %global_types # I = global_types
:promote_type_iter
cmp_rax, %0 # IF NULL == I
je %promote_type_done # Just be done
mov_rbx,[rax+BYTE] !48 # I->NAME
cmp_rbx,rcx # IF(A->NAME == I->NAME)
je %promote_type_done # Be done
cmp_rbx,rdx # IF(B->NAME == I->NAME)
je %promote_type_done # Be done
mov_rbx,[rax+BYTE] !24 # I->INDIRECT
mov_rbx,[rbx+BYTE] !48 # I->INDIRECT->NAME
cmp_rbx,rcx # IF(A->NAME == I->INDIRECT->NAME)
je %promote_type_done # Be done
cmp_rbx,rdx # IF(B->NAME == I->INDIRECT->NAME)
je %promote_type_done # Be done
mov_rax,[rax] # I = I->NEXT
jmp %promote_type_iter # Keep going
:promote_type_done
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# common_recursion function
# Receives FUNCTION F in RAX
# Returns Nothing
# Walks global_token list and update output_list
# Updates current_target
# Uses RBX to hold FUNCTION F and struct type* last_type
:common_recursion
push_rbx # Protect RBX
mov_rbx,rax # Put FUNCTION F safely out of the way
lea_rax,[rip+DWORD] %common_recursion_string_0 # Using "push_rax\t#_common_recursion\n"
call %emit_out # Emit it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax,rbx # Prepare for function call
mov_rbx,[rip+DWORD] %current_target # Get last type
call_rax # F();
mov_rax,[rip+DWORD] %current_target # Get current_target
call %promote_type # get the right type
mov_[rip+DWORD],rax %current_target # Set new current_target
lea_rax,[rip+DWORD] %common_recursion_string_1 # Using "pop_rbx\t# _common_recursion\n"
call %emit_out # Emit it
pop_rbx # Restore RBX
ret
:common_recursion_string_0
"push_rax #_common_recursion
"
:common_recursion_string_1
"pop_rbx # _common_recursion
"
# require_match function
# Receives char* message in RAX and char* required in RBX
# Returns nothing
# Uses RCX to hold message and updates global_token
:require_match
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # put the message somewhere safe
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %match # IF required == global_token->S
cmp_rax, %0 # we are fine
je %require_match_good # otherwise pain
# Deal with bad times
# call %line_error # Tell user what went wrong
mov_r15, %2 # write to standard error
mov_rax,rcx # using our message
call %File_Print # Print it
jmp %Exit_Failure # Abort HARD
:require_match_good
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->next
mov_[rip+DWORD],rax %global_token # global_token = global_token->next
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# uniqueID Function
# Receives char *S in RAX, struct token_list* l in RBX and char* num in RCX
# Returns updated struct token_list* L in RAX
:uniqueID
push_rbx # Protect RBX
push_rcx # Protect RCX
call %emit # emit(s, l)
mov_rbx,rax # Put L in correct place
lea_rax,[rip+DWORD] %underline # Using "_"
call %emit # emit("_", l)
mov_rbx,rax # Put L in correct place
mov_rax,rcx # Put num in correct place
call %emit # emit(num, l)
mov_rbx,rax # Put L in correct place
lea_rax,[rip+DWORD] %uniqueID_string_0 # Using "\n"
call %emit # emit("\n", l)
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:uniqueID_string_0
"
"
# uniqueID_out function
# Receives char* S in RAX and char* num in RBX
# Returns nothing
:uniqueID_out
push_rax # Protect RAX
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rbx # Put num in right spot
mov_rbx,[rip+DWORD] %output_list # Using output_list
call %uniqueID # Get updated list
mov_[rip+DWORD],rax %output_list # output_list = uniqueID(s, output_list, num)
pop_rcx # Restore RCX
pop_rbx # Restore RBX
pop_rax # Restore RAX
ret
# emit_out function
# Receives char* S in RAX
# Returns nothing
# Updates output_list
# MUST NOT ALTER REGISTERS
:emit_out
push_rax # Protect RAX
push_rbx # Protect RBX
mov_rbx,[rip+DWORD] %output_list # Using output_list
call %emit # emit it
mov_[rip+DWORD],rax %output_list # update it
pop_rbx # Restore RBX
pop_rax # Restore RAX
ret
# emit function
# Receives char *s in RAX and struct token_list* head in RBX
# Returns struct token_list* T in RAX
:emit
push_rcx # Protect RCX
mov_rcx,rax # put S out of the way
mov_rax, %40 # sizeof(struct token_list)
call %malloc # get T
mov_[rax],rbx # t->next = head;
mov_[rax+BYTE],rcx !16 # t->s = s;
pop_rcx # Restore RCX
ret
# escape_lookup function
# Receives char* c in RAX
# Returns integer value of char in RAX
# Aborts hard if unknown escape is received
# Uses RCX to hold char* C
:escape_lookup
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # Put char* C in safe place
mov_al,[rcx] # Load c[0]
movzx_rax,al # make it useful
cmp_rax, %92 # If '\\' != c[0]
jne %escape_lookup_done # Be done
mov_rbx,rcx # Prepare for walk
add_rbx, %1 # increment
mov_bl,[rbx] # load c[1]
movzx_rbx,bl # make it useful
cmp_rbx, %120 # Check if \x??
je %escape_lookup_hex # Deal with hex
# Deal with \? escapes
mov_rax, %10 # Guess "\n"
cmp_rbx, %110 # If n
je %escape_lookup_done # Be done
mov_rax, %9 # Guess "\t"
cmp_rbx, %116 # If t
je %escape_lookup_done # Be done
mov_rax,rbx # "\\", "'" and '"' all encode as themselves
cmp_rbx, %92 # If "\\"
je %escape_lookup_done # Be done
cmp_rbx, %39 # IF "'"
je %escape_lookup_done # Be done
cmp_rbx, %34 # IF '"'
je %escape_lookup_done # Be done
mov_rax, %13 # Guess "\r"
cmp_rbx, %114 # IF r
je %escape_lookup_done # Be done
# Looks like we have no clue what we are doing
# Aborting hard
mov_r15, %2 # write to standard error
lea_rax,[rip+DWORD] %escape_lookup_string_0 # Using "Unknown escape received: "
call %File_Print # Print it
mov_rax,rcx # Using C
call %File_Print # Print it
lea_rax,[rip+DWORD] %escape_lookup_string_1 # Using " Unable to process\n"
call %File_Print # Print it
jmp %Exit_Failure # Abort Hard
:escape_lookup_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:escape_lookup_hex
# Give up on C and just assume they know what they are doing
add_rcx, %2 # increment
mov_al,[rcx] # c[2]
movzx_rax,al # make it useful
add_rcx, %1 # increment
call %char2hex # Get the hex value
sal_rax, !4 # c << 4
mov_bl,[rcx] # c[3]
movzx_rbx,bl # make it useful
xchg_rax,rbx # protect c << 4
call %char2hex # Get the hex value
add_rax,rbx # hex(c[2]) << 4 + hex(c[3])
jmp %escape_lookup_done # Be done
:escape_lookup_string_0
"Unknown escape received: "
:escape_lookup_string_1
" Unable to process
"
# char2hex function
# Receives char in RAX
# Returns hex or aborts hard
:char2hex
sub_rax, %48 # Try 0-9
cmp_rax, %10 # Otherwise fun times
jl %char2hex_done # Be done
# Deal with A-F
and_rax, %0xDF # Unset High bit turning a-f into A-F
sub_rax, %7 # Shift down into position
cmp_rax, %10 # Everything below A is bad
jl %char2hex_fail # And should fail
cmp_rax, %16 # Make sure we are below F
jl %char2hex_done # If so be done
:char2hex_fail
# Time to fail hard
mov_r15, %2 # write to standard error
lea_rax,[rip+DWORD] %char2hex_string_0 # Using "Tried to print non-hex number\n"
call %File_Print # Print it
jmp %Exit_Failure # Abort Hard
:char2hex_done
ret
:char2hex_string_0
"Tried to print non-hex number
"
# parse_string function
# Receives char* string in RAX
# Returns cleaned up string
# Protects char* string in RBX
:parse_string
push_rbx # Protect RBX
mov_rbx,rax # Protect char* string
call %weird # Determine if we have a weird string
cmp_rax, %0 # If weird
je %parse_string_weird # Deal with it
# Dealing with regular string
mov_rax,rbx # Passing Char* string
call %collect_regular_string # Collect it
jmp %parse_string_done # Be done
:parse_string_weird
mov_rax,rbx # Passing Char* string
call %collect_weird_string # Collect it
:parse_string_done
pop_rbx # Restore RBX
ret
# weird function
# Receives char* string in RAX
# Returns true(0) or false(1) in RAX
# Uses RCX to hold char* string
:weird
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rax # Place string in safe place
add_rcx, %1 # increment past the "
:weird_reset
mov_al,[rcx] # Load a char
movzx_rax,al # Make it useful
cmp_rax, %0 # IF NULL == C
je %weird_false # Nothing weird found
cmp_rax, %92 # IF '\\'
jne %weird_escaped # Deal with escaping
# Deal with escape
mov_rax,rcx # We are passing the string
call %escape_lookup # to look it up
add_rcx, %1 # string = string + 1
mov_bl,[rcx] # get string[1]
movzx_rbx,bl # make it useful
cmp_rbx, %120 # IF 'x' == string[1]
jne %weird_escaped # otherwise skip the gap
add_rcx, %2 # string = string + 2
:weird_escaped
push_rax # Protect C in case we need it
lea_rbx,[rip+DWORD] %weird_string_0 # Use "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
call %In_Set # To find if weird
cmp_rax, %1 # IF TRUE
pop_rax # Restore C
jne %weird_true # Then not weird
add_rcx, %1 # string = string + 1
# Last chance for weird
lea_rbx,[rip+DWORD] %weird_string_1 # Use "\t\n\r "
call %In_Set # Check for special case
cmp_rax, %1 # IF TRUE
jne %weird_reset # Otherwise not in the special case
# Deal with possible special case
mov_al,[rcx] # Load string[1]
movzx_rax,al # Make it useful
cmp_rax, %58 # IF string[1] == ":"
je %weird_true # Then we hit the special case
jmp %weird_reset # Keep trying
:weird_done
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:weird_true
mov_rax, %0 # Return true
jmp %weird_done # Be done
:weird_false
mov_rax, %1 # Return false
jmp %weird_done # Be done
:weird_string_0
"
!#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
:weird_string_1
'09 0a 0d 20 00'
# collect_regular_string function
# Receives char* string in RAX
# Malloc and creates new string to return in RAX
# Uses RCX for return string and RDX for passed string
:collect_regular_string
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rdx,rax # Protect our passed string
mov_rax, %256 # We need 256 bytes of storage
call %malloc # Get our new pointer
mov_rcx,rax # put it in place
push_rax # protect until done
:collect_regular_string_reset
mov_al,[rdx] # string[0]
movzx_rax,al # Make it useful
cmp_rax, %0 # See if we hit the end
je %collect_regular_string_done # And be done
cmp_rax, %92 # IF string[0] == '\\'
je %collect_regular_string_escaped # Deal with that mess
# deal with boring char
mov_[rcx],al # hold_string[index] = string[0]
add_rcx, %1 # Increment it
add_rdx, %1 # Increment it
jmp %collect_regular_string_reset # And keep going
:collect_regular_string_escaped
mov_rax,rdx # Using string
call %escape_lookup # Get the char
mov_[rcx],al # hold_string[index] = escape_lookup(string)
add_rdx, %1 # Increment it
add_rcx, %1 # Increment it
mov_al,[rdx] # string[0]
movzx_rax,al # Make it useful
add_rdx, %1 # Increment it
cmp_rax, %120 # IF 'x' == string[1]
jne %collect_regular_string_reset # Otherwise keep going
add_rdx, %2 # Increment it
jmp %collect_regular_string_reset # Keep going
:collect_regular_string_done
mov_rax, %34 # Using '"'
mov_[rcx],al # hold_string[index] = '"'
add_rcx, %1 # Increment it
mov_rax, %10 # Using "\n"
mov_[rcx],al # hold_string[index] = '\n'
pop_rax # Return our new string
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# collect_weird_string function
# Receives char* string in RAX
# Mallocs and returns char* hold in RAX
# Uses RCX for char* hold and RDX for char* string
:collect_weird_string
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rdx,rax # Protect our passed string
mov_rax, %512 # We need 512 bytes of storage
call %malloc # Get our new pointer
mov_rcx,rax # put it in place
push_rax # protect until done
mov_rax, %39 # Using "'"
mov_[rcx],al # hold_string[index] = "'"
add_rcx, %1 # Increment it
add_rdx, %1 # Increment it
:collect_weird_string_reset
mov_al,[rdx] # Read a byte
movzx_rax,al # Make it useful
cmp_rax, %0 # IF NULL == string[0]
je %collect_weird_string_done # Be done
mov_rax, %32 # Using ' '
mov_[rcx],al # hold_string[index] = ' '
add_rcx, %1 # Increment it
mov_rax,rdx # Using string
call %escape_lookup # Get the char
call %hex8 # Update RCX
mov_al,[rdx] # Read a byte
movzx_rax,al # Make it useful
add_rdx, %1 # Increment it
cmp_rax, %92 # IF string[0] == '\\'
jne %collect_weird_string_reset # Otherwise keep going
mov_al,[rdx] # Read a byte
movzx_rax,al # Make it useful
add_rdx, %1 # Increment it
cmp_rax, %120 # IF 'x' == string[1]
jne %collect_weird_string_reset # Otherwise keep going
add_rdx, %2 # Increment it
jmp %collect_weird_string_reset # Keep going
:collect_weird_string_done
mov_rax, %32 # Using ' '
mov_[rcx],al # hold_string[index] = ' '
add_rcx, %1 # Increment it
mov_rax, %48 # Using '0'
mov_[rcx],al # hold_string[index] = '0'
add_rcx, %1 # Increment it
mov_[rcx],al # hold_string[index] = '0'
add_rcx, %1 # Increment it
mov_rax, %39 # Using "'"
mov_[rcx],al # hold_string[index] = "'"
add_rcx, %1 # Increment it
mov_rax, %10 # Using "\n"
mov_[rcx],al # hold_string[index] = '\n'
pop_rax # Return our new string
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# HEX to ascii routine
# Receives INT in RAX and CHAR* in RCX
# Stores ascii of INT in CHAR*
# Returns only modifying RAX and RCX
:hex8
push_rax # Protect bottom nibble
shr_rax, !4 # do high nibble first
call %hex4 # Store it
pop_rax # do low nibble
:hex4
and_rax, %0xF # isolate nibble
add_al, !0x30 # convert to ascii
cmp_al, !0x39 # valid digit?
jbe %hex1 # yes
add_al, !7 # use alpha range
:hex1
mov_[rcx],al # store result
add_rcx, %1 # next position
ret
# type_name function
# Receives nothing
# Returns type_size in RAX
# Uses RCX for STRUCT TYPE* RET
:type_name
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %struct # Using "struct"
call %match # IF global_token->S == "struct"
mov_rcx,rax # Protect structure
cmp_rax, %0 # need to skip over "struct"
jne %type_name_native # otherwise keep going
# Deal with possible STRUCTs
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx] # global_token->next
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
mov_rax,[rbx+BYTE] !16 # global_token->S
mov_rbx,[rip+DWORD] %global_types # get all known types
call %lookup_type # Find type if possible
mov_rcx,rax # Set ret
cmp_rax, %0 # IF NULL == ret
jne %type_name_common # We have to create struct
# Create a struct
call %create_struct # Create a new struct
mov_rcx, %0 # We wish to return NULL
jmp %type_name_done # be done
:type_name_native
# Deal only with native types
mov_rax,rbx # Put global_token->S in the right place
mov_rbx,[rip+DWORD] %global_types # get all known types
call %lookup_type # Find the type if possible
mov_rcx,rax # Set ret
cmp_rax, %0 # IF NULL == ret
jne %type_name_common # We need to abort hard
# Aborting hard
mov_r15, %2 # write to standard error
lea_rax,[rip+DWORD] %type_name_string_0 # Print header
call %File_Print # Print it
mov_rax,[rip+DWORD] %global_token # Using global token
mov_rax,[rax+BYTE] !16 # global_token->S
call %File_Print # Print it
lea_rax,[rip+DWORD] %type_name_string_1 # Print footer
call %File_Print # Print it
# call %line_error # Give details
jmp %Exit_Failure # Abort
:type_name_common
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx] # global_token->next
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
:type_name_iter
mov_rax,[rbx+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # make it useful
cmp_rax, %42 # IF global_token->S[0] == '*'
jne %type_name_done # recurse
# Deal with char**
mov_rcx,[rcx+BYTE] !24 # ret = ret->indirect
mov_rbx,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rbx] # global_token->next
mov_[rip+DWORD],rbx %global_token # global_token = global_token->next
jmp %type_name_iter # keep looping
:type_name_done
mov_rax,rcx # put ret in the right place
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:type_name_string_0
"Unknown type "
:type_name_string_1
"
"
# lookup_type function
# Receives char* s in RAX and struct type* start in RBX
# Returns struct type* in RAX
# Uses RBX for S and RCX for I
:lookup_type
push_rbx # Protect RBX
push_rcx # Protect RCX
mov_rcx,rbx # I = Start
mov_rbx,rax # Put S in place
:lookup_type_iter
cmp_rcx, %0 # Check if I == NULL
je %lookup_type_done # return NULL
mov_rax,[rcx+BYTE] !48 # I->NAME
call %match # Check if matching
cmp_rax, %0 # IF I->NAME == S
je %lookup_type_done # return it
mov_rcx,[rcx] # Otherwise I = I->NEXT
jmp %lookup_type_iter # And keep looping
:lookup_type_done
mov_rax,rcx # return either I or NULL
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# create_struct function
# Receives nothing
# Returns nothing
# Uses global_token to malloc a struct's definition
# Uses RCX for int OFFSET, RDX for struct type* head, RBP for struct type* I,
# RDI for member_size (Which is passed) and RSI for LAST
# RAX and RBX are used for scratch
:create_struct
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rbp # Protect RBP
push_rdi # Protect RDI
push_rsi # Protect RSI
mov_rcx, %0 # OFFSET = 0
mov_rdi, %0 # member_size = 0
mov_rax, %56 # sizeof(struct type)
call %malloc # malloc(sizeof(struct type))
mov_rdx,rax # Set HEAD
mov_rax, %56 # sizeof(struct type)
call %malloc # malloc(sizeof(struct type))
mov_rbp,rax # Set I
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_[rdx+BYTE],rax !48 # HEAD->NAME = global_token->S
mov_[rbp+BYTE],rax !48 # I->NAME = global_token->S
mov_[rdx+BYTE],rbp !24 # HEAD->INDIRECT = I
mov_[rbp+BYTE],rdx !24 # I->INDIRECT = HEAD
mov_rax,[rip+DWORD] %global_types # Using global_types
mov_[rdx],rax # HEAD->NEXT = global_types
mov_[rip+DWORD],rdx %global_types # global_types = HEAD
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax, %8 # Using register size
mov_[rbp+BYTE],rax !8 # I->SIZE = register size
lea_rax,[rip+DWORD] %create_struct_string_0 # Using "ERROR in create_struct\n Missing {\n"
lea_rbx,[rip+DWORD] %open_curly_brace # Using "{"
call %require_match # Make sure we have it
mov_rsi, %0 # LAST = NULL
:create_struct_iter
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # Make it useful
cmp_rax, %125 # IF global_token->S[0] == "}"
je %create_struct_done # be done
# Looks like we are adding members
# Lets see if it is a union
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
lea_rbx,[rip+DWORD] %union # Using "union"
call %match # IF match(global_token->s, "union")
cmp_rax, %0 # Deal with union
jne %create_struct_single # Otherwise deal with singles
# Deal with union
mov_rax,rsi # Put last in right place
mov_rbx,rcx # put offset in right place
call %build_union # ASSEMBLE
mov_rsi,rax # last = build_union(last, offset)
add_rcx,rdi # offset = offset + member_size
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
jmp %create_struct_iter # keep going
:create_struct_single
# deal with singles
mov_rax,rsi # Put last in right place
mov_rbx,rcx # put offset in right place
call %build_member # ASSEMBLE
mov_rsi,rax # last = build_union(last, offset)
add_rcx,rdi # offset = offset + member_size
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
jmp %create_struct_iter # keep going
:create_struct_done
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %create_struct_string_1 # Using "ERROR in create_struct\n Missing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
mov_[rdx+BYTE],rcx !8 # HEAD->SIZE = OFFSET
mov_[rdx+BYTE],rsi !32 # HEAD->MEMBERS = LAST
mov_[rbp+BYTE],rsi !32 # I->MEMBERS = LAST
pop_rsi # Restore RSI
pop_rdi # Restore RDI
pop_rbp # Restore RBP
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:create_struct_string_0
"ERROR in create_struct
Missing {
"
:create_struct_string_1
"ERROR in create_struct
Missing ;
"
# lookup_member function
# Receives struct type* parent in RAX and char* name in RBX
# Returns struct type* I in RAX
# Uses char* NAME in RBX, RCX for struct type* I and RDX to hold parent for errors
# Aborts hard if not found
:lookup_member
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rdx,rax # Protect Parent
mov_rcx,[rax+BYTE] !32 # struct type* I = parent->MEMBERS
:lookup_member_iter
cmp_rcx, %0 # IF I == NULL
je %lookup_member_fail # Abort HARD
mov_rax,[rcx+BYTE] !48 # Using I->NAME
call %match # IF I->NAME == NAME
cmp_rax, %0 # Then we have found the member
mov_rax,rcx # Prepare for return
mov_rcx,[rcx+BYTE] !32 # Prepare for loop I = I->MEMBERS
jne %lookup_member_iter # Looks like we are looping
# I is already in RAX
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:lookup_member_fail
mov_r15, %2 # write to standard error
lea_rax,[rip+DWORD] %lookup_member_string_0 # Using "ERROR in lookup_member "
call %File_Print # print it
mov_rax,[rdx+BYTE] !48 # PARENT->NAME
call %File_Print # print it
lea_rax,[rip+DWORD] %arrow_string # Using "->"
call %File_Print # print it
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
call %File_Print # print it
lea_rax,[rip+DWORD] %lookup_member_string_1 # Using " does not exist\n"
call %File_Print # print it
# call %line_error # Write useful debug info
lea_rax,[rip+DWORD] %lookup_member_string_2 # Using "\n"
call %File_Print # print it
jmp %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
# Receives struct type* last in RAX, int offset in RBX and global member_size in RDI
# Updates member_size in RDI and returns struct type* I in RAX
# Uses RCX for struct type* member_type and RDX for struct type* I
:build_member
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rdx,rax # Put last out of the way
mov_rax, %56 # Allocate type
call %malloc # Get I
mov_[rax+BYTE],rdx !32 # I->MEMBERS = LAST
mov_[rax+BYTE],rbx !16 # I->OFFSET = OFFSET
mov_rdx,rax # Put I in place
call %type_name # Get member_type
mov_rcx,rax # Put in place
mov_[rdx+BYTE],rcx !40 # I->TYPE = MEMBER_TYPE
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rbx,[rax+BYTE] !16 # global_token->S
mov_[rdx+BYTE],rbx !48 # I->NAME = global_token->S
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
# Check if we have an array
mov_rbx,[rax+BYTE] !16 # global_token->S
lea_rax,[rip+DWORD] %open_bracket # Using "["
call %match # IF global_token->S == "["
cmp_rax, %0 # Then we have to deal with arrays in our structs
je %build_member_array # So deal with that pain
# Deal with non-array case
mov_rax,[rcx+BYTE] !8 # member_type->SIZE
mov_[rdx+BYTE],rax !8 # I->SIZE = member_type->SIZE
jmp %build_member_done # Be done
:build_member_array
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax,[rax+BYTE] !16 # global_token->S
call %numerate_string # convert number
mov_rbx,[rcx+BYTE] !40 # member_type->TYPE
mov_rbx,[rbx+BYTE] !8 # member_type->TYPE->SIZE
imul_rax,rbx # member_type->type->size * numerate_string(global_token->s)
mov_[rdx+BYTE],rax !8 # I->SIZE = member_type->type->size * numerate_string(global_token->s)
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %build_member_string_0 # Using "Struct only supports [num] form\n"
lea_rbx,[rip+DWORD] %close_bracket # Using "]"
call %require_match # Make sure we have it
:build_member_done
mov_rdi,[rdx+BYTE] !8 # MEMBER_SIZE = I->SIZE
mov_[rdx+BYTE],rcx !40 # I->TYPE = MEMBER_TYPE
mov_rax,rdx # Return I
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:build_member_string_0
"Struct only supports [num] form
"
# build_union function
# Receives struct type* last in RAX, int offset in RBX and global member_size in RDI
# Updates member_size in RDI and returns struct type* LAST in RAX
# Uses RCX for struct type* last, RDX for int offset, RSI for int size and RDI for int member_size
:build_union
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rsi # Protect RSI
mov_rcx,rax # Put LAST in right spot
mov_rdx,rbx # Put OFFSET in right spot
mov_rsi, %0 # SIZE = 0
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
lea_rax,[rip+DWORD] %build_union_string_0 # Using "ERROR in build_union\nMissing {\n"
lea_rbx,[rip+DWORD] %open_curly_brace # Using "{"
call %require_match # Make sure we have it
:build_union_iter
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax+BYTE] !16 # global_token->S
mov_al,[rax] # global_token->S[0]
movzx_rax,al # make it useful
cmp_rax, %125 # IF global_token->S[0] == "}"
je %build_union_done # Be done
# Collect union member
mov_rax,rcx # Passing LAST
mov_rbx,rdx # Passing offset
call %build_member # build_member(last, offset)
mov_rcx,rax # last = build_member(last, offset)
cmp_rsi,rdi # IF member_size > size
jg %build_union_size # Then update size
# deal with member_size > size
mov_rsi,rdi # SIZE = MEMBER_SIZE
:build_union_size
lea_rax,[rip+DWORD] %build_union_string_1 # Using "ERROR in build_union\nMissing ;\n"
lea_rbx,[rip+DWORD] %semicolon # Using ";"
call %require_match # Make sure we have it
jmp %build_union_iter # Keep going
:build_union_done
mov_rdi,rsi # MEMBER_SIZE = SIZE
mov_rax,[rip+DWORD] %global_token # Using global_token
mov_rax,[rax] # global_token->NEXT
mov_[rip+DWORD],rax %global_token # global_token = global_token->NEXT
mov_rax,rcx # Return last
pop_rsi # Restore RSI
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:build_union_string_0
"ERROR in build_union
Missing {
"
:build_union_string_1
"ERROR in build_union
Missing ;
"
# sym_declare function
# Receives char *s in RAX, struct type* t in RBX, and struct token_list* list in RCX
# Returns struct token_list* in RAX
# Uses RAX for A
:sym_declare
push_rdx # Protect RDX
mov_rdx,rax # Get char *S safely out of the way
mov_rax, %40 # Using sizeof(struct token_list)
call %malloc # Get pointer to A
mov_[rax],rcx # A->NEXT = LIST
mov_[rax+BYTE],rdx !16 # A->S = S
mov_[rax+BYTE],rbx !24 # A->TYPE = T
pop_rdx # Restore RDX
ret
# match function
# Receives CHAR* in RAX and CHAR* in RBX
# Returns 0 (TRUE) or 1 (FALSE) in RAX
:match
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
mov_rcx,rax # S1 in place
mov_rdx,rbx # S2 in place
:match_Loop
mov_al,[rcx] # S1[0]
movzx_rax,al # Make it useful
mov_bl,[rdx] # S2[0]
movzx_rbx,bl # Make it useful
cmp_rax,rbx # See if they match
jne %match_False # If not
add_rcx, %1 # S1 = S1 + 1
add_rdx, %1 # S2 = S2 + 1
cmp_rax, %0 # If reached end of string
je %match_Done # Perfect match
jmp %match_Loop # Otherwise keep looping
:match_False
mov_rax, %1 # Return false
:match_Done
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# numerate_number function
# Receives an INT A in RAX
# Returns char* result in RAX
# Allocates 16 bytes of memory
# Behaves badly when given a negative number too large
# Uses RAX for temp, RBX for DIVISOR, RDX for mod/0, RSI for result[i] and RBP for A
:numerate_number
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rsi # Protect RSI
push_rbp # Protect RBP
mov_rbp,rax # Protect A
mov_rax, %16 # 16 bytes
call %malloc # Get our pointer
push_rax # Protect our pointer
mov_rsi,rax # put pointer in right place
mov_rbx, %1000000000 # Set divisor to largest positive number that fits in 32bits
cmp_rbp, %0 # Deal with 0 case
je %numerate_number_ZERO # If it is
jg %numerate_number_positive # If it is positive
# Deal with negative case
mov_rax, %45 # Using "-"
mov_[rsi],al # Write it
add_rsi, %1 # increment
imul_rbp, %-1 # A = A * -1
:numerate_number_positive
mov_rdx, %0 # Set top to 0
mov_rax,rbp # Using A as bottom
idiv_rbx # rdx:rax % rbx -> rdx + rdx:rax / rbx -> rax [Even if we don't want it]
cmp_rax, %0 # IF 0 == (a / divisor)
jne %numerate_number_iter # Clean up those leading Zeros
mov_rdx, %0 # Set top to 0
mov_rax,rbx # Using Divisor for bottom
mov_rbx, %10 # Make this shit work because idiv 10 doesn't work
idiv_rbx # rdx:rax % 10 -> rdx + rdx:rax / 10 -> rax [Even if we don't want it]
mov_rbx,rax # Update divisor
jmp %numerate_number_positive # Keep collecting
:numerate_number_iter
cmp_rbx, %0 # IF DIVISOR < 0
jle %numerate_number_done # Be done
mov_rdx, %0 # Set top to 0
mov_rax,rbp # Using A as bottom
idiv_rbx # rdx:rax % rbx -> rdx + rdx:rax / rbx -> rax [Even if we don't want it]
add_rax, %48 # ((a / divisor) + 48)
mov_[rsi],al # Write it
mov_rbp,rdx # a = a % divisor
mov_rdx, %0 # Set top to 0
mov_rax,rbx # Using Divisor for bottom
mov_rbx, %10 # Make this shit work because idiv 10 doesn't work
idiv_rbx # rdx:rax % 10 -> rdx + rdx:rax / 10 -> rax [Even if we don't want it]
mov_rbx,rax # Update divisor
add_rsi, %1 # increment
jmp %numerate_number_iter # Keep going
:numerate_number_done
pop_rax # Restore our result
pop_rbp # Restore RBP
pop_rsi # Restore RSI
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
:numerate_number_ZERO
mov_rax, %48 # Using '0'
mov_[rsi],al # Write it
add_rsi, %1 # increment
jmp %numerate_number_done # Be done
# numerate_string function
# Receives CHAR* in RAX
# Returns value of CHAR* in RAX
# Uses RAX for VALUE, RBX for S, RCX for CH and RSI for NEGATIVE?
:numerate_string
push_rbx # Protect RBX
push_rcx # Protect RCX
push_rdx # Protect RDX
push_rsi # Protect RSI
mov_rbx,rax # put S in correct place
mov_rax, %0 # Initialize to Zero
:numerate_string_loop
mov_cl,[rbx+BYTE] !1 # S[1]
movzx_rcx,cl # make it useful
cmp_rcx, %120 # IF 'x' == S[1]
je %numerate_hex # Deal with hex input
# Assume decimal input
mov_rsi, %0 # Assume no negation
mov_cl,[rbx] # S[0]
movzx_rcx,cl # make it useful
cmp_rcx, %45 # IF '-' == S[0]
jne %numerate_decimal # Skip negation
mov_rsi, %1 # Set FLAG
add_rbx, %1 # S = S + 1
:numerate_decimal
mov_cl,[rbx] # S[0]
movzx_rcx,cl # make it useful
cmp_rcx, %0 # IF NULL == S[0]
je %numerate_decimal_done # We are done
imul_rax, %10 # VALUE = VALUE * 10
sub_rcx, %48 # CH = CH - '0'
cmp_rcx, %9 # Check for illegal
jg %numerate_string_fail # If CH > '9'
cmp_rcx, %0 # Check for illegal
jl %numerate_string_fail # IF CH < 0
add_rax,rcx # VALUE = VALUE + CH
add_rbx, %1 # S = S + 1
jmp %numerate_decimal # Keep looping
:numerate_decimal_done
cmp_rsi, %1 # Check if need to negate
jne %numerate_string_done # Nope
imul_rax, %-1 # VALUE = VALUE * -1
jmp %numerate_string_done # Done
:numerate_hex
add_rbx, %2 # S = S + 2
:numerate_hex_loop
mov_cl,[rbx] # S[0]
movzx_rcx,cl # make it useful
cmp_rcx, %0 # IF NULL == S[0]
je %numerate_string_done # We are done
shl_rax, !4 # VALUE = VALUE << 4
sub_rcx, %48 # CH = CH - '0'
cmp_rcx, %10 # IF 10 >= CH
jl %numerate_hex_digit # NO
sub_rcx, %7 # Push A-F into range
:numerate_hex_digit
cmp_rcx, %15 # Check for illegal
jg %numerate_string_fail # If CH > 'F'
cmp_rcx, %0 # Check for illegal
jl %numerate_string_fail # IF CH < 0
add_rax,rcx # VALUE = VALUE + CH
add_rbx, %1 # S = S + 1
jmp %numerate_hex_loop # Keep looping
:numerate_string_fail
mov_rax, %0 # return ZERO
:numerate_string_done
pop_rsi # Restore RSI
pop_rdx # Restore RDX
pop_rcx # Restore RCX
pop_rbx # Restore RBX
ret
# Exit_Failure function
# Receives nothing
# And aborts hard
# Does NOT return
:Exit_Failure
mov_rax, %1 # All is wrong
jmp %Done_1 # Exit gracefully
# rcx: file handle
:close_file
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[rcx+BYTE] !16 # file_handle->close(file_handle)
mov_rsp,[rsp+BYTE] !40 # deallocate stack
ret
# rcx: handle
# rdx: &guid
# r9: agent_handle
# returns interface
:open_protocol
push_rax # allocate stack for interface
mov_r8,rsp # arg3 = &interface
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
push !1 # arg6 = EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
push !0 # arg5 = NULL
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %280 # system->boot->open_protocol(handle, &guid, &interface, agent_handle, 0, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL)
mov_rsp,[rsp+BYTE] !56 # deallocate stack
pop_rax # get interface
ret
# rcx: handle
# rdx: &guid
# r8: agent_handle
:close_protocol
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
mov_r9, %0 # arg4 = NULL
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %288 # system->boot->close_protocol(handle, &guid, agent_handle, 0)
mov_rsp,[rsp+BYTE] !40 # deallocate stack
ret
# rdx: number of bytes to allocate
# r14: system->boot
# returns pointer in rax
:allocate_pool
push_rdx # allocate stack for pool pointer
mov_r8,rsp # arg3 = &pool
mov_rcx, %2 # arg1 = EFI_LOADER_DATA
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool)
mov_rsp,[rsp+BYTE] !40 # deallocate stack
pop_rax # get pool
ret
# rcx: memory pool
# r14: system->boot
:free_pool
push_rsp # align stack to 16 bytes
push_[rsp] # align stack to 16 bytes
and_rsp, !-16 # align stack to 16 bytes
sub_rsp, %32 # allocate shadow stack space for UEFI function
call_[r14+DWORD] %72 # system->boot->free_pool(pool)
mov_rsp,[rsp+BYTE] !40 # deallocate stack
ret
# Switch to uefi stack
# does not change any other registers
:enter_uefi_stack
mov_[rip+DWORD],rax %temp_rax # save RAX
pop_rax # Save return address
mov_[rip+DWORD],rsp %user_stack # save user stack
mov_rsp,[rip+DWORD] %uefi_stack # restore system stack
push_rax # Restore return address
mov_rax,[rip+DWORD] %temp_rax # restore RAX
ret
# Switch to user stack
# does not change any other registers
:exit_uefi_stack
mov_[rip+DWORD],rax %temp_rax # save RAX
pop_rax # Save return address
mov_[rip+DWORD],rsp %uefi_stack # save system stack
mov_rsp,[rip+DWORD] %user_stack # restore user stack
push_rax # Restore return address
mov_rax,[rip+DWORD] %temp_rax # restore RAX
ret
# debug_list function
# Receives struct token_list* in RAX
# Prints contents of list and exits
# Does NOT return
:debug_list
mov_r12,rax # Protect the list pointer
mov_r15, %2 # write to standard error
:debug_list_iter
# Header
lea_rax,[rip+DWORD] %debug_list_string0 # Using our first string
call %File_Print # Print it
mov_rax,r12 # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
# NEXT
lea_rax,[rip+DWORD] %debug_list_string1 # Using our second string
call %File_Print # Print it
mov_rax,[r12] # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
# PREV
lea_rax,[rip+DWORD] %debug_list_string2 # Using our third string
call %File_Print # Print it
mov_rax,[r12+BYTE] !8 # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
# S
lea_rax,[rip+DWORD] %debug_list_string3 # Using our fourth string
call %File_Print # Print it
mov_rax,[r12+BYTE] !16 # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
# S Contents
lea_rax,[rip+DWORD] %debug_list_string4 # Using our fifth string
call %File_Print # Print it
mov_rax,[r12+BYTE] !16 # Use address of string
cmp_rax, %0 # IF NULL Pointer
jne %debug_list_null # otherwise display
lea_rax,[rip+DWORD] %debug_list_string_null # Give meaningful message instead
:debug_list_null
call %File_Print # Print it
# TYPE
lea_rax,[rip+DWORD] %debug_list_string5 # Using our sixth string
call %File_Print # Print it
mov_rax,[r12+BYTE] !24 # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
# ARGS/DEPTH
lea_rax,[rip+DWORD] %debug_list_string6 # Using our seventh string
call %File_Print # Print it
mov_rax,[r12+BYTE] !32 # Use address of pointer
call %numerate_number # Convert it into string
call %File_Print # Print it
mov_rax, %10 # Add "\n"
call %fputc # print it
call %fputc # print it
mov_r12,[r12] # TOKEN = TOKEN->NEXT
cmp_r12, %0 # Check if NULL
jne %debug_list_iter # iterate otherwise
mov_rax, %666 # All is HELL
jmp %abort # 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>::<"
# 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
"%"
:underline
"_"
:prim_types
:type_void
%type_int>type_void %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_void>type_void %0 # INDIRECT
NULL # MEMBERS
%type_void>type_void %0 # TYPE
%type_void_name>type_void %0 # NAME
:type_int
%type_char>type_int %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_int>type_int %0 # INDIRECT
NULL # MEMBERS
%type_int>type_int %0 # TYPE
%type_int_name>type_int %0 # NAME
:type_char
%type_file>type_char %0 # NEXT
%1 %0 # SIZE
NULL # OFFSET
%type_char_indirect>type_char %0 # INDIRECT
NULL # MEMBERS
%type_char>type_char %0 # TYPE
%type_char_name>type_char %0 # NAME
:type_char_indirect
%type_file>type_char_indirect %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_char_double_indirect>type_char_indirect %0 # INDIRECT
NULL # MEMBERS
%type_char_indirect>type_char_indirect %0 # TYPE
%type_char_indirect_name>type_char_indirect %0 # NAME
:type_char_double_indirect
%type_file>type_char_double_indirect %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_char_double_indirect>type_char_double_indirect %0 # INDIRECT
NULL # MEMBERS
%type_char_indirect>type_char_double_indirect %0xFFFFFFFF # TYPE
%type_char_double_indirect_name>type_char_double_indirect %0 # NAME
:type_file
%type_function>type_file %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_file>type_file %0 # INDIRECT
NULL # MEMBERS
%type_file>type_file %0 # TYPE
%type_file_name>type_file %0 # NAME
:type_function
%type_unsigned>type_function %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_function>type_function %0 # INDIRECT
NULL # MEMBERS
%type_function>type_function %0 # TYPE
%type_function_name>type_function %0 # NAME
:type_unsigned
%type_long>type_unsigned %0 # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_unsigned>type_unsigned %0 # INDIRECT
NULL # MEMBERS
%type_unsigned>type_unsigned %0 # TYPE
%type_unsigned_name>type_unsigned %0 # NAME
:type_long
NULL # NEXT
%8 %0 # SIZE
NULL # OFFSET
%type_long>type_long %0 # INDIRECT
NULL # MEMBERS
%type_long>type_long %0 # TYPE
%type_long_name>type_long %0 # NAME
:type_void_name
"void"
:type_int_name
"int"
:type_char_name
"char"
:type_char_indirect_name
"char*"
:type_char_double_indirect_name
"char**"
:type_file_name
"FILE"
:type_function_name
"FUNCTION"
:type_unsigned_name
"unsigned"
:type_long_name
"long"
:Address_of
NULL
:C
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
# Needed to zero pad pointer to 64 bits
NULL
:globals_list
NULL
:output_list
NULL
:string_index
NULL
:strings_list
NULL
# Protocol GUIDs
:LOADED_IMAGE_PROTOCOL
%0x5B1B31A1
@0x9562
@0x11D2
!0x8E !0x3F !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B
:SIMPLE_FS_PROTOCOL
%0x964E5B22
@0x6459
@0x11D2
!0x8E !0x39 !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B
:malloc_pool
NULL
:malloc_pointer
NULL
:uefi_stack
NULL
:user_stack
NULL
:temp_rax
NULL
:fin
NULL
:fout
NULL
:rootdir
NULL
:system
NULL
:image_handle
NULL
:root_device
NULL
:WCHAR
%0 # WCHAR with null terminator
:ELF_end