Compare commits
No commits in common. "cfc1c8e3b346db232e9c28fc7983b9d8756b7844" and "f1faac639c036dcd1bd0145362e405230cc0d947" have entirely different histories.
cfc1c8e3b3
...
f1faac639c
|
|
@ -1,7 +1,7 @@
|
||||||
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
|
# Makefile: Compile and link main.asm using nasm and mold, intermediate files in target/
|
||||||
|
|
||||||
TARGET_DIR := target
|
TARGET_DIR := target
|
||||||
SRC := src/lib.asm src/int_to_str.asm src/vec.asm src/tokeniser.asm src/file.asm
|
SRC := src/lib.asm src/int_to_str.asm src/vec.asm
|
||||||
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
|
OBJ := $(patsubst src/%.asm,$(TARGET_DIR)/%.o,$(SRC))
|
||||||
|
|
||||||
BIN_SRC := src/main.asm src/panic.asm
|
BIN_SRC := src/main.asm src/panic.asm
|
||||||
|
|
@ -28,7 +28,7 @@ test: test-bins
|
||||||
# pattern rule: compile each .rs into a binary with the same base name
|
# pattern rule: compile each .rs into a binary with the same base name
|
||||||
$(TARGET_DIR)/tests/%: tests/%.rs | $(OBJ) $(TARGET_DIR)/tests
|
$(TARGET_DIR)/tests/%: tests/%.rs | $(OBJ) $(TARGET_DIR)/tests
|
||||||
@echo "[$(RUSTC)] $< -> $@"
|
@echo "[$(RUSTC)] $< -> $@"
|
||||||
rustc -Clink-arg=-fuse-ld=mold --edition=2024 $(OBJ_LINK_ARGS) -g -o $@ $<
|
rustc -Clink-arg=-fuse-ld=mold $(OBJ_LINK_ARGS) -g -o $@ $<
|
||||||
|
|
||||||
$(TARGET_DIR):
|
$(TARGET_DIR):
|
||||||
mkdir -p $(TARGET_DIR)/tests
|
mkdir -p $(TARGET_DIR)/tests
|
||||||
|
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
section .data
|
|
||||||
file_error_msg db "Could not open file: "
|
|
||||||
file_error_msg_len equ $ - file_error_msg
|
|
||||||
|
|
||||||
|
|
||||||
section .text
|
|
||||||
global fopen_read
|
|
||||||
|
|
||||||
extern strlen
|
|
||||||
|
|
||||||
extern eprint_str
|
|
||||||
extern panic
|
|
||||||
extern error_to_str
|
|
||||||
extern eprint_error
|
|
||||||
|
|
||||||
;; Opens file for reading:
|
|
||||||
;; rdi: pointer to filename (null-terminated)
|
|
||||||
fopen_read:
|
|
||||||
mov rax, 2 ; syscall: open
|
|
||||||
mov rsi, 0 ; flags: O_RDONLY
|
|
||||||
mov rdx, 0 ; mode
|
|
||||||
syscall
|
|
||||||
cmp rax, 0
|
|
||||||
jl .file_error
|
|
||||||
ret ;fd in rax
|
|
||||||
|
|
||||||
.file_error:
|
|
||||||
push rdi
|
|
||||||
mov rdi, rax
|
|
||||||
call eprint_error
|
|
||||||
|
|
||||||
lea rdi, [rel file_error_msg]
|
|
||||||
mov rsi, file_error_msg_len
|
|
||||||
call eprint_str
|
|
||||||
|
|
||||||
pop rdi
|
|
||||||
call strlen ; get length of filename
|
|
||||||
mov rsi, rax ; r9 = filename length
|
|
||||||
call eprint_str
|
|
||||||
|
|
||||||
mov rdi, 10
|
|
||||||
push rdi
|
|
||||||
mov rdi, rsp
|
|
||||||
mov rsi, 1
|
|
||||||
call eprint_str
|
|
||||||
pop rdi
|
|
||||||
|
|
||||||
call panic
|
|
||||||
|
|
@ -26,7 +26,6 @@ global allocate
|
||||||
|
|
||||||
global is_alpha
|
global is_alpha
|
||||||
global is_numeric
|
global is_numeric
|
||||||
global is_whitespace
|
|
||||||
global is_id_continue
|
global is_id_continue
|
||||||
global is_id_start
|
global is_id_start
|
||||||
|
|
||||||
|
|
@ -38,8 +37,8 @@ extern panic
|
||||||
|
|
||||||
;; Abort the program with a default panic message
|
;; Abort the program with a default panic message
|
||||||
oom:
|
oom:
|
||||||
lea rdi, [rel oom_msg]
|
lea rdi, [oom_msg]
|
||||||
mov rsi, oom_msg_len
|
lea rsi, [oom_msg_len]
|
||||||
call eprint_str
|
call eprint_str
|
||||||
; exit with error code 1
|
; exit with error code 1
|
||||||
mov rax, 60 ; syscall: exit
|
mov rax, 60 ; syscall: exit
|
||||||
|
|
@ -292,8 +291,8 @@ eprint_error:
|
||||||
; let err_code = err_code;
|
; let err_code = err_code;
|
||||||
push rdi
|
push rdi
|
||||||
; eprint_str(ERROR_STR, ERROR_STR.len());
|
; eprint_str(ERROR_STR, ERROR_STR.len());
|
||||||
lea rdi, [rel error_msg]
|
lea rdi, [error_msg]
|
||||||
mov rsi, error_msg_len
|
lea rsi, [error_msg_len]
|
||||||
call eprint_str
|
call eprint_str
|
||||||
; let (err, len) = error_to_str(err_code);
|
; let (err, len) = error_to_str(err_code);
|
||||||
pop rdi
|
pop rdi
|
||||||
|
|
@ -366,13 +365,11 @@ is_numeric:
|
||||||
is_id_continue:
|
is_id_continue:
|
||||||
call is_alpha
|
call is_alpha
|
||||||
test rax, rax
|
test rax, rax
|
||||||
jne .is_id_continue_ret
|
je .is_id_continue_ret
|
||||||
call is_numeric
|
call is_numeric
|
||||||
test rax, rax
|
test rax, rax
|
||||||
jne .is_id_continue_ret
|
|
||||||
cmp cl, '_'
|
|
||||||
je .is_id_continue_ret
|
je .is_id_continue_ret
|
||||||
cmp cl, '-'
|
cmp cl, '_'
|
||||||
je .is_id_continue_ret
|
je .is_id_continue_ret
|
||||||
xor rax, rax
|
xor rax, rax
|
||||||
ret
|
ret
|
||||||
|
|
@ -384,7 +381,7 @@ is_id_continue:
|
||||||
is_id_start:
|
is_id_start:
|
||||||
call is_alpha
|
call is_alpha
|
||||||
test rax, rax
|
test rax, rax
|
||||||
jne .is_ret
|
je .is_ret
|
||||||
cmp cl, '_'
|
cmp cl, '_'
|
||||||
je .is_ret
|
je .is_ret
|
||||||
xor rax, rax
|
xor rax, rax
|
||||||
|
|
@ -395,7 +392,7 @@ is_id_start:
|
||||||
|
|
||||||
;; dil: byte to check
|
;; dil: byte to check
|
||||||
is_whitespace:
|
is_whitespace:
|
||||||
cmp dil, 32 ; space
|
cmp dil, ' '
|
||||||
je .is_ws
|
je .is_ws
|
||||||
cmp dil, 9 ; tab
|
cmp dil, 9 ; tab
|
||||||
je .is_ws
|
je .is_ws
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,14 @@ extern error_to_str
|
||||||
extern eprint_error
|
extern eprint_error
|
||||||
extern alloc_pages
|
extern alloc_pages
|
||||||
extern allocate
|
extern allocate
|
||||||
extern fopen_read
|
|
||||||
|
|
||||||
extern is_alpha
|
extern is_alpha
|
||||||
extern is_numeric
|
extern is_numeric
|
||||||
extern is_id_continue
|
extern is_id_continue
|
||||||
extern is_id_start
|
extern is_id_start
|
||||||
|
|
||||||
|
extern vec_tests
|
||||||
|
|
||||||
section .data
|
section .data
|
||||||
hello_msg db "Hello, World!", 10
|
hello_msg db "Hello, World!", 10
|
||||||
hello_msg_len equ $ - hello_msg
|
hello_msg_len equ $ - hello_msg
|
||||||
|
|
@ -70,6 +71,41 @@ compiler_entry:
|
||||||
.exit:
|
.exit:
|
||||||
call exit
|
call exit
|
||||||
|
|
||||||
|
|
||||||
|
;; Opens file for reading:
|
||||||
|
;; rdi: pointer to filename (null-terminated)
|
||||||
|
fopen_read:
|
||||||
|
mov rax, 2 ; syscall: open
|
||||||
|
mov rsi, 0 ; flags: O_RDONLY
|
||||||
|
mov rdx, 0 ; mode
|
||||||
|
syscall
|
||||||
|
cmp rax, 0
|
||||||
|
jl .file_error
|
||||||
|
ret ;fd in rax
|
||||||
|
|
||||||
|
.file_error:
|
||||||
|
push rdi
|
||||||
|
mov rdi, rax
|
||||||
|
call eprint_error
|
||||||
|
|
||||||
|
lea rdi, [rel file_error_msg]
|
||||||
|
lea rsi, [rel file_error_msg_len]
|
||||||
|
call eprint_str
|
||||||
|
|
||||||
|
pop rdi
|
||||||
|
call strlen ; get length of filename
|
||||||
|
mov rsi, rax ; r9 = filename length
|
||||||
|
call eprint_str
|
||||||
|
|
||||||
|
mov rdi, 10
|
||||||
|
push rdi
|
||||||
|
mov rdi, rsp
|
||||||
|
mov rsi, 1
|
||||||
|
call eprint_str
|
||||||
|
pop rdi
|
||||||
|
|
||||||
|
call panic
|
||||||
|
|
||||||
;; =============================
|
;; =============================
|
||||||
;; Tokeniser functions
|
;; Tokeniser functions
|
||||||
;; =============================
|
;; =============================
|
||||||
|
|
|
||||||
|
|
@ -1,498 +0,0 @@
|
||||||
section .text
|
|
||||||
extern panic
|
|
||||||
extern strlen
|
|
||||||
extern strcmp
|
|
||||||
extern streq
|
|
||||||
extern memcpy
|
|
||||||
extern eprint_str
|
|
||||||
extern exit
|
|
||||||
extern error_to_str
|
|
||||||
extern eprint_error
|
|
||||||
extern alloc_pages
|
|
||||||
extern allocate
|
|
||||||
extern fopen_read
|
|
||||||
|
|
||||||
extern is_alpha
|
|
||||||
extern is_numeric
|
|
||||||
extern is_id_continue
|
|
||||||
extern is_id_start
|
|
||||||
extern is_whitespace
|
|
||||||
|
|
||||||
global tokeniser_init
|
|
||||||
global tokeniser_print
|
|
||||||
global find_lexeme
|
|
||||||
|
|
||||||
;; =============================
|
|
||||||
;; Tokeniser functions
|
|
||||||
;; =============================
|
|
||||||
|
|
||||||
;; tokeniser state
|
|
||||||
section .data
|
|
||||||
global input_file
|
|
||||||
global buffer
|
|
||||||
global cursor
|
|
||||||
global buffer_len
|
|
||||||
|
|
||||||
input_file dd 0
|
|
||||||
buffer dq 0
|
|
||||||
cursor dq 0
|
|
||||||
buffer_len dq 0
|
|
||||||
|
|
||||||
;; each buffer is chunk_size bytes large
|
|
||||||
;; buffer header structure:
|
|
||||||
;; +0 (8 bytes): pointer buffer
|
|
||||||
;; +8 (8 bytes): size of buffer
|
|
||||||
|
|
||||||
;; Tokens:
|
|
||||||
;; [let, if, else, fn, return, loop, break, continue, true, false, i32, u32, bool, =, +, -, *, /, %, ==, !=, <, <=, >, >=, &&, ||, !, (, ), {, }, [, ], ;, ',', ]
|
|
||||||
|
|
||||||
section .bss
|
|
||||||
statbuf: resb 144
|
|
||||||
|
|
||||||
section .text
|
|
||||||
;; Initialises the tokeniser
|
|
||||||
;; rdx: pointer to filename (null-terminated)
|
|
||||||
tokeniser_init:
|
|
||||||
; open file for reading
|
|
||||||
; this panics if the file doesn't exist
|
|
||||||
call fopen_read
|
|
||||||
mov dword [rel input_file], eax ; store file descriptor
|
|
||||||
mov qword [rel cursor], 0
|
|
||||||
mov qword [rel buffer_len], 0
|
|
||||||
; fstat
|
|
||||||
mov rax, 5 ; syscall: fstat
|
|
||||||
mov rdi, [rel input_file] ; fd
|
|
||||||
lea rsi, [rel statbuf] ; statbuf
|
|
||||||
syscall
|
|
||||||
cmp rax, 0
|
|
||||||
jl .report_error
|
|
||||||
; get file size from statbuf
|
|
||||||
lea r15, [rel statbuf] ; st_size
|
|
||||||
mov r15, [r15 + 48] ; offset of st_size in stat struct
|
|
||||||
|
|
||||||
; allocate buffer
|
|
||||||
mov rdi, r15
|
|
||||||
call allocate
|
|
||||||
mov qword [rel buffer], rax
|
|
||||||
mov qword [rel buffer_len], r15
|
|
||||||
|
|
||||||
; read file into buffer
|
|
||||||
mov rax, 0 ; syscall: read
|
|
||||||
mov edi, [rel input_file] ; fd
|
|
||||||
mov rsi, [rel buffer] ; buf
|
|
||||||
mov rdx, [rel buffer_len] ; count
|
|
||||||
syscall
|
|
||||||
cmp rax, 0
|
|
||||||
jl .report_error
|
|
||||||
ret
|
|
||||||
.report_error:
|
|
||||||
mov rcx, rax
|
|
||||||
call eprint_error
|
|
||||||
call panic
|
|
||||||
|
|
||||||
section .rdata
|
|
||||||
tokeniser_buffer db "Tokeniser buffer: ", 10
|
|
||||||
tokeniser_buffer_len equ $ - tokeniser_buffer
|
|
||||||
|
|
||||||
section .text
|
|
||||||
tokeniser_print:
|
|
||||||
lea rdi, [rel tokeniser_buffer]
|
|
||||||
mov rsi, tokeniser_buffer_len
|
|
||||||
call eprint_str
|
|
||||||
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
mov rdi, [rel buffer]
|
|
||||||
add rdi, rax
|
|
||||||
mov rsi, [rel buffer_len]
|
|
||||||
call eprint_str
|
|
||||||
ret
|
|
||||||
|
|
||||||
section .rdata
|
|
||||||
global LEXEMES
|
|
||||||
global TOKENS
|
|
||||||
global LEXEME_LENS
|
|
||||||
global NUM_LEXEMES
|
|
||||||
|
|
||||||
align 8
|
|
||||||
LEXEMES:
|
|
||||||
dq LEX_NOT_A_LEXEME
|
|
||||||
dq LEX_LET
|
|
||||||
dq LEX_IF
|
|
||||||
dq LEX_ELSE
|
|
||||||
dq LEX_FN
|
|
||||||
dq LEX_RETURN
|
|
||||||
dq LEX_LOOP
|
|
||||||
dq LEX_BREAK
|
|
||||||
dq LEX_CONTINUE
|
|
||||||
dq LEX_TRUE
|
|
||||||
dq LEX_FALSE
|
|
||||||
dq LEX_BOOL
|
|
||||||
dq LEX_ARROW
|
|
||||||
dq LEX_I32
|
|
||||||
dq LEX_U32
|
|
||||||
dq LEX_EQUALS
|
|
||||||
dq LEX_PLUS
|
|
||||||
dq LEX_MINUS
|
|
||||||
dq LEX_RPARENS
|
|
||||||
dq LEX_LPARENS
|
|
||||||
dq LEX_RBRACE
|
|
||||||
dq LEX_LBRACE
|
|
||||||
dq LEX_COLON
|
|
||||||
dq LEX_SEMI
|
|
||||||
dq LEX_COMMA
|
|
||||||
dq LEX_PIPE
|
|
||||||
dq LEX_AMP
|
|
||||||
dq LEX_EQEQ
|
|
||||||
dq LEX_LBRACKET
|
|
||||||
dq LEX_RBRACKET
|
|
||||||
|
|
||||||
align 8
|
|
||||||
TOKENS:
|
|
||||||
db TOKEN_EOF ;; 0
|
|
||||||
db TOKEN_LET ;; 1
|
|
||||||
db TOKEN_IF ;; 2
|
|
||||||
db TOKEN_ELSE ;; 3
|
|
||||||
db TOKEN_FN ;; 4
|
|
||||||
db TOKEN_RETURN ;; 5
|
|
||||||
db TOKEN_LOOP ;; 6
|
|
||||||
db TOKEN_BREAK ;; 7
|
|
||||||
db TOKEN_CONTINUE ;; 8
|
|
||||||
db TOKEN_TRUE ;; 9
|
|
||||||
db TOKEN_FALSE ;; 10
|
|
||||||
db TOKEN_BOOL ;; 11
|
|
||||||
db TOKEN_ARROW ;; 12
|
|
||||||
db TOKEN_I32 ;; 13
|
|
||||||
db TOKEN_U32 ;; 14
|
|
||||||
db TOKEN_EQUALS ;; 15
|
|
||||||
db TOKEN_PLUS ;; 16
|
|
||||||
db TOKEN_MINUS ;; 17
|
|
||||||
db TOKEN_RPARENS ;; 18
|
|
||||||
db TOKEN_LPARENS ;; 19
|
|
||||||
db TOKEN_RBRACE ;; 20
|
|
||||||
db TOKEN_LBRACE ;; 21
|
|
||||||
db TOKEN_COLON ;; 22
|
|
||||||
db TOKEN_SEMI ;; 23
|
|
||||||
db TOKEN_COMMA ;; 24
|
|
||||||
db TOKEN_PIPE ;; 25
|
|
||||||
db TOKEN_AMP ;; 26
|
|
||||||
db TOKEN_EQEQ ;; 27
|
|
||||||
db TOKEN_LBRACKET ;; 28
|
|
||||||
db TOKEN_RBRACKET ;; 29
|
|
||||||
|
|
||||||
align 8
|
|
||||||
LEXEME_LENS:
|
|
||||||
dq 0
|
|
||||||
dq LEX_LET_len
|
|
||||||
dq LEX_IF_len
|
|
||||||
dq LEX_ELSE_len
|
|
||||||
dq LEX_FN_len
|
|
||||||
dq LEX_RETURN_len
|
|
||||||
dq LEX_LOOP_len
|
|
||||||
dq LEX_BREAK_len
|
|
||||||
dq LEX_CONTINUE_len
|
|
||||||
dq LEX_TRUE_len
|
|
||||||
dq LEX_FALSE_len
|
|
||||||
dq LEX_BOOL_len
|
|
||||||
dq LEX_ARROW_len
|
|
||||||
dq LEX_I32_len
|
|
||||||
dq LEX_U32_len
|
|
||||||
dq LEX_EQUALS_len
|
|
||||||
dq LEX_PLUS_len
|
|
||||||
dq LEX_MINUS_len
|
|
||||||
dq LEX_RPARENS_len
|
|
||||||
dq LEX_LPARENS_len
|
|
||||||
dq LEX_RBRACE_len
|
|
||||||
dq LEX_LBRACE_len
|
|
||||||
dq LEX_COLON_len
|
|
||||||
dq LEX_SEMI_len
|
|
||||||
dq LEX_COMMA_len
|
|
||||||
dq LEX_PIPE_len
|
|
||||||
dq LEX_AMP_len
|
|
||||||
dq LEX_EQEQ_len
|
|
||||||
dq LEX_LBRACKET_len
|
|
||||||
dq LEX_RBRACKET_len
|
|
||||||
|
|
||||||
align 8
|
|
||||||
NUM_LEXEMES: dq 30
|
|
||||||
|
|
||||||
LEX_NOT_A_LEXEME db "<not a lexeme>", 0
|
|
||||||
TOKEN_EOF equ 0
|
|
||||||
TOKEN_LET equ 1
|
|
||||||
LEX_LET db "let"
|
|
||||||
LEX_LET_len equ $ - LEX_LET
|
|
||||||
TOKEN_IF equ 2
|
|
||||||
LEX_IF db "if"
|
|
||||||
LEX_IF_len equ $ - LEX_IF
|
|
||||||
TOKEN_ELSE equ 3
|
|
||||||
LEX_ELSE db "else"
|
|
||||||
LEX_ELSE_len equ $ - LEX_ELSE
|
|
||||||
TOKEN_FN equ 4
|
|
||||||
LEX_FN db "fn"
|
|
||||||
LEX_FN_len equ $ - LEX_FN
|
|
||||||
TOKEN_RETURN equ 5
|
|
||||||
LEX_RETURN db "return"
|
|
||||||
LEX_RETURN_len equ $ - LEX_RETURN
|
|
||||||
TOKEN_LOOP equ 6
|
|
||||||
LEX_LOOP db "loop"
|
|
||||||
LEX_LOOP_len equ $ - LEX_LOOP
|
|
||||||
TOKEN_BREAK equ 7
|
|
||||||
LEX_BREAK db "break"
|
|
||||||
LEX_BREAK_len equ $ - LEX_BREAK
|
|
||||||
TOKEN_CONTINUE equ 8
|
|
||||||
LEX_CONTINUE db "continue"
|
|
||||||
LEX_CONTINUE_len equ $ - LEX_CONTINUE
|
|
||||||
TOKEN_TRUE equ 9
|
|
||||||
LEX_TRUE db "true"
|
|
||||||
LEX_TRUE_len equ $ - LEX_TRUE
|
|
||||||
TOKEN_FALSE equ 10
|
|
||||||
LEX_FALSE db "false"
|
|
||||||
LEX_FALSE_len equ $ - LEX_FALSE
|
|
||||||
TOKEN_BOOL equ 11
|
|
||||||
LEX_BOOL db "bool"
|
|
||||||
LEX_BOOL_len equ $ - LEX_BOOL
|
|
||||||
TOKEN_ARROW equ 12
|
|
||||||
LEX_ARROW db "->"
|
|
||||||
LEX_ARROW_len equ $ - LEX_ARROW
|
|
||||||
TOKEN_I32 equ 13
|
|
||||||
LEX_I32 db "i32"
|
|
||||||
LEX_I32_len equ $ - LEX_I32
|
|
||||||
TOKEN_U32 equ 14
|
|
||||||
LEX_U32 db "u32"
|
|
||||||
LEX_U32_len equ $ - LEX_U32
|
|
||||||
TOKEN_EQUALS equ 15
|
|
||||||
LEX_EQUALS db "="
|
|
||||||
LEX_EQUALS_len equ $ - LEX_EQUALS
|
|
||||||
TOKEN_PLUS equ 16
|
|
||||||
LEX_PLUS db "+"
|
|
||||||
LEX_PLUS_len equ $ - LEX_PLUS
|
|
||||||
TOKEN_MINUS equ 17
|
|
||||||
LEX_MINUS db "-"
|
|
||||||
LEX_MINUS_len equ $ - LEX_MINUS
|
|
||||||
TOKEN_RPARENS equ 18
|
|
||||||
LEX_RPARENS db ")"
|
|
||||||
LEX_RPARENS_len equ $ - LEX_RPARENS
|
|
||||||
TOKEN_LPARENS equ 19
|
|
||||||
LEX_LPARENS db "("
|
|
||||||
LEX_LPARENS_len equ $ - LEX_LPARENS
|
|
||||||
TOKEN_RBRACE equ 20
|
|
||||||
LEX_RBRACE db "}"
|
|
||||||
LEX_RBRACE_len equ $ - LEX_RBRACE
|
|
||||||
TOKEN_LBRACE equ 21
|
|
||||||
LEX_LBRACE db "{"
|
|
||||||
LEX_LBRACE_len equ $ - LEX_LBRACE
|
|
||||||
TOKEN_COLON equ 22
|
|
||||||
LEX_COLON db ":"
|
|
||||||
LEX_COLON_len equ $ - LEX_COLON
|
|
||||||
TOKEN_SEMI equ 23
|
|
||||||
LEX_SEMI db ";"
|
|
||||||
LEX_SEMI_len equ $ - LEX_SEMI
|
|
||||||
TOKEN_COMMA equ 24
|
|
||||||
LEX_COMMA db ","
|
|
||||||
LEX_COMMA_len equ $ - LEX_COMMA
|
|
||||||
TOKEN_PIPE equ 25
|
|
||||||
LEX_PIPE db "|"
|
|
||||||
LEX_PIPE_len equ $ - LEX_PIPE
|
|
||||||
TOKEN_AMP equ 26
|
|
||||||
LEX_AMP db "&"
|
|
||||||
LEX_AMP_len equ $ - LEX_AMP
|
|
||||||
TOKEN_EQEQ equ 27
|
|
||||||
LEX_EQEQ db "=="
|
|
||||||
LEX_EQEQ_len equ $ - LEX_EQEQ
|
|
||||||
TOKEN_LBRACKET equ 28
|
|
||||||
LEX_LBRACKET db "["
|
|
||||||
LEX_LBRACKET_len equ $ - LEX_LBRACKET
|
|
||||||
TOKEN_RBRACKET equ 29
|
|
||||||
LEX_RBRACKET db "]"
|
|
||||||
LEX_RBRACKET_len equ $ - LEX_RBRACKET
|
|
||||||
TOKEN_IDENT equ 30
|
|
||||||
LEX_IDENT db "<identifier>"
|
|
||||||
LEX_IDENT_len equ $ - LEX_IDENT
|
|
||||||
TOKEN_NUMBER equ 31
|
|
||||||
LEX_NUMBER db "<number>"
|
|
||||||
LEX_NUMBER_len equ $ - LEX_NUMBER
|
|
||||||
|
|
||||||
|
|
||||||
section .text
|
|
||||||
;; rdi: length of matched lexeme
|
|
||||||
is_ident:
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
push r12
|
|
||||||
push r13
|
|
||||||
push r14
|
|
||||||
push rdi
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
mov r12, [rel buffer]
|
|
||||||
mov r13, [rel buffer_len]
|
|
||||||
sub r13, rax
|
|
||||||
add r12, rax
|
|
||||||
|
|
||||||
; check first char is id_start
|
|
||||||
mov dil, [r12]
|
|
||||||
call is_id_start
|
|
||||||
test rax, rax
|
|
||||||
je .not_ident
|
|
||||||
mov r14, 1
|
|
||||||
.loop:
|
|
||||||
cmp r14, r13
|
|
||||||
jge .done
|
|
||||||
mov dil, [r12 + r14]
|
|
||||||
; check for id_continue
|
|
||||||
call is_id_continue
|
|
||||||
test rax, rax
|
|
||||||
je .done
|
|
||||||
inc r14
|
|
||||||
jmp .loop
|
|
||||||
.done:
|
|
||||||
; r14 is length of ident
|
|
||||||
mov rdi, [rsp]
|
|
||||||
cmp r14, rdi
|
|
||||||
jle .not_ident
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
add rax, r14
|
|
||||||
mov [rel cursor], rax
|
|
||||||
mov rax, 1
|
|
||||||
jmp .epilogue
|
|
||||||
.not_ident:
|
|
||||||
xor rax, rax
|
|
||||||
.epilogue:
|
|
||||||
pop rdi
|
|
||||||
pop r14
|
|
||||||
pop r13
|
|
||||||
pop r12
|
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
|
|
||||||
is_number:
|
|
||||||
xor rax, rax
|
|
||||||
ret
|
|
||||||
|
|
||||||
skip_whitespaces:
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
push r12
|
|
||||||
push r13
|
|
||||||
push r14
|
|
||||||
; let start = buffer.add(cursor);
|
|
||||||
; let end = buffer.add(buffer_len);
|
|
||||||
mov r12, [rel cursor]
|
|
||||||
mov r13, [rel buffer_len]
|
|
||||||
mov r14, [rel buffer]
|
|
||||||
; for ptr in start..end {
|
|
||||||
.loop:
|
|
||||||
cmp r12, r13
|
|
||||||
jge .done
|
|
||||||
mov dil, [r14 + r12]
|
|
||||||
call is_whitespace
|
|
||||||
test rax, rax
|
|
||||||
je .done
|
|
||||||
inc r12
|
|
||||||
jmp .loop
|
|
||||||
.done:
|
|
||||||
mov [rel cursor], r12
|
|
||||||
pop r14
|
|
||||||
pop r13
|
|
||||||
pop r12
|
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
|
|
||||||
find_lexeme:
|
|
||||||
push rbp
|
|
||||||
mov rbp, rsp
|
|
||||||
; skip whitespaces
|
|
||||||
call skip_whitespaces
|
|
||||||
; check length
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
mov rcx, [rel buffer_len]
|
|
||||||
; if cursor >= buffer_len {
|
|
||||||
cmp rax, rcx
|
|
||||||
jge .eof
|
|
||||||
jmp .start
|
|
||||||
.eof:
|
|
||||||
; return TOKEN_EOF;
|
|
||||||
mov rax, TOKEN_EOF
|
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
; }
|
|
||||||
.start:
|
|
||||||
push r12
|
|
||||||
mov r12, 1
|
|
||||||
; for 1..NUM_LEXEMES {
|
|
||||||
.loop:
|
|
||||||
cmp r12, [rel NUM_LEXEMES]
|
|
||||||
jge .not_found
|
|
||||||
; let lexeme = LEXEMES[i];
|
|
||||||
lea rdi, [rel LEXEMES]
|
|
||||||
mov rdi, [rdi + r12*8]
|
|
||||||
lea rdx, [rel LEXEME_LENS]
|
|
||||||
mov rsi, [rdx + r12*8]
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
mov rdx, [rel buffer]
|
|
||||||
add rdx, rax
|
|
||||||
; let len = LEXEME_LENS[i];
|
|
||||||
mov rcx, [rel buffer_len]
|
|
||||||
sub rcx, rax
|
|
||||||
jo .not_found
|
|
||||||
; if lexeme.len() > buffer.len() - cursor {
|
|
||||||
cmp rsi, rcx
|
|
||||||
jg .next
|
|
||||||
; continue;
|
|
||||||
; }
|
|
||||||
mov rcx, rsi
|
|
||||||
; if buffer[cursor..cursor+len] == lexeme {
|
|
||||||
call streq
|
|
||||||
test rax, rax
|
|
||||||
je .next
|
|
||||||
; if is_ident() {
|
|
||||||
call is_ident
|
|
||||||
test rax, rax
|
|
||||||
; return TOKEN_IDENT;
|
|
||||||
jne .is_ident
|
|
||||||
; } else if is_number() {
|
|
||||||
call is_number
|
|
||||||
test rax, rax
|
|
||||||
; return TOKEN_NUMBER;
|
|
||||||
jne .is_number
|
|
||||||
; } else {
|
|
||||||
mov rax, [rel cursor]
|
|
||||||
; cursor += len;
|
|
||||||
lea rdi, [rel LEXEME_LENS]
|
|
||||||
mov rdi, [rdi + r12*8]
|
|
||||||
add rax, rdi
|
|
||||||
mov [rel cursor], rax
|
|
||||||
; return TOKENS[i];
|
|
||||||
lea rax, [rel TOKENS]
|
|
||||||
mov al, [rax + r12]
|
|
||||||
and rax, 0xFF
|
|
||||||
jmp .epilogue
|
|
||||||
; }
|
|
||||||
.next:
|
|
||||||
inc r12
|
|
||||||
jmp .loop
|
|
||||||
; }
|
|
||||||
; }
|
|
||||||
.not_found:
|
|
||||||
; if is_ident() {
|
|
||||||
call is_ident
|
|
||||||
test rax, rax
|
|
||||||
; return TOKEN_IDENT;
|
|
||||||
jne .is_ident
|
|
||||||
; } else if is_number() {
|
|
||||||
call is_number
|
|
||||||
test rax, rax
|
|
||||||
; return TOKEN_NUMBER;
|
|
||||||
jne .is_number
|
|
||||||
; } else {
|
|
||||||
; return TOKEN_EOF;
|
|
||||||
mov rax, TOKEN_EOF
|
|
||||||
; }
|
|
||||||
.epilogue:
|
|
||||||
pop r12
|
|
||||||
pop rbp
|
|
||||||
ret
|
|
||||||
.is_ident:
|
|
||||||
mov rax, TOKEN_IDENT
|
|
||||||
jmp .epilogue
|
|
||||||
.is_number:
|
|
||||||
mov rax, TOKEN_NUMBER
|
|
||||||
jmp .epilogue
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
if let else fn
|
|
||||||
|
|
@ -1,116 +0,0 @@
|
||||||
#[unsafe(no_mangle)]
|
|
||||||
extern "C" fn panic() -> ! {
|
|
||||||
panic!("Called panic from external code.");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
struct Lexeme(u8);
|
|
||||||
|
|
||||||
impl Lexeme {
|
|
||||||
fn lex(&self) -> &'static str {
|
|
||||||
// SAFETY: lens contains the correct length for each lexeme, and lexemes
|
|
||||||
// contains pointers to valid 'static UTF-8 data.
|
|
||||||
unsafe {
|
|
||||||
core::str::from_utf8_unchecked(
|
|
||||||
core::slice::from_raw_parts(
|
|
||||||
(&raw const LEXEMES).add((self.0) as usize).read(),
|
|
||||||
(&raw const LEXEME_LENS).add((self.0) as usize).read(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
trait AsLexeme {
|
|
||||||
fn as_lexeme(self) -> Option<Lexeme>;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsLexeme for u8 {
|
|
||||||
fn as_lexeme(self) -> Option<Lexeme> {
|
|
||||||
match self {
|
|
||||||
1.. => Some(Lexeme(self)),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
unsafe extern "C" {
|
|
||||||
unsafe fn tokeniser_init(path: *const i8) -> ();
|
|
||||||
unsafe fn tokeniser_print() -> ();
|
|
||||||
unsafe fn is_ident(len: usize) -> bool;
|
|
||||||
unsafe fn is_number(len: usize) -> bool;
|
|
||||||
unsafe fn skip_whitespace() -> ();
|
|
||||||
unsafe fn find_lexeme() -> u8;
|
|
||||||
|
|
||||||
static mut LEXEMES: *const u8;
|
|
||||||
static mut LEXEME_LENS: usize;
|
|
||||||
static mut NUM_LEXEMES: usize;
|
|
||||||
static mut TOKENS: u8;
|
|
||||||
|
|
||||||
static mut input_file: u32;
|
|
||||||
static mut buffer: *mut u8;
|
|
||||||
static mut cursor: usize;
|
|
||||||
static mut buffer_len: usize;
|
|
||||||
|
|
||||||
unsafe fn exit(code: i32) -> !;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn collect_tokens() -> Vec<Lexeme> {
|
|
||||||
let mut lexemes = Vec::new();
|
|
||||||
unsafe {
|
|
||||||
while let Some(lexeme) = find_lexeme().as_lexeme() {
|
|
||||||
lexemes.push(lexeme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lexemes
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
unsafe {
|
|
||||||
// assert initial state
|
|
||||||
assert_eq!((&raw const input_file).read(), 0);
|
|
||||||
assert_eq!((&raw const buffer_len).read(), 0);
|
|
||||||
assert_eq!((&raw const cursor).read(), 0);
|
|
||||||
assert_eq!((&raw const buffer).read(), core::ptr::null_mut());
|
|
||||||
|
|
||||||
eprint!("Initializing tokeniser.. ");
|
|
||||||
tokeniser_init(c"tests/tokens/keywords.l".as_ptr());
|
|
||||||
eprintln!("ok.");
|
|
||||||
|
|
||||||
assert_eq!(&collect_tokens()[..], &[
|
|
||||||
Lexeme(4),
|
|
||||||
Lexeme(1),
|
|
||||||
Lexeme(2),
|
|
||||||
Lexeme(3),
|
|
||||||
Lexeme(4),
|
|
||||||
Lexeme(8),
|
|
||||||
Lexeme(13),
|
|
||||||
Lexeme(11),
|
|
||||||
Lexeme(10),
|
|
||||||
Lexeme(9),
|
|
||||||
Lexeme(5),
|
|
||||||
][..]);
|
|
||||||
|
|
||||||
eprint!("Initializing tokeniser.. ");
|
|
||||||
tokeniser_init(c"tests/tokens/delimiters.l".as_ptr());
|
|
||||||
eprintln!("ok.");
|
|
||||||
|
|
||||||
assert_eq!(&collect_tokens()[..], &[
|
|
||||||
Lexeme(19),
|
|
||||||
Lexeme(18),
|
|
||||||
Lexeme(28),
|
|
||||||
Lexeme(29),
|
|
||||||
Lexeme(21),
|
|
||||||
Lexeme(20),
|
|
||||||
Lexeme(24),
|
|
||||||
Lexeme(12),
|
|
||||||
Lexeme(23),
|
|
||||||
Lexeme(22),
|
|
||||||
Lexeme(15),
|
|
||||||
][..]);
|
|
||||||
|
|
||||||
eprintln!("Finished tokenising.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
()[]{},->;:=
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
fn my-function() -> bool {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
this-is-an-ident
|
|
||||||
another_ident123
|
|
||||||
_underscore_test
|
|
||||||
mixedCASEIdent
|
|
||||||
number12345
|
|
||||||
____
|
|
||||||
_
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
fn let if else fn continue
|
|
||||||
i32 bool false true
|
|
||||||
return
|
|
||||||
|
|
@ -7,7 +7,7 @@ pub struct BlobVec {
|
||||||
pub drop: Option<extern "C" fn(*mut u8)>,
|
pub drop: Option<extern "C" fn(*mut u8)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[unsafe(no_mangle)]
|
#[no_mangle]
|
||||||
extern "C" fn panic() -> ! {
|
extern "C" fn panic() -> ! {
|
||||||
panic!("Called panic from external code.");
|
panic!("Called panic from external code.");
|
||||||
}
|
}
|
||||||
|
|
@ -20,25 +20,14 @@ unsafe extern "C" {
|
||||||
unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8, size: usize);
|
unsafe fn vec_push(vec: *mut BlobVec, elem: *const u8, size: usize);
|
||||||
unsafe fn vec_pop(vec: *mut BlobVec);
|
unsafe fn vec_pop(vec: *mut BlobVec);
|
||||||
unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8;
|
unsafe fn vec_get(vec: *mut BlobVec, index: usize) -> *mut u8;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
unsafe fn vec_remove(vec: *mut BlobVec, index: usize);
|
unsafe fn vec_remove(vec: *mut BlobVec, index: usize);
|
||||||
#[allow(dead_code)]
|
|
||||||
unsafe fn vec_drop(vec: *mut BlobVec);
|
unsafe fn vec_drop(vec: *mut BlobVec);
|
||||||
|
|
||||||
|
unsafe fn exit(code: i32) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
static mut DROPS: usize = 1;
|
static mut DROPS: usize = 1;
|
||||||
fn get_drops() -> usize {
|
|
||||||
unsafe { (&raw const DROPS).read() }
|
|
||||||
}
|
|
||||||
unsafe fn update_drops(f: impl FnOnce(&mut usize)) {
|
|
||||||
unsafe {
|
|
||||||
let drops = &raw mut DROPS;
|
|
||||||
f(&mut *drops);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut vec = BlobVec {
|
let mut vec = BlobVec {
|
||||||
data: core::ptr::null_mut(),
|
data: core::ptr::null_mut(),
|
||||||
len: 0,
|
len: 0,
|
||||||
|
|
@ -54,9 +43,7 @@ fn main() {
|
||||||
|
|
||||||
extern "C" fn drop(ptr: *mut u8) {
|
extern "C" fn drop(ptr: *mut u8) {
|
||||||
unsafe {
|
unsafe {
|
||||||
update_drops(|drops| {
|
DROPS *= ptr.cast::<u32>().read() as usize;
|
||||||
*drops *= ptr.cast::<u32>().read() as usize;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,10 +56,10 @@ fn main() {
|
||||||
assert_eq!(as_slice::<u32>(&vec), &[2]);
|
assert_eq!(as_slice::<u32>(&vec), &[2]);
|
||||||
let retrieved = *(vec_get(&mut vec, 0) as *mut u32);
|
let retrieved = *(vec_get(&mut vec, 0) as *mut u32);
|
||||||
assert_eq!(retrieved, 2);
|
assert_eq!(retrieved, 2);
|
||||||
assert_eq!(get_drops(), 1);
|
assert_eq!(DROPS, 1);
|
||||||
vec_pop(&mut vec);
|
vec_pop(&mut vec);
|
||||||
assert_eq!(vec.len, 0);
|
assert_eq!(vec.len, 0);
|
||||||
assert_eq!(get_drops(), 2);
|
assert_eq!(DROPS, 2);
|
||||||
value = 3;
|
value = 3;
|
||||||
vec_push(&mut vec, &value as *const u32 as *const u8, 4);
|
vec_push(&mut vec, &value as *const u32 as *const u8, 4);
|
||||||
assert_eq!(as_slice::<u32>(&vec), &[3]);
|
assert_eq!(as_slice::<u32>(&vec), &[3]);
|
||||||
|
|
@ -82,7 +69,7 @@ fn main() {
|
||||||
assert_eq!(vec.len, 2);
|
assert_eq!(vec.len, 2);
|
||||||
vec_pop(&mut vec);
|
vec_pop(&mut vec);
|
||||||
vec_pop(&mut vec);
|
vec_pop(&mut vec);
|
||||||
assert_eq!(get_drops(), 2 * 3 * 5);
|
assert_eq!(DROPS, 2 * 3 * 5);
|
||||||
eprintln!("Push/pop test passed\n");
|
eprintln!("Push/pop test passed\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue