it doesn't crash (crazy)

This commit is contained in:
janis 2025-11-03 00:54:34 +01:00
parent a93f7edd62
commit 8e1af956b0
Signed by: janis
SSH key fingerprint: SHA256:bB1qbbqmDXZNT0KKD5c2Dfjg53JGhj7B3CFcLIzSqq8
3 changed files with 300 additions and 168 deletions

View file

@ -177,7 +177,9 @@ write_register_name:
;; rdi: arg index
;; Returns the `Operand` for the given argument index
;; Returns the input `Operand` for the given argument index:
;; On the SysV ABI, the first 6 integer/pointer args are passed in registers:
;; rdi, rsi, rdx, rcx, r8, r9
codegen_arg_to_operand:
push rbp
mov rbp, rsp
@ -222,6 +224,7 @@ codegen_arg_to_operand:
jmp .epilogue
.stack_arg:
; TODO: use these offsets in stack-vars instead of copying into new stack slots
sub rdi, 6
mov rax, 8
mul rdi
@ -235,9 +238,9 @@ codegen_arg_to_operand:
shl eax, 16
or eax, 8 ; Operand.width = 8
shl eax, 8
; or eax, 0 ; Operand.register = undef
; or eax, 0 ; Operand.register = undef
shl eax, 8
or eax, OPERAND_RBP_OFFSET ; Operand.kind
or eax, OPERAND_RBP_VALUE ; Operand.kind
.epilogue:
pop rbp
@ -362,6 +365,22 @@ codegen_allocate_place:
pop rbp
ret
;; rdi: *FunctionCtx
;; rsi: width
;; define-fn: fn codegen_allocate_stack_value(ctx: *mut FunctionCtx, width: u16) -> Operand
codegen_allocate_stack_value:
push rbp
mov rbp, rsp
call codegen_allocate_place
mov rsi, 0xF
not rsi
and rax, rsi ; clear kind to make it a value
and rax, OPERAND_RBP_VALUE ; Operand.kind = OPERAND_RBP_VALUE
pop rbp
ret
;; rdi: *FunctionCtx
;; rsi: width
;; define-fn: fn codegen_allocate_value(ctx: *mut FunctionCtx, width: u16) -> Operand
@ -401,7 +420,7 @@ codegen_allocate_value:
jmp .done
.alloc_stack:
call codegen_allocate_place
call codegen_allocate_stack_value
.done:
add rsp, 16
@ -422,10 +441,19 @@ codegen_free_operand:
mov [rsp + 8], rsi ; operand
mov al, byte [rsi] ; Operand.kind
xor rbx, rbx
cmp al, OPERAND_REGISTER
je .free_reg
cmp al, OPERAND_RBP_OFFSET
je .free_stack
sete bl
cmp al, OPERAND_REGISTER_PLACE
sete bl
test bl, bl
jnz .free_reg
cmp al, OPERAND_RBP_VALUE
sete bl
cmp al, OPERAND_RBP_PLACE
sete bl
test bl, bl
jnz .free_stack
jmp .done
.free_stack:
@ -1028,14 +1056,10 @@ codegen_expr:
; mov rax, {inner expr result}
mov [rsp + 16], rax
mov [rsp + 24], rdx
mov rax, qword [rel OPERAND_RAX]
mov rdx, qword [rel OPERAND_RAX + 8]
mov [rsp + 32], rax
mov [rsp + 40], rdx
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 32] ; dst
lea rsi, [rel OPERAND_RAX] ; dst
lea rdx, [rsp + 16] ; src
call codegen_move_dst_src
@ -1057,14 +1081,8 @@ codegen_expr:
.number:
; rax = *AstNode
mov [rsp + 16], rax ; scratch = *AstNode
mov byte [rsp + 32], OPERAND_IMMEDIATE ; Operand.kind
mov byte [rsp + 33], 0 ; Operand.register = undef
mov word [rsp + 34], 8 ; Operand.width = 8
mov word [rsp + 36], 0 ; Operand.len = 0
mov rbx, [rax + 8] ; AstNode.data
mov [rsp + 40], rbx ; Operand.value
mov [rsp + 40], rbx ; Imm value
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; width
@ -1072,11 +1090,42 @@ codegen_expr:
mov [rsp + 16], rax
mov [rsp + 24], rdx
mov rdx, [rsp + 40] ; Imm value
test rdx, rdx
jz .load_imm ; skip if zero
; fill bits
; !(!1u64 << imm.ilog2()) >> 1;
lzcnt rax, rdx
not al
mov rcx, -2
shlx rax, rcx, rax
not rax
shr rax, 1
; this gives a mask of the imm bits extended to the power of two bytes
movsx ecx, al ; sign-extend byte to word
movzx ecx, cx ; zero-extend to dword
movsx edx, ax ; sign-extend word to dword
or edx, ecx
mov eax, eax ; sign-extend dword to qword
or rdx, rax
je .load_imm ; skip if zero
; count bytes needed
; (z.ilog2() + 1) / 3
lzcnt rcx, rdx
mov edx, 64
sub edx, ecx
shr edx, 3
.load_imm:
test rdx, rdx
setz dl
mov rdi, [rsp] ; ctx
lea rdi, [rdi + 8] ; &ctx.text
lea rsi, [rsp + 16] ; dst
lea rdx, [rsp + 32] ; src
call codegen_move_dst_src
mov rcx, rdx ; byte count
mov rdx, [rsp + 40] ; immediate value
call codegen_load_imm
mov rax, qword [rsp + 16]
mov rdx, qword [rsp + 24]
@ -1130,7 +1179,7 @@ codegen_expr:
; allocate scratch value for rdx
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; width
call codegen_allocate_place
call codegen_allocate_value
mov [rsp + 64], rax
mov [rsp + 72], rdx
@ -1143,9 +1192,9 @@ codegen_expr:
; check if rhs is rdx
mov rax, [rsp + 48] ; right operand
and rax, 0xFFF
and rax, 0xFFFF
mov rdx, [rel OPERAND_RDX]
and rdx, 0xFFF
and rdx, 0xFFFF
cmp rax, rdx
jne .after_spill_rdx
@ -1320,25 +1369,9 @@ codegen_expr:
call vec_get
mov rdx, [rax + 8] ; offset
neg rdx
mov rax, qword [rel OPERAND_RBP]
mov [rsp + 16], rax
mov [rsp + 24], rdx
mov rax, qword [rel OPERAND_RBP_OFFS]
jmp .done
; allocate value (?)
mov rdi, [rsp + 8] ; &function_ctx
mov rsi, 8 ; width = size_of::<* const()>
call codegen_allocate_value
mov [rsp + 32], rax ; dst
mov [rsp + 40], rdx
; lea dst, [rbp - offset]
mov rdi, [rsp] ; ctx
lea rsi, [rdi + 8] ; &ctx.text
mov rdi, [rsp + 8] ; &function_ctx
lea rdx, [rsp + 32] ; dst
lea rcx, [rsp + 16] ; src
mov r8, 'lea '
call codegen_binary_op_rm64_rm64
.place_to_value:
.assignment:
.value_to_place:
@ -1369,16 +1402,30 @@ codegen_expr:
;; or: register: u4, width: u4
section .rdata
;; start-consts
; Register containing a Value
OPERAND_REGISTER equ 1 ; e.g. rax, rbx
OPERAND_RBP_OFFSET equ 2 ; e.g. mov/lea [rbp - 8]
OPERAND_RSP_OFFSET equ 3 ; e.g. [rsp + 16]
OPERAND_ADDRESS equ 4 ; e.g. [rel OPERAND_ADDRESS]
OPERAND_IMMEDIATE equ 5 ; e.g. 0x10
OPERAND_CONSTANT equ 6 ; e.g. OPERAND_CONSTANT
OPERAND_LABEL equ 7 ; e.g. label_1234
; RSP-relative stack-slot containing a Value, semantically not addressable
OPERAND_RBP_VALUE equ 2 ; e.g. [rsp + 16]
; RBP-relative stack-slot containing a Value, but addressable (derived from a Place)
OPERAND_RBP_PVALUE equ 3 ; e.g. mov [rbp - 8]
; Static-slot containing a Value
OPERAND_ADDRESS_VALUE equ 4 ; e.g. mov [rel OPERAND_ADDRESS]
OPERAND_LAST_VALUE equ 5 ; operand kinds > this are places
; RBP-relative stack-slot containing a Value, semantically addressable
OPERAND_RBP_OFFSET equ 6 ; e.g. mov [rbp - 8], rax or lea rax, [rbp - 8]
; Address of a static-slot containing a Value
OPERAND_ADDRESS_PLACE equ 7 ; e.g. lea [rel OPERAND_ADDRESS]
; Register containing an address (Place)
OPERAND_REGISTER_PLACE equ 8 ; e.g. [rax]
; RBP-relative stack-slot containing an address (Place)
OPERAND_RBP_PLACE equ 9 ; e.g. mov rax, [rbp - 8]; mov [rax], src
OPERAND_RBP_VALUE equ 10 ; e.g. mov [rbp - 8]
OPERAND_LAST_PLACE equ 10 ; operand kinds > this are not memory operands
; Immediate constant Value
OPERAND_IMMEDIATE equ 11 ; e.g. 0x10
; Special Operands whose semantics aren't fully defined yet
OPERAND_CONSTANT equ 12 ; e.g. OPERAND_CONSTANT
OPERAND_LABEL equ 13 ; e.g. label_1234
;; end-consts
WIDTH_BYTE db 'byte '
WIDTH_WORD db 'word '
@ -1387,11 +1434,23 @@ section .rdata
; Operand { kind: REGISTER, register: 0, width: 8, len: 0, padding: 0, value: 0 }
align 8
OPERAND_IMM dq 0x0008_000b, 0
align 8
OPERAND_RAX dq 0x0008_0001, 0
align 8
OPERAND_RAX_P dq 0x0008_0008, 0
align 8
OPERAND_RDX dq 0x0008_0301, 0
align 8
OPERAND_RBP dq 0x0008_0002, 0
OPERAND_RDX_P dq 0x0008_0308, 0
align 8
OPERAND_RBP_OFFS dq 0x0008_0006, 0
align 8
OPERAND_RBP_PV dq 0x0008_0003, 0
align 8
OPERAND_RBP_V dq 0x0008_0002, 0
align 8
OPERAND_RBP_P dq 0x0008_0009, 0
section .text
@ -1414,9 +1473,13 @@ codegen_write_operand:
je .register
cmp bl, OPERAND_RBP_OFFSET
je .rbp_offset
cmp bl, OPERAND_RSP_OFFSET
je .rsp_offset
cmp bl, OPERAND_ADDRESS
cmp bl, OPERAND_RBP_VALUE
je .rbp_offset
cmp bl, OPERAND_RBP_PVALUE
je .rbp_offset
cmp bl, OPERAND_ADDRESS_VALUE
je .address
cmp bl, OPERAND_ADDRESS_PLACE
je .address
cmp bl, OPERAND_IMMEDIATE
je .immediate
@ -1466,7 +1529,6 @@ codegen_write_operand:
jmp .epilogue
.rbp_offset:
.rsp_offset:
; {width} [rbp {+/-} offset]
mov rsi, [rsp + 8] ; op
movzx rsi, word [rsi + 2] ; Operand.width
@ -1608,6 +1670,8 @@ codegen_write_width:
cmp sil, 1
lea rdx, [rel WIDTH_BYTE]
je .write
cmp sil, 0
je .write
jmp .panic
.write:
mov rsi, rdx
@ -1619,31 +1683,6 @@ codegen_write_width:
.panic:
call panic
;; rdi: *text
;; rsi: src: *Operand
;; rdx: rbp offset
codegen_move_rbp_slot_src:
push rbp
mov rbp, rsp
sub rsp, 16
; construct dst Operand
mov byte [rsp + 0], OPERAND_RBP_OFFSET ; Operand.kind
mov byte [rsp + 1], 0 ; Operand.register = undef
mov word [rsp + 2], 8 ; Operand.width = 8
mov word [rsp + 4], 0 ; Operand.len = 0
mov qword [rsp + 8], rdx ; Operand.value = rbp offset
mov rdx, rsi
lea rsi, [rsp + 0] ; dst
call codegen_move_dst_src
add rsp, 16
pop rbp
ret
;; rdi: *function_ctx
;; rsi: *text
;; rdx: lhs: *Operand
@ -1666,7 +1705,7 @@ codegen_binary_op_rm64_rm64:
; if lhs.kind == REGISTER || lhs.kind < ADDRESS && rhs.kind == REGISTER {
cmp byte [rdx + 0], OPERAND_REGISTER
je .simple
cmp byte [rdx + 0], OPERAND_ADDRESS
cmp byte [rdx + 0], OPERAND_RBP_PVALUE
setb al
cmp byte [rcx + 0], OPERAND_REGISTER
sete bl
@ -1712,8 +1751,8 @@ codegen_binary_op_rm64_rm64:
jmp .epilogue
; } else {
.complex:
; if lhs.kind < ADDRESS {
cmp byte [rdx + 0], OPERAND_ADDRESS
; if lhs.kind < RBP_PVALUE {
cmp byte [rdx + 0], OPERAND_RBP_PVALUE
jae .check_rhs
; mov rax, rhs
@ -1741,8 +1780,8 @@ codegen_binary_op_rm64_rm64:
jmp .epilogue
.check_rhs:
; } else if rhs.kind < ADDRESS {
cmp byte [rcx + 0], OPERAND_ADDRESS
; } else if rhs.kind < RBP_PVALUE {
cmp byte [rcx + 0], OPERAND_RBP_PVALUE
jae .allocate_dst
; mov rax, lhs
mov rdi, [rsp + 8] ; *text
@ -1848,7 +1887,7 @@ codegen_binary_op_unchecked:
call codegen_write_operand
mov byte [rsp + 31], 10 ; newline
mov rdi, [rsp + 8] ; *text
mov rdi, [rsp] ; *text
lea rsi, [rsp + 31]
call vec_push
@ -1856,6 +1895,59 @@ codegen_binary_op_unchecked:
pop rbp
ret
;; rdi: *text
;; rsi: dst: *Operand
;; rdx: bits
;; rcx: width
codegen_load_imm:
push rbp
mov rbp, rsp
sub rsp, 32
mov [rsp], rdi ; *text
mov [rsp + 8], rsi ; dst
mov rax, [rel OPERAND_IMM]
mov [rsp + 16], rax ; Operand
mov [rsp + 24], rdx ; Operand.value
cmp byte [rsi + 0], OPERAND_LAST_VALUE
jg .panic ; unsupported dst kind
cmp rcx, 8
jl .direct
jg .panic ; unsupported immediate size
.indirect:
; mov rax, bits
; mov dst, rax
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RAX]
lea rdx, [rsp + 16] ; imm
mov rcx, 'mov '
call codegen_binary_op_unchecked
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; dst
lea rdx, [rel OPERAND_RAX]
mov rcx, 'mov '
call codegen_binary_op_unchecked
.direct:
; mov dst, bits
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; dst
lea rdx, [rsp + 16] ; imm
mov rcx, 'mov '
call codegen_binary_op_unchecked
add rsp, 32
pop rbp
ret
.panic:
call panic
;; rdi: *text
;; rsi: dst: *Operand
;; rdx: src: *Operand
@ -1864,14 +1956,27 @@ codegen_move_dst_src:
mov rbp, rsp
push rbx
sub rsp, 24
mov [rsp], rdi ; *text
mov [rsp + 8], rsi ; dst
mov [rsp + 16], rdx ; src
sub rsp, 32
mov [rsp], rdi ; *text
mov [rsp + 8], rsi ; dst
mov [rsp + 16], rdx ; src
mov qword [rsp + 24], 'mov ' ; op
cmp byte [rsi + 0], OPERAND_ADDRESS
cmp byte [rsi + 0], OPERAND_LAST_PLACE
jg .panic ; unsupported dst kind
cmp byte [rdx + 0], OPERAND_LAST_PLACE
jg .panic ; unsupported src kind
; op = src.is_place().then("lea ").else("mov ")
cmp byte [rdx + 0], OPERAND_LAST_VALUE
jb .mov
; an address stored in a stack slot has to be moved
cmp byte [rdx + 0], OPERAND_RBP_PLACE
je .mov
mov qword [rsp + 24], 'lea '
.mov:
; if dst.width != src.width
mov cx, word [rsi + 2] ; dst.width
mov bx, word [rdx + 2] ; src.width
@ -1888,55 +1993,70 @@ codegen_move_dst_src:
cmp byte [rsi + 0], OPERAND_REGISTER
je .do_move ; if dst == register, do move
; If dst != register and src != register, we cannot move directly into memory:
; there is no MOV m64, m64 or MOV m64, imm64 instruction.
; A smarter compiler could test for the immediate size and move most
; immediates directly into memory, but we are quite stupid!
; there is no MOV m64, m64 instruction.
cmp byte [rdx + 0], OPERAND_REGISTER
jne .xchg_rax
jne .indirect_rax
jmp .do_move
.xchg_rax:
; mov rax, [src]
.indirect_rax:
cmp byte [rsi + 0], OPERAND_RBP_PLACE
je .indirect_xchg
; op rax, [src]
; mov [dst], rax
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RAX]
mov rdx, [rsp + 16] ; src
call codegen_move_dst_src
mov rcx, [rsp + 24] ; op
call codegen_binary_op_unchecked
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; src
mov rsi, [rsp + 8] ; dst
lea rdx, [rel OPERAND_RAX]
call codegen_move_dst_src
mov rcx, 'mov '
call codegen_binary_op_unchecked
jmp .epilogue
.indirect_xchg:
; xchg rdx, dst
; mov rax, src
; mov [rdx], rax
; xchg rdx, dst
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RDX] ; rdx
mov rdx, [rsp + 8] ; dst
mov rcx, 'xchg '
call codegen_binary_op_unchecked
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RAX]
mov rdx, [rsp + 16] ; src
mov rcx, [rsp + 24] ; op
call codegen_binary_op_unchecked
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RDX_P] ; [rdx]
lea rdx, [rel OPERAND_RAX] ; rax
mov rcx, 'mov '
call codegen_binary_op_unchecked
mov rdi, [rsp] ; *text
lea rsi, [rel OPERAND_RDX] ; rdx
mov rdx, [rsp + 8] ; dst
mov rcx, 'xchg '
call codegen_binary_op_unchecked
jmp .epilogue
.do_move:
mov rdi, [rsp] ; *text
lea rsi, [rel MOV_RAX_COMMA]
mov rdx, 4
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 8] ; dst
call codegen_write_operand
mov rdi, [rsp] ; *text
lea rsi, [rel COMMA_RAX]
mov rdx, 2
call vec_extend
mov rdi, [rsp] ; *text
mov rsi, [rsp + 16] ; src
call codegen_write_operand
mov rdi, [rsp] ; *text
lea rsi, [rel COLON_NL]
inc rsi
call vec_push
mov rdx, [rsp + 16] ; src
mov rcx, [rsp + 24] ; op
call codegen_binary_op_unchecked
.epilogue:
add rsp, 24
add rsp, 32
pop rbx
pop rbp
ret

View file

@ -60,50 +60,57 @@ fn main() {
};
}
print_ast(
b"fn main() -> void { return 1 * 2 + 3 * 4; }",
|ast| unsafe { parse_func(ast) },
);
// print_ast(
// b"fn main() -> void { return 1 * 2 + 3 * 4; }",
// |ast| unsafe { parse_func(ast) },
// );
print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) });
print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe {
parse_func(ast)
});
print_ast(
b"fn main() -> void { ;;;return (1 + (2)); }",
|ast| unsafe { parse_func(ast) },
);
print_ast(
b"fn main() -> void { return (1 + (2 * 3)) / 4; }",
|ast| unsafe { parse_func(ast) },
);
print_ast(b"fn main() -> void { return 1 + 2 * 3; }", |ast| unsafe {
parse_func(ast)
});
// print_ast(b"3 + 4", |ast| unsafe { parse_expr(ast) });
// print_ast(b"fn main() -> void { return 1 + 2; }", |ast| unsafe {
// parse_func(ast)
// });
// print_ast(
// b"fn main() -> void { ;;;return (1 + (2)); }",
// |ast| unsafe { parse_func(ast) },
// );
// print_ast(
// b"fn main() -> void { return (1 + (2 * 3)) / 4; }",
// |ast| unsafe { parse_func(ast) },
// );
// print_ast(b"fn main() -> void { return 1 + 2 * 3; }", |ast| unsafe {
// parse_func(ast)
// });
print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe {
parse_func(ast)
});
// print_ast(b"fn main() -> void { let x: u32 = 4; }", |ast| unsafe {
// parse_func(ast)
// });
// print_ast(
// b"fn main(a: u32) -> void { let x: u32 = a + 4; }",
// |ast| unsafe { parse_func(ast) },
// );
// print_ast(
// b"fn main(a: u32) -> void {
// let y: u32 = a + 4;
// let y: *u32 = &y;
// return *y;
// }",
// |ast| unsafe { parse_func(ast) },
// );
// print_ast(
// b"fn main(a: u32) -> void {
// let y: u32 = a + 4;
// {
// let y: u32 = 10;
// }
// let y: *u32 = &y;
// return *y;
// }",
// |ast| unsafe { parse_func(ast) },
// );
print_ast(
b"fn main(a: u32) -> void { let x: u32 = a + 4; }",
|ast| unsafe { parse_func(ast) },
);
print_ast(
b"fn main(a: u32) -> void {
let y: u32 = a + 4;
let y: *u32 = &y;
return *y;
}",
|ast| unsafe { parse_func(ast) },
);
print_ast(
b"fn main(a: u32) -> void {
let y: u32 = a + 4;
{
let y: u32 = 10;
}
let y: *u32 = &y;
return *y;
b"fn main(a: *u32, b: u32) -> void {
*a = b;
a = &b;
}",
|ast| unsafe { parse_func(ast) },
);

View file

@ -21,6 +21,7 @@ unsafe extern "C" {
pub unsafe fn stackvar_cmp(a: *const (u64, u64), b: *const (u64, u64)) -> i32;
pub unsafe fn codegen_allocate_register(ctx: *mut FunctionCtx) -> u8;
pub unsafe fn codegen_allocate_place(ctx: *mut FunctionCtx, width: u16) -> Operand;
pub unsafe fn codegen_allocate_stack_value(ctx: *mut FunctionCtx, width: u16) -> Operand;
pub unsafe fn codegen_allocate_value(ctx: *mut FunctionCtx, width: u16) -> Operand;
pub unsafe fn codegen_free_operand(ctx: *mut FunctionCtx, operand: *const Operand) -> ();
pub unsafe fn codegen_function(ast: *const CodegenCtx, func_idx: u64) -> ();
@ -58,14 +59,18 @@ pub const TYPE_U32: u8 = 4;
pub const TYPE_STR: u8 = 5;
pub const TYPE_POINTER: u8 = 6;
pub const OPERAND_REGISTER: u32 = 1;
pub const OPERAND_RBP_OFFSET: u32 = 2;
pub const OPERAND_RSP_OFFSET: u32 = 3;
pub const OPERAND_ADDRESS: u32 = 4;
pub const OPERAND_IMMEDIATE: u32 = 5;
pub const OPERAND_CONSTANT: u32 = 6;
pub const OPERAND_LABEL: u32 = 7;
pub const OPERAND_RBP_VALUE: u32 = 2;
pub const OPERAND_RBP_PVALUE: u32 = 3;
pub const OPERAND_ADDRESS_VALUE: u32 = 4;
pub const OPERAND_LAST_VALUE: u32 = 5;
pub const OPERAND_RBP_OFFSET: u32 = 6;
pub const OPERAND_ADDRESS_PLACE: u32 = 7;
pub const OPERAND_REGISTER_PLACE: u32 = 8;
pub const OPERAND_RBP_PLACE: u32 = 9;
pub const OPERAND_LAST_PLACE: u32 = 10;
pub const OPERAND_IMMEDIATE: u32 = 11;
pub const OPERAND_CONSTANT: u32 = 12;
pub const OPERAND_LABEL: u32 = 13;
pub const TOKEN_EOF: u8 = 0;
pub const TOKEN_LET: u8 = 1;
pub const TOKEN_IF: u8 = 2;