X-Git-Url: https://git.rrq.au/?a=blobdiff_plain;f=impl.asm;h=6267b3e133980579a94bc8dacaf6654add18962e;hb=e528551bc019017d3a1313b9d8299d15cc5e3c82;hp=573646904581b28d7e9fc344f2137f6cda32519a;hpb=89a6a52d6128a4f9ac3c7aa26fc0df111e4160db;p=rrq%2Fjonasforth.git diff --git a/impl.asm b/impl.asm index 5736469..6267b3e 100644 --- a/impl.asm +++ b/impl.asm @@ -1,4 +1,30 @@ -segment readable executable +section '.text' code readable executable + +macro printlen msg, len { + push rsi + add rsp, 8 + + mov rcx, msg + mov rdx, len + call os_print_string + + sub rsp, 8 + pop rsi +} + +macro newline { + push $A + printlen rsp, 1 +} + +macro print msg { + printlen msg, msg#.len +} + +struc string bytes { + . db bytes + .len = $ - . +} ;; Find the given word in the dictionary of words. If no such word exists, ;; return 0. @@ -15,12 +41,12 @@ segment readable executable find: ;; RSI contains the entry we are currently looking at .loop: - movzx rcx, byte [rsi + 16] ; Length of word being looked at + movzx rcx, byte [rsi + 8 + 1] ; 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 + 16 + 1] ; Location of character being compared in entry + lea rdx, [rsi + 8 + 1 + 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] @@ -41,63 +67,65 @@ find: .found: ret -;; Read a word from standard input. Returns pointer to string containing word as -;; well as length. +;; Read a word from a buffer. Returns the buffer without the word, as well as +;; the word that was read (including lengths). ;; -;; Results: -;; * rdx = Length of string -;; * rdi = Pointer to string buffer +;; Inputs: +;; * rsi = Input buffer +;; * rcx = Length of buffer ;; -;; Clobbers pretty much everything. -read_word: +;; Outputs: +;; * rsi = Updated buffer +;; * rcx = Length of updated buffer +;; * rdi = Word buffer +;; * rdx = Length of word buffer +pop_word: .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 - - ;; We consider newlines and spaces to be whitespace. - cmp [.char_buffer], ' ' - je .skip_whitespace - cmp [.char_buffer], $A - je .skip_whitespace + mov al, [rsi] + cmp al, ' ' + je .got_whitespace + cmp al, $A + je .got_whitespace + jmp .alpha +.got_whitespace: + ;; The buffer starts with whitespace; discard the first character from the buffer. + inc rsi + dec rcx + jmp .skip_whitespace .alpha: ;; We got a character that wasn't whitespace. Now read the actual word. - mov [.length], 0 + mov rdi, rsi ; This is where the word starts + mov rdx, 1 ; Length of word .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], ' ' + ;; Extract character from original buffer: + inc rsi + dec rcx + + ;; When we hit whitespace, we are done with this word + mov al, [rsi] + cmp al, ' ' je .end - cmp [.char_buffer], $A - jne .read_alpha + cmp al, $A + je .end + + ;; It wasn't whitespace; add it to word buffer + inc rdx + jmp .read_alpha .end: - mov rdi, .buffer - movzx rdx, [.length] + ;; Finally, we want to skip one whitespace character after the word. + inc rsi + dec rcx ret ;; Parses a string. ;; ;; Parameters: -;; * [.length] = Length of string -;; * [.buffer] = Pointer to string buffer +;; * rcx = Length of string +;; * rdi = Pointer to string buffer ;; ;; Results: ;; * rax = Value @@ -108,7 +136,7 @@ parse_number: ;; Add (10^(rcx-1) * parse_char(rdi[length - rcx])) to the accumulated value ;; for each rcx. - mov rcx, [.length] + mov [.length], rcx .loop: ;; First, calcuate 10^(rcx - 1) mov rax, 1 @@ -125,12 +153,15 @@ parse_number: ;; Now, rax = 10^(rcx - 1). ;; We need to calulate the value of the character at rdi[length - rcx]. - mov rbx, rdi + mov rbx, rdi add rbx, [.length] sub rbx, rcx movzx rbx, byte [rbx] sub rbx, '0' + cmp rbx, 10 + jae .error + ;; Multiply this value by rax to get (10^(rcx-1) * parse_char(rdi[length - rcx])), ;; then add this to the result. mul rbx @@ -144,17 +175,20 @@ parse_number: mov rax, r8 ret +.error: + push rdi + print parse_number.error_msg + pop rdi + printlen rdi, [.length] + newline + mov rax, 100 + call os_terminate -segment readable writable +section '.data' readable writable find.search_length dq ? find.search_buffer dq ? -read_word.max_size = $FF -read_word.buffer rb read_word.max_size -read_word.length db ? -read_word.char_buffer db ? - -parse_number.buffer dq ? parse_number.length dq ? +parse_number.error_msg string "Invalid number: "