X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=main.asm;h=edcba0ae9421c712218041e64d4fc0872370f8d9;hb=2d2c007e5b5e2f9b79271d638863d77338969f38;hp=3187d043f0c730006a7ebf97ccf1c4587844272b;hpb=2f4b8a792fbf943f813bbcf09bff6ddd9f38855b;p=rrq%2Fjonasforth.git diff --git a/main.asm b/main.asm index 3187d04..edcba0a 100644 --- a/main.asm +++ b/main.asm @@ -59,8 +59,14 @@ macro forth label, name { dq docol } + + segment readable executable +entry main + +include "impl.asm" + main: cld ; Clear direction flag so LODSQ does the right thing. mov rbp, return_stack_top ; Initialize return stack @@ -95,37 +101,15 @@ forth_asm LIT, 'LIT' ;; dictionary entry for that word. If no such word exists, return 0. forth_asm FIND, 'FIND' mov [.rsi], rsi - pop [.search_length] - pop [.search_buffer] - ;; RSI contains the entry we are currently looking at + pop [find.search_length] + pop [find.search_buffer] mov rsi, [latest_entry] ; Start with the last added word + call find + push rsi -.loop: - movzx rcx, byte [rsi + 8] ; Length of word being looked at - cmp rcx, [.search_length] - jne .next ; If the words don't have the same length, we have the wrong word - - ;; Otherwise, we need to compare strings - lea rdx, [rsi + 8 + 1] ; Location of character being compared in entry - mov rdi, [.search_buffer] ; Location of character being compared in search buffer -.compare_char: - mov al, [rdx] - mov ah, [rdi] - cmp al, ah - jne .next ; They don't match; try again - inc rdx ; These characters match; look at the next ones - inc rdi - loop .compare_char - - jmp .found ; They match! We are done. - -.next: - mov rsi, [rsi] ; Look at the previous entry - cmp rsi, 0 - jnz .loop ; If there is no previous word, exit and return 0 - -.found: + mov rsi, [.rsi] + next push rsi mov rsi, [.rsi] @@ -200,98 +184,25 @@ forth SPACE, 'SPACE' ;; size. The pointer is valid until the next call to READ_WORD. forth_asm READ_WORD, 'READ-WORD' mov [.rsi], rsi - mov [.rax], rax - -.skip_whitespace: - ;; Read characters into .char_buffer until one of them is not whitespace. - mov rax, 0 - mov rdi, 0 - mov rsi, .char_buffer - mov rdx, 1 - syscall - cmp [.char_buffer], ' ' - je .skip_whitespace - cmp [.char_buffer], $A - je .skip_whitespace - -.alpha: - ;; We got a character that wasn't whitespace. Now read the actual word. - mov [.length], 0 - -.read_alpha: - mov al, [.char_buffer] - movzx rbx, [.length] - mov rsi, .buffer - add rsi, rbx - mov [rsi], al - inc [.length] - - mov rax, 0 - mov rdi, 0 - mov rsi, .char_buffer - mov rdx, 1 - syscall - - cmp [.char_buffer], ' ' - je .end - cmp [.char_buffer], $A - jne .read_alpha - -.end: - push .buffer - movzx rax, [.length] - push rax + call read_word + push rdi ; Buffer + push rdx ; Length mov rsi, [.rsi] - mov rax, [.rax] - next ;; Takes a string on the stack and replaces it with the decimal number that the ;; string represents. forth_asm PARSE_NUMBER, 'PARSE-NUMBER' - pop [.length] ; Length - pop rdi ; String pointer - mov r8, 0 ; Result + pop [parse_number.length] ; Length + pop [parse_number.buffer] ; String pointer - ;; Add (10^(rcx-1) * parse_char(rdi[length - rcx])) to the accumulated value - ;; for each rcx. - mov rcx, [.length] -.loop: - ;; First, calcuate 10^(rcx - 1) - mov rax, 1 - - mov r9, rcx - .exp_loop: - dec r9 - jz .break - mov rbx, 10 - mul rbx - jmp .exp_loop - .break: - - ;; Now, rax = 10^(rcx - 1). - - ;; We need to calulate the value of the character at rdi[length - rcx]. - mov rbx, rdi - add rbx, [.length] - sub rbx, rcx - movzx rbx, byte [rbx] - sub rbx, '0' - - ;; Multiply this value by rax to get (10^(rcx-1) * parse_char(rdi[length - rcx])), - ;; then add this to the result. - mul rbx - - ;; Add that value to r8 - add r8, rax - - dec rcx - jnz .loop - - push r8 + push rsi + call parse_number + pop rsi + push rax ; Result next forth READ_NUMBER, 'READ-NUMBER' @@ -331,6 +242,15 @@ forth HELLO, 'HELLO' dq NEWLINE dq EXIT +;; The INTERPRET word reads and interprets user input. It's behavior depends on +;; the current STATE. It provides special handling for integers. (TODO) +forth INTERPRET, 'INTERPRET' + dq READ_WORD + dq FIND + dq TCFA + dq EXEC + dq EXIT + ;; .U prints the value on the stack as an unsigned integer in hexadecimal. forth_asm DOTU, '.U' mov [.length], 0 @@ -392,26 +312,44 @@ forth_asm DOTU, '.U' pop rsi next +;; Takes a value and an address, and stores the value at the given address. +forth_asm PUT, '!' + pop rbx ; Address + pop rax ; Value + mov [rbx], rax + next + +;; Takes an address and returns the value at the given address. +forth_asm GET, '@' + pop rax + mov rax, [rax] + push rax + next + +;; Get the location of the STATE variable. It can be set with '!' and read with +;; '@'. +forth STATE, 'STATE' + dq LIT, var_STATE + dq EXIT + forth MAIN, 'MAIN' dq HELLO - dq READ_WORD, FIND, TCFA, EXEC - dq BRANCH, -8 * 5 + dq INTERPRET + dq BRANCH, -8 * 2 dq TERMINATE segment readable writable latest_entry dq initial_latest_entry -FIND.search_length dq ? -FIND.search_buffer dq ? +;; The STATE variable is 0 when the interpreter is executing, and non-zero when +;; it is compiling. +var_STATE dq 0 + FIND.rsi dq ? READ_WORD.rsi dq ? -READ_WORD.rax dq ? -READ_WORD.max_size = $FF -READ_WORD.buffer rb READ_WORD.max_size -READ_WORD.length db ? -READ_WORD.char_buffer db ? +READ_WORD.rbp dq ? DOTU.chars db '0123456789ABCDEF' DOTU.buffer rq 16 ; 64-bit number has no more than 16 digits in hex @@ -419,8 +357,6 @@ DOTU.rbuffer rq 16 DOTU.length dq ? DOTU.printed_length dq ? -PARSE_NUMBER.length dq ? - ;; Return stack rq $2000 return_stack_top: