;; Copyright (C) 2017 Jeremiah Orians
;; This file is part of stage0.
;;
;; stage0 is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; stage0 is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with stage0.  If not, see <http://www.gnu.org/licenses/>.

DEFINE ADDI8_EAX 83C0
DEFINE ADDI8_EBX 83C3
DEFINE ADDI8_ECX 83C1
DEFINE ADDI8_EDX 83C2
DEFINE ADDI8_ESI 83C6
DEFINE ADD_eax_into_ebx 01C3
DEFINE ADD_ebx_into_eax 01D8
DEFINE ADD_ecx_into_eax 01C8
DEFINE ADD_edi_into_ecx 01F9
DEFINE AND_EAX_EBX 21D8
DEFINE ANDI32_EAX 25
DEFINE CALL_EAX FFD0
DEFINE CALL32 E8
DEFINE CMPI8_EAX 83F8
DEFINE CMPI8_EBP 83fd
DEFINE CMPI8_EBX 83FB
DEFINE CMPI8_ECX 83F9
DEFINE CMPI8_EDX 83FA
DEFINE CMPI8_ESI 83FE
DEFINE CMP_EAX_EBX 39D8
DEFINE CMP_EAX_ECX 39C8
DEFINE CMP_EBX_ECX 39D9
DEFINE CMP_ECX_EBX 39CB
DEFINE CMP_EDI_ESI 39FE
DEFINE CMP_EBX_EDX 39D3
DEFINE COPY_EAX_to_EBP 89C5
DEFINE COPY_EAX_to_EBX 89C3
DEFINE COPY_EAX_to_ECX 89C1
DEFINE COPY_EAX_to_EDX 89C2
DEFINE COPY_EAX_to_ESI 89C6
DEFINE COPY_EBP_to_EAX 89E8
DEFINE COPY_EBX_to_EAX 89D8
DEFINE COPY_EBX_to_ECX 89D9
DEFINE COPY_EBX_to_EDX 89DA
DEFINE COPY_ECX_to_EAX 89C8
DEFINE COPY_ECX_to_EBX 89CB
DEFINE COPY_EDI_to_ESI 89FE
DEFINE COPY_EDX_to_EAX 89D0
DEFINE COPY_EDX_to_EBP 89D5
DEFINE COPY_EDX_to_EBX 89D3
DEFINE COPY_ESI_to_EAX 89F0
DEFINE COPY_ESI_to_EDI 89F7
DEFINE IDIV_EBX F7FB
DEFINE IMUL_EAX_by_EBX 0FAFC3
DEFINE IMULI8_EAX 6BC0
DEFINE IMULI8_EBP 6BED
DEFINE INT_80 CD80
DEFINE JBE8 76
DEFINE JE32 0F84
DEFINE JG32 0F8F
DEFINE JG8 7F
DEFINE JL32 0F8C
DEFINE JLE32 0F8E
DEFINE JMP32 E9
DEFINE JNE32 0F85
DEFINE LEA32_ECX_from_esp 8D0C24
DEFINE LOAD32_Absolute32_eax A1
DEFINE LOAD32_Absolute32_ebx 8B1D
DEFINE LOAD32_Absolute32_ecx 8B0D
DEFINE LOAD32_EAX_from_EAX 8B00
DEFINE LOAD32_EAX_from_EAX_Immediate8 8B40
DEFINE LOAD32_EAX_from_EBP_Immediate8 8B45
DEFINE LOAD32_EAX_from_EBX 8B03
DEFINE LOAD32_EAX_from_EBX_Immediate8 8B43
DEFINE LOAD32_EAX_from_ECX_Immediate8 8B41
DEFINE LOAD32_EAX_from_EDX_Immediate8 8B42
DEFINE LOAD32_EBP_from_EBP 8B6D00
DEFINE LOAD32_EBX_from_EAX_Immediate8 8B58
DEFINE LOAD32_EBX_from_EBX 8B1B
DEFINE LOAD32_EBX_from_EBX_Immediate8 8B5B
DEFINE LOAD32_EBX_from_ECX_Immediate8 8B59
DEFINE LOAD32_ECX_from_EAX_Immediate8 8B48
DEFINE LOAD32_ECX_from_EBX 8B0B
DEFINE LOAD32_ECX_from_ECX 8B09
DEFINE LOAD32_ECX_from_ECX_Immediate8 8B49
DEFINE LOAD32_ECX_from_EDX_Immediate8 8B4A
DEFINE LOAD32_EDI_from_EDX_Immediate8 8B7A
DEFINE LOAD32_EDX_from_EDX_Immediate8 8B52
DEFINE LOAD8_al_from_EAX 8A00
DEFINE LOAD8_al_from_EBX 8A03
DEFINE LOAD8_al_from_ECX 8A01
DEFINE LOAD8_al_from_EDX 8A02
DEFINE LOAD8_bl_from_EBX 8A1B
DEFINE LOAD8_bl_from_ECX 8A19
DEFINE LOAD8_bl_from_EDX 8A1A
DEFINE LOAD8_cl_from_EBX 8A0B
DEFINE LOAD8_cl_from_EBX_Immediate8 8A4B
DEFINE LOADI32_EAX B8
DEFINE LOADI32_EBX BB
DEFINE LOADI32_ECX B9
DEFINE LOADI32_EDI BF
DEFINE LOADI32_EDX BA
DEFINE LOADI32_ESI BE
DEFINE MOVZX_al 0FB6C0
DEFINE MOVZX_bl 0FB6DB
DEFINE MOVZX_cl 0FB6C9
DEFINE NULL 00000000
DEFINE POP_EAX 58
DEFINE POP_EBP 5D
DEFINE POP_EBX 5B
DEFINE POP_ECX 59
DEFINE POP_EDI 5F
DEFINE POP_EDX 5A
DEFINE POP_ESI 5E
DEFINE PUSH_EAX 50
DEFINE PUSH_EBP 55
DEFINE PUSH_EBX 53
DEFINE PUSH_ECX 51
DEFINE PUSH_EDI 57
DEFINE PUSH_EDX 52
DEFINE PUSH_ESI 56
DEFINE RETURN C3
DEFINE SALI8_EAX C1E0
DEFINE SHRI8_EAX C1E8
DEFINE SHRI8_EBX C1EB
DEFINE STORE32_Absolute32_eax A3
DEFINE STORE32_Absolute32_ebx 891D
DEFINE STORE32_Absolute32_ecx 890D
DEFINE STORE32_Absolute32_edx 8915
DEFINE STORE32_EAX_into_EBP_Immediate8 8945
DEFINE STORE32_EAX_into_EBX 8903
DEFINE STORE32_EAX_into_ECX_Immediate8 8941
DEFINE STORE32_EAX_into_EDX 8902
DEFINE STORE32_EAX_into_EDX_Immediate8 8942
DEFINE STORE32_EBP_into_EDX_Immediate8 896A
DEFINE STORE32_EBX_into_EAX 8918
DEFINE STORE32_EBX_into_EAX_Immediate8 8958
DEFINE STORE32_EBX_into_EDX_Immediate8 895A
DEFINE STORE32_ECX_into_EAX 8908
DEFINE STORE32_ECX_into_EAX_Immediate8 8948
DEFINE STORE32_ECX_into_EDX_Immediate8 894A
DEFINE STORE32_EDX_into_EAX_Immediate8 8950
DEFINE STORE32_EDX_into_EBP_Immediate8 8955
DEFINE STORE32_ESI_into_EBP_Immedate8 8975
DEFINE STORE32_ESI_into_EDX_Immedate8 8972
DEFINE STORE8_al_into_Address_EBX 8803
DEFINE STORE8_al_into_Address_ECX 8801
DEFINE STORE8_al_into_Address_ESI 8806
DEFINE STORE8_bl_into_Address_ECX 8819
DEFINE SUBI8_EAX 83E8
DEFINE SUBI8_ECX 83E9
DEFINE SUBI8_ESI 83EE
DEFINE SWAP_EAX_EBX 93


	;; Register usage:
	;; EAX => Temps

	;; Struct TYPE format: (size 28)
	;; NEXT => 0
	;; SIZE => 4
	;; OFFSET => 8
	;; INDIRECT => 12
	;; MEMBERS => 16
	;; TYPE => 20
	;; NAME => 24

	;; Struct TOKEN_LIST format: (size 20)
	;; NEXT => 0
	;; LOCALS/PREV => 4
	;; S => 8
	;; TYPE => 12
	;; ARGS/DEPTH => 16

; Where the ELF Header is going to hit
; Simply jump to _start
; Our main function
:_start
	POP_EAX                                     ; Get the number of arguments
	POP_EBX                                     ; Get the program name
	POP_EBX                                     ; Get the actual input name
	LOADI32_ECX %0                              ; prepare read_only
	LOADI32_EAX %5                              ; the syscall number for open()
	INT_80                                      ; Now open that damn file
	STORE32_Absolute32_eax &Input_file          ; Preserve the file pointer we were given

	POP_EBX                                     ; Get the actual output name
	LOADI32_ECX %577                            ; Prepare file as O_WRONLY|O_CREAT|O_TRUNC
	LOADI32_EDX %384                            ; Prepare file as RW for owner only (600 in octal)
	LOADI32_EAX %5                              ; the syscall number for open()
	INT_80                                      ; Now open that damn file
	CMPI8_EAX !0                                ; Check for missing output
	JG32 %_start_out                            ; Have real input
	LOADI32_EAX %1                              ; Use stdout

:_start_out
	STORE32_Absolute32_eax &Output_file         ; Preserve the file pointer we were given

	LOADI32_EAX %45                             ; the Syscall # for SYS_BRK
	LOADI32_EBX %0                              ; Get current brk
	INT_80                                      ; Let the kernel do the work
	STORE32_Absolute32_eax &MALLOC              ; Set our malloc pointer
	LOADI32_EAX %0                              ; HEAD = NULL
	CALL32 %read_all_tokens                     ; Read all tokens
	CALL32 %Reverse_List                        ; Reverse order
;	CALL32 %debug_list                          ; Try to figure out what is wrong
	STORE32_Absolute32_eax &global_token        ; Set global_token
	CALL32 %program                             ; Convert into program
	LOADI32_EAX &header_string1                 ; Our header string
	CALL32 %File_Print                          ; Print it
	LOAD32_Absolute32_eax &output_list          ; Our output_list
	CALL32 %recursive_output                    ; Print core program
;	LOADI32_EAX &header_string2                 ; Our Enable debug
;	CALL32 %File_Print                          ; Print it
	LOADI32_EAX &header_string3                 ; Our second label
	CALL32 %File_Print                          ; Print it
	LOAD32_Absolute32_eax &globals_list         ; Our globals
	CALL32 %recursive_output                    ; Get them
	LOADI32_EAX &header_string4                 ; Our final header
	CALL32 %File_Print                          ; Print it
	LOAD32_Absolute32_eax &strings_list         ; Our strings
	CALL32 %recursive_output                    ; Get them
	LOADI32_EAX &header_string5                 ; Make this a bare assembly
	CALL32 %File_Print                          ; Print it

:Done
	; program completed Successfully
	LOADI32_EBX %0                              ; All is well
	LOADI32_EAX %1                              ; put the exit syscall number in eax
	INT_80                                      ; Call it a good day

:header_string1  "
# Core program
"
:header_string2  "
:ELF_data
"
:header_string3  "
# Program global variables
"
:header_string4  "
# Program strings
"
:header_string5  "
:ELF_end
"


;; read_all_tokens function
;; Receives Token_List* in EAX
;; Tokenizes all input and returns updated list in EAX
;; Returns TOKEN in EAX
;; Uses EAX for C
:read_all_tokens
	STORE32_Absolute32_eax &Token
	CALL32 %fgetc
:read_all_tokens_loop
	CMPI8_EAX !-4                               ; Check for EOF
	JE32 %read_all_tokens_done                  ; Stop if found
	CALL32 %get_token                           ; Read all tokens
	JMP32 %read_all_tokens_loop                 ; Loop
:read_all_tokens_done
	LOAD32_Absolute32_eax &Token
	RETURN


;; get_token function
;; Receives INT in EAX
;; Makes a list of TOKEN_LIST
;; C and STRING_INDEX are stored in memory, ECX is used for S and EDX is used for current
;; Returns C in EAX
:get_token
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX

	STORE32_Absolute32_eax &C                   ; Set C

	LOADI32_EAX %20                             ; Malloc CURRENT
	CALL32 %malloc                              ; Get Pointer
	COPY_EAX_to_EDX                             ; Set CURRENT

	LOADI32_EAX %256                            ; Malloc the string
	CALL32 %malloc                              ; Get pointer to S
	COPY_EAX_to_ECX                             ; Set S
	STORE32_ECX_into_EDX_Immediate8 !8          ; CURRENT->S = S
:reset
	STORE32_Absolute32_ecx &string_index        ; S[0]
	LOAD32_Absolute32_eax &C                    ; Using C

	CALL32 %clear_white_space                   ; Clear WhiteSpace
	STORE32_Absolute32_eax &C                   ; Set C

	CMPI8_EAX !-4                               ; Check for EOF
	JE32 %get_token_abort                       ; if EOF abort

	CMPI8_EAX !35                               ; Check for '#'
	JNE32 %get_token_alpha                      ; Nope

	;; Deal with # line comments
	CALL32 %purge_macro                         ; Let it handle it
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %reset                                ; Try again

:get_token_alpha
	LOAD32_Absolute32_eax &C                    ; Send C
	LOADI32_EBX &alphas                         ; Get alphanumerics
	CALL32 %In_Set                              ; See if in set
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %get_token_symbol                     ; Otherwise

	;; Store keywords
	LOAD32_Absolute32_eax &C                    ; Send C
	CALL32 %preserve_keyword                    ; Store
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %get_token_done                       ; Be done with this token

:get_token_symbol
	LOAD32_Absolute32_eax &C                    ; Send C
	LOADI32_EBX &symbols                        ; Get symbols
	CALL32 %In_Set                              ; See if in set
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %get_token_strings                    ; Otherwise

	;; Store symbols
	LOAD32_Absolute32_eax &C                    ; Send C
	CALL32 %preserve_symbol                     ; Store
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %get_token_done                       ; Be done with this token

:get_token_strings
	LOAD32_Absolute32_eax &C                    ; Send C
	LOADI32_EBX &strings                        ; Get strings
	CALL32 %In_Set                              ; See if in set
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %get_token_comment                    ; Otherwise

	;; Store String
	LOAD32_Absolute32_eax &C                    ; Send C
	CALL32 %consume_word                        ; Store
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %get_token_done                       ; Be done with this token

:get_token_comment
	LOAD32_Absolute32_eax &C                    ; Send C
	CMPI8_EAX !47                               ; IF '/' == C
	JNE32 %get_token_else                       ; Otherwise

	CALL32 %consume_byte                        ; Hope it just is '/'
	STORE32_Absolute32_eax &C                   ; Set C

	CMPI8_EAX !42                               ; IF '*' we have '/*'
	JNE32 %get_token_comment_line               ; Check for '//'

	;; Deal with /* block comments */
	CALL32 %fgetc                               ; get next C
	STORE32_Absolute32_eax &C                   ; Set C
:get_token_comment_block_outer
	LOAD32_Absolute32_eax &C                    ; Using C
	CMPI8_EAX !47                               ; IF '/' != C
	JE32 %get_token_comment_block_done          ; be done

:get_token_comment_block_inner
	LOAD32_Absolute32_eax &C                    ; Using C
	CMPI8_EAX !42                               ; IF '*' != C
	JE32 %get_token_comment_block_iter          ; jump over

	;; Deal with inner loop
	CALL32 %fgetc                               ; get next C
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %get_token_comment_block_inner        ; keep going

:get_token_comment_block_iter
	CALL32 %fgetc                               ; get next C
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %get_token_comment_block_outer

:get_token_comment_block_done
	CALL32 %fgetc                               ; get next C
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %reset                                ; throw away, try again

:get_token_comment_line
	CMPI8_EAX !47                               ; IF '/' we have //
	JNE32 %get_token_done                       ; keep if just '/'

	;; Deal with // line comment
	CALL32 %fgetc                               ; drop to match
	STORE32_Absolute32_eax &C                   ; Set C
	JMP32 %reset                                ; throw away, try again

:get_token_else
	LOAD32_Absolute32_eax &C                    ; Send C
	CALL32 %consume_byte
	STORE32_Absolute32_eax &C                   ; Set C

:get_token_done
	LOAD32_Absolute32_eax &Token                ; TOKEN
	STORE32_EAX_into_EDX_Immediate8 !4          ; CURRENT->PREV = TOKEN
	STORE32_EAX_into_EDX                        ; CURRENT->NEXT = TOKEN
	STORE32_Absolute32_edx &Token               ; TOKEN = CURRENT

:get_token_abort
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	LOAD32_Absolute32_eax &C                    ; Return C
	RETURN


;; Malloc isn't actually required if the program being built fits in the initial memory
;; However, it doesn't take much to add it.
;; Requires [MALLOC] to be initialized and EAX to have the number of desired bytes
:malloc
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	LOAD32_Absolute32_ebx &MALLOC               ; Using the current pointer
	ADD_eax_into_ebx                            ; Request the number of desired bytes
	LOADI32_EAX %45                             ; the Syscall # for SYS_BRK
	INT_80                                      ; call the Kernel
	LOAD32_Absolute32_eax &MALLOC               ; Return pointer
	STORE32_Absolute32_ebx &MALLOC              ; Update pointer
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; clear_white_space function
;; Receives INT C in EAX
;; Returns first non-whitespace char in EAX
:clear_white_space
	CMPI8_EAX !32                               ; Check for ' '
	JE32 %clear_white_space_wipe                ; wipe it out

	CMPI8_EAX !10                               ; Check for '\n'
	JE32 %clear_white_space_wipe                ; wipe it output

	CMPI8_EAX !9                                ; Check for '\t'
	JNE32 %clear_white_space_done               ; looks like non-whitespace

:clear_white_space_wipe
	CALL32 %fgetc                               ; Read a new byte
	CMPI8_EAX !-4                               ; Check for EOF
	JE32 %clear_white_space_done                ; Short circuit
	JMP32 %clear_white_space                    ; iterate

:clear_white_space_done
	RETURN


;; In_Set function
;; Receives Char C in EAX and CHAR* in EBX
;; Returns 1 if true, zero if false in EAX
:In_Set
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
:In_Set_loop
	LOAD8_cl_from_EBX                           ; Read char
	MOVZX_cl                                    ; Zero extend it

	CMP_EAX_ECX                                 ; See if they match
	JE32 %In_Set_True                           ; return true

	CMPI8_ECX !0                                ; Check for NULL
	JE32 %In_Set_False                          ; return false

	ADDI8_EBX !1                                ; s = s + 1
	JMP32 %In_Set_loop                          ; Keep looping

:In_Set_True
	LOADI32_EAX %1                              ; Set True
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:In_Set_False
	LOADI32_EAX %0                              ; Set FALSE
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:alphas  "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz"
:symbols  "<=>|&!-"
:strings  '22 27 00'


;; purge_macro function
;; Receives CH in EAX
;; Reads chars until Line feed is read
;; returns line feed
:purge_macro
	CALL32 %fgetc                               ; read next char
	CMPI8_EAX !10                               ; Check for '\n'
	JNE32 %purge_macro                          ; Keep going
	RETURN


;; preserve_keyword function
;; Receives INT C in EAX
;; collects all chars in keyword
;; Returns C in EAX
;; Uses ECX for INT C
:preserve_keyword
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; Setup C
	LOADI32_EBX &alphas                         ; Concerning ourselves with "abc.."
:preserve_keyword_loop
	CALL32 %In_Set                              ; Check if alphanumerics
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %preserve_keyword_label               ; Otherwise check for label

	COPY_ECX_to_EAX                             ; Pass C
	CALL32 %consume_byte                        ; consume that byte
	COPY_EAX_to_ECX                             ; Update C
	JMP32 %preserve_keyword_loop                ; keep looping

:preserve_keyword_label
	COPY_ECX_to_EAX                             ; Fix return
	CMPI8_EAX !58                               ; Check for ':'
	JNE32 %preserve_keyword_done                ; be done

	;; Fix our goto label
	CALL32 %fixup_label                         ; Fix the label
	LOADI32_EAX %32                             ; Return Whitespace

:preserve_keyword_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; preserve_symbol function
;; Receives INT C in EAX
;; collects all chars in symbol
;; Returns C in EAX
;; Uses ECX for INT C
:preserve_symbol
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; Setup C
	LOADI32_EBX &symbols                        ; Concerning ourselves with "<=>.."
:preserve_symbol_loop
	CALL32 %In_Set                              ; Check if symbol
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %preserve_symbol_done                 ; Otherwise be done

	COPY_ECX_to_EAX                             ; Pass C
	CALL32 %consume_byte                        ; consume that byte
	COPY_EAX_to_ECX                             ; Update C
	JMP32 %preserve_symbol_loop                 ; keep looping

:preserve_symbol_done
	COPY_ECX_to_EAX                             ; Fix return
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; consume_word function
;; receives INT C in EAX
;; returns INT C in EAX
;; Uses EAX for C, EBX for FREQ and ECX for ESCAPE
:consume_word
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_EBX                             ; FREQ = C
	LOADI32_ECX %0                              ; ESCAPE = FALSE
:consume_word_loop
	CMPI8_ECX !0                                ; IF !ESCAPE
	JNE32 %consume_word_escape                  ; Enable escape

	CMPI8_EAX !92                               ; if '\\'
	JNE32 %consume_word_iter                    ; keep state

	LOADI32_ECX %1                              ; ESCAPE = TRUE
	JMP32 %consume_word_iter                    ; keep going

:consume_word_escape
	LOADI32_ECX %0                              ; ESCAPE = FALSE

:consume_word_iter
	CALL32 %consume_byte                        ; read next char

	CMPI8_ECX !0                                ; IF ESCAPE
	JNE32 %consume_word_loop                    ; keep looping

	CMP_EAX_EBX                                 ; IF C != FREQ
	JNE32 %consume_word_loop                    ; keep going

	CALL32 %fgetc                               ; return next char
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; consume_byte function
;; Receives INT C in EAX
;; Inserts C into string S, updates String S
;; Returns Next char in EAX
:consume_byte
	PUSH_EBX                                    ; Protect EBX
	LOAD32_Absolute32_ebx &string_index         ; S[0]
	STORE8_al_into_Address_EBX                  ; S[0] = C
	ADDI8_EBX !1                                ; S = S + 1
	STORE32_Absolute32_ebx &string_index        ; Update S
	CALL32 %fgetc
	POP_EBX                                     ; Restore EBX
	RETURN


;; fixup_label function
;; Receives S in ECX
;; prepends ':' to string and returns registers unchanged
;; Uses EAX for HOLD, EBX for PREV and ECX for S[0]
:fixup_label
	PUSH_EAX                                    ; Protect EAX
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOADI32_EAX %58                             ; HOLD = ':'
	LOAD32_ECX_from_EDX_Immediate8 !8           ; HOLD_STRING[0]
:fixup_label_loop
	COPY_EAX_to_EBX                             ; PREV = HOLD
	LOAD8_al_from_ECX                           ; HOLD = HOLD_STRING[I]
	MOVZX_al                                    ; make useful
	STORE8_bl_into_Address_ECX                  ; HOLD_STRING[I] = PREV
	ADDI8_ECX !1                                ; I = I + 1
	CMPI8_EAX !0                                ; IF NULL == HOLD
	JNE32 %fixup_label_loop                     ; Keep looping

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	POP_EAX                                     ; Restore EAX
	RETURN


;; fgetc function
;; Loads FILE* from [INPUT_FILE]
;; Returns -4 (EOF) or char in EAX
:fgetc
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	LOADI32_EAX %-4                             ; Put EOF in eax
	PUSH_EAX                                    ; Assume bad (If nothing read, value will remain EOF)
	LEA32_ECX_from_esp                          ; Get stack address
	LOAD32_Absolute32_ebx &Input_file           ; Where are we reading from
	LOADI32_EAX %3                              ; the syscall number for read
	LOADI32_EDX %1                              ; set the size of chars we want
	INT_80                                      ; call the Kernel
	POP_EAX                                     ; Get either char or EOF
	CMPI8_EAX !-4                               ; Check for EOF
	JE32 %fgetc_done                            ; Return as is
	MOVZX_al                                    ; Make it useful
:fgetc_done
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; Reverse_List function
;; Receives List in EAX
;; Returns the list reversed in EAX
:Reverse_List
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_EBX                             ; Set HEAD
	LOADI32_EAX %0                              ; ROOT = NULL
:Reverse_List_Loop
	CMPI8_EBX !0                                ; WHILE HEAD != NULL
	JE32 %Reverse_List_Done                     ; Stop otherwise

	LOAD32_ECX_from_EBX                         ; NEXT = HEAD->NEXT
	STORE32_EAX_into_EBX                        ; HEAD->NEXT = ROOT
	COPY_EBX_to_EAX                             ; ROOT = HEAD
	COPY_ECX_to_EBX                             ; HEAD = NEXT
	JMP32 %Reverse_List_Loop                    ; Keep Going

:Reverse_List_Done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; recursive_output function
;; Receives list in EAX
;; walks the list and prints the I->S for all nodes backwards
;; Uses EBX for I
:recursive_output
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CMPI8_EAX !0                                ; Check for NULL
	JE32 %recursive_output_done                 ; Skip the work
	COPY_EAX_to_EBX                             ; I = Head

	LOAD32_EAX_from_EBX                         ; Iterate to next Token
	CALL32 %recursive_output                    ; Recurse

	LOAD32_EAX_from_EBX_Immediate8 !8           ; Using S
	CALL32 %File_Print                          ; Print it

:recursive_output_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; File_Print function
;; Receives CHAR* in EAX
;; calls fputc for every non-null char
:File_Print
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_EBX                             ; Protect S
	CMPI8_EAX !0                                ; Protect against nulls
	JE32 %File_Print_Done                       ; Simply don't try to print them
:File_Print_Loop
	LOAD8_al_from_EBX                           ; Read byte
	MOVZX_al                                    ; zero extend
	CMPI8_EAX !0                                ; Check for NULL
	JE32 %File_Print_Done                       ; Stop at NULL

	CALL32 %fputc                               ; write it
	ADDI8_EBX !1                                ; S = S + 1
	JMP32 %File_Print_Loop                      ; Keep going

:File_Print_Done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; fputc function
;; receives CHAR in EAX and load FILE* from [OUTPUT_FILE]
;; writes char and returns
:fputc
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_EAX                                    ; We are writing eax
	LEA32_ECX_from_esp                          ; Get stack address
	LOAD32_Absolute32_ebx &Output_file          ; Write to target file
	LOADI32_EAX %4                              ; the syscall number for write
	LOADI32_EDX %1                              ; set the size of chars we want
	INT_80                                      ; call the Kernel
	POP_EAX                                     ; Restore stack
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; program function
;; receives nothing, returns nothing
;; Uses EAX for type_size
:program
	;; The binary initialized the globals to null, so we can skip those steps
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX

:new_type
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	CMPI8_EAX !0                                ; Check if NULL
	JE32 %program_done                          ; Be done if null

	LOAD32_EBX_from_EAX_Immediate8 !8           ; GLOBAL_TOKEN->S
	LOADI32_EAX &constant                       ; "CONSTANT"
	CALL32 %match                               ; IF GLOBAL_TOKEN->S == "CONSTANT"
	CMPI8_EAX !0                                ; If true
	JNE32 %program_else                         ; Looks like not a constant

	;; Deal with minimal constant case
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EBX %0                              ; NULL
	LOAD32_Absolute32_ecx &global_constant_list ; global_constant_list
	CALL32 %sym_declare                         ; Declare that constant
	STORE32_Absolute32_eax &global_constant_list ; global_constant_list = sym_declare(global_token->s, NULL, global_constant_list);

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX                         ; global_token->next
	STORE32_EBX_into_EAX_Immediate8 !16         ; global_constant_list->arguments = global_token->next

	LOAD32_EBX_from_EBX                         ; global_token->next->next
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->next->next
	JMP32 %new_type                             ; go around again

:program_else
	CALL32 %type_name                           ; Figure out the type_size
	CMPI8_EAX !0                                ; IF NULL == type_size
	JE32 %new_type                              ; it was a new type

	;; Add to global symbol table
	COPY_EAX_to_EBX                             ; put type_size in the right spot
	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD32_Absolute32_ecx &global_symbol_list   ; Using global_symbol_list
	CALL32 %sym_declare                         ; Declare symbol
	STORE32_Absolute32_eax &global_symbol_list  ; global_symbol_list = sym_declare(global_token->s, type_size, global_symbol_list);
	LOAD32_Absolute32_ebx &global_token         ; Using global token
	LOAD32_EBX_from_EBX                         ; global_token->next
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->next

	LOAD32_Absolute32_ebx &global_token         ; Using global token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &semicolon                      ; ";"
	CALL32 %match                               ; if(match(";", global_token->s))
	CMPI8_EAX !0                                ; If true
	JNE32 %program_function                     ; looks like not a match

	;; Deal with the global variable
	LOAD32_Absolute32_ebx &globals_list         ; Using globals_list
	LOADI32_EAX &program_string_0               ; ":GLOBAL_"
	CALL32 %emit                                ; Emit it
	COPY_EAX_to_EBX                             ; update globals_list

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !4           ; global token->prev
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global token->prev->s
	CALL32 %emit                                ; Emit it

	COPY_EAX_to_EBX                             ; update globals_list
	LOADI32_EAX &program_string_1               ; "\nNULL\n"
	CALL32 %emit                                ; Emit it
	STORE32_Absolute32_eax &globals_list        ; update globals_list

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
	JMP32 %new_type                             ; go around again

:program_function
	LOAD32_Absolute32_ebx &global_token         ; Using global token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_paren                     ; "("
	CALL32 %match                               ; if(match(";", global_token->s))
	CMPI8_EAX !0                                ; If true
	JNE32 %program_error                        ; Otherwise deal with error case

	;; Deal with function definition
	CALL32 %declare_function                    ; Lets get the parsing rolling
	JMP32 %new_type                             ; Keep looping through functions

:program_error
	;; Deal with the case of something we don't support
	;; NOT IMPLEMENTED

:program_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

;; Strings needed by the program function
:program_string_0  ":GLOBAL_"
:program_string_1  "
NULL
"


;; declare_function function
;; Receives nothing and returns nothing
;; Sets current function and adds it to the global function list
:declare_function
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOADI32_EAX %0                              ; Using NULL
	STORE32_Absolute32_eax &current_count       ; current_count = 0

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !4           ; global token->prev
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global token->prev->s
	LOADI32_EBX %0                              ; NULL
	LOAD32_Absolute32_ecx &global_function_list ; global_function_list
	CALL32 %sym_declare                         ; sym_declare(global_token->prev->s, NULL, global_function_list);
	STORE32_Absolute32_eax &function            ; function = sym_declare(global_token->prev->s, NULL, global_function_list);
	STORE32_Absolute32_eax &global_function_list ; global_function_list = function

	CALL32 %collect_arguments                   ; collect all of the function arguments

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global token->s
	LOADI32_EBX &semicolon                      ; ";"
	CALL32 %match                               ; IF global token->s == ";"
	CMPI8_EAX !0                                ; If true
	JNE32 %declare_function_full                ; It was a prototype

	;; Deal with prototypes
	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX                         ; global token->next
	STORE32_Absolute32_eax &global_token        ; global token = global token->next
	JMP32 %declare_function_done                ; Move on

:declare_function_full
	;; Deal with full function definitions
	LOADI32_EAX &declare_function_string_0      ; "# Defining function "
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &function             ; function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->s
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &declare_function_string_1      ; "\n:FUNCTION_"
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &function             ; function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->s
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &declare_function_string_3      ; "\n"
	CALL32 %emit_out                            ; emit it

	CALL32 %statement                           ; Recursively get the function pieces

	LOAD32_Absolute32_eax &output_list          ; output
	LOAD32_EAX_from_EAX_Immediate8 !8           ; output->s
	LOADI32_EBX &declare_function_string_2      ; "RETURN\n"
	CALL32 %match                               ; IF output->s == "RETURN\n"
	CMPI8_EAX !0                                ; If true we can skip adding it
	JE32 %declare_function_done                 ; otherwise we need to add it

	;; Add the return to the end of a function lacking a return;
	LOADI32_EAX &declare_function_string_2      ; "RETURN\n"
	CALL32 %emit_out                            ; emit it

:declare_function_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:declare_function_string_0  "# Defining function "
:declare_function_string_1  "
:FUNCTION_"
:declare_function_string_2  "RETURN
"
:declare_function_string_3  "
"


;; collect_arguments function
;; Receives nothing
;; Returns Nothing
;; Adds arguments to the function definition
;; holds struct type* type_size in ECX, then replace with struct token_list* a in ECX when type_size is used
:collect_arguments
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
:collect_arguments_loop
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &close_paren                    ; ")"
	CALL32 %match                               ; IF global_token->S == ")"
	CMPI8_EAX !0                                ; we reached the end
	JE32 %collect_arguments_done                ; be done

	;; deal with the case of there are arguments
	CALL32 %type_name                           ; Get the type
	COPY_EAX_to_ECX                             ; put type_size safely out of the way

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &close_paren                    ; ")"
	CALL32 %match                               ; IF global_token->S == ")"
	CMPI8_EAX !0                                ; is a foo(int, char,void) case
	JE32 %collect_arguments_common              ; deal with commas

	;; Trying second else
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &comma                          ; ","
	CALL32 %match                               ; IF global_token->S == ","
	CMPI8_EAX !0                                ; then deal with the common
	JE32 %collect_arguments_common              ; case of commas between arguments

	;; deal with foo(int a, char b)
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	COPY_ECX_to_EBX                             ; put type_size in the right place
	LOAD32_Absolute32_ecx &function             ; Using function
	LOAD32_ECX_from_ECX_Immediate8 !16          ; function->args
	CALL32 %sym_declare                         ; sym_declare(global_token->s, type_size, function->arguments);
	COPY_EAX_to_ECX                             ; put a in a safe place

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args
	CMPI8_EAX !0                                ; IF function->args == NULL
	JNE32 %collect_arguments_another            ; otherwise it isn't the first

	;; Deal with the case of first argument in the function
	LOADI32_EAX %-4                             ; -4
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->depth = -4
	JMP32 %collect_arguments_next               ; get to next

:collect_arguments_another
	;; deal with the case of non-first arguments
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args->depth
	SUBI8_EAX !4                                ; function->args->depth - 4
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->depth = function->args->depth - 4

:collect_arguments_next
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOAD32_Absolute32_eax &function             ; Using function
	STORE32_ECX_into_EAX_Immediate8 !16         ; function->args = a

:collect_arguments_common
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &comma                          ; ","
	CALL32 %match                               ; IF global_token->S == ","
	CMPI8_EAX !0                                ; then deal with the comma
	JNE32 %collect_arguments_loop               ; otherwise loop

	;; keep foo(bar(), 1) expressions working
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
	JMP32 %collect_arguments_loop               ; keep going

:collect_arguments_done
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; statement function
;; Receives nothing
;; Returns nothing
;; Walks down global_token recursively to collect the contents of the function
:statement
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_curly_brace               ; "{"
	CALL32 %match                               ; IF global_token->S == "{"
	JNE32 %statement_label                      ; otherwise try label

	;; deal with { statement }
	CALL32 %recursive_statement                 ; Statements inside of statements for days
	JMP32 %statement_done                       ; Be done

:statement_label
	LOAD8_al_from_EBX                           ; global_token->S[0]
	MOVZX_al                                    ; make it useful
	CMPI8_EAX !58                               ; IF global_token->S == ':'
	JNE32 %statement_local                      ; otherwise try locals

	;; deal with labels
	COPY_EBX_to_EAX                             ; put global_token->S in the right spot
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &statement_string_0             ; Using "\t#C goto label\n"
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
	JMP32 %statement_done                       ; be done

:statement_local
	COPY_EBX_to_EAX                             ; put global_token->S in the right place
	LOADI32_EBX &prim_types                     ; pointer to primative types
	CALL32 %lookup_type                         ; See if found
	CMPI8_EAX !0                                ; IF NULL == lookup_type(global_token->S, prim_types)
	JNE32 %statement_local_success              ; Sweet a new local

	;; Second chance
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &struct                         ; "struct"
	CALL32 %match                               ; IF global_token->S == "struct"
	CMPI8_EAX !0                                ; then we are a local
	JNE32 %statement_if                         ; otherwise try IF

:statement_local_success
	CALL32 %collect_local                       ; Grab those locals
	JMP32 %statement_done                       ; be done

:statement_if
	LOADI32_EAX &if_string                      ; Using "if"
	CALL32 %match                               ; IF global_token->S == "if"
	CMPI8_EAX !0                                ; then we have an if statement
	JNE32 %statement_do                         ; otherwise try DO

	;; Deal with IF statement
	CALL32 %process_if                          ; DO IT
	JMP32 %statement_done                       ; be done

:statement_do
	LOADI32_EAX &do_string                      ; Using "do"
	CALL32 %match                               ; IF global_token->S == "do"
	CMPI8_EAX !0                                ; then we have a do statement
	JNE32 %statement_while                      ; otherwise try WHILE

	;; Deal with DO statement
	CALL32 %process_do                          ; DO IT
	JMP32 %statement_done                       ; be done

:statement_while
	LOADI32_EAX &while_string                   ; Using "while"
	CALL32 %match                               ; IF global_token->S == "while"
	CMPI8_EAX !0                                ; then we have a while statement
	JNE32 %statement_for                        ; otherwise try FOR

	;; Deal with WHILE statement
	CALL32 %process_while                       ; DO IT
	JMP32 %statement_done                       ; be done

:statement_for
	LOADI32_EAX &for_string                     ; Using "for"
	CALL32 %match                               ; IF global_token->S == "for"
	CMPI8_EAX !0                                ; then we have a for statement
	JNE32 %statement_asm                        ; otherwise try ASM

	;; Deal with FOR statement
	CALL32 %process_for                         ; DO IT
	JMP32 %statement_done                       ; be done

:statement_asm
	LOADI32_EAX &asm_string                     ; Using "asm"
	CALL32 %match                               ; IF global_token->S == "asm"
	CMPI8_EAX !0                                ; then we have an asm statement
	JNE32 %statement_goto                       ; otherwise try GOTO

	;; Deal with ASM statement
	CALL32 %process_asm                         ; Hit it
	JMP32 %statement_done                       ; be done

:statement_goto
	LOADI32_EAX &goto_string                    ; Using "goto"
	CALL32 %match                               ; IF global_token->S == "goto"
	CMPI8_EAX !0                                ; then we have a goto statement
	JNE32 %statement_return                     ; Otherwise try RETURN

	;; Deal with GOTO statement
	LOADI32_EAX &statement_string_1             ; Using "JUMP %"
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &statement_string_2             ; Using "\n"
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOADI32_EAX &statement_string_4             ; Using "ERROR in statement\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure it has the required
	JMP32 %statement_done                       ; Be done

:statement_return
	LOADI32_EAX &return_string                  ; Using "return"
	CALL32 %match                               ; IF global_token->S == "return"
	CMPI8_EAX !0                                ; then we have a return statement
	JNE32 %statement_break                      ; Otherwise try BREAK

	;; Deal with RETURN Statement
	CALL32 %return_result                       ; Return anything they want
	JMP32 %statement_done                       ; be done

:statement_break
	LOADI32_EAX &break_string                   ; Using "break"
	CALL32 %match                               ; IF global_token->S == "break"
	CMPI8_EAX !0                                ; then we have a break statement
	JNE32 %statement_continue                   ; Otherwise try CONTINUE

	;; Deal with BREAK statement
	CALL32 %process_break                       ; Lets do some damage
	JMP32 %statement_done                       ; be done

:statement_continue
	LOADI32_EAX &continue_string                ; Using "continue"
	CALL32 %match                               ; IF global_token->S == "continue"
	CMPI8_EAX !0                                ; then we have a continue statement
	JNE32 %statement_else                       ; Otherwise we are punting to an expression

	;; Deal with CONTINUE statement
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOADI32_EAX &statement_string_3             ; Using "\n#continue statement\n"
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &statement_string_4             ; Using "ERROR in statement\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Don't forget the ";"
	JMP32 %statement_done                       ; Be done

:statement_else
	CALL32 %expression                          ; Collect expression
	LOADI32_EAX &statement_string_4             ; Using "ERROR in statement\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; make sure we have it

:statement_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:statement_string_0  "	#C goto label
"
:statement_string_1  "JUMP %"
:statement_string_2  "
"
:statement_string_3  "
#continue statement
"
:statement_string_4  "ERROR in statement
Missing ;
"


;; recursive_statement function
;; Receives nothing
;; Returns nothing
;; Walks the global_token list to build the contents of statements
;; Uses struct token_list* frame in ECX
:recursive_statement
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOAD32_Absolute32_ecx &function             ; Using function
	LOAD32_ECX_from_ECX_Immediate8 !4           ; frame = function->locals

:recursive_statement_loop
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &close_curly_brace              ; Using "}"
	CALL32 %match                               ; IF global_token->S == "}"
	CMPI8_EAX !0                                ; Then we are done recursing
	JE32 %recursive_statement_cleanup           ; and then we clean up

	;; Deal with the recursive calls
	CALL32 %statement                           ; Deal with another statement
	JMP32 %recursive_statement_loop             ; loop some more

:recursive_statement_cleanup
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOADI32_EAX &recursive_statement_string_0   ; Using "RETURN\n"
	LOAD32_Absolute32_ebx &output_list          ; Using output
	LOAD32_EBX_from_EBX_Immediate8 !8           ; output->S
	CALL32 %match                               ; IF output->S == "RETURN\n"
	CMPI8_EAX !0                                ; Then we can skip the clean up
	JE32 %recursive_statement_done              ; and be done

	;; Deal with cleanup
	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EBX_from_EBX_Immediate8 !4           ; i = function->locals
	LOADI32_EAX &recursive_statement_string_1   ; Using "POP_ebx\t# _recursive_statement_locals\n"

:recursive_statement_locals
	CMP_ECX_EBX                                 ; IF frame != i
	JE32 %recursive_statement_done              ; Otherwise be done

	;; Lets emit
	CALL32 %emit_out                            ; emit it
	LOAD32_EBX_from_EBX                         ; i = i->next
	JMP32 %recursive_statement_locals           ; keep going

:recursive_statement_done
	LOAD32_Absolute32_eax &function             ; Using function
	STORE32_ECX_into_EAX_Immediate8 !4          ; function->locals = frame
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:recursive_statement_string_0  "RETURN
"
:recursive_statement_string_1  "POP_ebx	# _recursive_statement_locals
"


;; return_result function
;; Receives nothing
;; Returns nothing
;; Cleans up function and generates return
;; Also handles returning expressions
:return_result
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next

	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; make it useful
	CMPI8_EAX !59                               ; If global_token->S[0] == ';'
	JE32 %return_result_cleanup                 ; Go straight to cleanup

	CALL32 %expression                          ; get the expression we are returning

:return_result_cleanup
	LOADI32_EAX &return_result_string_0         ; Using "ERROR in return_result\nMISSING ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EBX_from_EBX_Immediate8 !4           ; function->locals
	LOADI32_EAX &return_result_string_1         ; Using "POP_ebx\t# _return_result_locals\n"
:return_result_locals
	CMPI8_EBX !0                                ; IF NULL == i
	JE32 %return_result_done                    ; Be done

	CALL32 %emit_out                            ; Emit out pop
	LOAD32_EBX_from_EBX                         ; i = i->NEXT
	JMP32 %return_result_locals                 ; Keep going

:return_result_done
	LOADI32_EAX &return_result_string_2         ; Using "RETURN\n"
	CALL32 %emit_out                            ; Emit it
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:return_result_string_0  "ERROR in return_result
MISSING ;
"
:return_result_string_1  "POP_ebx	# _return_result_locals
"
:return_result_string_2  "RETURN
"


;; collect_local function
;; Receives nothing
;; Returns nothing
;; Walks global_token list to create function locals
;; Uses ECX for struct token_list* A
:collect_local
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %type_name                           ; Get the local's type

	COPY_EAX_to_EBX                             ; Put struct type* type_size in the right place
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD32_Absolute32_ecx &function             ; Using function
	LOAD32_ECX_from_ECX_Immediate8 !4           ; function->locals
	CALL32 %sym_declare                         ; Declare it
	COPY_EAX_to_ECX                             ; put it away safely

	;; Try for main
	LOADI32_EAX &main_string                    ; Using "main"
	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EBX_from_EBX_Immediate8 !8           ; function->S
	CALL32 %match                               ; IF match("main", function->s)
	CMPI8_EAX !0                                ; possible
	JNE32 %collect_local_fresh                  ; try to see if fresh function

	;; Ok we are in main, now to see if main is fresh
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !4           ; function->locals
	CMPI8_EAX !0                                ; IF NULL == function->locals
	JNE32 %collect_local_fresh                  ; try to see if fresh function

	;; Sweet we are in a fresh main
	LOADI32_EAX %-20                            ; We start at -20
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->DEPTH = -20
	JMP32 %collect_local_common                 ; Go to the commons

:collect_local_fresh
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args
	CMPI8_EAX !0                                ; IF NULL == function->args
	JNE32 %collect_local_first                  ; Otherwise see if first

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !4           ; function->locals
	CMPI8_EAX !0                                ; IF NULL == function->locals
	JNE32 %collect_local_first                  ; Otherwise try first

	;; Sweet we are in a fresh function
	LOADI32_EAX %-8                             ; We start at -8
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->DEPTH = -8
	JMP32 %collect_local_common                 ; Go to the commons

:collect_local_first
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !4           ; function->locals
	CMPI8_EAX !0                                ; IF NULL == function->locals
	JNE32 %collect_local_else                   ; Looks like we are just another local

	;; Ok we are the first local
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->args->depth
	SUBI8_EAX !8                                ; function->arguments->depth - 8
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->DEPTH = function->arguments->depth - 8
	JMP32 %collect_local_common                 ; Go to the commons

:collect_local_else
	;; Always the last to know
	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !4           ; function->locals
	LOAD32_EAX_from_EAX_Immediate8 !16          ; function->locals->depth
	SUBI8_EAX !4                                ; function->locals->depth - 4
	STORE32_EAX_into_ECX_Immediate8 !16         ; a->DEPTH = function->locals->depth - 4

:collect_local_common
	LOAD32_Absolute32_eax &function             ; Using function

	STORE32_ECX_into_EAX_Immediate8 !4          ; function->locals = a
	LOAD32_ECX_from_ECX_Immediate8 !8           ; a->S

	LOADI32_EAX &collect_local_string_0         ; Using "# Defining local "
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &collect_local_string_1         ; Using "\n"
	CALL32 %emit_out                            ; emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOAD32_EBX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; Using "="
	CALL32 %match                               ; IF match("=", global_token->s)
	CMPI8_EAX !0                                ; Deal with assignment
	JNE32 %collect_local_done                   ; Otherwise finish it

	;; Deal with assignment
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	CALL32 %expression                          ; Recurse

:collect_local_done
	LOADI32_EAX &collect_local_string_2         ; Using "ERROR in collect_local\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &collect_local_string_3         ; Using "PUSH_eax\t#"
	CALL32 %emit_out                            ; emit it

	COPY_ECX_to_EAX                             ; put A->S where it belongs
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &collect_local_string_1         ; Using "\n"
	CALL32 %emit_out                            ; emit it

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:collect_local_string_0  "# Defining local "
:collect_local_string_1  "
"
:collect_local_string_2  "ERROR in collect_local
Missing ;
"
:collect_local_string_3  "PUSH_eax	#"


;; process_asm function
;; Receives nothing
;; Returns nothing
;; Simply inlines the asm statements
;; Uses EBX for global_token temp storage
:process_asm
	PUSH_EBX                                    ; Protect EBX
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &process_asm_string_0           ; Using "ERROR in process_asm\nMISSING (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
:process_asm_iter
	LOAD32_EAX_from_EBX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !34                               ; IF global_token->S[0] == '\"'
	JNE32 %process_asm_done                     ; Otherwise be done

	LOAD32_EAX_from_EBX_Immediate8 !8           ; global_token->S
	ADDI8_EAX !1                                ; global_token->S + 1
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &process_asm_string_1           ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_EBX_from_EBX                         ; global_token->NEXT
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->NEXT
	JMP32 %process_asm_iter                     ; keep going

:process_asm_done
	LOADI32_EAX &process_asm_string_2           ; Using "ERROR in process_asm\nMISSING )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &process_asm_string_3           ; Using "ERROR in process_asm\nMISSING ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	POP_EBX                                     ; Restore EBX
	RETURN

:process_asm_string_0  "ERROR in process_asm
MISSING (
"
:process_asm_string_1  "
"
:process_asm_string_2  "ERROR in process_asm
MISSING )
"
:process_asm_string_3  "ERROR in process_asm
MISSING ;
"


;; process_if function
;; Receives nothing
;; Returns Nothing
;; Increments current_count recurses into expression + statement
;; Uses ECX for char* NUMBER_STRING
:process_if
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &current_count        ; Using current count
	COPY_EAX_to_EBX                             ; Preparing for update
	ADDI8_EBX !1                                ; current_count + 1
	STORE32_Absolute32_ebx &current_count       ; current_count = current_count + 1
	CALL32 %numerate_number                     ; convert to string
	COPY_EAX_to_ECX                             ; put NUMBER_STRING in place

	LOADI32_EAX &process_if_string_0            ; Using "# IF_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &process_if_string_1            ; Using "ERROR in process_if\nMISSING (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %expression                          ; Recurse to get the IF(...) part

	LOADI32_EAX &process_if_string_2            ; Using "TEST\nJUMP_EQ %ELSE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_if_string_3            ; Using "ERROR in process_if\nMISSING )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %statement                           ; Recursive to get the IF(){...} part

	LOADI32_EAX &process_if_string_4            ; Using "JUMP %_END_IF_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_if_string_5            ; Using ":ELSE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &else_string                    ; Using "else"
	CALL32 %match                               ; IF global_token->S == "else"
	CMPI8_EAX !0                                ; Then we need to collect the else too
	JNE32 %process_if_done                      ; Otherwise finish up

	;; deal with else statement
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	CALL32 %statement                           ; Recurse to get the ELSE {...} part

:process_if_done
	LOADI32_EAX &process_if_string_6            ; Using ":_END_IF_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:process_if_string_0  "# IF_"
:process_if_string_1  "ERROR in process_if
MISSING (
"
:process_if_string_2  "TEST
JUMP_EQ %ELSE_"
:process_if_string_3  "ERROR in process_if
MISSING )
"
:process_if_string_4  "JUMP %_END_IF_"
:process_if_string_5  ":ELSE_"
:process_if_string_6  ":_END_IF_"


;; save_break_frame microfunction
;; Overwrites EAX and EBX
;; Saves break frame on stack
;; Returns to caller
:save_break_frame
	POP_EBX                                     ; Save return Address
	LOAD32_Absolute32_eax &break_frame          ; Get break_frame
	PUSH_EAX                                    ; Store as nested_locals
	LOAD32_Absolute32_eax &break_target_head    ; Get break_target_head
	PUSH_EAX                                    ; Store as nested_break_head
	LOAD32_Absolute32_eax &break_target_func    ; Get break_target_func
	PUSH_EAX                                    ; Store as nested_break_func
	LOAD32_Absolute32_eax &break_target_num     ; Get break_target_num
	PUSH_EAX                                    ; Store as nested_break_num
	PUSH_EBX                                    ; Put return back in place
	RETURN                                      ; Return to caller


;; restore_break_frame microfunction
;; Overwrites EAX and EBX
;; Restores break frame from stack
;; Returns to caller
:restore_break_frame
	POP_EBX                                     ; Save return Address
	POP_EAX                                     ; Get nested_break_num
	STORE32_Absolute32_eax &break_target_num    ; Restore break_target_num
	POP_EAX                                     ; Get nested_break_func
	STORE32_Absolute32_eax &break_target_func   ; Restore break_target_func
	POP_EAX                                     ; Get nested_break_head
	STORE32_Absolute32_eax &break_target_head   ; Restore break_target_head
	POP_EAX                                     ; Get nested_locals
	STORE32_Absolute32_eax &break_frame         ; Restore break_frame
	PUSH_EBX                                    ; Put return back in place
	RETURN                                      ; Return to caller


;; set_break_frame microfunction
;; Receives char* head in EAX and char* num in EBX
;; Overwrites EAX and EBX
;; Returns to calling function
:set_break_frame
	STORE32_Absolute32_eax &break_target_head   ; update break_target_head
	STORE32_Absolute32_ebx &break_target_num    ; update break_target_num
	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EAX_from_EBX_Immediate8 !4           ; function->LOCALS
	STORE32_Absolute32_eax &break_frame         ; break_frame = function->LOCALS
	LOAD32_EAX_from_EBX_Immediate8 !8           ; function->S
	STORE32_Absolute32_eax &break_target_func   ; break_target_func = function->S
	RETURN                                      ; Return to sender


;; process_do function
;; Receives Nothing
;; Returns Nothing
;; Increments current_count and leverages save/restore_break_frame pieces
;; Uses ECX for char* NUMBER_STRING
:process_do
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %save_break_frame                    ; Save the frame

	LOAD32_Absolute32_eax &current_count        ; Using current count
	COPY_EAX_to_EBX                             ; Preparing for update
	ADDI8_EBX !1                                ; current_count + 1
	STORE32_Absolute32_ebx &current_count       ; current_count = current_count + 1
	CALL32 %numerate_number                     ; convert to string
	COPY_EAX_to_ECX                             ; put NUMBER_STRING in place

	LOADI32_EAX &process_do_string_0            ; Using "DO_END_"
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %set_break_frame                     ; Set the frame

	LOADI32_EAX &process_do_string_1            ; Using ":DO_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	CALL32 %statement                           ; Do the DO {...} part

	LOADI32_EAX &process_do_string_2            ; Using "ERROR in process_do\nMISSING while\n"
	LOADI32_EBX &while_string                   ; Using "while"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &process_do_string_3            ; Using "ERROR in process_do\nMISSING (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %expression                          ; Do the WHILE (...) part

	LOADI32_EAX &process_do_string_4            ; Using "ERROR in process_do\nMISSING )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &process_do_string_5            ; Using "ERROR in process_do\nMISSING ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &process_do_string_6            ; Using "TEST\nJUMP_NE %DO_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_do_string_7            ; Using ":DO_END_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	CALL32 %restore_break_frame                 ; Restore the old break frame

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:process_do_string_0  "DO_END_"
:process_do_string_1  ":DO_"
:process_do_string_2  "ERROR in process_do
MISSING while
"
:process_do_string_3  "ERROR in process_do
MISSING (
"
:process_do_string_4  "ERROR in process_do
MISSING )
"
:process_do_string_5  "ERROR in process_do
MISSING ;
"
:process_do_string_6  "TEST
JUMP_NE %DO_"
:process_do_string_7  ":DO_END_"


;; process_while function
;; Receives nothing
;; Returns nothing
;; Increments current_count and leverages save/restore_break_frame pieces
;; Uses ECX for char* NUMBER_STRING
:process_while
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %save_break_frame                    ; Save break_frame

	LOAD32_Absolute32_eax &current_count        ; Using current count
	COPY_EAX_to_EBX                             ; Preparing for update
	ADDI8_EBX !1                                ; current_count + 1
	STORE32_Absolute32_ebx &current_count       ; current_count = current_count + 1
	CALL32 %numerate_number                     ; convert to string
	COPY_EAX_to_ECX                             ; put NUMBER_STRING in place

	LOADI32_EAX &process_while_string_0         ; Using "END_WHILE_"
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %set_break_frame                     ; Set it and forget it

	LOADI32_EAX &process_while_string_1         ; Using ":WHILE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &process_while_string_2         ; Using "ERROR in process_while\nMISSING (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %expression                          ; Deal with the WHILE (...) part

	LOADI32_EAX &process_while_string_3         ; Using "TEST\nJUMP_EQ %END_WHILE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_while_string_4         ; Using "# THEN_while_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_while_string_5         ; Using "ERROR in process_while\nMISSING )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %statement                           ; Deal with the {....} part

	LOADI32_EAX &process_while_string_6         ; Using "JUMP %WHILE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_while_string_7         ; Using ":END_WHILE_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	CALL32 %restore_break_frame                 ; Restore the old break frame

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:process_while_string_0  "END_WHILE_"
:process_while_string_1  ":WHILE_"
:process_while_string_2  "ERROR in process_while
MISSING (
"
:process_while_string_3  "TEST
JUMP_EQ %END_WHILE_"
:process_while_string_4  "# THEN_while_"
:process_while_string_5  "ERROR in process_while
MISSING )
"
:process_while_string_6  "JUMP %WHILE_"
:process_while_string_7  ":END_WHILE_"


;; process_for function
;; Receives Nothing
;; Returns Nothing
;; Increments current_count and leverages save/restore_break_frame pieces
;; Uses ECX for char* NUMBER_STRING
:process_for
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %save_break_frame                    ; Save the frame

	LOAD32_Absolute32_eax &current_count        ; Using current count
	COPY_EAX_to_EBX                             ; Preparing for update
	ADDI8_EBX !1                                ; current_count + 1
	STORE32_Absolute32_ebx &current_count       ; current_count = current_count + 1
	CALL32 %numerate_number                     ; convert to string
	COPY_EAX_to_ECX                             ; put NUMBER_STRING in place

	LOADI32_EAX &process_for_string_0           ; Using "FOR_END_"
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %set_break_frame                     ; Set it and forget it

	LOADI32_EAX &process_for_string_1           ; Using "# FOR_initialization_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &process_for_string_2           ; Using "ERROR in process_for\nMISSING (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make Sure we have it

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &semicolon                      ; Using ";"
	CALL32 %match                               ; IF global_token->S == ";"
	CMPI8_EAX !0                                ; Then no initializer
	JE32 %process_for_terminator                ; And skip getting the expression

	;; Deal with FOR (...; case
	CALL32 %expression                          ; Get the FOR ( ... ; part

:process_for_terminator
	LOADI32_EAX &process_for_string_3           ; Using ":FOR_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_4           ; Using "ERROR in process_for\nMISSING ;1\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %expression                          ; Get the FOR ( ; ... ; Part

	LOADI32_EAX &process_for_string_5           ; Using "TEST\nJUMP_EQ %FOR_END_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_6           ; Using "JUMP %FOR_THEN_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_7           ; Using ":FOR_ITER_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_8           ; Using "ERROR in process_for\nMISSING ;2\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %expression                          ; Get the FOR (;;...) part

	LOADI32_EAX &process_for_string_9           ; Using "JUMP %FOR_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_10          ; Using ":FOR_THEN_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_11          ; Using "ERROR in process_for\nMISSING )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %statement                           ; Get FOR (;;) {...} part

	LOADI32_EAX &process_for_string_12          ; Using "JUMP %FOR_ITER_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Passing NUMBER_STRING
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	LOADI32_EAX &process_for_string_13          ; Using ":FOR_END_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID_out                        ; uniqueID_out(function->s, number_string)

	CALL32 %restore_break_frame                 ; Restore the old break frame

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:process_for_string_0  "FOR_END_"
:process_for_string_1  "# FOR_initialization_"
:process_for_string_2  "ERROR in process_for
MISSING (
"
:process_for_string_3  ":FOR_"
:process_for_string_4  "ERROR in process_for
MISSING ;1
"
:process_for_string_5  "TEST
JUMP_EQ %FOR_END_"
:process_for_string_6  "JUMP %FOR_THEN_"
:process_for_string_7  ":FOR_ITER_"
:process_for_string_8  "ERROR in process_for
MISSING ;2
"
:process_for_string_9  "JUMP %FOR_"
:process_for_string_10 ":FOR_THEN_"
:process_for_string_11 "ERROR in process_for
MISSING )
"
:process_for_string_12 "JUMP %FOR_ITER_"
:process_for_string_13 ":FOR_END_"


;; process_break function
;; Receives nothing
;; Returns nothing
;; Handles the break out of loops case
;; Uses EBX for struct token_list* break_frame and ECX for struct token_list* I
:process_break
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &break_target_head    ; Catch big error
	CMPI8_EAX !0                                ; IF(NULL == break_target_head)
	JE32 %process_break_bad                     ; I'm sorry Mr White but you have stage-3 lung cancer

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_ECX_from_EAX_Immediate8 !4           ; I = function->LOCALS
	LOAD32_Absolute32_ebx &break_frame          ; Put break_frame in the right spot
	LOADI32_EAX &process_break_string_1         ; Using "POP_ebx\t# break_cleanup_locals\n"

:process_break_iter
	CMPI8_ECX !0                                ; IF (NULL == I)
	JE32 %process_break_cleaned                 ; We are done

	CMP_EBX_ECX                                 ; IF I != break_frame
	JE32 %process_break_cleaned                 ; We are done

	CALL32 %emit_out                            ; Emit it
	LOAD32_ECX_from_ECX                         ; I = I->NEXT
	JMP32 %process_break_iter                   ; Keep looping

:process_break_cleaned
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &process_break_string_2         ; Using "JUMP %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &break_target_head    ; Get what we are in
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &break_target_func    ; Get what function we are in
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &underline                      ; Using "_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &break_target_num     ; Get dem digits
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &process_break_string_3         ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &process_break_string_4         ; Using "ERROR in break statement\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:process_break_bad
	;; Breaking badly
	LOADI32_EAX %2                              ; Using standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
;	CALL32 %line_error                          ; Write useful debug info
	COPY_ECX_to_EAX                             ; put S in the right place
	CALL32 %File_Print                          ; print it

	LOADI32_EAX &process_break_string_0         ; Ending string
	CALL32 %File_Print                          ; print it
	JMP32 %Exit_Failure                         ; Abort Hard

:process_break_string_0  "Not inside of a loop or case statement"
:process_break_string_1  "POP_ebx	# break_cleanup_locals
"
:process_break_string_2  "JUMP %"
:process_break_string_3  "
"
:process_break_string_4  "ERROR in break statement
Missing ;
"


;; expression function
;; Receives Nothing
;; Returns Nothing
;; Walks global_token and updates output_list
;; Uses EAX and EBX for match and ECX for char* store
:expression
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %bitwise_expr                        ; Collect bitwise expressions

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; "="
	CALL32 %match                               ; IF global_token->S == "="
	CMPI8_EAX !0                                ; We have to deal with assignment
	JNE32 %expression_done                      ; Looks like nope

	;; Deal with possible assignment
	LOADI32_ECX &expression_string_1            ; Assume "STORE_CHAR\n" by default
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !4           ; global_token->PREV
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->PREV->S
	LOADI32_EAX &close_bracket                  ; Using "]"
	CALL32 %match                               ; IF global_token->S == "]"
	CMPI8_EAX !0                                ; Then we might have a char
	JNE32 %expression_int                       ; Otherwise INT

	LOAD32_Absolute32_ebx &current_target       ; Using current_target
	LOAD32_EBX_from_EBX_Immediate8 !24          ; current_target->NAME
	LOADI32_EAX &type_char_indirect_name        ; Using "char*"
	CALL32 %match                               ; Intentional inefficiency because I feel like it
	CMPI8_EAX !0                                ; IF current_target->NAME == "char*"
	JNE32 %expression_int                       ; Do char anyway

	JMP32 %expression_common                    ; Looks like we have to use "STORE_CHAR\n"

:expression_int
	LOADI32_ECX &expression_string_0            ; Use "STORE_INTEGER\n"

:expression_common
	LOADI32_EAX &expression                     ; Passing expression
	CALL32 %common_recursion                    ; Recurse
	COPY_ECX_to_EAX                             ; Using Store
	CALL32 %emit_out                            ; Emit it
	LOADI32_EAX %0                              ; Using NULL
	STORE32_Absolute32_eax &current_target      ; current_target = NULL

:expression_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:expression_string_0  "STORE_INTEGER
"
:expression_string_1  "STORE_CHAR
"


;; bitwise_expr function
;; Receives nothing
;; Returns nothing
;; Walks global_token list and updates output list
;; Just calls other functions
:bitwise_expr
	CALL32 %relational_expr                     ; Walk up the tree
	CALL32 %bitwise_expr_stub                   ; Let general recursion do the work
	RETURN


;; bitwise_expr_stub function
;; Receives nothing
;; Returns Nothing
;; Just calls general_recursion a bunch
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
:bitwise_expr_stub
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX

	LOADI32_EAX &relational_expr                ; Using relational_expr
	LOADI32_EBX &bitwise_expr_stub_string_0     ; Using "AND_eax_ebx\n"
	LOADI32_ECX &bitwise_and                    ; Using "&"
	LOADI32_EDX &bitwise_expr_stub              ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &relational_expr                ; Using relational_expr
	LOADI32_EBX &bitwise_expr_stub_string_0     ; Using "AND_eax_ebx\n"
	LOADI32_ECX &logical_and                    ; Using "&&"
	LOADI32_EDX &bitwise_expr_stub              ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &relational_expr                ; Using relational_expr
	LOADI32_EBX &bitwise_expr_stub_string_1     ; Using "OR_eax_ebx\n"
	LOADI32_ECX &bitwise_or                     ; Using "|"
	LOADI32_EDX &bitwise_expr_stub              ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &relational_expr                ; Using relational_expr
	LOADI32_EBX &bitwise_expr_stub_string_1     ; Using "OR_eax_ebx\n"
	LOADI32_ECX &logical_or                     ; Using "||"
	LOADI32_EDX &bitwise_expr_stub              ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &relational_expr                ; Using relational_expr
	LOADI32_EBX &bitwise_expr_stub_string_2     ; Using "XOR_ebx_eax_into_eax\n"
	LOADI32_ECX &bitwise_xor                    ; Using "^"
	LOADI32_EDX &bitwise_expr_stub              ; And recurse
	CALL32 %general_recursion                   ; Hit it

	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:bitwise_expr_stub_string_0  "AND_eax_ebx
"
:bitwise_expr_stub_string_1  "OR_eax_ebx
"
:bitwise_expr_stub_string_2  "XOR_ebx_eax_into_eax
"


;; relational_expr function
;; Receives nothing
;; Returns Nothing
;; Walks global_token list and updates output list
;; just calls other function
:relational_expr
	CALL32 %additive_expr                       ; Walk up the tree
	CALL32 %relational_expr_stub                ; Recurse
	RETURN


;; relational_expr_stub function
;; Receives nothing
;; Returns Nothing
;; Just calls general_recursion a bunch
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
:relational_expr_stub
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_0  ; Using "CMP\nSETL\nMOVEZBL\n"
	LOADI32_ECX &less_than_string               ; Using "<"
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_1  ; Using "CMP\nSETLE\nMOVEZBL\n"
	LOADI32_ECX &less_than_equal_string         ; Using "<="
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_2  ; Using "CMP\nSETGE\nMOVEZBL\n"
	LOADI32_ECX &greater_than_equal_string      ; Using ">="
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_3  ; Using "CMP\nSETG\nMOVEZBL\n"
	LOADI32_ECX &greater_than_string            ; Using ">"
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_4  ; Using "CMP\nSETE\nMOVEZBL\n"
	LOADI32_ECX &equal_to_string                ; Using "=="
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &additive_expr                  ; Using additive_expr
	LOADI32_EBX &relational_expr_stub_string_5  ; Using "CMP\nSETNE\nMOVEZBL\n"
	LOADI32_ECX &not_equal_string               ; Using "!="
	LOADI32_EDX &relational_expr_stub           ; And recurse
	CALL32 %general_recursion                   ; Hit it

	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:relational_expr_stub_string_0  "CMP
SETL
MOVEZBL
"
:relational_expr_stub_string_1  "CMP
SETLE
MOVEZBL
"
:relational_expr_stub_string_2  "CMP
SETGE
MOVEZBL
"
:relational_expr_stub_string_3  "CMP
SETG
MOVEZBL
"
:relational_expr_stub_string_4  "CMP
SETE
MOVEZBL
"
:relational_expr_stub_string_5  "CMP
SETNE
MOVEZBL
"


;; additive_expr function
;; Receives nothing
;; Returns Nothing
;; Walks global_token list and updates output list
;; just calls other function
:additive_expr
	CALL32 %postfix_expr                        ; Walk up the tree
	CALL32 %additive_expr_stub                  ; Recurse
	RETURN


;; additive_expr_stub function
;; Receives nothing
;; Returns Nothing
;; Just calls general_recursion a bunch
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
:additive_expr_stub
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_0    ; Using "ADD_ebx_to_eax\n"
	LOADI32_ECX &plus_string                    ; Using "+"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_1    ; Using "SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n"
	LOADI32_ECX &minus_string                   ; Using "-"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_2    ; Using "MULTIPLY_eax_by_ebx_into_eax\n"
	LOADI32_ECX &multiply_string                ; Using "*"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_3    ; Using "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nDIVIDE_eax_by_ebx_into_eax\n"
	LOADI32_ECX &divide_string                  ; Using "/"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_4    ; Using "XCHG_eax_ebx\nLOAD_IMMEDIATE_edx %0\nMODULUS_eax_from_ebx_into_ebx\nMOVE_edx_to_eax\n"
	LOADI32_ECX &modulus_string                 ; Using "%"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_5    ; Using "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAL_eax_cl\n"
	LOADI32_ECX &left_shift_string              ; Using "<<"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	LOADI32_EAX &postfix_expr                   ; Using postfix_expr
	LOADI32_EBX &additive_expr_stub_string_6    ; Using "COPY_eax_to_ecx\nCOPY_ebx_to_eax\nSAR_eax_cl\n"
	LOADI32_ECX &right_shift_string             ; Using ">>"
	LOADI32_EDX &additive_expr_stub             ; And recurse
	CALL32 %general_recursion                   ; Hit it

	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:additive_expr_stub_string_0  "ADD_ebx_to_eax
"
:additive_expr_stub_string_1  "SUBTRACT_eax_from_ebx_into_ebx
MOVE_ebx_to_eax
"
:additive_expr_stub_string_2  "MULTIPLY_eax_by_ebx_into_eax
"
:additive_expr_stub_string_3  "XCHG_eax_ebx
LOAD_IMMEDIATE_edx %0
DIVIDE_eax_by_ebx_into_eax
"
:additive_expr_stub_string_4  "XCHG_eax_ebx
LOAD_IMMEDIATE_edx %0
MODULUS_eax_from_ebx_into_ebx
MOVE_edx_to_eax
"
:additive_expr_stub_string_5  "COPY_eax_to_ecx
COPY_ebx_to_eax
SAL_eax_cl
"
:additive_expr_stub_string_6  "COPY_eax_to_ecx
COPY_ebx_to_eax
SAR_eax_cl
"


;; postfix_expr function
;; Receives nothing
;; Returns Nothing
;; Walks global_token list and updates output list
;; just calls other function
:postfix_expr
	CALL32 %primary_expr                        ; Walk up the tree
	CALL32 %postfix_expr_stub                   ; Recurse
	RETURN


;; postfix_expr_stub function
;; Receives nothing
;; Returns Nothing
;; Checks for "[" and "->" and deals with them otherwise does nothing
;; Uses EAX, EBX, ECX and EDX for passing constants to general recursion
:postfix_expr_stub
	PUSH_EBX                                    ; Protect EBX
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_bracket                   ; Using "["
	CALL32 %match                               ; IF global_token->S == "["
	CMPI8_EAX !0                                ; then we have an array
	JNE32 %postfix_expr_stub_arrow              ; Otherwise try arrow

	;; Deal with array
	CALL32 %postfix_expr_array                  ; Get it
	CALL32 %postfix_expr_stub                   ; Recurse

:postfix_expr_stub_arrow
	LOADI32_EAX &arrow_string                   ; Using "->"
	CALL32 %match                               ; IF global_token->S == "->"
	CMPI8_EAX !0                                ; Then we need to deal with struct offsets
	JNE32 %postfix_expr_stub_done               ; Otherwise be done

	;; Deal with arrow
	CALL32 %postfix_expr_arrow                  ; Get it
	CALL32 %postfix_expr_stub                   ; Recurse

:postfix_expr_stub_done
	POP_EBX                                     ; Restore EBX
	RETURN


;; unary_expr_sizeof function
;; Receives nothing
;; Returns nothing
;; Uses ECX for A->SIZE
:unary_expr_sizeof
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &unary_expr_sizeof_string_0     ; Using "ERROR in unary_expr\nMissing (\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	CALL32 %type_name                           ; Get the type
	LOAD32_ECX_from_EAX_Immediate8 !4           ; Set A->TYPE

	LOADI32_EAX &unary_expr_sizeof_string_1     ; Using "ERROR in unary_expr\nMissing )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &unary_expr_sizeof_string_2     ; Using "LOAD_IMMEDIATE_eax %"
	CALL32 %emit_out                            ; Emit it

	COPY_ECX_to_EAX                             ; Put A->SIZE in the right place
	CALL32 %numerate_number                     ; Turn into string
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &unary_expr_sizeof_string_3     ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:unary_expr_sizeof_string_0  "ERROR in unary_expr
Missing (
"
:unary_expr_sizeof_string_1  "ERROR in unary_expr
Missing )
"
:unary_expr_sizeof_string_2  "LOAD_IMMEDIATE_eax %"
:unary_expr_sizeof_string_3  "
"


;; postfix_expr_array function
;; Receives Nothing
;; Returns Nothing
;; Uses EBX for struct type* ARRAY and ECX for char* ASSIGN
:postfix_expr_array
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &current_target       ; ARRAY = current_target
	PUSH_EAX                                    ; Protect it

	LOADI32_EAX &expression                     ; Using expression
	CALL32 %common_recursion                    ; Recurse

	POP_EBX                                     ; Restore array
	STORE32_Absolute32_ebx &current_target      ; current_target = ARRAY

	LOADI32_ECX &postfix_expr_array_string_0    ; ASSIGN = "LOAD_INTEGER\n"

	LOADI32_EAX &type_char_indirect_name        ; Using "char*"
	LOAD32_EBX_from_EBX_Immediate8 !24          ; current_target->NAME
	CALL32 %match                               ; IF current_target->NAME == "char*"
	CMPI8_EAX !0                                ; load a byte
	JNE32 %postfix_expr_array_large             ; Otherwise adjust

	;; Deal with loading byte
	LOADI32_ECX &postfix_expr_array_string_1    ; ASSIGN = "LOAD_BYTE\n"
	JMP32 %postfix_expr_array_common            ; Do the next bit

:postfix_expr_array_large
	;; deal with arrays made of things other than chars
	LOADI32_EAX &postfix_expr_array_string_2    ; Using "SAL_eax_Immediate8 !"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &current_target       ; Using current_target
	LOAD32_EAX_from_EAX_Immediate8 !12          ; current_target->INDIRECT
	LOAD32_EAX_from_EAX_Immediate8 !4           ; current_target->INDIRECT->SIZE
	CALL32 %ceil_log2                           ; ceil_log2(current_target->indirect->size)
	CALL32 %numerate_number                     ; numerate_number(ceil_log2(current_target->indirect->size))
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &postfix_expr_array_string_3    ; Using "\n"
	CALL32 %emit_out                            ; Emit it

:postfix_expr_array_common
	LOADI32_EAX &postfix_expr_array_string_4    ; Using "ADD_ebx_to_eax\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &postfix_expr_array_string_5    ; Using "ERROR in postfix_expr\nMissing ]\n"
	LOADI32_EBX &close_bracket                  ; Using "]"
	CALL32 %require_match                       ; Make sure we have it

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; Using "="
	CALL32 %match                               ; IF global_token->S == "="
	CMPI8_EAX !0                                ; We need to preserve address
	JNE32 %postfix_expr_array_done              ; Otherwise be done

	;; Clearing out assign
	LOADI32_ECX &postfix_expr_array_string_6    ; ASSIGN = ""

:postfix_expr_array_done
	COPY_ECX_to_EAX                             ; Using ASSIGN
	CALL32 %emit_out                            ; Emit it

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:postfix_expr_array_string_0  "LOAD_INTEGER
"
:postfix_expr_array_string_1  "LOAD_BYTE
"
:postfix_expr_array_string_2  "SAL_eax_Immediate8 !"
:postfix_expr_array_string_3  "
"
:postfix_expr_array_string_4  "ADD_ebx_to_eax
"
:postfix_expr_array_string_5  "ERROR in postfix_expr
Missing ]
"
:postfix_expr_array_string_6  ""


;; ceil_log2 function
;; Receives int a in EAX
;; Performs log2 on A and
;; Returns result in EAX
;; Uses EBX for INT A and ECX for INT RESULT
:ceil_log2
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOADI32_ECX %0                              ; RESULT = 0

	COPY_EAX_to_EBX                             ; put A in right place
	SUBI8_EAX !1                                ; (A - 1)
	AND_EAX_EBX                                 ; A & (A - 1)
	CMPI8_EAX !0                                ; IF 0 == (A & (A - 1))
	JNE32 %ceil_log2_iter                       ; Starting from -1

	LOADI32_ECX %-1                             ; RESULT = -1

:ceil_log2_iter
	CMPI8_EBX !0                                ; IF A > 0
	JLE32 %ceil_log2_done                       ; Otherwise be done

	ADDI8_ECX !1                                ; RESULT = RESULT + 1
	SHRI8_EBX !1                                ; A = A >> 1
	JMP32 %ceil_log2_iter                       ; Keep looping

:ceil_log2_done
	COPY_ECX_to_EAX                             ; Return RESULT
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; postfix_expr_arrow function
;; Receives nothing
;; Returns nothing
;; Emits a bunch and updates current_target
;; Uses EBX for struct type* I
:postfix_expr_arrow
	PUSH_EBX                                    ; Protect EBX
	LOADI32_EAX &postfix_expr_arrow_string_0    ; Using "# looking up offset\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOAD32_EBX_from_EAX_Immediate8 !8           ; Using global_token->S
	LOAD32_Absolute32_eax &current_target       ; Using current_target
	CALL32 %lookup_member                       ; lookup_member(current_target, global_token->s)
	COPY_EAX_to_EBX                             ; struct type* I = lookup_member(current_target, global_token->s)

	LOAD32_EAX_from_EAX_Immediate8 !20          ; I->TYPE
	STORE32_Absolute32_eax &current_target      ; current_target = I->TYPE

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOAD32_EAX_from_EBX_Immediate8 !8           ; I->OFFSET
	CMPI8_EAX !0                                ; IF 0 != I->OFFSET
	JE32 %postfix_expr_arrow_first              ; Then we don't need to do an offset

	;; Deal with needing an offset
	LOADI32_EAX &postfix_expr_arrow_string_1    ; Using "# -> offset calculation\nLOAD_IMMEDIATE_ebx %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_EAX_from_EBX_Immediate8 !8           ; I->OFFSET
	CALL32 %numerate_number                     ; Convert to string
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &postfix_expr_arrow_string_2    ; Using "\nADD_ebx_to_eax\n"
	CALL32 %emit_out                            ; Emit it

:postfix_expr_arrow_first
	LOAD32_EAX_from_EBX_Immediate8 !4           ; I->SIZE
	CMPI8_EAX !4                                ; IF I->SIZE >= 4
	JL32 %postfix_expr_arrow_done               ; Otherwise be done

	;; Last chance for load
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EBX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; Using "="
	CALL32 %match                               ; IF global_token->S == "="
	CMPI8_EAX !0                                ; Then we have assignment and should not load
	JE32 %postfix_expr_arrow_done               ; Be done

	;; Deal with load case
	LOADI32_EAX &postfix_expr_arrow_string_3    ; Using "LOAD_INTEGER\n"
	CALL32 %emit_out                            ; Emit it

:postfix_expr_arrow_done
	POP_EBX                                     ; Restore EBX
	RETURN

:postfix_expr_arrow_string_0  "# looking up offset
"
:postfix_expr_arrow_string_1  "# -> offset calculation
LOAD_IMMEDIATE_ebx %"
:postfix_expr_arrow_string_2  "
ADD_ebx_to_eax
"
:postfix_expr_arrow_string_3  "LOAD_INTEGER
"


;; primary_expr function
;; Receives nothing
;; Returns nothing
:primary_expr
	PUSH_EBX                                    ; Protect EBX

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EBX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &sizeof_string                  ; Using "sizeof"
	CALL32 %match                               ; See if match
	CMPI8_EAX !0                                ; IF match
	JNE32 %primary_expr_neg                     ; Otherwise try negatives

	;; Deal with sizeof
	CALL32 %unary_expr_sizeof                   ; Lets do this
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_neg
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !45                               ; IF global_token->S[0] == "-"
	JNE32 %primary_expr_not                     ; Otherwise try logical NOT

	;; Deal with negative numbers
	LOADI32_EAX &primary_expr_string_0          ; Using "LOAD_IMMEDIATE_eax %0\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &postfix_expr                   ; Passing postfix_expr
	CALL32 %common_recursion                    ; Get what it is notting

	LOADI32_EAX &primary_expr_string_1          ; Using "SUBTRACT_eax_from_ebx_into_ebx\nMOVE_ebx_to_eax\n"
	CALL32 %emit_out                            ; Emit it
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_not
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !33                               ; IF global_token->S[0] == "!"
	JNE32 %primary_expr_bin                     ; Otherwise try '~'

	;; Deal with logical not
	LOADI32_EAX &primary_expr_string_2          ; Using "LOAD_IMMEDIATE_eax %1\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &postfix_expr                   ; Passing postfix_expr
	CALL32 %common_recursion                    ; Get what it is notting

	LOADI32_EAX &primary_expr_string_3          ; Using "XOR_ebx_eax_into_eax\n"
	CALL32 %emit_out                            ; Emit it
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_bin
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !126                              ; IF global_token->S[0] == "~"
	JNE32 %primary_expr_paren                   ; Otherwise try paren

	;; Deal with binary NOT
	LOADI32_EAX &postfix_expr                   ; Passing postfix_expr
	CALL32 %common_recursion                    ; Get what it is notting
	LOADI32_EAX &primary_expr_string_4          ; Using "NOT_eax\n"
	CALL32 %emit_out                            ; Emit it
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_paren
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !40                               ; IF global_token->S[0] == "("
	JNE32 %primary_expr_ch                      ; Otherwise try char

	;; deal with nesting
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT
	CALL32 %expression                          ; Lets recurse
	LOADI32_EAX &primary_expr_string_5          ; Using "Error in Primary expression\nDidn't get )\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_ch
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !39                               ; Using "'"
	JNE32 %primary_expr_str                     ; Otherwise try string

	;; Deal with chars
	CALL32 %primary_expr_char                   ; Handle that char
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_str
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !34                               ; Using '\"'
	JNE32 %primary_expr_var                     ; Otherwise try a variable

	;; Deal with strings
	CALL32 %primary_expr_string                 ; Handle that string
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_var
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	LOADI32_EBX &primary_expr_string_6          ; Using "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
	CALL32 %In_Set                              ; See if we have a match
	CMPI8_EAX !1                                ; IF match
	JNE32 %primary_expr_num                     ; otherwise try number

	;; Deal with variables
	CALL32 %primary_expr_variable               ; Deal with variable
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_num
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	LOADI32_EBX &primary_expr_string_7          ; Using "0123456789"
	CALL32 %In_Set                              ; See if we have a match
	CMPI8_EAX !1                                ; IF match
	JNE32 %primary_expr_fail                    ; otherwise we failed hard

	;; Deal with numbers
	CALL32 %primary_expr_number                 ; Collect the number
	JMP32 %primary_expr_done                    ; Be done

:primary_expr_fail
	;; looks like we hit bad input
	;; abort before it gets bad
	CALL32 %primary_expr_failure                ; No match means failure
:primary_expr_done
	POP_EBX                                     ; Restore EBX
	RETURN

:primary_expr_string_0  "LOAD_IMMEDIATE_eax %0
"
:primary_expr_string_1  "SUBTRACT_eax_from_ebx_into_ebx
MOVE_ebx_to_eax
"
:primary_expr_string_2  "LOAD_IMMEDIATE_eax %1
"
:primary_expr_string_3  "XOR_ebx_eax_into_eax
"
:primary_expr_string_4  "NOT_eax
"
:primary_expr_string_5  "Error in Primary expression
Didn't get )
"
:primary_expr_string_6  "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_"
:primary_expr_string_7  "0123456789"


;; primary_expr_variable function
;; Receives nothing
;; Returns nothing
;; Walks global and updates output
;; Uses EAX for struct token_list* a and ECX for char* S
:primary_expr_variable
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_ECX_from_EAX_Immediate8 !8           ; S = global_token->S
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	COPY_ECX_to_EAX                             ; Using S
	LOAD32_Absolute32_ebx &global_constant_list ; Using global_constant_list
	CALL32 %sym_lookup                          ; sym_lookup(s, global_constant_list)
	CMPI8_EAX !0                                ; IF NULL == sym_lookup(s, global_constant_list)
	JE32 %primary_expr_variable_local           ; Try locals next

	;; Deal with constant load
	LOAD32_EBX_from_EAX_Immediate8 !16          ; a->ARGS
	LOADI32_EAX &primary_expr_variable_string_2 ; Using "LOAD_IMMEDIATE_eax %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_EAX_from_EBX_Immediate8 !8           ; a->ARGS->S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &primary_expr_variable_string_1 ; Using "\n"
	CALL32 %emit_out                            ; Emit it
	JMP32 %primary_expr_variable_done           ; Be done

:primary_expr_variable_local
	COPY_ECX_to_EAX                             ; Using S
	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EBX_from_EBX_Immediate8 !4           ; function->locals
	CALL32 %sym_lookup                          ; sym_lookup(s, function->locals)
	CMPI8_EAX !0                                ; IF NULL == sym_lookup(s, function->locals)
	JE32 %primary_expr_variable_arguments       ; try arguments next

	;; Deal with local load
	CALL32 %variable_load                       ; Collect it
	JMP32 %primary_expr_variable_done           ; Be done

:primary_expr_variable_arguments
	COPY_ECX_to_EAX                             ; Using S
	LOAD32_Absolute32_ebx &function             ; Using function
	LOAD32_EBX_from_EBX_Immediate8 !16          ; function->args
	CALL32 %sym_lookup                          ; sym_lookup(s, function->args)
	CMPI8_EAX !0                                ; IF NULL == sym_lookup(s, global_constant_list)
	JE32 %primary_expr_variable_function        ; try functions next

	;; Deal with argument load
	CALL32 %variable_load                       ; Collect it
	JMP32 %primary_expr_variable_done           ; Be done

:primary_expr_variable_function
	COPY_ECX_to_EAX                             ; Using S
	LOAD32_Absolute32_ebx &global_function_list ; Using global_function_list
	CALL32 %sym_lookup                          ; sym_lookup(s, global_function_list)
	CMPI8_EAX !0                                ; IF NULL == sym_lookup(s, global_function_list)
	JE32 %primary_expr_variable_global          ; try globals next

	;; Deal with functions
	CALL32 %function_load                       ; Deal with the function
	JMP32 %primary_expr_variable_done           ; Be done

:primary_expr_variable_global
	COPY_ECX_to_EAX                             ; Using S
	LOAD32_Absolute32_ebx &global_symbol_list   ; Using global_symbol_list
	CALL32 %sym_lookup                          ; sym_lookup(s, global_symbol_list)
	CMPI8_EAX !0                                ; IF NULL == sym_lookup(s, global_symbol_list)
	JE32 %primary_expr_variable_error           ; Give up

	;; Deal with globals
	CALL32 %global_load                         ; Collect that global
	JMP32 %primary_expr_variable_done           ; Be done

:primary_expr_variable_error
	LOADI32_EAX %2                              ; Using standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
;	CALL32 %line_error                          ; Write useful debug info
	COPY_ECX_to_EAX                             ; put S in the right place
	CALL32 %File_Print                          ; print it

	LOADI32_EAX &primary_expr_variable_string_0 ; Ending string
	CALL32 %File_Print                          ; print it
	JMP32 %Exit_Failure                         ; Abort Hard

:primary_expr_variable_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:primary_expr_variable_string_0  " is not a defined symbol
"
:primary_expr_variable_string_1  "
"
:primary_expr_variable_string_2  "LOAD_IMMEDIATE_eax %"


;; function_call function
;; Receives char* S in EAX and int BOOL in EBX
;; Builds stack frames before and tears them down after function calls
;; Uses ECX for char* S, EDX for int BOOL, ESI for PASSED
:function_call
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_ESI                                    ; Protect ESI
	COPY_EAX_to_ECX                             ; Put S in place
	COPY_EBX_to_EDX                             ; Put BOOL in place
	LOADI32_ESI %0                              ; PASSED = 0

	LOADI32_EAX &function_call_string_0         ; Using "ERROR in process_expression_list\nNo ( was found\n"
	LOADI32_EBX &open_paren                     ; Using "("
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_EAX &function_call_string_1         ; Using "PUSH_edi\t# Prevent overwriting in recursion\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_2         ; Using "PUSH_ebp\t# Protect the old base pointer\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_3         ; Using "COPY_esp_to_edi\t# Copy new base pointer\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !41                               ; IF global_token->S[0] == ")"
	JE32 %function_call_gen_done                ; Then no arguments to send

	;; looks like we have arguments to collect
	CALL32 %expression                          ; Collect the argument

	LOADI32_EAX &function_call_string_4         ; Using "PUSH_eax\t#_process_expression1\n"
	CALL32 %emit_out                            ; Emit it
	LOADI32_ESI %1                              ; PASSED = 1

:function_call_gen_iter
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !44                               ; IF global_token->S[0] == ","
	JNE32 %function_call_gen_done               ; Otherwise we are done

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	CALL32 %expression                          ; Collect the argument

	LOADI32_EAX &function_call_string_5         ; Using "PUSH_eax\t#_process_expression2\n"
	CALL32 %emit_out                            ; Emit it
	ADDI8_ESI !1                                ; PASSED = PASSED + 1
	JMP32 %function_call_gen_iter               ; Keep trying

:function_call_gen_done
	;; All is collected
	LOADI32_EAX &function_call_string_6         ; Using "ERROR in process_expression_list\nNo ) was found\n"
	LOADI32_EBX &close_paren                    ; Using ")"
	CALL32 %require_match                       ; Make sure we have it

	CMPI8_EDX !0                                ; IF(BOOL == TRUE)
	JNE32 %function_call_static                 ; Otherwise it is a static call

	;; Deal with a passed function pointer
	LOADI32_EAX &function_call_string_7         ; Using "LOAD_BASE_ADDRESS_eax %"
	CALL32 %emit_out                            ; Emit it

	COPY_ECX_to_EAX                             ; Using S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_8         ; Using "\nLOAD_INTEGER\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_9         ; Using "COPY_edi_to_ebp\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_10        ; Using "CALL_eax\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_13        ; Using "POP_ebx\t# _process_expression_locals\n"
	JMP32 %function_call_cleanup                ; Clean up

:function_call_static
	;; Deal with fixed function name
	LOADI32_EAX &function_call_string_9         ; Using "COPY_edi_to_ebp\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_11        ; Using "CALL_IMMEDIATE %FUNCTION_"
	CALL32 %emit_out                            ; Emit it

	COPY_ECX_to_EAX                             ; Using S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_12        ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_13        ; Using "POP_ebx\t# _process_expression_locals\n"

:function_call_cleanup
	CMPI8_ESI !0                                ; IF PASSED > 0
	JLE32 %function_call_done                   ; Otherwise be done

	;; The desired string is already in EAX
	CALL32 %emit_out                            ; Emit it

	SUBI8_ESI !1                                ; PASSED = PASSED - 1
	JMP32 %function_call_cleanup                ; Keep going

:function_call_done
	LOADI32_EAX &function_call_string_14        ; Using "POP_ebp\t# Restore old base pointer\n"
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_call_string_15        ; Using "POP_edi\t# Prevent overwrite\n"
	CALL32 %emit_out                            ; Emit it

	POP_ESI                                     ; Restore ESI
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:function_call_string_0  "ERROR in process_expression_list
No ( was found
"
:function_call_string_1  "PUSH_edi	# Prevent overwriting in recursion
"
:function_call_string_2  "PUSH_ebp	# Protect the old base pointer
"
:function_call_string_3  "COPY_esp_to_edi	# Copy new base pointer
"
:function_call_string_4  "PUSH_eax	#_process_expression1
"
:function_call_string_5  "PUSH_eax	#_process_expression2
"
:function_call_string_6  "ERROR in process_expression_list
No ) was found
"
:function_call_string_7  "LOAD_BASE_ADDRESS_eax %"
:function_call_string_8  "
LOAD_INTEGER
"
:function_call_string_9  "COPY_edi_to_ebp
"
:function_call_string_10 "CALL_eax
"
:function_call_string_11 "CALL_IMMEDIATE %FUNCTION_"
:function_call_string_12 "
"
:function_call_string_13 "POP_ebx	# _process_expression_locals
"
:function_call_string_14 "POP_ebp	# Restore old base pointer
"
:function_call_string_15 "POP_edi	# Prevent overwrite
"


;; variable_load function
;; Receives struct token_list* A in EAX
;; Returns nothing
;; Updates output and current_target
;; Uses ECX for A
:variable_load
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; Protect A

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_paren                     ; Using "("
	CALL32 %match                               ; IF global_token->S == "("
	CMPI8_EAX !0                                ; Then it might be a function
	JNE32 %variable_load_regular                ; Otherwise it is regular

	LOAD32_EBX_from_ECX_Immediate8 !12          ; A->TYPE
	LOAD32_EBX_from_EBX_Immediate8 !24          ; A->TYPE->NAME
	LOADI32_EAX &type_function_name             ; Using "FUNCTION"
	CALL32 %match                               ; IF A->TYPE->NAME == "FUNCTION"
	CMPI8_EAX !0                                ; Then it must be a function
	JNE32 %variable_load_regular                ; otherwise just another regular

	;; deal with function
	LOAD32_EAX_from_ECX_Immediate8 !16          ; A->DEPTH
	CALL32 %numerate_number                     ; Convert to string
	LOADI32_EBX %0                              ; pass 0 for true
	CALL32 %function_call                       ; Create the function call
	JMP32 %variable_load_done                   ; Be done

:variable_load_regular
	LOAD32_EAX_from_ECX_Immediate8 !12          ; A->TYPE
	STORE32_Absolute32_eax &current_target      ; current_target = A->TYPE

	LOADI32_EAX &variable_load_string_0         ; Using "LOAD_BASE_ADDRESS_eax %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_EAX_from_ECX_Immediate8 !16          ; A->DEPTH
	CALL32 %numerate_number                     ; Convert to string
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &variable_load_string_1         ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	;; Check for special case of assignment
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; Using "="
	CALL32 %match                               ; IF global_token->S == "="
	CMPI8_EAX !0                                ; Then we skip loading
	JE32 %variable_load_done                    ; And be done

	;; Deal with common case
	LOADI32_EAX &variable_load_string_2         ; Using "LOAD_INTEGER\n"
	CALL32 %emit_out                            ; Emit it

:variable_load_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:variable_load_string_0  "LOAD_BASE_ADDRESS_eax %"
:variable_load_string_1  "
"
:variable_load_string_2  "LOAD_INTEGER
"


;; function_load function
;; Receives struct token_list* a in EAX
;; Returns nothing
;; Uses ECX to hold A->S
:function_load
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_EAX_from_EAX_Immediate8 !8           ; A->S
	COPY_EAX_to_ECX                             ; Protect A->S
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_paren                     ; Using "("
	CALL32 %match                               ; IF global_token->S == "("
	CMPI8_EAX !0                                ; The we need to do a function call
	JNE32 %function_load_regular                ; Otherwise just load it's address

	;; Deal with function call
	COPY_ECX_to_EAX                             ; Using A->S
	LOADI32_EBX %1                              ; Using FALSE
	CALL32 %function_call                       ; Deal with it
	JMP32 %function_load_done                   ; Be done

:function_load_regular
	LOADI32_EAX &function_load_string_0         ; Using "LOAD_IMMEDIATE_eax &FUNCTION_"
	CALL32 %emit_out                            ; Emit it

	COPY_ECX_to_EAX                             ; Using A->S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &function_load_string_1         ; Using "\n"
	CALL32 %emit_out                            ; Emit it

:function_load_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:function_load_string_0  "LOAD_IMMEDIATE_eax &FUNCTION_"
:function_load_string_1  "
"


;; global_load function
;; Receives struct token_list* A in EAX
;; Returns nothing
;; Uses EBX to hold A->S
:global_load
	PUSH_EBX                                    ; Protect EBX
	COPY_EAX_to_EBX                             ; Set as A
	LOAD32_EBX_from_EBX_Immediate8 !8           ; Set as A->S

	LOAD32_EAX_from_EAX_Immediate8 !12          ; A->TYPE
	STORE32_Absolute32_eax &current_target      ; current_target = A->TYPE

	LOADI32_EAX &global_load_string_0           ; Using "LOAD_IMMEDIATE_eax &GLOBAL_"
	CALL32 %emit_out                            ; Emit it

	COPY_EBX_to_EAX                             ; Using A->S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &global_load_string_1           ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &equal                          ; "="
	CALL32 %match                               ; IF global_token->S == "="
	CMPI8_EAX !0                                ; We need to skip for assignment
	JE32 %global_load_done                      ; and be done

	;; Otherwise we are loading the contents
	LOADI32_EAX &global_load_string_2           ; Using "LOAD_INTEGER\n"
	CALL32 %emit_out                            ; Emit it

:global_load_done
	POP_EBX                                     ; Restore EBX
	RETURN

:global_load_string_0  "LOAD_IMMEDIATE_eax &GLOBAL_"
:global_load_string_1  "
"
:global_load_string_2  "LOAD_INTEGER
"


;; sym_lookup function
;; Receives char* S in EAX and struct token_list* symbol_list in EBX
;; Uses I->S in EAX, S in EBX and I in ECX
;; Returns match or NULL
:sym_lookup
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EBX_to_ECX                             ; I = symbol_list
	COPY_EAX_to_EBX                             ; Put S in the right place
:sym_lookup_iter
	CMPI8_ECX !0                                ; IF NULL == I
	JE32 %sym_lookup_done                       ; We failed to find match

	LOAD32_EAX_from_ECX_Immediate8 !8           ; Using I->S
	CALL32 %match                               ; IF I->S == S
	CMPI8_EAX !0                                ; then be done
	JE32 %sym_lookup_done                       ; Failed

	LOAD32_ECX_from_ECX                         ; I = I->NEXT
	JMP32 %sym_lookup_iter                      ; otherwise keep looping

:sym_lookup_done
	COPY_ECX_to_EAX                             ; Return I
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; primary_expr_number function
;; Receives nothing
;; Returns nothing
;; Simply uses current global token to update output and then steps to next global_token
:primary_expr_number
	LOADI32_EAX &primary_expr_number_string_0   ; Using "LOAD_IMMEDIATE_eax %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %emit_out                            ; Emit it

	LOADI32_EAX &primary_expr_number_string_1   ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT
	RETURN

:primary_expr_number_string_0  "LOAD_IMMEDIATE_eax %"
:primary_expr_number_string_1  "
"


;; primary_expr_string function
;; receives nothing
;; Returns nothing
;; creates entries for string and calls to generate string output
;; uses ECX for char* number_string
:primary_expr_string
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_ebx &current_count        ; Using current_count
	COPY_EBX_to_EAX                             ; And putting it in the right place
	CALL32 %numerate_number                     ; Get the string
	COPY_EAX_to_ECX                             ; protect number_string

	ADDI8_EBX !1                                ; current_count + 1
	STORE32_Absolute32_ebx &current_count       ; current_count = current_count + 1

	LOADI32_EAX &primary_expr_string_string_0   ; Using "LOAD_IMMEDIATE_eax &STRING_"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	COPY_ECX_to_EBX                             ; Put number_string in the right place
	CALL32 %uniqueID_out                        ; Make it unique

	;; Generate the target
	LOADI32_EAX &primary_expr_string_string_1   ; Using ":STRING_"
	LOAD32_Absolute32_ebx &strings_list         ; Using strings_list
	CALL32 %emit                                ; Emit it
	COPY_EAX_to_EBX                             ; put new strings_list in place

	LOAD32_Absolute32_eax &function             ; Using function
	LOAD32_EAX_from_EAX_Immediate8 !8           ; function->S
	CALL32 %uniqueID                            ; Make it unique
	COPY_EAX_to_EBX                             ; put new strings_list in place

	;; Parse the string
	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %parse_string                        ; convert to useful form
	CALL32 %emit                                ; Emit it
	STORE32_Absolute32_eax &strings_list        ; Update Strings _list

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:primary_expr_string_string_0  "LOAD_IMMEDIATE_eax &STRING_"
:primary_expr_string_string_1  ":STRING_"


;; primary_expr_char function
;; Receives nothing
;; Returns nothing
;; Updates output_list using global_token
:primary_expr_char
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOADI32_EAX &primary_expr_char_string_0     ; Using "LOAD_IMMEDIATE_eax %"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	ADDI8_EAX !1                                ; global_token->S + 1
	CALL32 %escape_lookup                       ; Get the char
	CALL32 %numerate_number                     ; Convert to string
	CALL32 %emit_out                            ; emit it

	LOADI32_EAX &primary_expr_char_string_1     ; Using "\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:primary_expr_char_string_0  "LOAD_IMMEDIATE_eax %"
:primary_expr_char_string_1  "
"


;; primary_expr_failure function
;; Receives nothing
;; Does not return but aborts hard
;; Complains about the bad input
:primary_expr_failure
;	CALL32 %line_error                          ; Get line of issue
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	LOADI32_EAX &primary_expr_failure_string_0  ; Using "Received "
	CALL32 %File_Print                          ; Print it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %File_Print                          ; Print it

	LOADI32_EAX &primary_expr_failure_string_1  ; Using " in primary_expr\n"
	CALL32 %File_Print                          ; Print it
	JMP32 %Exit_Failure                         ; Abort Hard

:primary_expr_failure_string_0  "Received "
:primary_expr_failure_string_1  " in primary_expr
"


;; general_recursion function
;; Receives FUNCTION F in EAX, char* S in EBX, char* name in ECX and FUNCTION iterate in EDX
;; Returns nothing
;; Uses ECX for char* S, EDX for FUNCTION iterate and EBP for FUNCTION F
;; But generally recurses a shitload
:general_recursion
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_EBP                                    ; Protect EBP
	COPY_EAX_to_EBP                             ; Protect F
	COPY_ECX_to_EAX                             ; Put name in the right place
	COPY_EBX_to_ECX                             ; Protect S

	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	CALL32 %match                               ; IF match(name, global_token->s)
	CMPI8_EAX !0                                ; If true we do
	JNE32 %general_recursion_done               ; Otherwise skip it

	;; Deal with the recursion
	COPY_EBP_to_EAX                             ; Put F in the right place
	CALL32 %common_recursion                    ; Recurse

	COPY_ECX_to_EAX                             ; Put S in the right place
	CALL32 %emit_out                            ; Emit it

	COPY_EDX_to_EAX                             ; Put iterate in the right place
	CALL_EAX                                    ; Down the rabbit hole

:general_recursion_done
	POP_EBP                                     ; Restore EBP
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; promote_type function
;; Receives struct type* a in EAX and struct type* b in EBX
;; Returns the most recent type in EAX
;; Uses EAX for struct type* I, ECX for struct type* A and EDX for struct type* B
:promote_type
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	CMPI8_EBX !0                                ; IF NULL == B
	JE32 %promote_type_done                     ; Just return A

	COPY_EAX_to_ECX                             ; Put A in place
	COPY_EBX_to_EDX                             ; Put B in place
	COPY_EBX_to_EAX                             ; IF NULL == A
	CMPI8_ECX !0                                ; Then we just return B
	JE32 %promote_type_done                     ; Be done

	;; Looks like we need to walk the list
	LOAD32_ECX_from_ECX_Immediate8 !24          ; A->NAME
	LOAD32_EDX_from_EDX_Immediate8 !24          ; B->NAME
	LOAD32_Absolute32_eax &global_types         ; I = global_types
:promote_type_iter
	CMPI8_EAX !0                                ; IF NULL == I
	JE32 %promote_type_done                     ; Just be done

	LOAD32_EBX_from_EAX_Immediate8 !24          ; I->NAME
	CMP_ECX_EBX                                 ; IF(A->NAME == I->NAME)
	JE32 %promote_type_done                     ; Be done

	CMP_EBX_EDX                                 ; IF(B->NAME == I->NAME)
	JE32 %promote_type_done                     ; Be done

	LOAD32_EBX_from_EAX_Immediate8 !12          ; I->INDIRECT
	LOAD32_EBX_from_EBX_Immediate8 !24          ; I->INDIRECT->NAME

	CMP_ECX_EBX                                 ; IF(A->NAME == I->INDIRECT->NAME)
	JE32 %promote_type_done                     ; Be done

	CMP_EBX_EDX                                 ; IF(B->NAME == I->INDIRECT->NAME)
	JE32 %promote_type_done                     ; Be done

	LOAD32_EAX_from_EAX                         ; I = I->NEXT
	JMP32 %promote_type_iter                    ; Keep going

:promote_type_done
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; common_recursion function
;; Receives FUNCTION F in EAX
;; Returns Nothing
;; Walks global_token list and update output_list
;; Updates current_target
;; Uses EBX to hold FUNCTION F and struct type* last_type
:common_recursion
	PUSH_EBX                                    ; Protect EBX
	COPY_EAX_to_EBX                             ; Put FUNCTION F safely out of the way
	LOADI32_EAX &common_recursion_string_0      ; Using "PUSH_eax\t#_common_recursion\n"
	CALL32 %emit_out                            ; Emit it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	COPY_EBX_to_EAX                             ; Prepare for function call
	LOAD32_Absolute32_ebx &current_target       ; Get last type
	CALL_EAX                                    ; F();
	LOAD32_Absolute32_eax &current_target       ; Get current_target
	CALL32 %promote_type                        ; get the right type
	STORE32_Absolute32_eax &current_target      ; Set new current_target

	LOADI32_EAX &common_recursion_string_1      ; Using "POP_ebx\t# _common_recursion\n"
	CALL32 %emit_out                            ; Emit it
	POP_EBX                                     ; Restore EBX
	RETURN

:common_recursion_string_0  "PUSH_eax	#_common_recursion
"
:common_recursion_string_1  "POP_ebx	# _common_recursion
"


;; require_match function
;; Receives char* message in EAX and char* required in EBX
;; Returns nothing
;; Uses ECX to hold message and updates global_token
:require_match
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; put the message somewhere safe
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %match                               ; IF required == global_token->S
	CMPI8_EAX !0                                ; we are fine
	JE32 %require_match_good                    ; otherwise pain

	;; Deal will bad times
;	CALL32 %line_error                          ; Tell user what went wrong
	LOADI32_EAX %2                              ; Using standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	COPY_ECX_to_EAX                             ; using our message
	CALL32 %File_Print                          ; Print it
	JMP32 %Exit_Failure                         ; Abort HARD

:require_match_good
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->next
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->next
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; uniqueID Function
;; Receives char *S in EAX, struct token_list* l in EBX and char* num in ECX
;; Returns updated struct token_list* L in EAX
:uniqueID
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	CALL32 %emit                                ; emit(s, l)
	COPY_EAX_to_EBX                             ; Put L in correct place
	LOADI32_EAX &underline                      ; Using "_"
	CALL32 %emit                                ; emit("_", l)
	COPY_EAX_to_EBX                             ; Put L in correct place
	COPY_ECX_to_EAX                             ; Put num in correct place
	CALL32 %emit                                ; emit(num, l)
	COPY_EAX_to_EBX                             ; Put L in correct place
	LOADI32_EAX &uniqueID_string_0              ; Using "\n"
	CALL32 %emit                                ; emit("\n", l)
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:uniqueID_string_0  "
"


;; uniqueID_out function
;; Receives char* S in EAX and char* num in EBX
;; Returns nothing
:uniqueID_out
	PUSH_EAX                                    ; Protect EAX
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EBX_to_ECX                             ; Put num in right spot
	LOAD32_Absolute32_ebx &output_list          ; Using output_list
	CALL32 %uniqueID                            ; Get updated list
	STORE32_Absolute32_eax &output_list         ; output_list = uniqueID(s, output_list, num)
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	POP_EAX                                     ; Restore EAX
	RETURN


;; emit_out function
;; Receives char* S in EAX
;; Returns nothing
;; Updates output_list
;; MUST NOT ALTER REGISTERS
:emit_out
	PUSH_EAX                                    ; Protect EAX
	PUSH_EBX                                    ; Protect EBX
	LOAD32_Absolute32_ebx &output_list          ; Using output_list
	CALL32 %emit                                ; emit it
	STORE32_Absolute32_eax &output_list         ; update it
	POP_EBX                                     ; Restore EBX
	POP_EAX                                     ; Restore EAX
	RETURN


;; emit function
;; Receives char *s in EAX and struct token_list* head in EBX
;; Returns struct token_list* T in EAX
:emit
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; put S out of the way
	LOADI32_EAX %20                             ; sizeof(struct token_list)
	CALL32 %malloc                              ; get T
	STORE32_EBX_into_EAX                        ; t->next = head;
	STORE32_ECX_into_EAX_Immediate8 !8          ; t->s = s;
	POP_ECX                                     ; Restore ECX
	RETURN


;; escape_lookup function
;; Receives char* c in EAX
;; Returns integer value of char in EAX
;; Aborts hard if unknown escape is received
;; Uses ECX to hold char* C
:escape_lookup
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; Put char* C in safe place
	LOAD8_al_from_ECX                           ; Load c[0]
	MOVZX_al                                    ; make it useful
	CMPI8_EAX !92                               ; If '\\' != c[0]
	JNE32 %escape_lookup_done                   ; Be done

	COPY_ECX_to_EBX                             ; Prepare for walk
	ADDI8_EBX !1                                ; increment
	LOAD8_bl_from_EBX                           ; load c[1]
	MOVZX_bl                                    ; make it useful

	CMPI8_EBX !120                              ; Check if \x??
	JE32 %escape_lookup_hex                     ; Deal with hex

	;; Deal with \? escapes
	LOADI32_EAX %10                             ; Guess "\n"
	CMPI8_EBX !110                              ; If n
	JE32 %escape_lookup_done                    ; Be done

	LOADI32_EAX %9                              ; Guess "\t"
	CMPI8_EBX !116                              ; If t
	JE32 %escape_lookup_done                    ; Be done

	COPY_EBX_to_EAX                             ; "\\", "'" and '\"' all encode as themselves
	CMPI8_EBX !92                               ; If "\\"
	JE32 %escape_lookup_done                    ; Be done
	CMPI8_EBX !39                               ; IF "'"
	JE32 %escape_lookup_done                    ; Be done
	CMPI8_EBX !34                               ; IF '\"'
	JE32 %escape_lookup_done                    ; Be done

	LOADI32_EAX %13                             ; Guess "\r"
	CMPI8_EBX !114                              ; IF r
	JE32 %escape_lookup_done                    ; Be done

	;; Looks like we have no clue what we are doing
	;; Aborting hard
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	LOADI32_EAX &escape_lookup_string_0         ; Using "Unknown escape received: "
	CALL32 %File_Print                          ; Print it
	COPY_ECX_to_EAX                             ; Using C
	CALL32 %File_Print                          ; Print it
	LOADI32_EAX &escape_lookup_string_1         ; Using " Unable to process\n"
	CALL32 %File_Print                          ; Print it
	JMP32 %Exit_Failure                         ; Abort Hard

:escape_lookup_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:escape_lookup_hex
	;; Give up on C and just assume they know what they are doing
	ADDI8_ECX !2                                ; increment
	LOAD8_al_from_ECX                           ; c[2]
	MOVZX_al                                    ; make it useful
	ADDI8_ECX !1                                ; increment
	CALL32 %char2hex                            ; Get the hex value
	SALI8_EAX !4                                ; c << 4
	LOAD8_bl_from_ECX                           ; c[3]
	MOVZX_bl                                    ; make it useful
	SWAP_EAX_EBX                                ; protect c << 4
	CALL32 %char2hex                            ; Get the hex value
	ADD_ebx_into_eax                            ; hex(c[2]) << 4 + hex(c[3])
	JMP32 %escape_lookup_done                   ; Be done

:escape_lookup_string_0  "Unknown escape received: "
:escape_lookup_string_1  " Unable to process
"


;; char2hex function
;; Receives char in EAX
;; Returns hex or aborts hard
:char2hex
	SUBI8_EAX !48                               ; Try 0-9
	CMPI8_EAX !10                               ; Otherwise fun times
	JL32 %char2hex_done                         ; Be done

	;; Deal with A-F
	ANDI32_EAX %0xDF                            ; Unset High bit turning a-f into A-F
	SUBI8_EAX !7                                ; Shift down into position
	CMPI8_EAX !10                               ; Everything below A is bad
	JL32 %char2hex_fail                         ; And should fail
	CMPI8_EAX !16                               ; Make sure we are below F
	JL32 %char2hex_done                         ; If so be done

:char2hex_fail
	;; Time to fail hard
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	LOADI32_EAX &char2hex_string_0              ; Using "Tried to print non-hex number\n"
	CALL32 %File_Print                          ; Print it
	JMP32 %Exit_Failure                         ; Abort Hard

:char2hex_done
	RETURN

:char2hex_string_0  "Tried to print non-hex number
"


;; parse_string function
;; Receives char* string in EAX
;; Returns cleaned up string
;; Protects char* string in EBX
:parse_string
	PUSH_EBX                                    ; Protect EBX
	COPY_EAX_to_EBX                             ; Protect char* string
	CALL32 %weird                               ; Determine if we have a weird string
	CMPI8_EAX !0                                ; If weird
	JE32 %parse_string_weird                    ; Deal with it

	;; Dealing with regular string
	COPY_EBX_to_EAX                             ; Passing Char* string
	CALL32 %collect_regular_string              ; Collect it
	JMP32 %parse_string_done                    ; Be done

:parse_string_weird
	COPY_EBX_to_EAX                             ; Passing Char* string
	CALL32 %collect_weird_string                ; Collect it

:parse_string_done
	POP_EBX                                     ; Restore EBX
	RETURN


;; weird function
;; Receives char* string in EAX
;; Returns true(0) or false(1) in EAX
;; Uses ECX to hold char* string
:weird
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EAX_to_ECX                             ; Place string in safe place
	ADDI8_ECX !1                                ; increment past the '\"'
:weird_reset
	LOAD8_al_from_ECX                           ; Load a char
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !0                                ; IF NULL == C
	JE32 %weird_false                           ; Nothing weird found

	CMPI8_EAX !92                               ; IF '\\'
	JNE32 %weird_escaped                        ; Deal with escaping

	;; Deal with escape
	COPY_ECX_to_EAX                             ; We are passing the string
	CALL32 %escape_lookup                       ; to look it up

	ADDI8_ECX !1                                ; string = string + 1
	LOAD8_bl_from_ECX                           ; get string[1]
	MOVZX_bl                                    ; make it useful
	CMPI8_EBX !120                              ; IF 'x' == string[1]
	JNE32 %weird_escaped                        ; otherwise skip the gap

	ADDI8_ECX !2                                ; string = string + 2

:weird_escaped
	PUSH_EAX                                    ; Protect C in case we need it
	LOADI32_EBX &weird_string_0                 ; Use "\t\n !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
	CALL32 %In_Set                              ; To find if weird
	CMPI8_EAX !1                                ; IF TRUE
	POP_EAX                                     ; Restore C
	JNE32 %weird_true                           ; Then not weird

	ADDI8_ECX !1                                ; string = string + 1

	;; Last chance for weird
	LOADI32_EBX &weird_string_1                 ; Use "\t\n\r "
	CALL32 %In_Set                              ; Check for special case
	CMPI8_EAX !1                                ; IF TRUE
	JNE32 %weird_reset                          ; Otherwise not in the special case

	;; Deal with possible special case
	LOAD8_al_from_ECX                           ; Load string[1]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !58                               ; IF string[1] == ":"
	JE32 %weird_true                            ; Then we hit the special case
	JMP32 %weird_reset                          ; Keep trying

:weird_done
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:weird_true
	LOADI32_EAX %0                              ; Return true
	JMP32 %weird_done                           ; Be done

:weird_false
	LOADI32_EAX %1                              ; Return false
	JMP32 %weird_done                           ; Be done

:weird_string_0  "	
 !#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
:weird_string_1  '09 0A 0D 20' ; "\t\n\r "


;; collect_regular_string function
;; Receives char* string in EAX
;; Malloc and creates new string to return in EAX
;; Uses ECX for return string and EDX for passed string
:collect_regular_string
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_EDX                             ; Protect our passed string
	LOADI32_EAX %256                            ; We need 256bytes of storage
	CALL32 %malloc                              ; Get our new pointer
	COPY_EAX_to_ECX                             ; put it in place
	PUSH_EAX                                    ; protect until done
:collect_regular_string_reset
	LOAD8_al_from_EDX                           ; string[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !0                                ; See if we hit the end
	JE32 %collect_regular_string_done           ; And be done

	CMPI8_EAX !92                               ; IF string[0] == '\\'
	JE32 %collect_regular_string_escaped        ; Deal with that mess

	;; deal with boring char
	STORE8_al_into_Address_ECX                  ; hold_string[index] = string[0]
	ADDI8_ECX !1                                ; Increment it
	ADDI8_EDX !1                                ; Increment it
	JMP32 %collect_regular_string_reset         ; And keep going

:collect_regular_string_escaped
	COPY_EDX_to_EAX                             ; Using string
	CALL32 %escape_lookup                       ; Get the char
	STORE8_al_into_Address_ECX                  ; hold_string[index] = escape_lookup(string)
	ADDI8_EDX !1                                ; Increment it
	ADDI8_ECX !1                                ; Increment it
	LOAD8_al_from_EDX                           ; string[0]
	MOVZX_al                                    ; Make it useful
	ADDI8_EDX !1                                ; Increment it
	CMPI8_EAX !120                              ; IF 'x' == string[1]
	JNE32 %collect_regular_string_reset         ; Otherwise keep going

	ADDI8_EDX !2                                ; Increment it
	JMP32 %collect_regular_string_reset         ; Keep going

:collect_regular_string_done
	LOADI32_EAX %34                             ; Using '\"'
	STORE8_al_into_Address_ECX                  ; hold_string[index] = '\"'
	ADDI8_ECX !1                                ; Increment it
	LOADI32_EAX %10                             ; Using "\n"
	STORE8_al_into_Address_ECX                  ; hold_string[index] = '\n'
	POP_EAX                                     ; Return our new string
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; collect_weird_string function
;; Receives char* string in EAX
;; Mallocs and returns char* hold in EAX
;; Uses ECX for char* hold and EDX for char* string
:collect_weird_string
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_EDX                             ; Protect our passed string
	LOADI32_EAX %512                            ; We need 512bytes of storage
	CALL32 %malloc                              ; Get our new pointer
	COPY_EAX_to_ECX                             ; put it in place
	PUSH_EAX                                    ; protect until done

	LOADI32_EAX %39                             ; Using "'"
	STORE8_al_into_Address_ECX                  ; hold_string[index] = "'"
	ADDI8_ECX !1                                ; Increment it
	ADDI8_EDX !1                                ; Increment it
:collect_weird_string_reset
	LOAD8_al_from_EDX                           ; Read a byte
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !0                                ; IF NULL == string[0]
	JE32 %collect_weird_string_done             ; Be done

	LOADI32_EAX %32                             ; Using ' '
	STORE8_al_into_Address_ECX                  ; hold_string[index] = ' '
	ADDI8_ECX !1                                ; Increment it

	COPY_EDX_to_EAX                             ; Using string
	CALL32 %escape_lookup                       ; Get the char
	CALL32 %hex8                                ; Update ECX

	LOAD8_al_from_EDX                           ; Read a byte
	MOVZX_al                                    ; Make it useful
	ADDI8_EDX !1                                ; Increment it
	CMPI8_EAX !92                               ; IF string[0] == '\\'
	JNE32 %collect_weird_string_reset           ; Otherwise keep going

	LOAD8_al_from_EDX                           ; Read a byte
	MOVZX_al                                    ; Make it useful
	ADDI8_EDX !1                                ; Increment it
	CMPI8_EAX !120                              ; IF 'x' == string[1]
	JNE32 %collect_weird_string_reset           ; Otherwise keep going

	ADDI8_EDX !2                                ; Increment it
	JMP32 %collect_weird_string_reset           ; Keep going

:collect_weird_string_done
	LOADI32_EAX %32                             ; Using ' '
	STORE8_al_into_Address_ECX                  ; hold_string[index] = ' '
	ADDI8_ECX !1                                ; Increment it
	LOADI32_EAX %48                             ; Using '0'
	STORE8_al_into_Address_ECX                  ; hold_string[index] = '0'
	ADDI8_ECX !1                                ; Increment it
	STORE8_al_into_Address_ECX                  ; hold_string[index] = '0'
	ADDI8_ECX !1                                ; Increment it
	LOADI32_EAX %39                             ; Using "'"
	STORE8_al_into_Address_ECX                  ; hold_string[index] = "'"
	ADDI8_ECX !1                                ; Increment it
	LOADI32_EAX %10                             ; Using "\n"
	STORE8_al_into_Address_ECX                  ; hold_string[index] = '\n'
	POP_EAX                                     ; Return our new string
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; HEX to ascii routine
;; Receives INT in EAX and CHAR* in ECX
;; Stores ascii of INT in CHAR*
;; Returns only modifying EAX and ECX
:hex8
	PUSH_EAX                                    ; Protect bottom nibble
	SHRI8_EAX !4                                ; do high nibble first
	CALL32 %hex4                                ; Store it
	POP_EAX                                     ; do low nibble
:hex4
	ANDI32_EAX %0xF                             ; isolate nibble
	ADDI8_EAX !48                               ; convert to ascii
	CMPI8_EAX !57                               ; valid digit?
	JBE8 !hex1                                  ; yes
	ADDI8_EAX !7                                ; use alpha range
:hex1
	STORE8_al_into_Address_ECX                  ; store result
	ADDI8_ECX !1                                ; next position
	RETURN


;; type_name function
;; Receives nothing
;; Returns type_size in EAX
;; Uses ECX for STRUCT TYPE* RET
:type_name
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &struct                         ; Using "struct"
	CALL32 %match                               ; IF global_token->S == "struct"
	COPY_EAX_to_ECX                             ; Protect structure
	CMPI8_EAX !0                                ; need to skip over "struct"
	JNE32 %type_name_native                     ; otherwise keep going

	;; Deal with possible STRUCTs
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX                         ; global_token->next
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->next
	LOAD32_EAX_from_EBX_Immediate8 !8           ; global_token->S
	LOAD32_Absolute32_ebx &global_types         ; get all known types
	CALL32 %lookup_type                         ; Find type if possible
	COPY_EAX_to_ECX                             ; Set ret

	CMPI8_EAX !0                                ; IF NULL == ret
	JNE32 %type_name_common                     ; We have to create struct

	;; Create a struct
	CALL32 %create_struct                       ; Create a new struct
	LOADI32_ECX %0                              ; We wish to return NULL
	JMP32 %type_name_done                       ; be done

:type_name_native
	;; Deal only with native types
	COPY_EBX_to_EAX                             ; Put global_token->S in the right place
	LOAD32_Absolute32_ebx &global_types         ; get all known types
	CALL32 %lookup_type                         ; Find the type if possible
	COPY_EAX_to_ECX                             ; Set ret

	CMPI8_EAX !0                                ; IF NULL == ret
	JNE32 %type_name_common                     ; We need to abort hard

	;; Aborting hard
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	LOADI32_EAX &type_name_string_0             ; Print header
	CALL32 %File_Print                          ; Print it

	LOAD32_Absolute32_eax &global_token         ; Using global token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %File_Print                          ; Print it

	LOADI32_EAX &type_name_string_1             ; Print footer
	CALL32 %File_Print                          ; Print it

;	CALL32 %line_error                          ; Give details
	JMP32 %Exit_Failure                         ; Abort

:type_name_common
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX                         ; global_token->next
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->next

:type_name_iter
	LOAD32_EAX_from_EBX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; make it useful
	CMPI8_EAX !42                               ; IF global_token->S[0] == '*'
	JNE32 %type_name_done                       ; recurse

	;; Deal with char**
	LOAD32_ECX_from_ECX_Immediate8 !12          ; ret = ret->indirect
	LOAD32_Absolute32_ebx &global_token         ; Using global_token
	LOAD32_EBX_from_EBX                         ; global_token->next
	STORE32_Absolute32_ebx &global_token        ; global_token = global_token->next
	JMP32 %type_name_iter                       ; keep looping

:type_name_done
	COPY_ECX_to_EAX                             ; put ret in the right place
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:type_name_string_0  "Unknown type "
:type_name_string_1  "
"


;; lookup_type function
;; Receives char* s in EAX and struct type* start in EBX
;; Returns struct type* in EAX
;; Uses EBX for S and ECX for I
:lookup_type
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	COPY_EBX_to_ECX                             ; I = Start
	COPY_EAX_to_EBX                             ; Put S in place
:lookup_type_iter
	CMPI8_ECX !0                                ; Check if I == NULL
	JE32 %lookup_type_done                      ; return NULL

	LOAD32_EAX_from_ECX_Immediate8 !24          ; I->NAME
	CALL32 %match                               ; Check if matching
	CMPI8_EAX !0                                ; IF I->NAME == S
	JE32 %lookup_type_done                      ; return it

	LOAD32_ECX_from_ECX                         ; Otherwise I = I->NEXT
	JMP32 %lookup_type_iter                     ; And keep looping

:lookup_type_done
	COPY_ECX_to_EAX                             ; return either I or NULL
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; create_struct function
;; Receives nothing
;; Returns nothing
;; Uses global_token to malloc a struct's definition
;; Uses ECX for int OFFSET, EDX for struct type* head, EBP for struct type* I,
;; EDI for member_size (Which is passed) and ESI for LAST
;; EAX and EBX are used for scratch
:create_struct
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_EBP                                    ; Protect EBP
	PUSH_EDI                                    ; Protect EDI
	PUSH_ESI                                    ; Protect ESI
	LOADI32_ECX %0                              ; OFFSET = 0
	LOADI32_EDI %0                              ; member_size = 0

	LOADI32_EAX %28                             ; sizeof(struct type)
	CALL32 %malloc                              ; malloc(sizeof(struct type))
	COPY_EAX_to_EDX                             ; Set HEAD

	LOADI32_EAX %28                             ; sizeof(struct type)
	CALL32 %malloc                              ; malloc(sizeof(struct type))
	COPY_EAX_to_EBP                             ; Set I

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	STORE32_EAX_into_EDX_Immediate8 !24         ; HEAD->NAME = global_token->S
	STORE32_EAX_into_EBP_Immediate8 !24         ; I->NAME = global_token->S

	STORE32_EBP_into_EDX_Immediate8 !12         ; HEAD->INDIRECT = I
	STORE32_EDX_into_EBP_Immediate8 !12         ; I->INDIRECT = HEAD

	LOAD32_Absolute32_eax &global_types         ; Using global_types
	STORE32_EAX_into_EDX                        ; HEAD->NEXT = global_types
	STORE32_Absolute32_edx &global_types        ; global_types = HEAD

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX %4                              ; Using register size
	STORE32_EAX_into_EBP_Immediate8 !4          ; I->SIZE = register size

	LOADI32_EAX &create_struct_string_0         ; Using "ERROR in create_struct\n Missing {\n"
	LOADI32_EBX &open_curly_brace               ; Using "{"
	CALL32 %require_match                       ; Make sure we have it

	LOADI32_ESI %0                              ; LAST = NULL

:create_struct_iter
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; Make it useful
	CMPI8_EAX !125                              ; IF global_token->S[0] == "}"
	JE32 %create_struct_done                    ; be done

	;; Looks like we are adding members
	;; Lets see if it is a union
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EBX &union                          ; Using "union"
	CALL32 %match                               ; IF match(global_token->s, "union")
	CMPI8_EAX !0                                ; Deal with union
	JNE32 %create_struct_single                 ; Otherwise deal with singles

	;; Deal with union
	COPY_ESI_to_EAX                             ; Put last in right place
	COPY_ECX_to_EBX                             ; put offset in right place
	CALL32 %build_union                         ; ASSEMBLE
	COPY_EAX_to_ESI                             ; last = build_union(last, offset)
	ADD_edi_into_ecx                            ; offset = offset + member_size

	LOADI32_EAX &create_struct_string_1         ; Using "ERROR in create_struct\n Missing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it
	JMP32 %create_struct_iter                   ; keep going

:create_struct_single
	;; deal with singles
	COPY_ESI_to_EAX                             ; Put last in right place
	COPY_ECX_to_EBX                             ; put offset in right place
	CALL32 %build_member                        ; ASSEMBLE
	COPY_EAX_to_ESI                             ; last = build_union(last, offset)
	ADD_edi_into_ecx                            ; offset = offset + member_size

	LOADI32_EAX &create_struct_string_1         ; Using "ERROR in create_struct\n Missing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it
	JMP32 %create_struct_iter                   ; keep going

:create_struct_done
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &create_struct_string_1         ; Using "ERROR in create_struct\n Missing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it

	STORE32_ECX_into_EDX_Immediate8 !4          ; HEAD->SIZE = OFFSET
	STORE32_ESI_into_EDX_Immedate8 !16          ; HEAD->MEMBERS = LAST
	STORE32_ESI_into_EBP_Immedate8 !16          ; I->MEMBERS = LAST

	POP_ESI                                     ; Restore ESI
	POP_EDI                                     ; Restore EDI
	POP_EBP                                     ; Restore EBP
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:create_struct_string_0  "ERROR in create_struct
 Missing {
"
:create_struct_string_1  "ERROR in create_struct
 Missing ;
"


;; lookup_member function
;; Receives struct type* parent in EAX and char* name in EBX
;; Returns struct type* I in EAX
;; Uses char* NAME in EBX, ECX for struct type* I and EDX to hold parent for errors
;; Aborts hard if not found
:lookup_member
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_EDX                             ; Protect Parent
	LOAD32_ECX_from_EAX_Immediate8 !16          ; struct type* I = parent->MEMBERS
:lookup_member_iter
	CMPI8_ECX !0                                ; IF I == NULL
	JE32 %lookup_member_fail                    ; Abort HARD

	LOAD32_EAX_from_ECX_Immediate8 !24          ; Using I->NAME
	CALL32 %match                               ; IF I->NAME == NAME
	CMPI8_EAX !0                                ; Then we have found the member
	COPY_ECX_to_EAX                             ; Prepare for return
	LOAD32_ECX_from_ECX_Immediate8 !16          ; Prepare for loop I = I->MEMBERS
	JNE32 %lookup_member_iter                   ; Looks like we are looping

	;; I is already in EAX
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:lookup_member_fail
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error
	LOADI32_EAX &lookup_member_string_0         ; Using "ERROR in lookup_member "
	CALL32 %File_Print                          ; print it

	LOAD32_EAX_from_EDX_Immediate8 !24          ; PARENT->NAME
	CALL32 %File_Print                          ; print it

	LOADI32_EAX &arrow_string                   ; Using "->"
	CALL32 %File_Print                          ; print it

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %File_Print                          ; print it

	LOADI32_EAX &lookup_member_string_1         ; Using " does not exist\n"
	CALL32 %File_Print                          ; print it

;	CALL32 %line_error                          ; Write useful debug info

	LOADI32_EAX &lookup_member_string_2         ; Using "\n"
	CALL32 %File_Print                          ; print it
	JMP32 %Exit_Failure                         ; Abort Hard

:lookup_member_string_0  "ERROR in lookup_member "
:lookup_member_string_1  " does not exist
"
:lookup_member_string_2  "
"


;; build_member function
;; Receives struct type* last in EAX, int offset in EBX and global member_size in EDI
;; Updates member_size in EDI and returns struct type* I in EAX
;; Uses ECX for struct type* member_type and EDX for struct type* I
:build_member
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_EDX                             ; Put last out of the way
	LOADI32_EAX %28                             ; Allocate type
	CALL32 %malloc                              ; Get I
	STORE32_EDX_into_EAX_Immediate8 !16         ; I->MEMBERS = LAST
	STORE32_EBX_into_EAX_Immediate8 !8          ; I->OFFSET = OFFSET
	COPY_EAX_to_EDX                             ; Put I in place

	CALL32 %type_name                           ; Get member_type
	COPY_EAX_to_ECX                             ; Put in place
	STORE32_ECX_into_EDX_Immediate8 !20         ; I->TYPE = MEMBER_TYPE
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EBX_from_EAX_Immediate8 !8           ; global_token->S
	STORE32_EBX_into_EDX_Immediate8 !24         ; I->NAME = global_token->S
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	;; Check if we have an array
	LOAD32_EBX_from_EAX_Immediate8 !8           ; global_token->S
	LOADI32_EAX &open_bracket                   ; Using "["
	CALL32 %match                               ; IF global_token->S == "["
	CMPI8_EAX !0                                ; Then we have to deal with arrays in our structs
	JE32 %build_member_array                    ; So deal with that pain

	;; Deal with non-array case
	LOAD32_EAX_from_ECX_Immediate8 !4           ; member_type->SIZE
	STORE32_EAX_into_EDX_Immediate8 !4          ; I->SIZE = member_type->SIZE
	JMP32 %build_member_done                    ; Be done

:build_member_array
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	CALL32 %numerate_string                     ; convert number
	LOAD32_EBX_from_ECX_Immediate8 !20          ; member_type->TYPE
	LOAD32_EBX_from_EBX_Immediate8 !4           ; member_type->TYPE->SIZE
	IMUL_EAX_by_EBX                             ; member_type->type->size * numerate_string(global_token->s)
	STORE32_EAX_into_EDX_Immediate8 !4          ; I->SIZE = member_type->type->size * numerate_string(global_token->s)

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &build_member_string_0          ; Using "Struct only supports [num] form\n"
	LOADI32_EBX &close_bracket                  ; Using "]"
	CALL32 %require_match                       ; Make sure we have it

:build_member_done
	LOAD32_EDI_from_EDX_Immediate8 !4           ; MEMBER_SIZE = I->SIZE
	STORE32_ECX_into_EDX_Immediate8 !20         ; I->TYPE = MEMBER_TYPE
	COPY_EDX_to_EAX                             ; Return I

	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:build_member_string_0  "Struct only supports [num] form
"


;; build_union function
;; Receives struct type* last in EAX, int offset in EBX and global member_size in EDI
;; Updates member_size in EDI and returns struct type* LAST in EAX
;; Uses ECX for struct type* last, EDX for int offset, ESI for int size and EDI for int member_size
:build_union
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_ESI                                    ; Protect ESI
	COPY_EAX_to_ECX                             ; Put LAST in right spot
	COPY_EBX_to_EDX                             ; Put OFFSET in right spot
	LOADI32_ESI %0                              ; SIZE = 0

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	LOADI32_EAX &build_union_string_0           ; Using "ERROR in build_union\nMissing {\n"
	LOADI32_EBX &open_curly_brace               ; Using "{"
	CALL32 %require_match                       ; Make sure we have it

:build_union_iter
	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX_Immediate8 !8           ; global_token->S
	LOAD8_al_from_EAX                           ; global_token->S[0]
	MOVZX_al                                    ; make it useful
	CMPI8_EAX !125                              ; IF global_token->S[0] == "}"
	JE32 %build_union_done                      ; Be done

	;; Collect union member
	COPY_ECX_to_EAX                             ; Passing LAST
	COPY_EDX_to_EBX                             ; Passing offset
	CALL32 %build_member                        ; build_member(last, offset)
	COPY_EAX_to_ECX                             ; last = build_member(last, offset)

	CMP_EDI_ESI                                 ; IF member_size > size
	JG32 %build_union_size                      ; Then update size

	;; deal with member_size > size
	COPY_EDI_to_ESI                             ; SIZE = MEMBER_SIZE

:build_union_size
	LOADI32_EAX &build_union_string_1           ; Using "ERROR in build_union\nMissing ;\n"
	LOADI32_EBX &semicolon                      ; Using ";"
	CALL32 %require_match                       ; Make sure we have it
	JMP32 %build_union_iter                     ; Keep going

:build_union_done
	COPY_ESI_to_EDI                             ; MEMBER_SIZE = SIZE

	LOAD32_Absolute32_eax &global_token         ; Using global_token
	LOAD32_EAX_from_EAX                         ; global_token->NEXT
	STORE32_Absolute32_eax &global_token        ; global_token = global_token->NEXT

	COPY_ECX_to_EAX                             ; Return last

	POP_ESI                                     ; Restore ESI
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:build_union_string_0  "ERROR in build_union
Missing {
"
:build_union_string_1  "ERROR in build_union
Missing ;
"


;; sym_declare function
;; Receives char *s in EAX, struct type* t in EBX, and struct token_list* list in ECX
;; Returns struct token_list* in EAX
;; Uses EAX for A
:sym_declare
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_EDX                             ; Get char *S safely out of the way
	LOADI32_EAX %20                             ; Using sizeof(struct token_list)
	CALL32 %malloc                              ; Get pointer to A
	STORE32_ECX_into_EAX                        ; A->NEXT = LIST
	STORE32_EDX_into_EAX_Immediate8 !8          ; A->S = S
	STORE32_EBX_into_EAX_Immediate8 !12         ; A->TYPE = T
	POP_EDX                                     ; Restore EDX
	RETURN


;; match function
;; Receives CHAR* in EAX and CHAR* in EBX
;; Returns 0 (TRUE) or 1 (FALSE) in EAX
:match
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	COPY_EAX_to_ECX                             ; S1 in place
	COPY_EBX_to_EDX                             ; S2 in place
:match_Loop
	LOAD8_al_from_ECX                           ; S1[0]
	MOVZX_al                                    ; Make it useful
	LOAD8_bl_from_EDX                           ; S2[0]
	MOVZX_bl                                    ; Make it useful
	CMP_EAX_EBX                                 ; See if they match
	JNE32 %match_False                          ; If not

	ADDI8_ECX !1                                ; S1 = S1 + 1
	ADDI8_EDX !1                                ; S2 = S2 + 1
	CMPI8_EAX !0                                ; If reached end of string
	JE32 %match_Done                            ; Perfect match
	JMP32 %match_Loop                           ; Otherwise keep looping

:match_False
	LOADI32_EAX %1                              ; Return false
:match_Done
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; numerate_number function
;; Receives an INT A in EAX
;; Returns char* result in EAX
;; Allocates 16 bytes of memory
;; Behaves badly when given a negative number too large
;; Uses EAX for temp, EBX for DIVISOR, EDX for mod/0, ESI for result[i] and EBP for A
:numerate_number
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_ESI                                    ; Protect ESI
	PUSH_EBP                                    ; Protect EBP
	COPY_EAX_to_EBP                             ; Protect A

	LOADI32_EAX %16                             ; 16bytes
	CALL32 %malloc                              ; Get our pointer
	PUSH_EAX                                    ; Protect our pointer
	COPY_EAX_to_ESI                             ; put pointer in right place
	LOADI32_EBX %0x3B9ACA00                     ; Set divisor to largest positive number that fits in 32bits

	CMPI8_EBP !0                                ; Deal with 0 case
	JE32 %numerate_number_ZERO                  ; If it is
	JG32 %numerate_number_positive              ; If it is positive

	;; Deal with negative case
	LOADI32_EAX %45                             ; Using "-"
	STORE8_al_into_Address_ESI                  ; Write it
	ADDI8_ESI !1                                ; increment
	IMULI8_EBP !-1                              ; A = A * -1

:numerate_number_positive
	LOADI32_EDX %0                              ; Set top to 0
	COPY_EBP_to_EAX                             ; Using A as bottom
	IDIV_EBX                                    ; edx:eax % ebx -> edx + edx:eax / ebx -> eax [Even if we don't want it]
	CMPI8_EAX !0                                ; IF 0 == (a / divisor)
	JNE32 %numerate_number_iter                 ; Clean up those leading Zeros

	LOADI32_EDX %0                              ; Set top to 0
	COPY_EBX_to_EAX                             ; Using Divisor for bottom
	LOADI32_EBX %10                             ; Make this shit work because idiv 10 doesn't work
	IDIV_EBX                                    ; edx:eax % 10 -> edx + edx:eax / 10 -> eax [Even if we don't want it]
	COPY_EAX_to_EBX                             ; Update divisor
	JMP32 %numerate_number_positive             ; Keep collecting

:numerate_number_iter
	CMPI8_EBX !0                                ; IF DIVISOR < 0
	JLE32 %numerate_number_done                 ; Be done

	LOADI32_EDX %0                              ; Set top to 0
	COPY_EBP_to_EAX                             ; Using A as bottom
	IDIV_EBX                                    ; edx:eax % ebx -> edx + edx:eax / ebx -> eax [Even if we don't want it]
	ADDI8_EAX !48                               ; ((a / divisor) + 48)
	STORE8_al_into_Address_ESI                  ; Write it
	COPY_EDX_to_EBP                             ; a = a % divisor

	LOADI32_EDX %0                              ; Set top to 0
	COPY_EBX_to_EAX                             ; Using Divisor for bottom
	LOADI32_EBX %10                             ; Make this shit work because idiv 10 doesn't work
	IDIV_EBX                                    ; edx:eax % 10 -> edx + edx:eax / 10 -> eax [Even if we don't want it]
	COPY_EAX_to_EBX                             ; Update divisor

	ADDI8_ESI !1                                ; increment
	JMP32 %numerate_number_iter                 ; Keep going

:numerate_number_done
	POP_EAX                                     ; Restore our result
	POP_EBP                                     ; Restore EBP
	POP_ESI                                     ; Restore ESI
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN

:numerate_number_ZERO
	LOADI32_EAX %48                             ; Using '0'
	STORE8_al_into_Address_ESI                  ; Write it
	ADDI8_ESI !1                                ; increment
	JMP32 %numerate_number_done                 ; Be done


;; numerate_string function
;; Receives CHAR* in EAX
;; Returns value of CHAR* in EAX
;; Uses EAX for VALUE, EBX for S, ECX for CH and ESI for NEGATIVE?
:numerate_string
	PUSH_EBX                                    ; Protect EBX
	PUSH_ECX                                    ; Protect ECX
	PUSH_EDX                                    ; Protect EDX
	PUSH_ESI                                    ; Protect ESI
	COPY_EAX_to_EBX                             ; put S in correct place
	LOADI32_EAX %0                              ; Initialize to Zero
:numerate_string_loop
	LOAD8_cl_from_EBX_Immediate8 !1             ; S[1]
	MOVZX_cl                                    ; make it useful
	CMPI8_ECX !120                              ; IF 'x' == S[1]
	JE32 %numerate_hex                          ; Deal with hex input

	;; Assume decimal input
	LOADI32_ESI %0                              ; Assume no negation
	LOAD8_cl_from_EBX                           ; S[0]
	MOVZX_cl                                    ; make it useful
	CMPI8_ECX !45                               ; IF '-' == S[0]
	JNE32 %numerate_decimal                     ; Skip negation

	LOADI32_ESI %1                              ; Set FLAG
	ADDI8_EBX !1                                ; S = S + 1

:numerate_decimal
	LOAD8_cl_from_EBX                           ; S[0]
	MOVZX_cl                                    ; make it useful
	CMPI8_ECX !0                                ; IF NULL == S[0]
	JE32 %numerate_decimal_done                 ; We are done

	IMULI8_EAX !10                              ; VALUE = VALUE * 10
	SUBI8_ECX !48                               ; CH = CH - '0'
	CMPI8_ECX !9                                ; Check for illegal
	JG32 %numerate_string_fail                  ; If CH > '9'
	CMPI8_ECX !0                                ; Check for illegal
	JL32 %numerate_string_fail                  ; IF CH < 0
	ADD_ecx_into_eax                            ; VALUE = VALUE + CH
	ADDI8_EBX !1                                ; S = S + 1
	JMP32 %numerate_decimal                     ; Keep looping

:numerate_decimal_done
	CMPI8_ESI !1                                ; Check if need to negate
	JNE32 %numerate_string_done                 ; Nope

	IMULI8_EAX !-1                              ; VALUE = VALUE * -1
	JMP32 %numerate_string_done                 ; Done

:numerate_hex
	ADDI8_EBX !2                                ; S = S + 2
:numerate_hex_loop
	LOAD8_cl_from_EBX                           ; S[0]
	MOVZX_cl                                    ; make it useful
	CMPI8_ECX !0                                ; IF NULL == S[0]
	JE32 %numerate_string_done                  ; We are done

	SALI8_EAX !4                                ; VALUE = VALUE << 4
	SUBI8_ECX !48                               ; CH = CH - '0'
	CMPI8_ECX !10                               ; IF 10 >= CH
	JL32 %numerate_hex_digit                    ; NO
	SUBI8_ECX !7                                ; Push A-F into range
:numerate_hex_digit
	CMPI8_ECX !15                               ; Check for illegal
	JG32 %numerate_string_fail                  ; If CH > 'F'
	CMPI8_ECX !0                                ; Check for illegal
	JL32 %numerate_string_fail                  ; IF CH < 0
	ADD_ecx_into_eax                            ; VALUE = VALUE + CH
	ADDI8_EBX !1                                ; S = S + 1
	JMP32 %numerate_hex_loop                    ; Keep looping

:numerate_string_fail
	LOADI32_EAX %0                              ; return ZERO

:numerate_string_done
	POP_ESI                                     ; Restore ESI
	POP_EDX                                     ; Restore EDX
	POP_ECX                                     ; Restore ECX
	POP_EBX                                     ; Restore EBX
	RETURN


;; Exit_Failure function
;; Receives nothing
;; And aborts hard
;; Does NOT return
:Exit_Failure
	LOADI32_EBX %1                              ; All is wrong
	LOADI32_EAX %1                              ; put the exit syscall number in eax
	INT_80                                      ; Call it a bad day

;; Keywords
:union  "union"
:struct  "struct"
:constant  "CONSTANT"
:main_string  "main"
:argc_string  "argc"
:argv_string  "argv"
:if_string  "if"
:else_string  "else"
:do_string  "do"
:while_string  "while"
:for_string  "for"
:asm_string  "asm"
:goto_string  "goto"
:return_string  "return"
:break_string  "break"
:continue_string  "continue"
:sizeof_string  "sizeof"
:plus_string  "+"
:minus_string  "-"
:multiply_string  "*"
:divide_string  "/"
:modulus_string  "%"
:left_shift_string  "<<"
:right_shift_string  ">>"
:less_than_string  "<"
:less_than_equal_string  "<="
:greater_than_equal_string  ">="
:greater_than_string  ">"
:equal_to_string  "=="
:not_equal_string  "!="
:bitwise_and  "&"
:logical_and  "&&"
:bitwise_or  "|"
:logical_or  "||"
:bitwise_xor  "^"
:arrow_string  "->"


;; Frequently Used strings
;; Generally used by require_match
:open_curly_brace  "{"
:close_curly_brace  "}"
:open_paren  "("
:close_paren  ")"
:open_bracket  "["
:close_bracket  "]"
:comma  ","
:semicolon  ";"
:equal  "="
:percent  "%"
:newline  "\n"
:underline  "_"


:prim_types
:type_void
	&type_int                                   ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_void                                  ; INDIRECT
	%0                                          ; MEMBERS
	&type_void                                  ; TYPE
	&type_void_name                             ; NAME
:type_void_name  "void"

:type_int
	&type_char                                  ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_int                                   ; INDIRECT
	%0                                          ; MEMBERS
	&type_int                                   ; TYPE
	&type_int_name                              ; NAME
:type_int_name  "int"

:type_char
	&type_file                                  ; NEXT
	%1                                          ; SIZE
	%0                                          ; OFFSET
	&type_char_indirect                         ; INDIRECT
	%0                                          ; MEMBERS
	&type_char                                  ; TYPE
	&type_char_name                             ; NAME
:type_char_name  "char"

:type_char_indirect
	&type_file                                  ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_char_double_indirect                  ; INDIRECT
	%0                                          ; MEMBERS
	&type_char_indirect                         ; TYPE
	&type_char_indirect_name                    ; NAME
:type_char_indirect_name  "char*"

:type_char_double_indirect
	&type_file                                  ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_char_double_indirect                  ; INDIRECT
	%0                                          ; MEMBERS
	&type_char_indirect                         ; TYPE
	&type_char_double_indirect_name             ; NAME
:type_char_double_indirect_name  "char**"

:type_file
	&type_function                              ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_file                                  ; INDIRECT
	%0                                          ; MEMBERS
	&type_file                                  ; TYPE
	&type_file_name                             ; NAME
:type_file_name  "FILE"

:type_function
	&type_unsigned                              ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_function                              ; INDIRECT
	%0                                          ; MEMBERS
	&type_function                              ; TYPE
	&type_function_name                         ; NAME
:type_function_name  "FUNCTION"

:type_unsigned
	&type_long                                  ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_unsigned                              ; INDIRECT
	%0                                          ; MEMBERS
	&type_unsigned                              ; TYPE
	&type_unsigned_name                         ; NAME
:type_unsigned_name  "unsigned"

:type_long
	%0                                          ; NEXT
	%4                                          ; SIZE
	%0                                          ; OFFSET
	&type_long                                  ; INDIRECT
	%0                                          ; MEMBERS
	&type_long                                  ; TYPE
	&type_long_name                             ; NAME
:type_long_name  "long"

;; debug_list function
;; Receives struct token_list* in EAX
;; Prints contents of list and exits
;; Does NOT return
:debug_list
	COPY_EAX_to_EBP                             ; Protect the list pointer
	LOADI32_EAX %2                              ; Using Standard error
	STORE32_Absolute32_eax &Output_file         ; write to standard error

:debug_list_iter
	;; Header
	LOADI32_EAX &debug_list_string0             ; Using our first string
	CALL32 %File_Print                          ; Print it
	COPY_EBP_to_EAX                             ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	;; NEXT
	LOADI32_EAX &debug_list_string1             ; Using our second string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !0           ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	;; PREV
	LOADI32_EAX &debug_list_string2             ; Using our third string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !4           ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	;; S
	LOADI32_EAX &debug_list_string3             ; Using our fourth string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !8           ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	;; S Contents
	LOADI32_EAX &debug_list_string4             ; Using our fifth string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !8           ; Use address of string
	CMPI8_EAX !0                                ; IF NULL Pointer
	JNE32 %debug_list_null                      ; otherwise display
	LOADI32_EAX &debug_list_string_null         ; Give meaningful message instead
:debug_list_null
	CALL32 %File_Print                          ; Print it

	;; TYPE
	LOADI32_EAX &debug_list_string5             ; Using our sixth string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !12          ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	;; ARGS/DEPTH
	LOADI32_EAX &debug_list_string6             ; Using our seventh string
	CALL32 %File_Print                          ; Print it
	LOAD32_EAX_from_EBP_Immediate8 !16          ; Use address of pointer
	CALL32 %numerate_number                     ; Convert it into string
	CALL32 %File_Print                          ; Print it

	LOADI32_EAX %10                             ; Add "\n"
	CALL32 %fputc                               ; print it
	CALL32 %fputc                               ; print it

	LOAD32_EBP_from_EBP                         ; TOKEN = TOKEN->NEXT
	CMPI8_EBP !0                                ; Check if NULL
	JNE32 %debug_list_iter                      ; iterate otherwise

	LOADI32_EBX %666                            ; All is HELL
	LOADI32_EAX %1                              ; put the exit syscall number in eax
	INT_80                                      ; Call it a bad day

:debug_list_string0  "Token_list node at address: "
:debug_list_string1  "
NEXT address: "
:debug_list_string2  "
PREV address: "
:debug_list_string3  "
S address: "
:debug_list_string4  "
The contents of S are: "
:debug_list_string5  "
TYPE address: "
:debug_list_string6  "
ARGUMENTS address: "
:debug_list_string_null  ">::<NULL>::<"


:Address_of
	NULL
:C
	NULL
:Input_file
	NULL
:MALLOC
	NULL
:Output_file
	NULL
:Token
	NULL
:break_frame
	NULL
:break_target_func
	NULL
:break_target_head
	NULL
:break_target_num
	NULL
:current_count
	NULL
:current_target
	NULL
:function
	NULL
:global_constant_list
	NULL
:global_function_list
	NULL
:global_symbol_list
	NULL
:global_token
	NULL
:global_types
	&prim_types
:globals_list
	NULL
:output_list
	NULL
:string_index
	NULL
:strings_list
	NULL

:ELF_end
