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