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