A minimal C compiler in x86 assembly

A minimal C compiler in x86 assembly

This is another awesome !!

; Copyright (C) 2016 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 .

;; A Minimal C Compiler

;; type Cells are in the following form:

;; NEXT (0), SIZE (4), OFFSET (8), INDIRECT (12), MEMBERS (16), TYPE (20), NAME (24)

;; token_list Cells are in the following form:

;; NEXT (0), LOCALS/PREV (4), S (8), TYPE/FILENAME (12), ARGUMENTS/DEPTH/LINENUMBER (16)

;; Each being the length of a register [32bits]

;;

;; STACK space: End of program -> 512KB (0x80000) [Could be reduced]

;; HEAP space: 512KB -> End of Memory

;; R15 is the STACK pointer

;; R14 is the HEAP pointer

:start

;; Prep TAPE_02

LOADUI R0 0x1101

FOPEN_WRITE

;; Prep TAPE_01

LOADUI R0 0x1100

FOPEN_READ

:main

LOADUI R0 0x1100 ; Pass Tape_01 for reading

LOADR32 R14 @HEAP ; Setup Initial HEAP

LOADUI R15 $STACK ; Setup Initial STACK

CALLI R15 @read_all_tokens ; Read all Tokens in Tape_01

CALLI R15 @reverse_list ; Fix Token Order

; CALLI R15 @debug_list ; Lets try to debug token errors

MOVE R13 R0 ; Set global_token for future reading

FALSE R12 ; Set struct token_list* out to NULL

FALSE R11 ; Set struct token_list* list_strings to NULL

FALSE R10 ; Set struct token_list* globals_list to NULL

CALLI R15 @program ; Build our output

LOADUI R0 $header_string1 ; Using our first header string

LOADUI R1 0x1101 ; Using Tape_02

CALLI R15 @file_print ; Write string

MOVE R0 R12 ; using Contents of output_list

CALLI R15 @recursive_output ; Recursively write

LOADUI R0 $header_string2 ; Using our second header string

CALLI R15 @file_print ; Write string

MOVE R0 R10 ; using Contents of globals_list

CALLI R15 @recursive_output ; Recursively write

LOADUI R0 $header_string3 ; Using our third header string

CALLI R15 @file_print ; Write string

MOVE R0 R11 ; using Contents of strings_list

CALLI R15 @recursive_output ; Recursively write

LOADUI R0 $header_string4 ; Using our final header string

CALLI R15 @file_print ; Write string

HALT ; We have completed compiling our input

;; Symbol lists

:global_constant_list

NOP

:global_symbol_list

NOP

:global_function_list

NOP

;; Pointer to initial HEAP ADDRESS

:HEAP

‘00080000’

;; Output strings

:header_string1

# Core program

:header_string2

# Program global variables

:header_string3

# Program strings

:header_string4

:ELF_end

;; clearWhiteSpace function

;; Receives a character in R0 and FILE* in R1 and line_num in R11

;; Returns first non-whitespace character in R0

:clearWhiteSpace

CMPSKIPI.NE R0 32 ; Check for a Space

JUMP @clearWhiteSpace_reset ; Looks like we need to remove a space

CMPSKIPI.NE R0 9 ; Check for a tab

JUMP @clearWhiteSpace_reset ; Looks like we need to remove a tab

CMPSKIPI.E R0 10 ; Check for a newline

RET R15 ; Looks we found a non-whitespace

ADDUI R11 R11 1 ; Increment line number

;; Fall through to iterate to next char

:clearWhiteSpace_reset

FGETC ; Get next char

JUMP @clearWhiteSpace ; Iterate

;; consume_byte function

;; Receives a char in R0, FILE* in R1 and index in R13

;; Returns next char in R0

:consume_byte

STOREX8 R0 R14 R13 ; Put char onto HEAP

ADDUI R13 R13 1 ; Increment index

FGETC ; Get next char

RET R15

;; consume_word function

;; Receives a char in R0, FILE* in R1, FREQUENT in R2 and index in R13

;; Returns next char in R0

:consume_word

PUSHR R3 R15 ; Protect R3

FALSE R3 ; ESCAPE is FALSE

:consume_word_reset

JUMP.NZ R3 @consume_word_iter1

CMPSKIPI.NE R0 92 ; If

TRUE R3 ; Looks like we are in an escape

JUMP @consume_word_iter2

:consume_word_iter1

FALSE R3 ; Looks like we are no longer in an escape

:consume_word_iter2

CALLI R15 @consume_byte ; Store the char

JUMP.NZ R3 @consume_word_reset ; If escape loop

CMPJUMPI.NE R0 R2 @consume_word_reset ; if not matching frequent loop

FGETC ; Get a new char to return

POPR R3 R15 ; Restore R3

RET R15

;; fixup_label function

;; Receives nothing (But uses R14 as HEAP pointer)

;; Returns 32 in R0 and no other registers altered

:fixup_label

PUSHR R1 R15 ; Protect R1 from change

PUSHR R2 R15 ; Protect R2 from change

LOADUI R0 58 ; Set HOLD to :

FALSE R2 ; Set I to 0

:fixup_label_reset

MOVE R1 R0 ; Set PREV=HOLD

LOADXU8 R0 R14 R2 ; Read hold_string[I] into HOLD

STOREX8 R1 R14 R2 ; Set hold_string[I]=PREV

ADDUI R2 R2 1 ; increment I

JUMP.NZ R0 @fixup_label_reset ; Loop until we hit a NULL

;; clean up

ADDUI R2 R2 1 ; increment I

LOADUI R0 32 ; Put 32 in R0

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; in_set2 function

;; Receives a Char in R0, FILE* in R1, char* in R2 and index in R13

;; Return result in R2

:in_set2

PUSHR R3 R15 ; Protect R3 from changes

:in_set2_reset

LOADU8 R3 R2 0 ; Get char from list

JUMP.Z R3 @in_set2_fail ; Stop when 0==s[0]

CMPJUMPI.E R0 R3 @in_set2_done ; We found a match

ADDUI R2 R2 1 ; Increment to next char

JUMP.NZ R3 @in_set2_reset ; Iterate if not NULL

:in_set2_fail

;; Looks like not found

FALSE R2 ; Return FALSE

:in_set2_done

CMPSKIPI.E R2 0 ; Provided not FALSE

TRUE R2 ; The result is true

POPR R3 R15 ; Restore R3

RET R15

;; in_set function

;; Receives a Char in R0, char* in R1

;; Return result in R0

:in_set

PUSHR R2 R15 ; Protect R3 from changes

:in_set_reset

LOADU8 R2 R1 0 ; Get char from list

JUMP.Z R2 @in_set_fail ; Stop when 0==s[0]

CMPJUMPI.E R0 R2 @in_set_done ; We found a match

ADDUI R1 R1 1 ; Increment to next char

JUMP.NZ R2 @in_set_reset ; Iterate if not NULL

:in_set_fail

;; Looks like not found

FALSE R1 ; Return FALSE

:in_set_done

CMPSKIPI.E R1 0 ; Provided not FALSE

TRUE R2 ; The result is true

MOVE R0 R2 ; Put result in correct place

POPR R2 R15 ; Restore R3

RET R15

;; Common in_set strings of interest

;; As Raw strings (“) is forbidden and ‘ has some restrictions

:nice_chars

!#$%&'()*+,-./0123456789:;?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^_`abcdefghijklmnopqrstuvwxyz{|}~”

:keyword_chars

“abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_”

:variable_chars

“abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_”

:symbol_chars

“|&!-”

:hex_chars

“0123456789ABCDEF”

:digit_chars

“0123456789”

:whitespace_chars

;; preserve_keyword function

;; Receives a Char in R0, FILE* in R1 and index in R13

;; Overwrites R2

;; Returns next CHAR

:preserve_keyword

LOADUI R2 $keyword_chars ; Using keyword list of chars

CALLI R15 @in_set2 ; Check if in list

JUMP.Z R2 @preserve_keyword_label ; if not in set, stop iterating

:preserve_keyword_reset

CALLI R15 @consume_byte ; Consume another byte

JUMP @preserve_keyword ; Iterate

:preserve_keyword_label

CMPSKIPI.NE R0 58 ; Check for label (:)

CALLI R15 @fixup_label ; Looks like we found one

RET R15

;; preserve_symbol function

;; Receives a Char in R0, FILE* in R1 and index in R13

;; Overwrites R2

;; Returns next CHAR

:preserve_symbol

LOADUI R2 $symbol_chars ; Using symbol list of chars

CALLI R15 @in_set2 ; Check if in list

JUMP.NZ R2 @preserve_symbol_reset

;; Looks we didn’t find anything we wanted to preserve

RET R15

:preserve_symbol_reset

CALLI R15 @consume_byte ; Consume another byte

JUMP @preserve_symbol ; Iterate

;; purge_macro function

;; Receives a Char in R0, FILE* in R1 and index in R13

;; Returns next CHAR via jumping to get_token_reset

:purge_macro

CMPSKIPI.NE R0 10 ; Check for Line Feed

JUMP @get_token_reset ; Looks like we found it, call it done

FGETC ; Looks like we need another CHAR

JUMP @purge_macro ; Keep looping

;; get_token function

;; Receives a Char in R0, FILE* in R1, line_num in R11 and TOKEN in R10

;; sets index in R13 and current in R12

;; Overwrites R2

;; Returns next CHAR

:get_token

PUSHR R12 R15 ; Preserve R12

PUSHR R13 R15 ; Preserve R13

COPY R12 R14 ; Save CURRENT’s Address

ADDUI R14 R14 20 ; Update Malloc to free space for string

:get_token_reset

FALSE R13 ; Reset string_index to 0

CALLI R15 @clearWhiteSpace ; Clear any leading whitespace

CMPSKIPI.NE R0 35 ; Deal with # line macros

JUMP @purge_macro ; Returns at get_token_reset

;; Check for keywords

LOADUI R2 $keyword_chars ; Using keyword list

CALLI R15 @in_set2 ; Check if keyword

JUMP.Z R2 @get_token_symbol ; if not a keyword

CALLI R15 @preserve_keyword ; Yep its a keyword

JUMP @get_token_done ; Be done with token

;; Check for symbols

:get_token_symbol

LOADUI R2 $symbol_chars ; Using symbol list

CALLI R15 @in_set2 ; Check if symbol

JUMP.Z R2 @get_token_char ; If not a symbol

CALLI R15 @preserve_symbol ; Yep its a symbol

JUMP @get_token_done ; Be done with token

;; Check for char

:get_token_char

CMPSKIPI.E R0 39 ; Check if ‘

JUMP @get_token_string ; Not a ‘

COPY R2 R0 ; Prepare for consume_word

CALLI R15 @consume_word ; Call it

JUMP @get_token_done ; Be done with token

;; Check for string

:get_token_string

CMPSKIPI.E R0 34 ; Check if ”

JUMP @get_token_EOF ; Not a ”

COPY R2 R0 ; Prepare for consume_word

CALLI R15 @consume_word ; Call it

JUMP @get_token_done ; Be done with token

;; Check for EOF

:get_token_EOF

CMPSKIPI.L R0 0 ; If c S to String

ADD R14 R14 R13 ; Add string length to HEAP

STORE32 R10 R12 0 ; CURRENT->NEXT=TOKEN

STORE32 R10 R12 4 ; CURRENT->PREV=TOKE

STORE32 R11 R12 16 ; CURRENT->LINENUM=LINE_NUM

MOVE R10 R12 ; SET TOKEN to CURRENT

POPR R13 R15 ; Restore R13

POPR R12 R15 ; Restore R12

RET R15

;; reverse_list function

;; Receives a Token_list in R0

;; Returns List in Reverse order in R0

:reverse_list

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

FALSE R1 ; Set ROOT to NULL

CMPJUMPI.E R0 R1 @reverse_list_done ; ABORT if given a NULL

:reverse_list_reset

LOAD32 R2 R0 0 ; SET next to HEAD->NEXT

STORE32 R1 R0 0 ; SET HEAD->NEXT to ROOT

MOVE R1 R0 ; SET ROOT to HEAD

MOVE R0 R2 ; SET HEAD to NEXT

JUMP.NZ R0 @reverse_list_reset ; Iterate if HEAD not NULL

:reverse_list_done

MOVE R0 R1 ; SET Result to ROOT

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; read_all_tokens function

;; Receives a FILE* in R0

;; sets line_num in R11 and TOKEN in R10

;; Overwrites R2

;; Returns struct token_list* in R0

:read_all_tokens

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R10 R15 ; Protect R10

PUSHR R11 R15 ; Protect R11

MOVE R1 R0 ; Set R1 as FILE*

FGETC ; Read our first CHAR

LOADUI R11 1 ; Start line_num at 1

FALSE R10 ; First token is NULL

:read_all_tokens_reset

JUMP.NP R0 @read_all_tokens_done

CALLI R15 @get_token

JUMP @read_all_tokens_reset

:read_all_tokens_done

MOVE R0 R10 ; Return the Token

POPR R11 R15 ; Restore R11

POPR R10 R15 ; Restore R10

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; parse_string function

;; Receives char* string in R0

;; R14 is HEAP Pointer

;; Returns char* in R0

:parse_string

PUSHR R1 R15 ; Protect R1

COPY R1 R0 ; Make a copy of STRING

CALLI R15 @weird ; Check if string is weird

SWAP R0 R1

JUMP.Z R1 @parse_string_regular ; Deal with regular strings

;; Looks like we have a weirdo

CALLI R15 @collect_weird_string ; Create our weird string

JUMP @parse_string_done ; Simply return what was created

:parse_string_regular

CALLI R15 @collect_regular_string

:parse_string_done

POPR R1 R15 ; Restore R1

RET R15

;; weird function

;; Analyze string to determine if it’s output would be weird for mescc-tools

;; Receives char* in R0

;; Returns BOOL in R0

:weird

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

FALSE R2 ; Assume FALSE

ADDUI R3 R0 1 ; STRING=STRING + 1

:weird_iter

JUMP.NZ R2 @weird_done ; Stop if TRUE

LOADU8 R4 R3 0 ; C=STRING[0]

JUMP.Z R4 @weird_done ; Be done at NULL Termination

CMPSKIPI.E R4 92 ; If not ‘\’

JUMP @weird_post_escape ; Looks like no escape analysis

;; Deal with the mess

COPY R0 R3 ; Using STRING

CALLI R15 @escape_lookup ; Get our CHAR

MOVE R4 R0 ; C=ESCAPE_LOOKUP(STRING)

LOADU8 R0 R3 1 ; STRING[1]

CMPSKIPI.NE R0 120 ; if ‘x’==STRING[1]

ADDUI R3 R3 2 ; STRING=STRING + 2

ADDUI R3 R3 1 ; STRING=STRING + 1

:weird_post_escape

LOADUI R1 $nice_chars ; using list of nice CHARS

COPY R0 R4 ; using copy of C

CALLI R15 @in_set ; Use in_set

CMPSKIPI.NE R0 0 ; IF TRUE

TRUE R2 ; Return TRUE

ADDUI R3 R3 1 ; STRING=STRING + 1

LOADUI R1 $whitespace_chars ; Check Whitespace Chars

COPY R0 R4 ; Using copy of C

CALLI R15 @in_set ; Use in_set

JUMP.Z R0 @weird_iter ; If False simply loop

LOADU8 R0 R3 0 ; STRING[1]

CMPSKIPI.NE R0 58 ; If ‘:’==STRING[1]

TRUE R2 ; Flip flag

JUMP @weird_iter ; Keep trying to find an answer

:weird_done

MOVE R0 R2 ; Whatever is in R2 is the answer

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; collect_weird_string function

;; Converts weird string into a form mescc-tools can handle cleanly

;; Receives char* in R0

;; R14 is HEAP Pointer and $hex_chars as the table

;; Returns char* in R0

:collect_weird_string

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

LOADUI R4 $hex_chars ; Pointer to TABLE

COPY R3 R14 ; Get HOLD

MOVE R2 R0 ; Put STRING in Place

LOADUI R0 39 ; Prefix with ‘

PUSH8 R0 R3 ; HOLD[0]=”’ && HOLD=HOLD + 1

:collect_weird_string_iter

ADDUI R2 R2 1 ; STRING=STRING + 1

LOADUI R0 32 ; Insert ‘ ‘

PUSH8 R0 R3 ; HOLD[0]=’ ‘ && HOLD=HOLD + 1

COPY R0 R2 ; copy STRING

CALLI R15 @escape_lookup ; Get char value

ANDI R1 R0 0x0F ; Save Bottom out of the way

SR0I R0 4 ; Isolate Top

LOADXU8 R0 R4 R0 ; Using Table

LOADXU8 R1 R4 R1 ; Using Table

PUSH8 R0 R3 ; HOLD[0]=TABLE[(TEMP>> 4)] && HOLD=HOLD + 1

PUSH8 R1 R3 ; HOLD[0]=TABLE[(TEMP & 15)] && HOLD=HOLD + 1

LOADU8 R0 R2 0 ; STRING[0]

JUMP.Z R0 @collect_weird_string_done ; Stop if NULL

CMPSKIPI.E R0 92 ; IF STRING[0] !=’\’

JUMP @collect_weird_string_check ; Deal with iteration

LOADU8 R0 R2 1 ; STRING[1]

CMPSKIPI.NE R0 120 ; If STRING[1]==’x’

ADDUI R2 R2 2 ; STRING=STRING + 2

ADDUI R2 R2 1 ; STRING=STRING + 1

:collect_weird_string_check

LOADU8 R0 R2 1 ; STRING[1]

JUMP.NZ R0 @collect_weird_string_iter

:collect_weird_string_done

LOADUI R0 32 ; Insert ‘ ‘

PUSH8 R0 R3 ; HOLD[0]=’ ‘ && HOLD=HOLD + 1

LOADUI R0 48 ; Insert ‘0’

PUSH8 R0 R3 ; HOLD[0]=’0′ && HOLD=HOLD + 1

PUSH8 R0 R3 ; HOLD[0]=’0′ && HOLD=HOLD + 1

LOADUI R0 39 ; Insert ”’

PUSH8 R0 R3 ; HOLD[0]=”’ && HOLD=HOLD + 1

LOADUI R0 10 ; Insert ‘n’

PUSH8 R0 R3 ; HOLD[0]=’n’ && HOLD=HOLD + 1

ADDUI R3 R3 1 ; NULL Terminate

SWAP R3 R14 ; CALLOC HOLD

MOVE R0 R3 ; Return HOLD

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; hex function

;; Receives Char in R0

;; Return Int in R0

:hex

SUBUI R0 R0 48 ; First shift

CMPSKIPI.GE R0 10 ; If 0-9

RET R15 ; Be done

;; Deal with A-F

ANDI R0 R0 0xDF ; Unset high bit

SUBUI R0 R0 7 ; Shift them down

CMPSKIPI.GE R0 10 ; if between 9 and A

JUMP @hex_error ; Throw an error

CMPSKIPI.L R0 16 ; if> F

JUMP @hex_error ; Throw an error

RET R15

:hex_error

LOADUI R0 $hex_error_message ; Our message

FALSE R1 ; For human

CALLI R15 @file_print ; write it

CALLI R15 @line_error ; More info

HALT

:hex_error_message

“Tried to print non-hex number

;; escape_lookup function

;; Receives char* in R0

;; Returns char in R0

:escape_lookup

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

MOVE R1 R0 ; Put C in the right spot

FALSE R2 ; Our flag for done

LOADU8 R0 R1 0 ; c[0]

CMPSKIPI.E R0 92 ; If C[0] !=’\’

JUMP @escape_lookup_none ; Deal with none case

LOADU8 R0 R1 1 ; c[1]

CMPSKIPI.NE R0 120 ; if x??

JUMP @escape_lookup_hex

;; Deal with ? escapes

CMPSKIPI.NE R0 110 ; If n

LOADUI R2 10 ; return n

CMPSKIPI.NE R0 116 ; If t

LOADUI R2 9 ; return t

CMPSKIPI.NE R0 92 ; If \

LOADUI R2 92 ; return \

CMPSKIPI.NE R0 39 ; If ‘

LOADUI R2 39 ; return ‘

CMPSKIPI.NE R0 34 ; If ”

LOADUI R2 34 ; return ”

CMPSKIPI.NE R0 114 ; If r

LOADUI R2 13 ; return r

JUMP.Z R2 @escape_lookup_error ; Looks like we got something weird

JUMP @escape_lookup_done ; Otherwise just use our R2

:escape_lookup_none

MOVE R2 R0 ; We just return the char at C[0]

JUMP @escape_lookup_done ; Be done

:escape_lookup_hex

LOADU8 R0 R1 2 ; c[2]

CALLI R15 @hex ; Get first char

SL0I R0 4 ; Shift our first nybble

MOVE R2 R0 ; Protect our top nybble

LOADU8 R0 R1 3 ; c[3]

CALLI R15 @hex ; Get second char

ADD R2 R2 R0 ; x??=> ? NAME

LOAD32 R0 R5 24 ; A->NAME

CMPJUMPI.E R0 R1 @promote_type_done ; break

LOAD32 R0 R4 24 ; B->NAME

CMPJUMPI.E R0 R1 @promote_type_done ; break

LOAD32 R1 R3 12 ; I->INDIRECT

LOAD32 R1 R1 24 ; I->INDIRECT->NAME

LOAD32 R0 R5 24 ; A->NAME

CMPJUMPI.E R0 R1 @promote_type_done ; break

LOAD32 R0 R4 24 ; B->NAME

CMPJUMPI.E R0 R1 @promote_type_done ; break

LOAD32 R3 R3 0 ; I=I->NEXT

JUMP.NZ R3 @promote_type_iter ; Loop if not NULL

:promote_type_done

MOVE R0 R3 ; Return I

POPR R5 R15 ; Restore R5

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

:promote_type_abort1

POPR R1 R15 ; Restore R1

:promote_type_abort0

RET R15

;; common_recursion function

;; Receives FUNCTION* in R0

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:common_recursion

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

MOVE R2 R0 ; Protect F

COPY R1 R8 ; LAST_TYPE=CURRENT_TARGET

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $common_recursion_string0 ; Header string

CALLI R15 @emit_out ; Our header

CALL R2 R15 ; CALL F()

COPY R0 R8 ; Using CURRENT_TARGET

CALLI R15 @promote_type ; Promote type

MOVE R8 R0 ; update CURRENT_TARGET

LOADUI R0 $common_recursion_string1 ; Footer string

CALLI R15 @emit_out ; Our footer

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:common_recursion_string0

“PUSH_eax #_common_recursion

:common_recursion_string1

“POP_ebx # _common_recursion

;; general_recursion function

;; Receives FUNCTION F in R0, char* s in R1, char* name in R2

;; and FUNCTION ITERATE in R3

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns nothing

:general_recursion

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect S

PUSHR R0 R15 ; Protect F

COPY R0 R2 ; Using NAME

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==NAME

JUMP.Z R0 @general_recursion_done

;; deal with case of match

POPR R0 R15 ; Restore F

CALLI R15 @common_recursion ; Recurse

POPR R1 R15 ; Restore S

COPY R0 R1 ; Put S in correct place

CALLI R15 @emit_out ; emit it

CALL R3 R15 ; CALL ITERATE()

POPR R0 R15 ; Restore R0

RET R15 ; Don’t double pop

:general_recursion_done

POPR R0 R15 ; Restore F

POPR R1 R15 ; Restore S

POPR R0 R15 ; Restore R0

RET R15

;; ceil_log2 function

;; Receives INT A in R0

;; Returns LOG2(A) in R0

:ceil_log2

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

FALSE R2 ; RESULT=0

SUBI R1 R0 1 ; A – 1

AND R1 R1 R0 ; A & (A – 1)

CMPSKIPI.NE R1 0 ; IF (A & (A – 1))==0

LOADI R2 -1 ; RESULT=-1

:ceil_log2_iter

JUMP.Z R0 @ceil_log2_done ; IF A> 0

ADDI R2 R2 1 ; RESULT=RESULT + 1

SARI R0 1 ; A=A>> 1

JUMP @ceil_log2_iter ; Loop

:ceil_log2_done

MOVE R0 R2 ; Use RESULT

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; postfix_expr_arrow function

;; Receives nothing

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:postfix_expr_arrow

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOADUI R0 $postfix_expr_arrow_string0 ; Our header string

CALLI R15 @emit_out ; Emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

COPY R0 R8 ; Passing CURRENT_TARGET

LOAD32 R1 R13 8 ; Using GLOBAL_TOKEN->S

CALLI R15 @lookup_member ; Look it up

LOAD32 R2 R0 4 ; Protect I->SIZE

LOAD32 R8 R0 20 ; CURRENT_TARGET=I->TYPE

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R1 R0 8 ; I->OFFSET

JUMP.Z R1 @postfix_expr_arrow_offset ; If no offset needed skip the work

;; Deal with non-zero offsets

LOADUI R0 $postfix_expr_arrow_string1 ; Our first prefix

CALLI R15 @emit_out ; Emit it

LOADUI R0 $postfix_expr_arrow_string2 ; Our second prefix

CALLI R15 @emit_out ; Emit it

MOVE R0 R1 ; Put I->OFFSET in the right place

CALLI R15 @numerate_number ; Convert to string

CALLI R15 @emit_out ; Emit it

LOADUI R0 $postfix_expr_arrow_string3 ; Our postfix

CALLI R15 @emit_out ; Emit it

:postfix_expr_arrow_offset

LOADUI R0 $equal ; Using “=”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”=”

JUMP.NZ R0 @postfix_expr_arrow_done

LOADUI R0 4 ; Compare against 4

CMPJUMPI.L R0 R2 @postfix_expr_arrow_done

;; Deal with special case

LOADUI R0 $postfix_expr_arrow_string4 ; Our final string

CALLI R15 @emit_out ; Emit it

:postfix_expr_arrow_done

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:postfix_expr_arrow_string0

“# looking up offset

:postfix_expr_arrow_string1

“# -> offset calculation

:postfix_expr_arrow_string2

“LOAD_IMMEDIATE_ebx %”

:postfix_expr_arrow_string3

ADD_ebx_to_eax

:postfix_expr_arrow_string4

“LOAD_INTEGER

;; postfix_expr_array function

;; Receives nothing

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:postfix_expr_array

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

COPY R2 R8 ; ARRAY=CURRENT_TARGET

LOADUI R0 $expression ; Using EXPRESSION

CALLI R15 @common_recursion ; Recurse

MOVE R8 R2 ; CURRENT_TARGET=ARRAY

LOADUI R2 $postfix_expr_array_string0 ; ASSIGN=load integer

LOADUI R0 $type_char_indirect_name ; Using “char*”

LOAD32 R1 R8 24 ; CURRENT_TARGET->NAME

CALLI R15 @match ; IF CURRENT_TARGET->NAME==”char*”

CMPSKIPI.E R0 0 ; deal with Byte

LOADUI R2 $postfix_expr_array_string1 ; ASSIGN=load byte

JUMP.NZ R0 @postfix_expr_array_byte ; Skip if Byte

;; Deal with larger than byte

LOADUI R0 $postfix_expr_array_string2 ; Our shift

CALLI R15 @emit_out ; emit it

LOAD32 R0 R8 12 ; CURRENT_TARGET->INDIRECT

LOAD32 R0 R0 4 ; CURRENT_TARGET->INDIRECT->SIZE

CALLI R15 @ceil_log2 ; LOG2(CURRENT_TARGET->INDIRECT->SIZE)

CALLI R15 @numerate_number ; Convert to string

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

:postfix_expr_array_byte

LOADUI R0 $postfix_expr_array_string3 ; Add the offset

CALLI R15 @emit_out ; emit it

LOADUI R0 $postfix_expr_array_string4 ; Our final error message

LOADUI R1 $close_bracket ; Using “]”

CALLI R15 @require_match ; Ensure match

LOADUI R0 $equal ; Using “=”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”=”

CMPSKIPI.E R0 0 ; If match

LOADUI R2 $postfix_expr_array_string5 ; empty string

MOVE R0 R2 ; What ever string survived

CALLI R15 @emit_out ; emit it

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:postfix_expr_array_string0

“LOAD_INTEGER

:postfix_expr_array_string1

“LOAD_BYTE

:postfix_expr_array_string2

“SAL_eax_Immediate8 !”

:postfix_expr_array_string3

“ADD_ebx_to_eax

:postfix_expr_array_string4

“ERROR in postfix_expr

Missing ]

:postfix_expr_array_string5

“”

;; postfix_expr_stub function

;; Receives nothing

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:postfix_expr_stub

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

LOADUI R0 $open_bracket ; Using “[”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”[”

JUMP.Z R0 @postfix_expr_stub_next

;; Deal with “[” case

CALLI R15 @postfix_expr_array ; process

CALLI R15 @postfix_expr_stub ; recurse

:postfix_expr_stub_next

LOADUI R0 $arrow_string ; Using “->”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”->”

JUMP.Z R0 @postfix_expr_stub_done ; clean up

;; Deal with “->” case

CALLI R15 @postfix_expr_arrow ; Process

CALLI R15 @postfix_expr_stub ; recurse

:postfix_expr_stub_done

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

;; postfix_expr function

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:postfix_expr

CALLI R15 @primary_expr ; Walk up the tree

CALLI R15 @postfix_expr_stub ; Deal with nodes on this level

RET R15

;; additive_expr_stub function

;; receives nothing

;; returns nothing

;; Updates struct token_list*

:additive_expr_stub

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

;; Fixed pieces

LOADUI R0 $postfix_expr ; Set First argument

LOADUI R3 $additive_expr_stub

;; The + bit

LOADUI R1 $additive_expr_stub_string0 ; Our first operation

LOADUI R2 $plus_string ; Using “+”

CALLI R15 @general_recursion

;; The – bit

LOADUI R1 $additive_expr_stub_string1 ; Our second operation

LOADUI R2 $minus_string ; Using “-”

CALLI R15 @general_recursion

;; The * bit

LOADUI R1 $additive_expr_stub_string2 ; Our third operation

LOADUI R2 $multiply_string ; Using “*”

CALLI R15 @general_recursion

;; The / bit

LOADUI R1 $additive_expr_stub_string3 ; Our fourth operation

LOADUI R2 $divide_string ; Using “/”

CALLI R15 @general_recursion

;; The % bit

LOADUI R1 $additive_expr_stub_string4 ; Our fifth operation

LOADUI R2 $modulus_string ; Using “%”

CALLI R15 @general_recursion

;; The> bit

LOADUI R1 $additive_expr_stub_string6 ; Our final operation

LOADUI R2 $right_shift_string ; Using “>>”

CALLI R15 @general_recursion

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:additive_expr_stub_string0

“ADD_ebx_to_eax

:additive_expr_stub_string1

“SUBTRACT_eax_from_ebx_into_ebx

MOVE_ebx_to_eax

:additive_expr_stub_string2

“MULTIPLY_eax_by_ebx_into_eax

:additive_expr_stub_string3

“XCHG_eax_ebx

LOAD_IMMEDIATE_edx %0

DIVIDE_eax_by_ebx_into_eax

:additive_expr_stub_string4

“XCHG_eax_ebx

LOAD_IMMEDIATE_edx %0

MODULUS_eax_from_ebx_into_ebx

MOVE_edx_to_eax

:additive_expr_stub_string5

“COPY_eax_to_ecx

COPY_ebx_to_eax

SAL_eax_cl

:additive_expr_stub_string6

“COPY_eax_to_ecx

COPY_ebx_to_eax

SAR_eax_cl

;; additive_expr function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:additive_expr

CALLI R15 @postfix_expr ; Walk up the tree

CALLI R15 @additive_expr_stub ; Deal with nodes at this level

RET R15

;; relational_expr_stub function

;; receives nothing

;; returns nothing

;; Updates struct token_list*

:relational_expr_stub

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

;; Fixed pieces

LOADUI R0 $additive_expr ; Set First argument

LOADUI R3 $relational_expr_stub

;; The bit

LOADUI R1 $relational_expr_stub_string3 ; Our fourth operation

LOADUI R2 $greater_than_string ; Using “>”

CALLI R15 @general_recursion

;; The==bit

LOADUI R1 $relational_expr_stub_string4 ; Our fifth operation

LOADUI R2 $equal_to_string ; Using “==”

CALLI R15 @general_recursion

;; The !=bit

LOADUI R1 $relational_expr_stub_string5 ; Our final operation

LOADUI R2 $not_equal_string ; Using “!=”

CALLI R15 @general_recursion

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:relational_expr_stub_string0

“CMP

SETL

MOVEZBL

:relational_expr_stub_string1

“CMP

SETLE

MOVEZBL

:relational_expr_stub_string2

“CMP

SETGE

MOVEZBL

:relational_expr_stub_string3

“CMP

SETG

MOVEZBL

:relational_expr_stub_string4

“CMP

SETE

MOVEZBL

:relational_expr_stub_string5

“CMP

SETNE

MOVEZBL

;; relational_expr function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:relational_expr

CALLI R15 @additive_expr ; Walk up the tree

CALLI R15 @relational_expr_stub ; Deal with nodes at this level

RET R15

;; relational_expr_stub function

;; receives nothing

;; returns nothing

;; Updates struct token_list*

:bitwise_expr_stub

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

;; Fixed pieces

LOADUI R0 $relational_expr ; Set First argument

LOADUI R3 $bitwise_expr_stub

;; The & bit

LOADUI R1 $bitwise_expr_stub_string0 ; Our first operation

LOADUI R2 $bitwise_and ; Using “&”

CALLI R15 @general_recursion

;; The && bit

LOADUI R1 $bitwise_expr_stub_string0 ; Our first operation

LOADUI R2 $logical_and ; Using “&&”

CALLI R15 @general_recursion

;; The | bit

LOADUI R1 $bitwise_expr_stub_string1 ; Our second operation

LOADUI R2 $bitwise_or ; Using “|”

CALLI R15 @general_recursion

;; The || bit

LOADUI R1 $bitwise_expr_stub_string1 ; Our second operation

LOADUI R2 $logical_or ; Using “||”

CALLI R15 @general_recursion

;; The ^ bit

LOADUI R1 $bitwise_expr_stub_string2 ; Our second operation

LOADUI R2 $bitwise_xor ; Using “^”

CALLI R15 @general_recursion

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:bitwise_expr_stub_string0

“AND_eax_ebx

:bitwise_expr_stub_string1

“OR_eax_ebx

:bitwise_expr_stub_string2

“XOR_ebx_eax_into_eax

;; bitwise_expr function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:bitwise_expr

CALLI R15 @relational_expr ; Walk up the tree

CALLI R15 @bitwise_expr_stub ; Deal with nodes at this level

RET R15

;; primary_expr function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:primary_expr

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

LOADUI R0 $sizeof_string ; Load “sizeof”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”sizeof”

JUMP.Z R0 @primary_expr_negate ; Guess not

;; Deal with sizeof expression

CALLI R15 @unary_expr_sizeof ; Do real work

JUMP @primary_expr_done ; Wrap up

:primary_expr_negate

LOADU8 R0 R1 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 45 ; IF GLOBAL_TOKEN->S[0]==’-‘

JUMP @primary_expr_bang ; If not try ‘!’

;; Deal with -a and -4 expressions

LOADUI R0 $primary_expr_str0 ; Load HEADER

CALLI R15 @emit_out ; emit it

LOADUI R0 $primary_expr ; Using PRIMARY_EXPR

CALLI R15 @common_recursion ; Recurse

LOADUI R0 $primary_expr_str1 ; add footer

CALLI R15 @emit_out ; emit it

JUMP @primary_expr_done ; Wrap up

:primary_expr_bang

CMPSKIPI.E R0 33 ; IF GLOBAL_TOKEN->S[0]==”!”

JUMP @primary_expr_nested ; If not try ‘(‘

;; deal with !a expressions

LOADUI R0 $primary_expr_str2 ; Load HEADER

CALLI R15 @emit_out ; emit it

LOADUI R0 $postfix_expr ; Using POSTFIX_EXPR

CALLI R15 @common_recursion ; Recurse

LOADUI R0 $primary_expr_str3 ; add footer

CALLI R15 @emit_out ; emit it

JUMP @primary_expr_done ; Wrap up

:primary_expr_nested

CMPSKIPI.E R0 40 ; IF GLOBAL_TOKEN->S[0]=='(‘

JUMP @primary_expr_ch ; If not try ‘char’

;; Deal with ( expr )

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

CALLI R15 @expression ; Recurse

LOADUI R0 $primary_expr_str4 ; Using error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Make sure we have closing match

JUMP @primary_expr_done ; Wrap up

:primary_expr_ch

CMPSKIPI.E R0 39 ; IF GLOBAL_TOKEN->S[0]==”’

JUMP @primary_expr_st ; If not try “string”

;; Deal with ‘char’

CALLI R15 @primary_expr_char ; Collect char

JUMP @primary_expr_done ; Wrap up

:primary_expr_st

CMPSKIPI.E R0 34 ; IF GLOBAL_TOKEN->S[0]=='”‘

JUMP @primary_expr_var ; If not try variables

;; deal with “string”

CALLI R15 @primary_expr_string ; Collect string

JUMP @primary_expr_done ; Wrap up

:primary_expr_var

LOADUI R1 $variable_chars ; Using a-z+A-Z+_

CALLI R15 @in_set ; IF GLOBAL_TOKEN->S[0] in a-z+A-Z+_

JUMP.Z R0 @primary_expr_num

;; Deal with foo TODO

CALLI R15 @primary_expr_variable ; deal with names

JUMP @primary_expr_done ; Wrap up

:primary_expr_num

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

LOADUI R1 $digit_chars ; Using 0-9

CALLI R15 @in_set ; IF GLOBAL_TOKEN->S[0] in 0-9

JUMP.Z R0 @primary_expr_failure ; Fail HARD

;; Deal with 5

CALLI R15 @primary_expr_number ; deal with number

:primary_expr_done

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:primary_expr_str0

“LOAD_IMMEDIATE_eax %0

:primary_expr_str1

“SUBTRACT_eax_from_ebx_into_ebx

MOVE_ebx_to_eax

:primary_expr_str2

“LOAD_IMMEDIATE_eax %1

:primary_expr_str3

“XOR_ebx_eax_into_eax

:primary_expr_str4

“Error in Primary expression

Didn’t get )

;; expression function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:expression

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

CALLI R15 @bitwise_expr ; Check for more primitives first

LOADUI R0 $equal ; Using “=”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”=”

JUMP.Z R0 @expression_done ; Be done

;; Determine store type

LOADUI R3 $expression_string1 ; Assuming the default of STORE CHAR

;; First possible reason for INT

LOADUI R0 $close_bracket ; Using “]”

LOAD32 R1 R13 4 ; GLOBAL_TOKEN->PREV

LOAD32 R1 R1 8 ; GLOBAL_TOKEN->PREV->S

CALLI R15 @match ; IF GLOBAL_TOKEN->PREV->==”]”

CMPSKIPI.NE R0 0 ; IF FALSE

LOADUI R3 $expression_string0 ; STORE INTEGER

;; Second possible reason for INTeger

LOADUI R0 $type_char_indirect_name ; Using “char*”

LOAD32 R1 R8 24 ; CURRENT_TARGET->NAME

CALLI R15 @match ; IF CURRENT_TARGET->NAME==”char*”

CMPSKIPI.NE R0 0 ; IF FALSE

LOADUI R3 $expression_string0 ; STORE INTEGER

;; Recurse to evaluate expression being stored

LOADUI R0 $expression ; Using expression

CALLI R15 @common_recursion ; Perform common recursion

;; Put our string and clean up

MOVE R0 R3 ; Using our STORED string

CALLI R15 @emit_out ; emit it

FALSE R8 ; CURRENT_TARGET=NULL

:expression_done

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:expression_string0

“STORE_INTEGER

:expression_string1

“STORE_CHAR

;; process_if function

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_if

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOADR32 R0 @current_count ; Using CURRENT_COUNT

ADDUI R1 R0 1 ; CURRENT_COUNT=CURRENT_COUNT + 1

STORER32 R1 @current_count ; Update CURRENT_COUNT

CALLI R15 @numerate_number ; Convert CURRENT_COUNT to string

MOVE R2 R0 ; Protect our string

LOADUI R0 $process_if_string0 ; using first string

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

COPY R1 R2 ; Using our current count string

CALLI R15 @uniqueID_out ; Add unique identifier

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $process_if_string1 ; Our first error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Make sure we have what we need

CALLI R15 @expression ; Recurse to get our boolean expression

LOADUI R0 $process_if_string2 ; Our test and jump

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

COPY R1 R2 ; Using our current count string

CALLI R15 @uniqueID_out ; Add unique identifier

LOADUI R0 $process_if_string3 ; Our second error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Make sure we have what we need

CALLI R15 @statement ; Collect our if statement

LOADUI R0 $process_if_string4 ; Our jump over else

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

COPY R1 R2 ; Using our current count string

CALLI R15 @uniqueID_out ; Add unique identifier

LOADUI R0 $process_if_string5 ; Our else label

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; Add unique identifier

LOADUI R0 $else_string ; Using “else”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”else”

JUMP.Z R0 @process_if_else ; Looks like no else

;; Deal with else

LOAD32 R13 R13 0 ; GLOBAL_TOKEN= GLOBAL_TOKEN->NEXT

CALLI R15 @statement ; Grab else statement

:process_if_else

LOADUI R0 $process_if_string6 ; Our jump over else

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

COPY R1 R2 ; Using our current count string

CALLI R15 @uniqueID_out ; Add unique identifier

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:process_if_string0

“# IF_”

:process_if_string1

“ERROR in process_if

MISSING (

:process_if_string2

“TEST

JUMP_EQ %ELSE_”

:process_if_string3

“ERROR in process_if

MISSING )

:process_if_string4

“JUMP %_END_IF_”

:process_if_string5

“:ELSE_”

:process_if_string6

“:_END_IF_”

;; save_break_frame microfunction

;; Overwrites R0 and R1

;; Saves break frame on stack

;; Returns to caller

:save_break_frame

POPR R1 R15 ; Save return address

LOADR32 R0 @break_frame ; Obtain BREAK_FRAME

PUSHR R0 R15 ; Protect BREAK_FRAME

LOADR32 R0 @break_target_head ; obtain HEAD

PUSHR R0 R15 ; Protect HEAD

LOADR32 R0 @break_target_func ; obtain FUNC

PUSHR R0 R15 ; Protect FUNC

LOADR32 R0 @break_target_num ; obtain NUM

PUSHR R0 R15 ; Protect NUM

PUSHR R1 R15 ; Set where we are returning to

RET R15

;; restore_break_frame microfunction

;; Overwrites R0 and R1

;; Restores break frame from stack

;; Returns to caller

:restore_break_frame

POPR R1 R15 ; Save return address

POPR R0 R15 ; obtain NUM

STORER32 R0 @break_target_num ; Restore NUM

POPR R0 R15 ; obtain FUNC

STORER32 R0 @break_target_func ; Restore FUNC

POPR R0 R15 ; obtain HEAD

STORER32 R0 @break_target_head ; Restore HEAD

POPR R0 R15 ; obtain BREAK_FRAME

STORER32 R0 @break_frame ; Restore BREAK_FRAME

PUSHR R1 R15 ; Set where we are returning to

RET R15

;; set_break_frame microfunction

;; Receives char* num in R0, char* head in R1

;; Overwrites R0

;; Sets break frame using

;; R9 holding FUNC

;; Returns to calling function

:set_break_frame

STORER32 R1 @break_target_head ; update BREAK_TARGET_HEAD

STORER32 R0 @break_target_num ; Update BREAK_TARGET_NUM

LOAD32 R0 R9 4 ; Using FUNCTION->LOCALS

STORER32 R0 @break_frame ; update BREAK_FRAME

LOAD32 R0 R9 8 ; Using FUNCTION->S

STORER32 R0 @break_target_func ; update BREAK_TARGET_FUNC

RET R15

;; process_for function

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_for

PUSHR R2 R15 ; Protect R2

PUSHR R1 R15 ; Protect R1

PUSHR R0 R15 ; Protect R0

CALLI R15 @save_break_frame ; Save break frame

LOADR32 R0 @current_count ; Using CURRENT_COUNT

ADDUI R1 R0 1 ; CURRENT_COUNT=CURRENT_COUNT + 1

STORER32 R1 @current_count ; Update CURRENT_COUNT

CALLI R15 @numerate_number ; Convert to string

COPY R2 R0 ; Protect NUMBER_STRING

LOADUI R1 $process_for_string0 ; Get new HEAD

CALLI R15 @set_break_frame ; Set the break frame values

LOADUI R0 $process_for_string1 ; Our comment header

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $process_for_string2 ; Our first error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Verify match

LOADUI R0 $semicolon ; Using “;”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S — “;”

CMPSKIPI.NE R0 0 ; If GLOBAL_TOKEN->S !=”;”

CALLI R15 @expression ; Skip that step

LOADUI R0 $process_for_string3 ; Our comment header

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string4 ; Our second error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Verify match

CALLI R15 @expression ; TEST logic required

LOADUI R0 $process_for_string5 ; Our comment header

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string6 ; Our comment header

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string7 ; Our comment header

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string8 ; Our third error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Verify match

CALLI R15 @expression ; Iterator logic

LOADUI R0 $process_for_string9 ; Our comment header

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string10 ; Our comment header

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string11 ; Our final error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Verify match

CALLI R15 @statement ; Main body

LOADUI R0 $process_for_string12 ; Our comment header

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_for_string13 ; Our comment header

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

CALLI R15 @restore_break_frame ; Restore break frame

POPR R0 R15 ; Restore R0

POPR R1 R15 ; Restore R1

POPR R2 R15 ; Restore R2

RET R15

:process_for_string0

“FOR_END_”

:process_for_string1

“# FOR_initialization_”

:process_for_string2

“ERROR in process_for

MISSING (

:process_for_string3

“:FOR_”

:process_for_string4

“ERROR in process_for

MISSING ;1

:process_for_string5

“TEST

JUMP_EQ %FOR_END_”

:process_for_string6

“JUMP %FOR_THEN_”

:process_for_string7

“:FOR_ITER_”

:process_for_string8

“ERROR in process_for

MISSING ;2

:process_for_string9

“JUMP %FOR_”

:process_for_string10

“:FOR_THEN_”

:process_for_string11

“ERROR in process_for

MISSING )

:process_for_string12

“JUMP %FOR_ITER_”

:process_for_string13

“:FOR_END_”

;; process_do function

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_do

PUSHR R2 R15 ; Protect R2

PUSHR R1 R15 ; Protect R1

PUSHR R0 R15 ; Protect R0

CALLI R15 @save_break_frame ; Save break frame

LOADR32 R0 @current_count ; Using CURRENT_COUNT

ADDUI R1 R0 1 ; CURRENT_COUNT=CURRENT_COUNT + 1

STORER32 R1 @current_count ; Update CURRENT_COUNT

CALLI R15 @numerate_number ; Convert to string

COPY R2 R0 ; Protect NUMBER_STRING

LOADUI R1 $process_do_string0 ; Using our desired head

CALLI R15 @set_break_frame ; Set the break frame values

LOADUI R0 $process_do_string1 ; Our label

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

CALLI R15 @statement ; Collect our Do statement

LOADUI R0 $process_do_string2 ; our first error message

LOADUI R1 $while_string ; Using “while”

CALLI R15 @require_match ; Check for match

LOADUI R0 $process_do_string3 ; our second error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Check for match

CALLI R15 @expression ; Our logical expression

LOADUI R0 $process_do_string4 ; our third error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Check for match

LOADUI R0 $process_do_string5 ; our final error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Check for match

LOADUI R0 $process_do_string6 ; Our test string

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Put NUMBER_STRING in right place

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_do_string7 ; Our end label string

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

CALLI R15 @restore_break_frame ; Restore break frame

POPR R0 R15 ; Restore R0

POPR R1 R15 ; Restore R1

POPR R2 R15 ; Restore R2

RET R15

:process_do_string0

“DO_END_”

:process_do_string1

“:DO_”

:process_do_string2

“ERROR in process_do

MISSING while

:process_do_string3

“ERROR in process_do

MISSING (

:process_do_string4

“ERROR in process_do

MISSING )

:process_do_string5

“ERROR in process_do

MISSING ;

:process_do_string6

“TEST

JUMP_NE %DO_”

:process_do_string7

“:DO_END_”

;; process_while function

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_while

PUSHR R2 R15 ; Protect R2

PUSHR R1 R15 ; Protect R1

PUSHR R0 R15 ; Protect R0

CALLI R15 @save_break_frame ; Save break frame

LOADR32 R0 @current_count ; Using CURRENT_COUNT

ADDUI R1 R0 1 ; CURRENT_COUNT=CURRENT_COUNT + 1

STORER32 R1 @current_count ; Update CURRENT_COUNT

CALLI R15 @numerate_number ; Convert to string

COPY R2 R0 ; Protect NUMBER_STRING

LOADUI R1 $process_while_string0 ; Set HEAD

CALLI R15 @set_break_frame ; Set the break frame values

LOADUI R0 $process_while_string1 ; Our head label

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $process_while_string2 ; Our first error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Check for match

CALLI R15 @expression ; Collect test expression

LOADUI R0 $process_while_string3 ; Our test and jump

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_while_string4 ; Our trailing comment

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_while_string5 ; Our first error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Check for match

CALLI R15 @statement ; Collect our loop statement

LOADUI R0 $process_while_string6 ; Our test and jump

CALLI R15 @emit_out ; emit it

COPY R1 R2 ; Using NUMBER_STRING

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

LOADUI R0 $process_while_string7 ; Our trailing comment

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; FUNCTION->S

CALLI R15 @uniqueID_out ; emit it

CALLI R15 @restore_break_frame ; Restore break frame

POPR R0 R15 ; Restore R0

POPR R1 R15 ; Restore R1

POPR R2 R15 ; Restore R2

RET R15

:process_while_string0

“END_WHILE_”

:process_while_string1

“:WHILE_”

:process_while_string2

“ERROR in process_while

MISSING (

:process_while_string3

“TEST

JUMP_EQ %END_WHILE_”

:process_while_string4

“# THEN_while_”

:process_while_string5

“ERROR in process_while

MISSING )

:process_while_string6

“JUMP %WHILE_”

:process_while_string7

“:END_WHILE_”

;; return_result function

;; Receives nothing

;; Returns nothing

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

:return_result

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 59 ; IF GLOBAL_TOKEN->S[0]==’;’

CALLI R15 @expression ; Evaluate expression

LOADUI R0 $return_result_string0 ; Using or error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Require a match to “;”

LOADUI R0 $return_result_string1 ; Our pop command

LOAD32 R1 R9 4 ; FUNCTION->LOCALS

:return_result_iter

JUMP.Z R1 @return_result_done ; Be done when we hit NULL

CALLI R15 @emit_out ; Put the string every iteration

LOAD32 R1 R1 0 ; I=I->NEXT

JUMP @return_result_iter ; Keep looping

:return_result_done

LOADUI R0 $return_result_string2 ; Our footer

CALLI R15 @emit_out ; emit it

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:return_result_string0

“ERROR in return_result

MISSING ;

:return_result_string1

“POP_ebx # _return_result_locals

:return_result_string2

“RETURN

;; process_break function

;; Receives nothing

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_break

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOADR32 R0 @break_target_head ; BREAK_TARGET_HEAD

JUMP.NZ R0 @process_break_NON_NULL

;; Deal with NULL==BREAK_TARGET_HEAD

LOADUI R0 $process_break_string0 ; Our first error message

FALSE R1 ; Write for User

CALLI R15 @file_print ; write it

CALLI R15 @line_error ; Give useful info

LOADUI R0 $newline ; Using “n”

CALLI R15 @file_print ; Print it

HALT

:process_break_NON_NULL

LOADR32 R2 @break_frame ; BREAK_FRAME

LOAD32 R1 R9 4 ; I=FUNCTION->LOCALS

LOADUI R0 $process_break_string1 ; Our pop string

:process_break_iter

CMPJUMPI.E R1 R2 @process_break_done ; IF I==BREAK_FRAME

JUMP.Z R1 @process_break_done ; IF NULL==I break

CALLI R15 @emit_out ; emit pop

LOAD32 R1 R1 0 ; I=I->NEXT

JUMP @process_break_iter ; Loop

:process_break_done

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $process_break_string2 ; Our jump string

CALLI R15 @emit_out ; emit it

LOADR32 R0 @break_target_head ; Our HEAD string

CALLI R15 @emit_out ; emit it

LOADR32 R0 @break_target_func ; Our FUNC string

CALLI R15 @emit_out ; emit it

LOADUI R0 $underline ; Using “_”

CALLI R15 @emit_out ; emit it

LOADR32 R0 @break_target_num ; Our NUM string

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

LOADUI R0 $process_break_string3 ; Our final error string

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Make sure we get that match

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:process_break_string0

“Not inside of a loop or case statement

:process_break_string1

“POP_ebx # break_cleanup_locals

:process_break_string2

“JUMP %”

:process_break_string3

“ERROR in break statement

Missing ;

:break_frame

NOP

:break_target_head

NOP

:break_target_func

NOP

:break_target_num

NOP

;; process_asm function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:process_asm

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

;; First required match

LOADUI R0 $process_asm_string0 ; Using our First error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Make sure of our required match

:process_asm_iter

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 34 ; IF GLOBAL_TOKEN->S[0]=='”‘

JUMP @process_asm_done ; Otherwise be done

;; Add block of assembly

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

ADDUI R0 R0 1 ; GLOBAL_TOKEN->S + 1

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @process_asm_iter

:process_asm_done

LOADUI R0 $process_asm_string1 ; Using our First error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Make sure of our required match

LOADUI R0 $process_asm_string2 ; Using our First error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Make sure of our required match

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:process_asm_string0

“ERROR in process_asm

MISSING (

:process_asm_string1

“ERROR in process_asm

MISSING )

:process_asm_string2

“ERROR in process_asm

MISSING ;

;; recursive_statement function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:recursive_statement

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R3 R9 4 ; FRAME=FUNCTION->LOCALS

:recursive_statement_iter

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

LOADUI R0 $close_curly_brace ; ‘}’

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”}”

JUMP.NZ R0 @recursive_statement_cleanup

;; Lets collect those statements

CALLI R15 @statement ; Collect next statement

JUMP @recursive_statement_iter ; Iterate

:recursive_statement_cleanup

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R1 R12 8 ; OUT->S

LOADUI R0 $recursive_statement_string0 ; “RETURNn”

CALLI R15 @match ; IF OUT->S==”RETURNn”

JUMP.NZ R0 @recursive_statement_done ; Save some work

;; Lets pop them all off

LOAD32 R2 R9 4 ; FUNC->LOCALS

LOADUI R0 $recursive_statement_string1 ; Our POP string

:recursive_statement_pop

CMPJUMPI.E R2 R3 @recursive_statement_done

CALLI R15 @emit_out ; emit it

LOAD32 R2 R2 0 ; I=I->NEXT

JUMP.NZ R2 @recursive_statement_pop ; Keep looping

:recursive_statement_done

STORE32 R3 R9 4 ; FUNC->LOCALS=FRAME

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:recursive_statement_string0

“RETURN

:recursive_statement_string1

“POP_ebx # _recursive_statement_locals

;; statement function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:statement

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOAD32 R2 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R2 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 123 ; If GLOBAL_TOKEN->S[0] !='{‘

JUMP @statement_label ; Try next match

;; Deal with { statements }

CALLI R15 @recursive_statement

JUMP @statement_done ; All done

:statement_label

CMPSKIPI.E R0 58 ; If GLOBAL_TOKEN->S[0] !=’:’

JUMP @statement_collect_local ; Try next match

;; Deal with :label

LOAD32 R0 R13 8 ; Using GLOBAL_TOKEN->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $statement_string0 ; Using label string

CALLI R15 @emit_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @statement_done ; Move on to next thing

:statement_collect_local

LOADUI R0 $struct ; Using “struct”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”struct”

JUMP.NZ R0 @statement_collect_local_0

;; Otherwise check if it is a primitive

LOADUI R0 $prim_types ; Using the Primitive types list

SWAP R0 R1 ; Put in correct order

CALLI R15 @lookup_type ; Check if a primitive type

JUMP.Z R0 @statement_process_if ; If not try the next one

:statement_collect_local_0

CALLI R15 @collect_local ; Collect the local

JUMP @statement_done ; And move on

:statement_process_if

LOADUI R0 $if_string ; Using “if”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”if”

JUMP.Z R0 @statement_process_do

CALLI R15 @process_if ; Collect that if statement

JUMP @statement_done ; Move on to next thing

:statement_process_do

LOADUI R0 $do_string ; Using “do”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”do”

JUMP.Z R0 @statement_process_while

CALLI R15 @process_do ; Collect that do statement

JUMP @statement_done ; Move on to next thing

:statement_process_while

LOADUI R0 $while_string ; Using “while”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”while”

JUMP.Z R0 @statement_process_for

CALLI R15 @process_while ; Collect that while statement

JUMP @statement_done ; Move on to next thing

:statement_process_for

LOADUI R0 $for_string ; Using “for”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”for”

JUMP.Z R0 @statement_process_asm

CALLI R15 @process_for ; Collect that FOR statement

JUMP @statement_done ; Move on to next thing

:statement_process_asm

LOADUI R0 $asm_string ; Using “asm”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”asm”

JUMP.Z R0 @statement_goto

CALLI R15 @process_asm ; Collect that ASM statement

JUMP @statement_done ; Move on to next thing

:statement_goto

LOADUI R0 $goto_string ; Using “goto”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”goto”

JUMP.Z R0 @statement_return_result

;; Deal with goto label:

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $statement_string1 ; Using our JUMP string

CALLI R15 @emit_out ; emit it

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; “n”

CALLI R15 @emit_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $statement_string2 ; Using our error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Make sure of our required match

JUMP @statement_done ; Move on

:statement_return_result

LOADUI R0 $return_string ; Using “return”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”return”

JUMP.Z R0 @statement_break

;; Deal with return statements in functions

CALLI R15 @return_result ; Do all of the work

JUMP @statement_done ; Move on to next

:statement_break

LOADUI R0 $break_string ; Using “break”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”break”

JUMP.Z R0 @statement_continue

;; Let break function deal with updating out

CALLI R15 @process_break ; Do all the work

JUMP @statement_done ; Move on to next

:statement_continue

LOADUI R0 $continue_string ; Using “continue”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”continue”

JUMP.Z R0 @statement_expression

;; Simple Continue compatibility

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $statement_string3 ; Using our continue comment string

CALLI R15 @emit_out ; emit it

LOADUI R0 $statement_string2 ; Using our error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Make sure of our required match

JUMP @statement_done ; Move on

:statement_expression

CALLI R15 @expression ; Do expression evaluation

LOADUI R0 $statement_string2 ; Load our error message

LOADUI R1 $semicolon ; use “;”

CALLI R15 @require_match ; Make sure GLOBAL_TOKEN->==”;”

:statement_done

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:statement_string0

” #C goto label

:statement_string1

“JUMP %”

:statement_string2

“ERROR in statement

MISSING ;

:statement_string3

#continue statement

;; collect_local function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:collect_local

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

CALLI R15 @type_name ; Get it’s type

MOVE R1 R0 ; Prepare for call

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOAD32 R2 R9 4 ; FUNC->LOCALS

CALLI R15 @sym_declare ; SET A

MOVE R2 R0 ; Protect A

;; Figure out depth

LOADUI R0 $main_string ; Using “main”

LOAD32 R1 R9 8 ; FUNC->S

CALLI R15 @match ; IF FUNC->S==”main”

JUMP.Z R0 @collect_local_0 ; Try next

LOAD32 R0 R9 4 ; FUNC->LOCALS

JUMP.NZ R0 @collect_local_0 ; Try next

LOADI R0 -20 ; The default depth for main

STORE32 R0 R2 16 ; A->DEPTH=-20

JUMP @collect_local_output ; Deal with header

:collect_local_0

LOAD32 R0 R9 16 ; FUNC->ARGS

JUMP.NZ R0 @collect_local_1 ; Try Next

LOAD32 R0 R9 4 ; FUNC->LOCALS

JUMP.NZ R0 @collect_local_1 ; Try Next

LOADI R0 -8 ; The default depth for foo()

STORE32 R0 R2 16 ; A->DEPTH=-8

JUMP @collect_local_output ; Deal with header

:collect_local_1

LOAD32 R0 R9 4 ; FUNC->LOCALS

JUMP.NZ R0 @collect_local_2 ; Try Next

LOAD32 R0 R9 16 ; FUNC->ARGS

LOAD32 R0 R0 16 ; FUNC->ARGS->DEPTH

SUBI R0 R0 8 ; DEPTH=FUNC->ARGS->DEPTH – 8

STORE32 R0 R2 16 ; A->DEPTH=DEPTH

JUMP @collect_local_output ; Deal with header

:collect_local_2

LOAD32 R0 R9 4 ; FUNC->LOCALS

LOAD32 R0 R0 16 ; FUNC->LOCALS->DEPTH

SUBI R0 R0 4 ; DEPTH=FUNC->LOCALS->DEPTH – 4

STORE32 R0 R2 16 ; A->DEPTH=DEPTH

:collect_local_output

STORE32 R2 R9 4 ; FUNC->LOCALS=A

;; Output header

LOADUI R0 $collect_local_string0 ; Starting with the comment

CALLI R15 @emit_out ; emit it

LOAD32 R0 R2 8 ; A->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

;; Deal with possible assignment

LOADUI R0 $equal ; Using “=”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”=”

JUMP.Z R0 @collect_local_nonassign

;; Deal with assignment of the local

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

CALLI R15 @expression ; Update OUT with the evaluation of the Expression

:collect_local_nonassign

LOADUI R0 $collect_local_string1 ; Our error message

LOADUI R1 $semicolon ; Using “;”

CALLI R15 @require_match ; Make sure GLOBAL_TOKEN->S==”;”

;; Final Footer

LOADUI R0 $collect_local_string2 ; Add our PUSH statement

CALLI R15 @emit_out ; emit it

LOAD32 R0 R2 8 ; A->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:collect_local_string0

“# Defining local ”

:collect_local_string1

“ERROR in collect_local

Missing ;

:collect_local_string2

“PUSH_eax #”

;; collect_arguments function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:collect_arguments

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

:collect_arguments_iter

LOADUI R0 $close_paren ; Using “)”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”)”

JUMP.NZ R0 @collect_arguments_done ; Be done

;; Collect the arguments

CALLI R15 @type_name ; Get what type we are working with

MOVE R1 R0 ; Put TYPE where it will be used

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.NE R0 41 ; IF GLOBAL_TOKEN->S[0]==’)’

JUMP @collect_arguments_iter3 ; foo(int,char,void) doesn’t need anything done

;; Check for foo(int a,…)

CMPSKIPI.NE R0 41 ; IF GLOBAL_TOKEN->S[0]==’,’

JUMP @collect_arguments_iter3 ; Looks like final case

;; Deal with foo(int a, …)

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOAD32 R2 R9 16 ; FUNC->ARGUMENTS

CALLI R15 @sym_declare ; Get A

MOVE R2 R0 ; Get A out of the way

:collect_arguments_func

LOAD32 R0 R9 16 ; FUNC->ARGS

CMPSKIPI.E R0 0 ; IF NULL==FUNC->ARGS

LOAD32 R0 R0 16 ; FUNC->ARGS->DEPTH

SUBI R0 R0 4 ; FUNC->ARGS->DEPTH – 4 or NULL – 4 (-4)

STORE32 R0 R2 16 ; A->DEPTH=VALUE

:collect_arguments_iter2

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

STORE32 R2 R9 16 ; FUNC->ARGUMENTS=A

:collect_arguments_iter3

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.NE R0 44 ; IF GLOBAL_TOKEN->S[0]==’,’

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @collect_arguments_iter ; Keep looping

:collect_arguments_done

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

;; declare_function function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; and struct token_list* global_list in R10

;; SETS R9 to struct token_list* FUNC

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:declare_function

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

FALSE R0 ; Using Zero

STORER32 R0 @current_count ; CURRENT_COUNT=0

LOAD32 R0 R13 4 ; GLOBAL_TOKEN->PREV

LOAD32 R0 R0 8 ; GLOBAL_TOKEN->PREV->S

FALSE R1 ; Passing NULL

LOADR32 R2 @global_function_list ; where the global function list is located

CALLI R15 @sym_declare ; declare FUNC

STORER32 R0 @global_function_list ; GLOBAL_FUNCTION_LIST=FUNC

MOVE R9 R0 ; SETS FUNC

CALLI R15 @collect_arguments ; Collect function arguments

LOAD32 R2 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R2 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.NE R0 59 ; IF GLOBAL_TOKEN->S[0]==’;’

JUMP @declare_function_prototype ; Don’t waste time

;; Looks like it is an actual function definition

LOADUI R0 $declare_function_string0 ; Using first string

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; Using FUNC->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

LOADUI R0 $declare_function_string1 ; Using second string

CALLI R15 @emit_out ; emit it

LOAD32 R0 R9 8 ; Using FUNC->S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

:declare_function_nonmain

FALSE R1 ; Cleaning up before call

CALLI R15 @statement ; Collect the statement

;; Prevent Duplicate Returns

LOAD32 R1 R12 8 ; OUT->S

LOADUI R0 $declare_function_string2 ; Our final string

CALLI R15 @match ; Check for Match

JUMP.NZ R0 @declare_function_done ; Clean up

;; Deal with adding the return

LOADUI R0 $declare_function_string2 ; Our final string

CALLI R15 @emit_out ; emit it

:declare_function_done

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:declare_function_prototype

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @declare_function_done ; Clean up

:declare_function_string0

“# Defining function ”

:declare_function_string1

“:FUNCTION_”

:declare_function_string2

“RETURN

:current_count

NOP

;; program function

;; Receives struct token_list* global_token in R13,

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; and struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:program

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

:program_iter

JUMP.Z R13 @program_done ; Looks like we read all the tokens

LOADUI R0 $constant ; Using the constant string

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; Check if they match

JUMP.Z R0 @program_type ; Looks like not

;; Deal with CONSTANT case

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

FALSE R1 ; Set NULL

LOADR32 R2 @global_constant_list ; GLOBAL_CONSTANTS_LIST

CALLI R15 @sym_declare ; Declare the global constant

STORER32 R0 @global_constant_list ; Update global constant

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

STORE32 R13 R0 16 ; GLOBAL_CONSTANT_LIST->ARGUMENTS=GLOBAL_TOKEN

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @program_iter ; Loop again

:program_type

CALLI R15 @type_name ; Get the type

JUMP.Z R0 @program_iter ; If newly defined type iterate

;; Looks like we got a defined type

MOVE R1 R0 ; Put the type where it can be used

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADUI R3 $global_symbol_list ; Get address of global symbol list

LOAD32 R2 R3 0 ; GLOBAL_SYMBOLS_LIST

CALLI R15 @sym_declare ; Declare that global symbol

STORE32 R0 R3 0 ; Update global symbol list

LOAD32 R3 R13 8 ; GLOBAL_TOKEN->S

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $semicolon ; Get semicolon string

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; Check if they match

JUMP.Z R0 @program_function ; If not a match

;; Deal with case of TYPE NAME;

COPY R1 R10 ; Using GLOBALS_LIST

LOADUI R0 $program_string0 ; Using the GLOBAL_ prefix

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Move new GLOBALS_LIST into Place

MOVE R0 R3 ; Use GLOBAL_TOKEN->PREV->S

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Move new GLOBALS_LIST into Place

LOADUI R0 $program_string1 ; Using the NOP postfix

CALLI R15 @emit ; emit it

MOVE R10 R0 ; Move new GLOBALS_LIST into Place

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

JUMP @program_iter

:program_function

LOADUI R0 $open_paren ; Get open paren string

CALLI R15 @match ; Check if they match

JUMP.Z R0 @program_assign ; If not a match

;; Deal with case of TYPE NAME(…)

CALLI R15 @declare_function

JUMP @program_iter

:program_assign

LOADUI R0 $equal ; Get equal string

CALLI R15 @match ; Check if they match

JUMP.Z R0 @program_error ; If not a match

COPY R1 R10 ; Using GLOBALS_LIST

LOADUI R0 $program_string0 ; Using the GLOBAL_ prefix

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Move new GLOBALS_LIST into Place

MOVE R0 R3 ; Use GLOBAL_TOKEN->PREV->S

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Move new GLOBALS_LIST into Place

LOADUI R0 $newline ; Using the Newline postfix

CALLI R15 @emit ; emit it

MOVE R10 R0 ; Update GLOBALS_LIST

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

LOADUI R1 $digit_chars ; 0-9

CALLI R15 @in_set ; Figure out if in set

JUMP.Z R0 @program_assign_string ; If not in sets

;; Looks like we have an int

COPY R1 R10 ; Using GLOBALS_LIST

LOADUI R0 $percent ; Using percent prefix

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Put GLOBALS_LIST into Place

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Put GLOBALS_LIST into Place

LOADUI R0 $newline ; Using newline postfix

CALLI R15 @emit ; emit it

MOVE R10 R0 ; Update GLOBALS_LIST

JUMP @program_assign_done ; Move on

:program_assign_string

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 34 ; If GLOBAL_TOKEN->S[0]=='”‘

JUMP @program_error ; If not we hit an error

;; Looks like we have a string

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @parse_string ; Parse it into useful form

COPY R1 R10 ; GLOBALS_LIST

CALLI R15 @emit ; emit it

MOVE R10 R0 ; Update GLOBALS_LIST

:program_assign_done

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $program_string4 ; Potential error message

LOADUI R1 $semicolon ; Checking for ;

CALLI R15 @require_match ; Catch those errors

JUMP @program_iter

:program_error

LOADUI R0 $program_string2 ; message part 1

FALSE R1 ; Show to user

CALLI R15 @file_print ; write

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @file_print ; write

LOADUI R0 $program_string3 ; message part 2

CALLI R15 @file_print ; write

CALLI R15 @line_error ; Provide a meaningful error message

HALT

:program_done

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:program_string0

“:GLOBAL_”

:program_string1

NULL

:program_string2

“Received ”

:program_string3

” in program

:program_string4

“ERROR in Program

Missing ;

;; sym_declare function

;; Receives char* in R0, struct type* in R1, struct token_list* in R2

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns struct token_list* in R0

:sym_declare

STORE32 R2 R14 0 ; A->NEXT=LIST

STORE32 R0 R14 8 ; A->S=S

STORE32 R1 R14 12 ; A->TYPE=T

ADDUI R0 R14 20 ; CALLOC struct token_list

SWAP R0 R14 ; Prepare for Return

RET R15

;; sym_lookup function

;; Receives char* in R0 and struct token_list in R1

;; Returns struct token_list* or NULL in R0

:sym_lookup

PUSHR R2 R15 ; Protect R2

MOVE R2 R1 ; Protect I

MOVE R1 R0 ; Put S in proper place

:sym_lookup_iter

JUMP.Z R2 @sym_lookup_done ; Stop if NULL

LOAD32 R0 R2 8 ; I->S

CALLI R15 @match ; if I->S==S

JUMP.NZ R0 @sym_lookup_done ; Stop if match

LOAD32 R2 R2 0 ; I=I->NEXT

JUMP @sym_lookup_iter ; Keep looping

:sym_lookup_done

MOVE R0 R2 ; Using R2 as our result

POPR R2 R15 ; Restore R2

RET R15

;; function_call function

;; Receives CHAR* S in R0 and INT BOOL in R1

;; struct token_list* out in R12,

;; struct token_list* string_list in R11

;; and struct token_list* global_list in R10

;; and struct token_list* FUNC in R9

;; and struct token_list* current_target in R8

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns the token_lists modified

:function_call

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

MOVE R2 R0 ; Protect S

MOVE R3 R1 ; Protect BOOL

LOADUI R0 $function_call_string0 ; Our first error message

LOADUI R1 $open_paren ; Using “(”

CALLI R15 @require_match ; Make sure of a match

FALSE R4 ; PASSED=0

LOADUI R0 $function_call_string1 ; Our first header

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string2 ; Our second header

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string3 ; Our third header

CALLI R15 @emit_out ; emit it

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.NE R0 41 ; IF GLOBAL_TOKEN->S[0] !=’)’

JUMP @function_call_collect_done ; looks like function()

;; Collect arguments

CALLI R15 @expression ; Deal with first argument

LOADUI R0 $function_call_string4 ; Push it onto stack

CALLI R15 @emit_out ; emit it

ADDUI R4 R4 1 ; PASSED=1

:function_call_collect_iter

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R0 44 ; IF GLOBAL_TOKEN->S[0] !=’,’

JUMP @function_call_collect_done ; looks like we are done collecting arguments

;; Collect another argument

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

CALLI R15 @expression ; Deal with Nth argument

LOADUI R0 $function_call_string5 ; Push it onto stack

CALLI R15 @emit_out ; emit it

ADDUI R4 R4 1 ; PASSED=PASSED + 1

JUMP @function_call_collect_iter ; Keep looping

:function_call_collect_done

LOADUI R0 $function_call_string6 ; Our second error message

LOADUI R1 $close_paren ; Using “)”

CALLI R15 @require_match ; Make sure of a match

JUMP.Z R3 @function_call_call_false ; if BOOL !=TRUE

;; Deal with TRUE==BOOL

LOADUI R0 $function_call_string7 ; Our first prefix

CALLI R15 @emit_out ; emit it

MOVE R0 R2 ; Using S

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string8 ; Our first postfix

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string9 ; Our second postfix

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string10 ; Our last postfix

CALLI R15 @emit_out ; emit it

JUMP @function_call_call_done ; Move on

:function_call_call_false

;; Deal with FALSE==BOOL

LOADUI R0 $function_call_string11 ; Our first prefix

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string12 ; Our last prefix

CALLI R15 @emit_out ; emit it

MOVE R0 R2 ; Using S

CALLI R15 @emit_out ; emit it

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

:function_call_call_done

LOADUI R0 $function_call_string13 ; Our POP

:function_call_pop_iter

JUMP.Z R4 @function_call_pop_done ; Skip POP if out of args on Stack

CALLI R15 @emit_out ; emit our POP

SUBI R4 R4 1 ; PASSED=PASSED – 1

JUMP @function_call_pop_iter ; Loop

:function_call_pop_done

LOADUI R0 $function_call_string14 ; Our first postfix

CALLI R15 @emit_out ; emit it

LOADUI R0 $function_call_string15 ; Our final postfix

CALLI R15 @emit_out ; emit it

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:function_call_string0

“ERROR in process_expression_list

No ( was found

:function_call_string1

“PUSH_edi # Prevent overwriting in recursion

:function_call_string2

“PUSH_ebp # Protect the old base pointer

:function_call_string3

“COPY_esp_to_edi # Copy new base pointer

:function_call_string4

“PUSH_eax #_process_expression1

:function_call_string5

“PUSH_eax #_process_expression2

:function_call_string6

“ERROR in process_expression_list

No ) was found

:function_call_string7

“LOAD_BASE_ADDRESS_eax %”

:function_call_string8

LOAD_INTEGER

:function_call_string9

“COPY_edi_to_ebp

:function_call_string10

“CALL_eax

:function_call_string11

“COPY_edi_to_ebp

:function_call_string12

“CALL_IMMEDIATE %FUNCTION_”

:function_call_string13

“POP_ebx # _process_expression_locals

:function_call_string14

“POP_ebp # Restore old base pointer

:function_call_string15

“POP_edi # Prevent overwrite

;; emit function

;; Receives char* in R0, struct token_list* in R1

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns struct token_list* in R0

:emit

PUSHR R2 R15 ; Protect R2

COPY R2 R14 ; Pointer to T

ADDUI R14 R14 20 ; CALLOC struct token_list

STORE32 R1 R2 0 ; T->NEXT=HEAD

STORE32 R0 R2 8 ; T->S=S

MOVE R0 R2 ; Put T in proper spot for return

POPR R2 R15 ; Restore R2

RET R15

;; emit_out function

;; Receives char* in R0

;; struct token_list* out in R12,

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns struct token_list* in R0

:emit_out

STORE32 R12 R14 0 ; T->NEXT=OUT

ADDUI R12 R14 20 ; Get T

SWAP R12 R14 ; CALLOC struct token_list

STORE32 R0 R12 8 ; T->S=S

RET R15

;; uniqueID function

;; Receives char* in R0, struct token_list* in R1 and char* in R2

;; Calls emit repeatedly

;; Returns struct token_list* in R0

:uniqueID

CALLI R15 @emit ; emit S

MOVE R1 R0 ; Put L in the correct place

LOADUI R0 $underline ; Using “_”

CALLI R15 @emit ; emit it

MOVE R1 R0 ; Put L in the correct place

COPY R0 R2 ; Put NUM in the correct place

CALLI R15 @emit ; emit NUM

MOVE R1 R0 ; Put L in the correct place

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit ; emit it

RET R15

;; uniqueID_out function

;; Receives char* in R0, char* in R1

;; Calls emit_out repeatedly

;; Returns nothing

:uniqueID_out

CALLI R15 @emit_out ; emit S

LOADUI R0 $underline ; Using “_”

CALLI R15 @emit_out ; emit it

COPY R0 R1 ; Put NUM in the correct place

CALLI R15 @emit_out ; emit NUM

LOADUI R0 $newline ; Using “n”

CALLI R15 @emit_out ; emit it

RET R15

;; file_print function

;; Receives pointer to string in R0 and FILE* in R1

;; Returns nothing

:file_print

PUSHR R2 R15 ; Protect R2 from Overwrite

MOVE R2 R0 ; Put string pointer into place

:file_print_read

LOAD8 R0 R2 0 ; Get a char

JUMP.Z R0 @file_print_done ; If NULL be done

FPUTC ; Write the Char

ADDUI R2 R2 1 ; Point at next CHAR

JUMP @file_print_read ; Loop again

:file_print_done

POPR R2 R15 ; Restore R2

RET R15

;; recursive_output function

;; Receives token_list in R0 and FILE* in R1

;; Returns nothing and alters nothing

:recursive_output

JUMP.Z R0 @recursive_output_abort ; Abort if NULL

PUSHR R2 R15 ; Preserve R2 from recursion

MOVE R2 R0 ; Preserve R0 from recursion

LOAD32 R0 R2 0 ; Using I->NEXT

CALLI R15 @recursive_output ; Recurse

LOAD32 R0 R2 8 ; Using I->S

CALLI R15 @file_print ; Write the string

MOVE R0 R2 ; Put R0 back

POPR R2 R15 ; Restore R0

:recursive_output_abort

RET R15

;; match function

;; Receives a CHAR* in R0, CHAR* in R1

;; Returns Bool in R0 indicating if strings match

:match

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

MOVE R2 R0 ; Put First string in place

MOVE R3 R1 ; Put Second string in place

LOADUI R4 0 ; Set initial index of 0

:match_cmpbyte

LOADXU8 R0 R2 R4 ; Get a byte of our first string

LOADXU8 R1 R3 R4 ; Get a byte of our second string

ADDUI R4 R4 1 ; Prep for next loop

CMPSKIP.NE R1 R0 ; Compare the bytes

JUMP.NZ R1 @match_cmpbyte ; Loop if bytes are equal

;; Done

FALSE R2 ; Default answer

CMPSKIP.NE R0 R1 ; If ended loop with everything matching

TRUE R2 ; Set as TRUE

MOVE R0 R2 ; Prepare for return

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; lookup_type function

;; Receives a CHAR* in R0 and struct type* in R1

;; Returns struct type* in R0 or NULL if no match

:lookup_type

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

MOVE R2 R1 ; Put START in correct place

MOVE R1 R0 ; Put S in correct place

:lookup_type_iter

LOAD32 R0 R2 24 ; Get I->NAME

CALLI R15 @match ; Check if I->NAME==S

JUMP.NZ R0 @lookup_type_done ; If match found be done

LOAD32 R2 R2 0 ; I=I->NEXT

JUMP.NZ R2 @lookup_type_iter ; Otherwise iterate until I==NULL

:lookup_type_done

MOVE R0 R2 ; Our answer (I or NULL)

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; lookup_member function

;; Receives struct type* parent in R0 and char* name in R1

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns struct type* of member in R0 or aborts with error

:lookup_member

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

LOAD32 R3 R0 24 ; PARENT->NAME for error

MOVE R2 R0 ; I=PARENT

:lookup_member_iter

LOAD32 R2 R2 16 ; I=I->MEMBERS

JUMP.Z R2 @lookup_member_error ; We failed hard

LOAD32 R0 R2 24 ; I->NAME

CALLI R15 @match ; IF I->NAME==NAME

JUMP.Z R0 @lookup_member_iter ; Loop again

:lookup_member_done

MOVE R0 R2 ; Put I in the correct place

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

:lookup_member_error

FALSE R1 ; Write to TTY

LOADUI R0 $lookup_member_string0 ; Our header string

CALLI R15 @file_print ; Print it

MOVE R0 R3 ; Using PARENT->NAME

CALLI R15 @file_print ; Print it

LOADUI R0 $arrow_string ; Using “->”

CALLI R15 @file_print ; Print it

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @file_print ; Print it

LOADUI R0 $lookup_member_string1 ; Our footer string

CALLI R15 @file_print ; Print it

CALLI R15 @line_error ; Give line info

LOADUI R0 $newline ; Our final addition

CALLI R15 @file_print ; Print it

HALT

:lookup_member_string0

“ERROR in lookup_member ”

:lookup_member_string1

” does not exist

;; build_member function

;; Receives a struct type* in R0, int in R1 and int in R2

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Modifies R2 to current member_size

;; Returns struct type* in R0

:build_member

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

PUSHR R5 R15 ; Protect R5

PUSHR R6 R15 ; Protect R6

MOVE R6 R1 ; Protect OFFSET

MOVE R4 R0 ; Protect LAST

CALLI R15 @type_name ; Get MEMBER_TYPE

MOVE R5 R0 ; Protect MEMBER_TYPE

ADDUI R3 R14 28 ; CALLOC struct type

SWAP R3 R14 ; SET I

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

STORE32 R0 R3 24 ; I->NAME=GLOBAL_TOKEN->S

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

STORE32 R4 R3 16 ; I->MEMBERS=LAST

LOADUI R0 $open_bracket ; Using “[”

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; IF GLOBAL_TOKEN->S==”[”

JUMP.Z R0 @build_member_single

;; Deal with type name [ number ] ;

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @numerate_string ; Convert string to int NUMBER

LOAD32 R1 R5 20 ; MEMBER_TYPE->TYPE

LOAD32 R1 R1 4 ; MEMBER_TYPE->TYPE->SIZE

MULU R0 R0 R1 ; MEMBER_TYPE->TYPE->SIZE * NUMBER

STORE32 R0 R3 4 ; I->SIZE=MEMBER_TYPE->TYPE->SIZE * NUMBER

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $build_member_string0 ; Our error message

LOADUI R1 $close_bracket ; Using “]”

CALLI R15 @require_match ; Make sure it is right

JUMP @build_member_done ; Skip over single steps

:build_member_single

LOAD32 R0 R5 4 ; MEMBER_TYPE->SIZE

STORE32 R0 R3 4 ; I->SIZE=MEMBER_TYPE->SIZE

:build_member_done

LOAD32 R2 R3 4 ; MEMBER_SIZE=I->SIZE

STORE32 R5 R3 20 ; I->TYPE=MEMBER_TYPE

STORE32 R6 R3 8 ; I->OFFSET=OFFSET

MOVE R1 R6 ; Restore OFFSET

MOVE R0 R3 ; RETURN I in R0

POPR R6 R15 ; Restore R6

POPR R5 R15 ; Restore R5

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

RET R15

:build_member_string0

“Struct only supports [num] form

;; build_union function

;; Receives a struct type* in R0, int in R1 and int in R2

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Modifies R2 to current member_size

;; Returns struct type* in R0

:build_union

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

PUSHR R5 R15 ; Protect R5

MOVE R4 R0 ; Protect LAST

MOVE R3 R1 ; Protect OFFSET

FALSE R5 ; SIZE=0

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $build_union_string0 ; ERROR MESSAGE

LOADUI R1 $open_curly_brace ; OPEN CURLY BRACE

CALLI R15 @require_match ; Ensure we have that curly brace

:build_union_iter

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

LOADUI R1 125 ; numerical value of }

CMPJUMPI.E R0 R1 @build_union_done ; No more looping required

MOVE R0 R4 ; We are passing last to be overwritten

MOVE R1 R3 ; We are also passing OFFSET

CALLI R15 @build_member ; To build_member to get new LAST and new member_size

CMPSKIP.LE R2 R5 ; If MEMBER_SIZE> SIZE

COPY R5 R2 ; SIZE=MEMMER_SIZE

MOVE R4 R0 ; Protect LAST

MOVE R3 R1 ; Protect OFFSET

LOADUI R0 $build_union_string1 ; ERROR MESSAGE

LOADUI R1 $semicolon ; SEMICOLON

CALLI R15 @require_match ; Ensure we have that curly brace

JUMP @build_union_iter ; Loop until we get that closing curly brace

:build_union_done

MOVE R2 R5 ; Setting MEMBER_SIZE=SIZE

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

MOVE R1 R3 ; Restore OFFSET

MOVE R0 R4 ; Restore LAST as we are turning that

POPR R5 R15 ; Restore R5

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

RET R15

:build_union_string0

“ERROR in build_union

Missing {

:build_union_string1

“ERROR in build_union

Missing ;

;; create_struct function

;; Receives Nothing

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns Nothing

:create_struct

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

PUSHR R5 R15 ; Protect R5

PUSHR R6 R15 ; Protect R6

FALSE R5 ; OFFSET=0

FALSE R2 ; MEMBER_SIZE=0

COPY R3 R14 ; SET HEAD

ADDUI R14 R14 28 ; CALLOC struct type

COPY R4 R14 ; SET I

ADDUI R14 R14 28 ; CALLOC struct type

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

STORE32 R0 R3 24 ; HEAD->NAME=GLOBAL_TOKEN->S

STORE32 R0 R4 24 ; I->NAME=GLOBAL_TOKEN->S

STORE32 R4 R3 12 ; HEAD->INDIRECT=I

STORE32 R3 R4 12 ; I->INDIRECT – HEAD

LOADR32 R0 @global_types ; Get Address of GLOBAL_TYPES

STORE R0 R3 0 ; HEAD->NEXT=GLOBAL_TYPES

STORER32 R3 @global_types ; GLOBAL_TYPES=HEAD

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 4 ; Standard Pointer SIZE

STORE32 R0 R4 4 ; I->SIZE=4

LOADUI R0 $create_struct_string0 ; ERROR MESSAGE

LOADUI R1 $open_curly_brace ; OPEN CURLY BRACE

CALLI R15 @require_match ; Ensure we have that curly brace

FALSE R6 ; LAST=NULL

:create_struct_iter

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R0 R0 0 ; GLOBAL_TOKEN->S[0]

LOADUI R1 125 ; Numerical value of }

CMPJUMPI.E R0 R1 @create_struct_done ; Stop looping if match

LOADUI R1 $union ; Pointer to string UNION

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; Check if they Match

SWAP R0 R6 ; Put LAST in place

MOVE R1 R5 ; Put OFFSET in place

JUMP.NZ R6 @create_struct_union ; Deal with union case

;; Deal with standard member case

CALLI R15 @build_member ; Sets new LAST and MEMBER_SIZE

JUMP @create_struct_iter2 ; reset for loop

:create_struct_union

CALLI R15 @build_union

:create_struct_iter2

ADD R5 R1 R2 ; OFFSET=OFFSET + MEMBER_SIZE

SWAP R0 R6 ; Put LAST in place

LOADUI R0 $create_struct_string1 ; ERROR MESSAGE

LOADUI R1 $semicolon ; SEMICOLON

CALLI R15 @require_match ; Ensure we have that semicolon

JUMP @create_struct_iter ; Keep Looping

:create_struct_done

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOADUI R0 $create_struct_string1 ; ERROR MESSAGE

LOADUI R1 $semicolon ; SEMICOLON

CALLI R15 @require_match ; Ensure we have that semicolon

STORE32 R5 R3 4 ; HEAD->SIZE=OFFSET

STORE32 R6 R3 16 ; HEAD->MEMBERS=LAST

STORE32 R6 R4 16 ; I->MEMBERS=LAST

POPR R6 R15 ; Restore R6

POPR R5 R15 ; Restore R5

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:create_struct_string0

“ERROR in create_struct

Missing {

:create_struct_string1

“ERROR in create_struct

Missing ;

;; type_name function

;; Receives Nothing

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns struct type* in R0

:type_name

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

LOADUI R0 $struct ; String for struct for comparison

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; Check if they match

CMPSKIPI.E R0 0 ; If STRUCTURE

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R2 R13 8 ; GLOBAL_TOKEN->S

LOADR32 R1 @global_types ; Check using the GLOBAL TYPES LIST

SWAP R0 R2 ; Put GLOBAL_TOKEN->S in the right place

CALLI R15 @lookup_type ; RET=lookup_type(GLOBAL_TOKEN->S)

MOVE R1 R2 ; Put STRUCTURE in the right place

CMPSKIP.E R0 R1 ; If RET==NULL and !STRUCTURE

JUMP @type_name_struct ; Guess not

;; Exit with useful error message

FALSE R1 ; We will want to be writing the error message for the Human

LOADUI R0 $type_name_string0 ; The first string

CALLI R15 @file_print ; Display it

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @file_print ; Display it

LOADUI R0 $newline ; Terminating linefeed

CALLI R15 @file_print ; Display it

CALLI R15 @line_error ; Give useful debug info

HALT ; Just exit

:type_name_struct

JUMP.NZ R0 @type_name_iter ; If was found

CALLI R15 @create_struct ; Otherwise create it

JUMP @type_name_done ; and be done

:type_name_iter

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

LOAD32 R1 R13 8 ; GLOBAL_TOKEN->S

LOADU8 R1 R1 0 ; GLOBAL_TOKEN->S[0]

CMPSKIPI.E R1 42 ; if GLOBAL_TOKEN->S[0]==’*’

JUMP @type_name_done ; Looks like Nope

LOAD32 R0 R0 12 ; RET=RET->INDIRECT

JUMP @type_name_iter ; Keep looping

:type_name_done

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

:type_name_string0

“Unknown type ”

;; line_error function

;; Receives Nothing

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns nothing

:line_error

PUSHR R0 R15 ; Protect R0

PUSHR R1 R15 ; Protect R1

LOADUI R0 $line_error_string0 ; Our leading string

FALSE R1 ; We want the user to see

CALLI R15 @file_print ; Print it

LOAD32 R0 R13 16 ; GLOBAL_TOKEN->LINENUMBER

CALLI R15 @numerate_number ; Get a string pointer for number

CALLI R15 @file_print ; And print it

POPR R1 R15 ; Restore R1

POPR R0 R15 ; Restore R0

RET R15

:line_error_string0

“In file: TTY1 On line: ”

;; require_match function

;; Receives char* in R0 and char* in R1

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns Nothing

:require_match

PUSHR R0 R15 ; Protect R0

PUSHR R2 R15 ; Protect R2

MOVE R2 R0 ; Get MESSAGE out of the way

LOAD32 R0 R13 8 ; GLOBAL_TOKEN->S

CALLI R15 @match ; Check if GLOBAL_TOKEN->S==REQUIRED

JUMP.NZ R0 @require_match_done ; Looks like it was a match

;; Terminate with an error

MOVE R0 R2 ; Put MESSAGE in required spot

FALSE R1 ; We want to write for user

CALLI R15 @file_print ; Write it

CALLI R15 @line_error ; And provide some debug info

HALT ; Then Stop immediately

:require_match_done

LOAD32 R13 R13 0 ; GLOBAL_TOKEN=GLOBAL_TOKEN->NEXT

POPR R2 R15 ; Restore R2

POPR R0 R15 ; Restore R0

RET R15

;; numerate_number function

;; Receives int in R0

;; R13 Holds pointer to global_token, R14 is HEAP Pointer

;; Returns pointer to string generated

:numerate_number

PUSHR R1 R15 ; Preserve R1

PUSHR R2 R15 ; Preserve R2

PUSHR R3 R15 ; Preserve R3

PUSHR R4 R15 ; Preserve R4

PUSHR R5 R15 ; Preserve R5

PUSHR R6 R15 ; Preserve R6

MOVE R3 R0 ; Move Integer out of the way

COPY R1 R14 ; Get pointer result

ADDUI R14 R14 16 ; CALLOC the 16 chars of space

FALSE R6 ; Set index to 0

JUMP.Z R3 @numerate_number_ZERO ; Deal with Special case of ZERO

JUMP.P R3 @numerate_number_Positive

LOADUI R0 45 ; Using –

STOREX8 R0 R1 R6 ; write leading –

ADDUI R6 R6 1 ; Increment by 1

NOT R3 R3 ; Flip into positive

ADDUI R3 R3 1 ; Adjust twos

:numerate_number_Positive

LOADR R2 @Max_Decimal ; Starting from the Top

LOADUI R5 10 ; We move down by 10

FALSE R4 ; Flag leading Zeros

:numerate_number_0

DIVIDE R0 R3 R3 R2 ; Break off top 10

CMPSKIPI.E R0 0 ; If Not Zero

TRUE R4 ; Flip the Flag

JUMP.Z R4 @numerate_number_1 ; Skip leading Zeros

ADDUI R0 R0 48 ; Shift into ASCII

STOREX8 R0 R1 R6 ; write digit

ADDUI R6 R6 1 ; Increment by 1

:numerate_number_1

DIV R2 R2 R5 ; Look at next 10

CMPSKIPI.E R2 0 ; If we reached the bottom STOP

JUMP @numerate_number_0 ; Otherwise keep looping

:numerate_number_done

FALSE R0 ; NULL Terminate

STOREX8 R0 R1 R6 ; write

MOVE R0 R1 ; Return pointer to our string

;; Cleanup

POPR R6 R15 ; Restore R6

POPR R5 R15 ; Restore R5

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

:numerate_number_ZERO

LOADUI R0 48 ; Using Zero

STOREX8 R0 R1 R6 ; write

ADDUI R6 R6 1 ; Increment by 1

JUMP @numerate_number_done ; Be done

:Max_Decimal

‘3B9ACA00′

;; numerate_string function

;; Receives pointer To string in R0

;; Returns number in R0 equal to value of string

;; Or Zero in the event of invalid string

:numerate_string

PUSHR R1 R15 ; Protect R1

PUSHR R2 R15 ; Protect R2

PUSHR R3 R15 ; Protect R3

PUSHR R4 R15 ; Protect R4

;; Initialize

MOVE R1 R0 ; Get Text pointer out of the way

FALSE R2 ; Set Negative flag to false

FALSE R3 ; Set current count to Zero

LOAD8 R0 R1 1 ; Get second byte

CMPSKIPI.NE R0 120 ; If the second byte is x

JUMP @numerate_string_hex ; treat string like hex

;; Deal with Decimal input

LOADUI R4 10 ; Multiply by 10

LOAD8 R0 R1 0 ; Get a byte

CMPSKIPI.NE R0 45 ; If – toggle flag

TRUE R2 ; So that we know to negate

CMPSKIPI.E R2 0 ; If toggled

ADDUI R1 R1 1 ; Move to next

:numerate_string_dec

LOAD8 R0 R1 0 ; Get a byte

CMPSKIPI.NE R0 0 ; If NULL

JUMP @numerate_string_done ; Be done

MUL R3 R3 R4 ; Shift counter by 10

SUBI R0 R0 48 ; Convert ascii to number

CMPSKIPI.GE R0 0 ; If less than a number

JUMP @numerate_string_done ; Terminate NOW

CMPSKIPI.L R0 10 ; If more than a number

JUMP @numerate_string_done ; Terminate NOW

ADDU R3 R3 R0 ; Don’t add to the count

ADDUI R1 R1 1 ; Move onto next byte

JUMP @numerate_string_dec

;; Deal with Hex input

:numerate_string_hex

LOAD8 R0 R1 0 ; Get a byte

CMPSKIPI.E R0 48 ; All hex strings start with 0x

JUMP @numerate_string_done ; Be done if not a match

ADDUI R1 R1 2 ; Move to after leading 0x

:numerate_string_hex_0

LOAD8 R0 R1 0 ; Get a byte

CMPSKIPI.NE R0 0 ; If NULL

JUMP @numerate_string_done ; Be done

SL0I R3 4 ; Shift counter by 16

SUBI R0 R0 48 ; Convert ascii number to number

CMPSKIPI.L R0 10 ; If A-F

SUBI R0 R0 7 ; Shove into Range

CMPSKIPI.L R0 16 ; If a-f

SUBI R0 R0 32 ; Shove into Range

ADDU R3 R3 R0 ; Add to the count

ADDUI R1 R1 1 ; Get next Hex

JUMP @numerate_string_hex_0

;; Clean up

:numerate_string_done

CMPSKIPI.E R2 0 ; If Negate flag has been set

NEG R3 R3 ; Make the number negative

MOVE R0 R3 ; Put number in R0

POPR R4 R15 ; Restore R4

POPR R3 R15 ; Restore R3

POPR R2 R15 ; Restore R2

POPR R1 R15 ; Restore R1

RET R15

;; 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

“>”

:less_than_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

“]”

:semicolon

“;”

:equal

“=”

:percent

“%”

:newline

:underline

“_”

;; Global types

;; NEXT (0), SIZE (4), OFFSET (8), INDIRECT (12), MEMBERS (16), TYPE (20), NAME (24)

:global_types

&type_void

:prim_types

:type_void

&type_int ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_void ; INDIRECT

NOP ; MEMBERS

&type_void ; TYPE

&type_void_name ; NAME

:type_void_name

“void”

:type_int

&type_char ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_int ; INDIRECT

NOP ; MEMBERS

&type_int ; TYPE

&type_int_name ; NAME

:type_int_name

“int”

:type_char

&type_file ; NEXT

’00 00 00 01′ ; SIZE

NOP ; OFFSET

&type_char_indirect ; INDIRECT

NOP ; MEMBERS

&type_char ; TYPE

&type_char_name ; NAME

:type_char_name

“char”

:type_char_indirect

&type_file ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_char_double_indirect ; INDIRECT

NOP ; MEMBERS

&type_char_indirect ; TYPE

&type_char_indirect_name ; NAME

:type_char_indirect_name

“char*”

:type_char_double_indirect

&type_file ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_char_double_indirect ; INDIRECT

NOP ; MEMBERS

&type_char_indirect ; TYPE

&type_char_double_indirect_name ; NAME

:type_char_double_indirect_name

“char**”

:type_file

&type_function ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_file ; INDIRECT

NOP ; MEMBERS

&type_file ; TYPE

&type_file_name ; NAME

:type_file_name

“FILE”

:type_function

&type_unsigned ; NEXT

’00 00 00 04′ ; SIZE

NOP ; OFFSET

&type_function ; INDIRECT

NOP ; MEMBERS

&type_function ; TYPE

&type_function_name ; NAME

:type_function_name

“FUNCTION”

:type_unsigned

NOP ; NEXT (NULL)

’00 00 00 04’ ; SIZE

NOP ; OFFSET

&type_unsigned ; INDIRECT

NOP ; MEMBERS

&type_unsigned ; TYPE

&type_unsigned_name ; NAME

:type_unsigned_name

“unsigned”

;; debug_list function

;; Receives struct token_list* in R0

;; Prints contents of list and HALTS

;; Does not return

:debug_list

MOVE R9 R0 ; Protect the list Pointer

FALSE R1 ; Write to TTY

:debug_list_iter

;; Header

LOADUI R0 $debug_list_string0 ; Using our first string

CALLI R15 @file_print ; Print it

COPY R0 R9 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; NEXT

LOADUI R0 $debug_list_string1 ; Using our second string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 0 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; PREV

LOADUI R0 $debug_list_string2 ; Using our third string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 4 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; S

LOADUI R0 $debug_list_string3 ; Using our fourth string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 8 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; S Contents

LOADUI R0 $debug_list_string4 ; Using our Prefix string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 8 ; Use address of pointer

CMPSKIPI.NE R0 0 ; If NULL Pointer

LOADUI R0 $debug_list_string_null ; Give meaningful message instead

CALLI R15 @file_print ; Print it

;; TYPE

LOADUI R0 $debug_list_string5 ; Using our fifth string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 12 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; PREV

LOADUI R0 $debug_list_string6 ; Using our sixth string

CALLI R15 @file_print ; Print it

LOAD32 R0 R9 16 ; Use address of pointer

CALLI R15 @numerate_number ; Convert it into a string

CALLI R15 @file_print ; Print it

;; Add some space

LOADUI R0 10 ; Using NEWLINE

FPUTC

FPUTC

;; Iterate if next not NULL

LOAD32 R9 R9 0 ; TOKEN=TOKEN->NEXT

JUMP.NZ R9 @debug_list_iter

;; Looks lke we are done, wrap it up

HALT

: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

“>::::
Read More
Share this on knowasiak.com to discuss with people on this topicSign up on Knowasiak.com now if you’re not registered yet.

Charlie Layers
WRITTEN BY

Charlie Layers

Fill your life with experiences so you always have a great story to tellBio: About:

Leave a Reply

Your email address will not be published. Required fields are marked *