From b18a37171829033246cacfbc347c82f6a1608d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andrius=20=C5=A0tikonas?= Date: Sat, 8 Oct 2022 01:20:46 +0100 Subject: [PATCH] Actually commit cc_amd64.M1 which was forgotten in the previous commit. --- amd64/Development/cc_amd64.S | 4 +- amd64/PE32-amd64.hex2 | 2 +- amd64/cc_amd64.M1 | 5719 ++++++++++++++++++++++++++++++++++ 3 files changed, 5722 insertions(+), 3 deletions(-) create mode 100644 amd64/cc_amd64.M1 diff --git a/amd64/Development/cc_amd64.S b/amd64/Development/cc_amd64.S index 63d91b6..76b052d 100644 --- a/amd64/Development/cc_amd64.S +++ b/amd64/Development/cc_amd64.S @@ -2544,7 +2544,7 @@ ceil_log2_iter: jle ceil_log2_done # Otherwise be done add rcx, 1 # RESULT = RESULT + 1 - shr rbx, 1 # A = A >> 1 + shr rbx # A = A >> 1 jmp ceil_log2_iter # Keep looping ceil_log2_done: @@ -4387,7 +4387,7 @@ numerate_number: 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 + 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 diff --git a/amd64/PE32-amd64.hex2 b/amd64/PE32-amd64.hex2 index aad4474..10fd1dd 100644 --- a/amd64/PE32-amd64.hex2 +++ b/amd64/PE32-amd64.hex2 @@ -51,7 +51,7 @@ F0 00 # SizeOfOptionalHeader 00 00 00 00 # ImageVersion 00 00 00 00 # SubsystemVersion 00 00 00 00 # Win32VersionValue -00 20 00 00 # SizeOfImage +00 00 10 00 # SizeOfImage 70 01 00 00 # SizeOfHeaders 00 00 00 00 # CheckSum (isn't used at all) 0A 00 # Subsystem diff --git a/amd64/cc_amd64.M1 b/amd64/cc_amd64.M1 new file mode 100644 index 0000000..71fd7e9 --- /dev/null +++ b/amd64/cc_amd64.M1 @@ -0,0 +1,5719 @@ +# 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 . + +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 and_rax, 4825 +DEFINE and_rax,rbx 4821D8 +DEFINE add_rbx,[rdi+BYTE] 48035F +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_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_[rax+BYTE],rbx 488958 +DEFINE mov_[rdx+BYTE],rcx 48894A +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_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],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],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 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 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 + 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, %16 # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !8 # rootfs->open_volume(rootfs, &rootdir) + add_rsp, %16 # 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 + + # Open file for reading + pop_r8 # arg3 = in + 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 + pop_r8 # 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 16 MiB of memory + mov_rdx, %0x1000000 # allocate 16 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, %0x1000000 # 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, %0x400000 # Allocate 4 MiB for user stack + call %malloc + mov_[rip+DWORD],rax %user_stack # Save 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 + # Free pool + push_rax # save exit code + + call %enter_uefi_stack # Switch back to UEFI stack + + 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 + mov_rsp,rbp # restore stack + 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 FILE* in R15 and 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 and FILE* in R15 +# 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 + mov_rsi, %0 # zero rsi + push_rsi # allocate stack + mov_r8,rsp # arg3 = &input + sub_rsp, %24 # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !32 # fin->read() + add_rsp, %24 # 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 + sub_rsp, %16 # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !8 # system->err->output_string(system->err, WCHAR*) + add_rsp, %16 # 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 + 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, %24 # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !40 # fout->write() + add_rsp, %40 # 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 # "RETURN\n" + call %match # IF output->s == "RETURN\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 # "RETURN\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 +"RETURN +" + +: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 "JUMP %" + 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 +"JUMP %" + +: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 "RETURN\n" + mov_rbx,[rip+DWORD] %output_list # Using output + mov_rbx,[rbx+BYTE] !16 # output->S + call %match # IF output->S == "RETURN\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 +"RETURN +" + +: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 "RETURN\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 +"RETURN +" + + +# 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\nJUMP_EQ %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 "JUMP %_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 +JUMP_EQ %ELSE_" + +:process_if_string_3 +"ERROR in process_if +MISSING ) +" + +:process_if_string_4 +"JUMP %_END_IF_" + +:process_if_string_5 +":ELSE_" + +:process_if_string_6 +":_END_IF_" + + +# save_break_frame microfunction +# Overwrites 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\nJUMP_NE %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 +JUMP_NE %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\nJUMP_EQ %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 "JUMP %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 +JUMP_EQ %END_WHILE_" + +:process_while_string_4 +"# THEN_while_" + +:process_while_string_5 +"ERROR in process_while +MISSING ) +" + +:process_while_string_6 +"JUMP %WHILE_" + +:process_while_string_7 +":END_WHILE_" + + +# process_for function +# 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\nJUMP_EQ %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 "JUMP %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 "JUMP %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 "JUMP %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 +JUMP_EQ %FOR_END_" + +:process_for_string_6 +"JUMP %FOR_THEN_" + +:process_for_string_7 +":FOR_ITER_" + +:process_for_string_8 +"ERROR in process_for +MISSING ;2 +" + +:process_for_string_9 +"JUMP %FOR_" + +:process_for_string_10 +":FOR_THEN_" + +:process_for_string_11 +"ERROR in process_for +MISSING ) +" + +:process_for_string_12 +"JUMP %FOR_ITER_" + +:process_for_string_13 +":FOR_END_" + + +# process_break function +# 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 "JUMP %" + 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 +"JUMP %" + +: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 "STORE_CHAR\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 "STORE_CHAR\n" + +:expression_int + lea_rcx,[rip+DWORD] %expression_string_0 # Use "STORE_INTEGER\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 +"STORE_INTEGER +" + +:expression_string_1 +"STORE_CHAR +" + + +# 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_rbx_rax_into_rax\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_rbx_rax_into_rax +" + + +# 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\nSETL\nMOVEZX\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\nSETLE\nMOVEZX\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\nSETGE\nMOVEZX\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\nSETG\nMOVEZX\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\nSETE\nMOVEZX\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\nSETNE\nMOVEZX\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 +SETL +MOVEZX +" + +:relational_expr_stub_string_1 +"CMP +SETLE +MOVEZX +" + +:relational_expr_stub_string_2 +"CMP +SETGE +MOVEZX +" + +:relational_expr_stub_string_3 +"CMP +SETG +MOVEZX +" + +:relational_expr_stub_string_4 +"CMP +SETE +MOVEZX +" + +:relational_expr_stub_string_5 +"CMP +SETNE +MOVEZX +" + + +# 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_rbx_to_rax\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 "SUBTRACT_rax_from_rbx_into_rbx\nMOVE_rbx_to_rax\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 "MULTIPLY_rax_by_rbx_into_rax\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_rax_rbx\nLOAD_IMMEDIATE_rdx %0\nDIVIDE_rax_by_rbx_into_rax\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_rax_rbx\nLOAD_IMMEDIATE_rdx %0\nMODULUS_rax_from_rbx_into_rbx\nMOVE_rdx_to_rax\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 "COPY_rax_to_rcx\nCOPY_rbx_to_rax\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 "COPY_rax_to_rcx\nCOPY_rbx_to_rax\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_rbx_to_rax +" + +:additive_expr_stub_string_1 +"SUBTRACT_rax_from_rbx_into_rbx +MOVE_rbx_to_rax +" + +:additive_expr_stub_string_2 +"MULTIPLY_rax_by_rbx_into_rax +" + +:additive_expr_stub_string_3 +"XCHG_rax_rbx +LOAD_IMMEDIATE_rdx %0 +DIVIDE_rax_by_rbx_into_rax +" + +:additive_expr_stub_string_4 +"XCHG_rax_rbx +LOAD_IMMEDIATE_rdx %0 +MODULUS_rax_from_rbx_into_rbx +MOVE_rdx_to_rax +" + +:additive_expr_stub_string_5 +"COPY_rax_to_rcx +COPY_rbx_to_rax +SAL_rax_cl +" + +:additive_expr_stub_string_6 +"COPY_rax_to_rcx +COPY_rbx_to_rax +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 "LOAD_IMMEDIATE_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 +"LOAD_IMMEDIATE_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 = "LOAD_INTEGER\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 = "LOAD_BYTE\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_Immediate8 !" + 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_rbx_to_rax\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 +"LOAD_INTEGER +" + +:postfix_expr_array_string_1 +"LOAD_BYTE +" + +:postfix_expr_array_string_2 +"SAL_rax_Immediate8 !" + +:postfix_expr_array_string_3 +" +" + +:postfix_expr_array_string_4 +"ADD_rbx_to_rax +" + +: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\nLOAD_IMMEDIATE_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_rbx_to_rax\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 "LOAD_INTEGER\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 +LOAD_IMMEDIATE_rbx %" + +:postfix_expr_arrow_string_2 +" +ADD_rbx_to_rax +" + +:postfix_expr_arrow_string_3 +"LOAD_INTEGER +" + + +# 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 "LOAD_IMMEDIATE_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 "SUBTRACT_rax_from_rbx_into_rbx\nMOVE_rbx_to_rax\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 "LOAD_IMMEDIATE_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_rbx_rax_into_rax\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 +"LOAD_IMMEDIATE_rax %0 +" + +:primary_expr_string_1 +"SUBTRACT_rax_from_rbx_into_rbx +MOVE_rbx_to_rax +" + +:primary_expr_string_2 +"LOAD_IMMEDIATE_rax %1 +" + +:primary_expr_string_3 +"XOR_rbx_rax_into_rax +" + +: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 "LOAD_IMMEDIATE_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 +"LOAD_IMMEDIATE_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 "COPY_RSP_to_RDI\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 "LOAD_BASE_ADDRESS_rax %" + call %emit_out # Emit it + + mov_rax,rcx # Using S + call %emit_out # Emit it + + lea_rax,[rip+DWORD] %function_call_string_8 # Using "\nLOAD_INTEGER\n" + call %emit_out # Emit it + + lea_rax,[rip+DWORD] %function_call_string_9 # Using "COPY_rdi_to_rbp\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 "COPY_rdi_to_rbp\n" + call %emit_out # Emit it + + lea_rax,[rip+DWORD] %function_call_string_11 # Using "CALL_IMMEDIATE %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 +"COPY_RSP_to_RDI # 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 +"LOAD_BASE_ADDRESS_rax %" + +:function_call_string_8 +" +LOAD_INTEGER +" + +:function_call_string_9 +"COPY_rdi_to_rbp +" + +:function_call_string_10 +"CALL_rax +" + +:function_call_string_11 +"CALL_IMMEDIATE %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 "LOAD_BASE_ADDRESS_rax %" + 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 "LOAD_INTEGER\n" + call %emit_out # Emit it + +:variable_load_done + pop_rcx # Restore RCX + pop_rbx # Restore RBX + ret + +:variable_load_string_0 +"LOAD_BASE_ADDRESS_rax %" + +:variable_load_string_1 +" +" + +:variable_load_string_2 +"LOAD_INTEGER +" + + +# 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 "LOAD_IMMEDIATE_rax &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 +"LOAD_IMMEDIATE_rax &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 "LOAD_IMMEDIATE_rax &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 "LOAD_INTEGER\n" + call %emit_out # Emit it + +:global_load_done + pop_rbx # Restore RBX + ret + +:global_load_string_0 +"LOAD_IMMEDIATE_rax &GLOBAL_" + +:global_load_string_1 +" +" + +:global_load_string_2 +"LOAD_INTEGER +" + + +# 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 "LOAD_IMMEDIATE_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 +"LOAD_IMMEDIATE_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 "LOAD_IMMEDIATE_rax &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_out # 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 +"LOAD_IMMEDIATE_rax &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 "LOAD_IMMEDIATE_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 +"LOAD_IMMEDIATE_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_token # Using global_token + 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_rax # allocate shadow stack space for UEFI function + call_[rcx+BYTE] !16 # file_handle->close(file_handle) + pop_rax # 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 !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) + add_rsp, %48 # deallocate stack + pop_rax # get interface + ret + +# rcx: handle +# rdx: &guid +# r8: agent_handle +:close_protocol + 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) + add_rsp, %32 # 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 + sub_rsp, %24 # allocate shadow stack space for UEFI + call_[r14+DWORD] %64 # system->boot->allocate_pool(EFI_LOADER_DATA, 2048, &pool) + add_rsp, %24 # deallocate stack + pop_rax # get pool + ret + +# rcx: memory pool +# r14: system->boot +:free_pool + push_rax # allocate shadow stack space for UEFI function + call_[r14+DWORD] %72 # system->boot->free_pool(pool) + pop_rax # 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 +">::::<" + +# Keywords +:union +"union" + +:struct +"struct" + +:constant +"CONSTANT" + +:main_string +"main" + +:argc_string +"argc" + +:argv_string +"argv" + +:if_string +"if" + +:else_string +"else" + +:do_string +"do" + +:while_string +"while" + +:for_string +"for" + +:asm_string +"asm" + +:goto_string +"goto" + +:return_string +"return" + +:break_string +"break" + +:continue_string +"continue" + +:sizeof_string +"sizeof" + +:plus_string +"+" + +:minus_string +"-" + +:multiply_string +"*" + +:divide_string +"/" + +:modulus_string +"%" + +:left_shift_string +"<<" + +:right_shift_string +">>" + +:less_than_string +"<" + +:less_than_equal_string +"<=" + +:greater_than_equal_string +">=" + +:greater_than_string +">" + +:equal_to_string +"==" + +:not_equal_string +"!=" + +:bitwise_and +"&" + +:logical_and +"&&" + +:bitwise_or +"|" + +:logical_or +"||" + +:bitwise_xor +"^" + +:arrow_string +"->" + + +# Frequently Used strings +# Generally used by require_match +:open_curly_brace +"{" + +:close_curly_brace +"}" + +:open_paren +"(" + +:close_paren +")" + +:open_bracket +"[" + +:close_bracket +"]" + +:comma +"," + +:semicolon +";" + +:equal +"=" + +:percent +"%" + +:newline +"\n" + +:underline +"_" + + +:prim_types +:type_void + %type_int>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 %0 # 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 +:LOADED_IMAGE_PROTOCOL_8 + !0x8E !0x3F !0 !0xA0 !0xC9 !0x69 !0x72 !0x3B + +:SIMPLE_FS_PROTOCOL + %0x0964E5B22 + @0x6459 + @0x11D2 +:SIMPLE_FS_PROTOCOL_8 + !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 + +:PE32_end