573646904581b28d7e9fc344f2137f6cda32519a
[rrq/jonasforth.git] / impl.asm
1 segment readable executable
2
3 ;; Find the given word in the dictionary of words. If no such word exists,
4 ;; return 0.
5 ;;
6 ;; Parameters:
7 ;;   * [find.search_length] = Length of the word in bytes.
8 ;;   * [find.search_buffer] = Pointer to the string containing the word.
9 ;;   * rsi = Pointer to the last entry in the dictionary.
10 ;;
11 ;; Results:
12 ;;   * rsi = Pointer to the found entry in the dictionary or 0.
13 ;;
14 ;; Clobbers rcx, rdx, rdi, rax.
15 find:
16   ;; RSI contains the entry we are currently looking at
17 .loop:
18   movzx rcx, byte [rsi + 16]    ; Length of word being looked at
19   cmp rcx, [.search_length]
20   jne .next    ; If the words don't have the same length, we have the wrong word
21
22   ;; Otherwise, we need to compare strings
23   lea rdx, [rsi + 16 + 1]       ; Location of character being compared in entry
24   mov rdi, [.search_buffer]     ; Location of character being compared in search buffer
25 .compare_char:
26   mov al, [rdx]
27   mov ah, [rdi]
28   cmp al, ah
29   jne .next                     ; They don't match; try again
30   inc rdx                       ; These characters match; look at the next ones
31   inc rdi
32   loop .compare_char
33
34   jmp .found                    ; They match! We are done.
35
36 .next:
37   mov rsi, [rsi]                ; Look at the previous entry
38   cmp rsi, 0
39   jnz .loop                    ; If there is no previous word, exit and return 0
40
41 .found:
42   ret
43
44 ;; Read a word from standard input. Returns pointer to string containing word as
45 ;; well as length.
46 ;;
47 ;; Results:
48 ;;   * rdx = Length of string
49 ;;   * rdi = Pointer to string buffer
50 ;;
51 ;; Clobbers pretty much everything.
52 read_word:
53 .skip_whitespace:
54   ;; Read characters into .char_buffer until one of them is not whitespace.
55   mov rax, 0
56   mov rdi, 0
57   mov rsi, .char_buffer
58   mov rdx, 1
59   syscall
60
61   ;; We consider newlines and spaces to be whitespace.
62   cmp [.char_buffer], ' '
63   je .skip_whitespace
64   cmp [.char_buffer], $A
65   je .skip_whitespace
66
67 .alpha:
68   ;; We got a character that wasn't whitespace. Now read the actual word.
69   mov [.length], 0
70
71 .read_alpha:
72   mov al, [.char_buffer]
73   movzx rbx, [.length]
74   mov rsi, .buffer
75   add rsi, rbx
76   mov [rsi], al
77   inc [.length]
78
79   mov rax, 0
80   mov rdi, 0
81   mov rsi, .char_buffer
82   mov rdx, 1
83   syscall
84
85   cmp [.char_buffer], ' '
86   je .end
87   cmp [.char_buffer], $A
88   jne .read_alpha
89
90 .end:
91   mov rdi, .buffer
92   movzx rdx, [.length]
93
94   ret
95
96 ;; Parses a string.
97 ;;
98 ;; Parameters:
99 ;;   * [.length] = Length of string
100 ;;   * [.buffer] = Pointer to string buffer
101 ;;
102 ;; Results:
103 ;;   * rax = Value
104 ;;
105 ;; Clobbers
106 parse_number:
107   mov r8, 0                     ; Result
108
109   ;; Add (10^(rcx-1) * parse_char(rdi[length - rcx])) to the accumulated value
110   ;; for each rcx.
111   mov rcx, [.length]
112 .loop:
113   ;; First, calcuate 10^(rcx - 1)
114   mov rax, 1
115
116   mov r9, rcx
117   .exp_loop:
118     dec r9
119     jz .break
120     mov rbx, 10
121     mul rbx
122     jmp .exp_loop
123   .break:
124
125   ;; Now, rax = 10^(rcx - 1).
126
127   ;; We need to calulate the value of the character at rdi[length - rcx].
128   mov rbx, rdi
129   add rbx, [.length]
130   sub rbx, rcx
131   movzx rbx, byte [rbx]
132   sub rbx, '0'
133
134   ;; Multiply this value by rax to get (10^(rcx-1) * parse_char(rdi[length - rcx])),
135   ;; then add this to the result.
136   mul rbx
137
138   ;; Add that value to r8
139   add r8, rax
140
141   dec rcx
142   jnz .loop
143
144   mov rax, r8
145   ret
146
147
148 segment readable writable
149
150 find.search_length dq ?
151 find.search_buffer dq ?
152
153 read_word.max_size = $FF
154 read_word.buffer rb read_word.max_size
155 read_word.length db ?
156 read_word.char_buffer db ?
157
158 parse_number.buffer dq ?
159 parse_number.length dq ?
160