start migration to better parsing of arguments
This commit is contained in:
@@ -69,19 +69,24 @@ start:
|
|||||||
;
|
;
|
||||||
; description:
|
; description:
|
||||||
; assembles the program from tokens located at TOKEN_TABLE_ADDR into a flat
|
; assembles the program from tokens located at TOKEN_TABLE_ADDR into a flat
|
||||||
; binary located at OUTPUT_ADDR. It's probably desirable to clear the output
|
; binary located at OUTPUT_ADDR.
|
||||||
; arena before calling this function.
|
; Behaviour is undefined when:
|
||||||
|
; - tokens are in an impossible order
|
||||||
|
; 0x1000 ; memory address, following byte should be a register
|
||||||
|
; 0x1000 ; not a register
|
||||||
|
; - operator tokens followed by the wrong number of arguments
|
||||||
|
; 0x004F ; hlt, expects 0 arguments
|
||||||
|
; 0x0000 ; rax, an argument
|
||||||
|
; - an undefined token is included, like 0x0051
|
||||||
;
|
;
|
||||||
; parameters:
|
; parameters:
|
||||||
; rdi = number of tokens in the token table
|
; rdi = number of tokens in the token table
|
||||||
; ------------------------------------------------------------------------------
|
; ------------------------------------------------------------------------------
|
||||||
|
|
||||||
assemble:
|
assemble:
|
||||||
xor rax, rax ; number of tokens processed
|
xor eax, eax ; rax = number of tokens processed
|
||||||
|
; rdi = number of tokens in table
|
||||||
.loop:
|
.loop:
|
||||||
cmp rax, rdi ; check incrementer against the number of tokens in the token
|
|
||||||
jge .break ; table. If overflown, break
|
|
||||||
|
|
||||||
push rdi
|
push rdi
|
||||||
xor edi, edi
|
xor edi, edi
|
||||||
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; next tte
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; next tte
|
||||||
@@ -90,16 +95,18 @@ assemble:
|
|||||||
; di = next tte
|
; di = next tte
|
||||||
call get_tte_type
|
call get_tte_type
|
||||||
; al = type of token
|
; al = type of token
|
||||||
|
|
||||||
|
; on stack:
|
||||||
|
; rax = number of tokens processed
|
||||||
|
; rdi = number of tokens in table
|
||||||
cmp al, 0x01 ; check if next tte's type is an operator
|
cmp al, 0x01 ; check if next tte's type is an operator
|
||||||
je .operator ; if so, handle case of operator
|
je .operator ; if so, handle case of operator
|
||||||
jne .continue_operator ; if not, jump past the case
|
jne .continue_operator ; if not, jump past the case
|
||||||
|
|
||||||
|
; di = tte of operator
|
||||||
.operator: ; if next tte's type is an operator:
|
.operator: ; if next tte's type is an operator:
|
||||||
push rax ; MUST be popped BEFORE returning to .continue_operator; it
|
|
||||||
; contains the type of token, which still needs to be used.
|
|
||||||
|
|
||||||
push rdi
|
push rdi
|
||||||
; di = tte
|
; di = tte of operator
|
||||||
call get_tte_typed_metadata
|
call get_tte_typed_metadata
|
||||||
; al = tte typed metadata
|
; al = tte typed metadata
|
||||||
pop rdi
|
pop rdi
|
||||||
@@ -108,19 +115,219 @@ assemble:
|
|||||||
|
|
||||||
cmp al, 0 ; check if operator has no operands
|
cmp al, 0 ; check if operator has no operands
|
||||||
je .operator_0 ; if so, handle case of no operands
|
je .operator_0 ; if so, handle case of no operands
|
||||||
jne .operator_with_args ; if not, jump to case of multiple operands
|
|
||||||
|
|
||||||
|
cmp al, 1 ; check if operator has one operand
|
||||||
|
je .operator_1 ; if so, handle case of one operand
|
||||||
|
|
||||||
|
cmp al, 2 ; check if operator has two operands
|
||||||
|
je .operator_2 ; if so, handle case of two operands
|
||||||
|
|
||||||
|
jmp .operator_with_args ; of not, handle case of some operands
|
||||||
|
|
||||||
|
; di = tte of operator
|
||||||
.operator_0:
|
.operator_0:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_0
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
push rdi
|
push rdi
|
||||||
; di = next tte
|
; di = tte of operator
|
||||||
call get_opcode
|
call get_opcode
|
||||||
; al = opcode
|
; al = opcode
|
||||||
call .output_byte
|
call .output_byte
|
||||||
pop rdi
|
pop rdi
|
||||||
|
|
||||||
pop rax ; from start of label .operator
|
jmp .continue
|
||||||
jmp .continue_operator
|
|
||||||
|
|
||||||
|
; di = tte of operator
|
||||||
|
.operator_1:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_1
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
; di = tte of operator
|
||||||
|
call get_opcode
|
||||||
|
; al = opcode
|
||||||
|
call .output_byte
|
||||||
|
pop rdi ; di = tte of operator
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
push rdi
|
||||||
|
push rax
|
||||||
|
xor edi, edi
|
||||||
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; di = next tte
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
and di, 0xFF00
|
||||||
|
cmp di, 0x1000 ; check if token is a memory address
|
||||||
|
pop rdi ; di = next tte
|
||||||
|
je .operator_1_memory_access
|
||||||
|
|
||||||
|
; di = next tte
|
||||||
|
call get_tte_type
|
||||||
|
; al = type of token
|
||||||
|
|
||||||
|
cmp al, 0x02 ; type: register
|
||||||
|
je .operator_1_register
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
; TODO figure out if this is relevant
|
||||||
|
.operator_1_memory_access:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_1_memory_access
|
||||||
|
call print.error
|
||||||
|
pop rsi
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
.operator_1_register:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_1_register
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
|
mov si, di ; si = `R/M` tte
|
||||||
|
mov di, 0x0000 ; di = `reg` tte
|
||||||
|
mov dl, 11b ; dl bits
|
||||||
|
call get_ModRM
|
||||||
|
; al = Mod R/M byte
|
||||||
|
call .output_byte
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.operator_2:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_2
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
; di = tte of operator
|
||||||
|
call get_opcode
|
||||||
|
; al = opcode
|
||||||
|
call .output_byte
|
||||||
|
pop rdi ; di = tte of operator
|
||||||
|
|
||||||
|
pop rax
|
||||||
|
pop rdi
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
push rdi
|
||||||
|
push rax
|
||||||
|
xor edi, edi
|
||||||
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; di = next tte
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
and di, 0xFF00
|
||||||
|
cmp di, 0x1000 ; check if token is a memory address
|
||||||
|
pop rdi ; di = next tte
|
||||||
|
je .operator_2_memory_access
|
||||||
|
|
||||||
|
; di = next tte
|
||||||
|
call get_tte_type
|
||||||
|
; al = type of token
|
||||||
|
|
||||||
|
cmp al, 0x02 ; type: register
|
||||||
|
je .operator_2_register
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.operator_2_memory_access:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_2_memory_access
|
||||||
|
call print.error
|
||||||
|
pop rsi
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
.operator_2_register:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_2_register
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
|
mov si, di ; si = `R/M` tte
|
||||||
|
|
||||||
|
pop rax
|
||||||
|
pop rdi
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
push rdi
|
||||||
|
push rax
|
||||||
|
xor edi, edi
|
||||||
|
mov di, [rax * TOKEN_TABLE_ENTRY_SIZE + TOKEN_TABLE_ADDR] ; di = next tte
|
||||||
|
|
||||||
|
push rdi
|
||||||
|
and di, 0xFF00
|
||||||
|
cmp di, 0x1000 ; check if token is a memory address
|
||||||
|
pop rdi ; di = next tte
|
||||||
|
je .operator_2_register_memory_access
|
||||||
|
|
||||||
|
; di = next tte
|
||||||
|
call get_tte_type
|
||||||
|
; al = type of token
|
||||||
|
|
||||||
|
cmp al, 0x02
|
||||||
|
je .operator_2_register_register
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total nnumber of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
.operator_2_register_memory_access:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_2_register_memory_access
|
||||||
|
call print.error
|
||||||
|
pop rsi
|
||||||
|
jmp halt
|
||||||
|
|
||||||
|
.operator_2_register_register:
|
||||||
|
push rsi
|
||||||
|
mov rsi, .msg_operator_2_register_register
|
||||||
|
call print.debug
|
||||||
|
pop rsi
|
||||||
|
|
||||||
|
; si = `R/M` tte
|
||||||
|
; di = `reg` tte
|
||||||
|
mov dl, 11b ; dl = mod bits
|
||||||
|
call get_ModRM
|
||||||
|
; al = Mod R/M byte
|
||||||
|
call .output_byte
|
||||||
|
|
||||||
|
pop rax ; rax = number of tokens processed
|
||||||
|
pop rdi ; rdi = total number of tokens
|
||||||
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break
|
||||||
|
jmp .loop
|
||||||
|
|
||||||
|
; di = tte of operator
|
||||||
.operator_with_args:
|
.operator_with_args:
|
||||||
mov [.pending_operator_num_args], al ; save # args fttb
|
mov [.pending_operator_num_args], al ; save # args fttb
|
||||||
|
|
||||||
@@ -131,13 +338,14 @@ assemble:
|
|||||||
mov [.pending_operator_opcode], al ; save opcode fttb
|
mov [.pending_operator_opcode], al ; save opcode fttb
|
||||||
pop rdi
|
pop rdi
|
||||||
|
|
||||||
pop rax ; from start of label .operator
|
jmp .continue
|
||||||
|
|
||||||
.continue_operator:
|
.continue_operator:
|
||||||
cmp al, 0x02 ; check if next tte's type is a register
|
cmp al, 0x02 ; check if next tte's type is a register
|
||||||
je .register ; if so, handle case of register
|
je .register ; if so, handle case of register
|
||||||
jne .continue_register ; if not, jump past the case
|
jne .continue_register ; if not, jump past the case
|
||||||
|
|
||||||
|
; di MUST be a valid register tte
|
||||||
.register: ; if next tte's type is a register:
|
.register: ; if next tte's type is a register:
|
||||||
call .dec_num_args ; because we've found an argument, we need 1 fewer noch
|
call .dec_num_args ; because we've found an argument, we need 1 fewer noch
|
||||||
|
|
||||||
@@ -195,10 +403,14 @@ assemble:
|
|||||||
jmp .continue_register
|
jmp .continue_register
|
||||||
|
|
||||||
.continue_register:
|
.continue_register:
|
||||||
|
|
||||||
|
.continue:
|
||||||
pop rax ; rax = number of tokens processed
|
pop rax ; rax = number of tokens processed
|
||||||
pop rdi ; rdi = total number of tokens
|
pop rdi ; rdi = total number of tokens
|
||||||
|
|
||||||
inc rax ; move to next token
|
inc rax
|
||||||
|
cmp rax, rdi
|
||||||
|
jge .break ; at end of table, break
|
||||||
jmp .loop
|
jmp .loop
|
||||||
|
|
||||||
.break:
|
.break:
|
||||||
@@ -227,6 +439,8 @@ assemble:
|
|||||||
pop rax
|
pop rax
|
||||||
ret
|
ret
|
||||||
|
|
||||||
|
; resets sketchy memory-based state
|
||||||
|
; TODO put this state in an accumulator or something
|
||||||
.reset_state:
|
.reset_state:
|
||||||
; I don't actually know if these `word` directives are needed
|
; I don't actually know if these `word` directives are needed
|
||||||
; TODO check that. I think they are, becasue Nasm doesn't record the size
|
; TODO check that. I think they are, becasue Nasm doesn't record the size
|
||||||
@@ -244,6 +458,15 @@ assemble:
|
|||||||
.first_argument dw UNRECOGNISED_TOKEN_ID ; first argument if there are two
|
.first_argument dw UNRECOGNISED_TOKEN_ID ; first argument if there are two
|
||||||
|
|
||||||
.next_output_byte dd OUTPUT_ADDR ; next empty byte in output
|
.next_output_byte dd OUTPUT_ADDR ; next empty byte in output
|
||||||
|
.msg_operator_0 db "operator_0", 0x0A, 0x00
|
||||||
|
.msg_operator_1 db "operator_1", 0x0A, 0x00
|
||||||
|
.msg_operator_1_memory_access db "operator_1_memory_access", 0x0A, 0x00
|
||||||
|
.msg_operator_1_register db "operator_1_register", 0x0A, 0x00
|
||||||
|
.msg_operator_2 db "operator_2", 0x0A, 0x00
|
||||||
|
.msg_operator_2_memory_access db "operator_2_memory_access", 0x0A, 0x00
|
||||||
|
.msg_operator_2_register db "operator_2_register", 0x0A, 0x00
|
||||||
|
.msg_operator_2_register_memory_access db "operator_2_register_memory_access", 0x0A, 0x00
|
||||||
|
.msg_operator_2_register_register db "operator_2_register_register", 0x0A, 0x00
|
||||||
|
|
||||||
; ------------------------------------------------------------------------------
|
; ------------------------------------------------------------------------------
|
||||||
; get_tte_type
|
; get_tte_type
|
||||||
@@ -664,11 +887,11 @@ tokenise:
|
|||||||
mov cx, ax ; cx = length counter for safe keeping
|
mov cx, ax ; cx = length counter for safe keeping
|
||||||
call evaluate_operand
|
call evaluate_operand
|
||||||
; dl = return code
|
; dl = return code
|
||||||
; ax = register's token ID
|
; rax = binary data
|
||||||
pop rsi
|
pop rsi
|
||||||
pop rdi ; rdi = first byte of operand
|
pop rdi ; rdi = first byte of operand
|
||||||
add di, cx ; rdi = last byte of operand
|
add di, cx ; rdi = last byte of operand
|
||||||
mov rcx, rax ; rcx = evaluate_operand's return value
|
mov rcx, rax ; rcx = evaluate_operand's binary return data
|
||||||
pop rax ; rax = number of tokens processed
|
pop rax ; rax = number of tokens processed
|
||||||
|
|
||||||
; operand is some reg
|
; operand is some reg
|
||||||
@@ -1563,8 +1786,6 @@ opcodes:
|
|||||||
msg_welcome db "Welcome to Twasm", 0x0A, 0x00
|
msg_welcome db "Welcome to Twasm", 0x0A, 0x00
|
||||||
msg_halt db "halted.", 0x0A, 0x00
|
msg_halt db "halted.", 0x0A, 0x00
|
||||||
|
|
||||||
token_terminator_8 db 0x00, " ", 0x0A, 0x0D, ",", 0x00, 0x00, 0x00
|
|
||||||
|
|
||||||
whitespace_2 db " ", 0x0D
|
whitespace_2 db " ", 0x0D
|
||||||
|
|
||||||
; test program
|
; test program
|
||||||
|
|||||||
Reference in New Issue
Block a user