blob: d1cea38b475a3c169d588f0390a19ac191c2e6dd [file] [log] [blame]
swissChilif7f1e2b2021-12-31 14:42:43 -08001;;; Assembly definitions of built-in Forth words
2;;; Assume this is included after all the relevant macros
3
4
5;;; INPUT & OUTPUT ROUTINES ;;;
6 ;; Read a key from the input. If STDIN is blank wait for a key
7 ;; press.
8 ;;
9 ;; TODO: Keep an internal buffer until RETURN is pressed, allow
10 ;; some line editing.
11 ;;
12 ;; Actually, that could be implemented in Forth for simplicity.
13 DEFWORD_RAW KEY, 'KEY'
14 CALL READ_KEY
15 PUSH AX
16 NEXT
17
18 ;; This routine returns the key in AL, but Forth wants it on the
19 ;; stack, so we have a helper function.
20READ_KEY:
21 GETSTDINSTATUS
22 TEST AL, AL
23 JZ .EOF
24
25 READCIN
26 XOR AH, AH ; We get the result in AL but we want
27 ; the whole word to be the correct
28 ; char.
29 RET
30
31.EOF: ; End of STDIN
32 ;; Check if line buffer is empty
33 READCIN
34 XOR AH, AH ; We don't care about the scan code
35 RET
36
37
38 %MACRO WHITESPACE 2
39 CMP %1, ' '
40 JE %2
41
42 CMP %1, 09h ; \t
43 JE %2
44
45 CMP %1, 0Ah ; \n
46 JE %2
47
48 CMP %1, 0Dh ; \r
49 JE %2
50 %ENDMACRO
51
52
53 ;; Read a word from the input, max 32 bytes. WORD is reserved in
54 ;; NASM sadly.
55 DEFWORD_RAW _WORD, 'WORD'
56READ_WORD:
57 MOV DI, WORD_BUFFER
58
59.START:
60 ;; First skip whitespace
61 CALL READ_KEY ; Char in AL
62
63 WHITESPACE AL, .START
64 CMP AL, '\'
65 JE .COMMENT
66
67.LOOP:
68 CMP AL, 'a'
69 JL .STORE
70 CMP AL, 'z'
71 JG .STORE
72
73 SUB AL, ('a' - 'A') ; To upper case
74
75.STORE:
76 STOSB ; Buffer char
77
78 CALL READ_KEY
79 WHITESPACE AL, .DONE
80 JMP .LOOP
81
82.COMMENT:
83 CALL READ_KEY
84 CMP AL, ASCII_RETURN
85 JNE .COMMENT
86 JE .START
87
88.DONE:
89 SUB DI, WORD_BUFFER ; Length
90 PUSH WORD_BUFFER
91 PUSH DI
92
93 NEXT
94
95
96 ;; ( string len -- num unparsed )
97 DEFWORD_RAW NUMBER, 'NUMBER'
98 POP DX ; Length
99 POP BX ; Index
100 ADD DX, BX ; End pointer
101 XOR AX, AX ; The number
102
103 XOR CX, CX ; CL - used for char
104
105.LOOP:
106 MOV CL, BYTE [BX]
107 CMP CL, '0'
108 JL .DONE
109 CMP CL, '9'
110 JG .DONE
111
112 SUB CL, '0'
113 MOV CH, 10 ; This needs to be reset each time
114 ; which is annoying
115 IMUL CH ; 8-bit IMUL operand means that the
116 ; result is just in AX, not extended
117 ; by DX. Perfect
118 XOR CH, CH
119 ADD AX, CX
120 INC BX
121 CMP BX, DX
122 JL .LOOP
123
124.DONE:
125 SUB DX, BX ; Number of chars unread
126 PUSH AX
127 PUSH DX
128 NEXT
129
130
131 ;; Emit a char from the stack
132 DEFWORD_RAW EMIT, 'EMIT'
133 POP DX
134 WRITECOUT
135 NEXT
136
137
138 DEFWORD_RAW CR, 'CR'
139 MOV DX, CRLF_MSG
140 WRITESOUT
141 NEXT
142
143
swissChilif8849dc2021-12-31 23:15:57 -0800144 DEFWORD_THREADED SPACE, 'SPACE'
145 DW LITERAL, ' ', EMIT, EXIT
146
147
swissChilif7f1e2b2021-12-31 14:42:43 -0800148 DEFWORD_RAW TYPE, 'TYPE'
149TYPE_STRING:
150 POP CX ; Length
151 POP BX ; Index
152 ADD CX, BX ; End pointer
153
154.LOOP:
155 MOV DL, BYTE [BX]
156 WRITECOUT
157
158 INC BX
159 CMP BX, CX
160 JNE .LOOP
161
162.DONE:
163 NEXT
164
165
166 ;; ( n -- )
167 DEFWORD_RAW DOT, '.'
168 POP AX ; The number
169
170DOT_INT:
171 TEST AX, AX
172 JNZ .START
173
174 MOV DX, '0'
175 WRITECOUT
176 NEXT
177
178.START:
179 MOV BX, 10 ; The base
180
181 ;; TODO: BUG: Depending on this value there is a maximum number
182 ;; that this routine will format, which is weird. For the value of
183 ;; 7 it is 1280.
184 MOV CX, 7
185.LOOP:
186 XOR DX, DX
187 DIV BX ; AX = quotient; DX = remainder
188 PUSH DX
189
190 LOOP .LOOP
191
192 MOV CX, 7
193 XOR BX, BX ; At start
194.REVERSE:
195 POP DX
196 OR BL, DL
197 JZ .END
198
199 ADD DL, '0'
200 WRITECOUT
201
202.END:
203 LOOP .REVERSE
204
205 NEXT
206
207
208;;; DATA ;;;
209 CRLF_MSG DB ASCII_RETURN, ASCII_NEWLINE, '$'
210
211 WORD_BUFFER TIMES 32 DB 0
212WORD_BUFFER_END: