update
[rrq/rrqforth.git] / stdio.asm
1 ;;; ========================================
2 ;;; Dynamic memory management. Allocated with MALLOC and released with
3 ;;; MUNMAP (see below)
4
5         ;; ( size -- addr )
6         ;; Allocates memory (using brk)
7         WORD p_malloc,'MALLOC',fasm
8         pushr rsi               ; pretend it's a FORTH word since it
9                                 ; ends via sys_mmap_asm
10         pop rax
11         push qword 0            ; address of mapping (suggestion)
12         push rax                ; length of mapping
13         push qword 3            ; protection mode PROT_READ | PROT_WRITE
14         push qword 8226         ; flags PRIVATE | ANONYMOUS | LOCKED
15         push qword -1           ; fd -1
16         push qword 0            ; offset
17         jmp sys_mmap_asm        ; exit via sys_mmap
18
19 ;;; ========================================
20 ;;; Input stream handling.
21 ;;;
22 ;;; An input stream for a file descriptor has a stream buffer that is
23 ;;; gradually filled on needs basis. The stream buffer includes a
24 ;;; header portion with:
25 ;;; * size of buffer (excluding the 32 byte head)
26 ;;; * source file descriptor (or -1 for pure in-core data)
27 ;;; * current fill
28 ;;; * current read position
29 ;;;
30 ;;; An input stream for a memory block as a "detached" stream head
31 ;;; with:
32 ;;; * block address
33 ;;; * -1
34 ;;; * size of block
35 ;;; * current read position
36
37         WORD p_stream,'STREAM',fasm
38         ;; ( fd size -- addr ) or ( block -1 -- addr )
39         ;; Allocates a stream buffer of the given size and initializes
40         ;; it to be filled from the given input file descriptor.
41         pushr rsi
42         mov rax,[rsp]
43         cmp rax,-1
44         je p_stream_MEM
45         push rax
46         DOFORTH p_malloc        ; ( fd size addr )
47         push qword [rsp]
48         push qword [rsp+16]     ; ( fd size addr addr size )
49         DOFORTH p_erase         ; ( fd size addr )
50         pop rax                 ; addr ( fd size )
51         pop rbx                 ; size ( fd )
52         sub rbx,32              ; reduce by header size
53         mov [rax],rbx
54         pop rbx
55         mov [rax+8],rbx
56         push rax
57         jmp exit
58
59 p_stream_MEM:
60         push 32                 ; size of detached header (wastefull?)
61         DOFORTH p_malloc        ; ( block addr )
62         pop rax                 ; header address
63         pop rbx                 ; block address
64         mov rcx,[rbx]           ; block content size (excludes size field)
65         add rbx,8               ; block content address
66         mov qword [rax],rbx     ; save block content address
67         mov qword [rax+8],-1    ; -1 = memblock flag
68         mov qword [rax+16],rcx  ; save block content size
69         mov qword [rax+24],0    ; current position
70         push rax
71         jmp exit
72
73         WORD p_clear_stream,'CLEAR-STREAM',fasm
74         ;; ( stream -- )
75         ;; Clear buffer of input stream
76         pop rax
77         mov rbx,qword [rax+16]  ; copy fill
78         mov qword [rax+24],rbx  ; into current
79         next
80
81         WORD p_stream_nchars,'STREAM-NCHARS',fasm
82         ;; ( stream -- n )
83         ;; Scan over whitespace in the stream buffer (without actually
84         ;; consuming) and tell how much then remains.
85         pushr rsi
86         mov rcx,qword [rsp]
87         mov rbx,qword [rcx+16] ; fill
88         sub rbx,qword [rcx+24] ; current
89         cmp qword [rcx+8],-1
90         je p_stream_nchars_memblock
91         mov rsi,rcx
92         add rsi,32
93         jmp p_stream_nchars_skipblanks
94 p_stream_nchars_memblock:
95         mov rsi,qword [rcx]
96 p_stream_nchars_skipblanks:
97         add rsi,qword [rcx+24] ; 
98         cmp rbx,0
99         je p_stream_nchars_done
100 p_stream_nchars_loop:
101         lodsb
102         cmp al,32
103         jg p_stream_nchars_done
104         dec rbx
105         jg p_stream_nchars_loop
106 p_stream_nchars_done:
107         mov qword [rsp],rbx
108         popr rsi
109         next
110
111 ;;; ========================================
112 ;;; Stream reading
113 ;;; READ-STREAM-CHAR ( stream -- ch )
114         
115         WORD p_read_stream_char,'READ-STREAM-CHAR',fasm
116         ;; ( stream -- ch )
117         pushr rsi
118         mov rax,qword [rsp]
119         mov rbx,qword [rax+16]  ; fill
120
121 p_read_stream_char.READ:
122         mov rcx,qword [rax+24]  ; current
123         cmp rbx,rcx
124         jg p_read_stream_char.CHAR
125
126         ;; pull in more from the source, if any
127         cmp qword [rax+8],-1    ; fd == -1 for "no source"
128         je p_read_stream_char.EOF
129         
130         push qword [rax+8]      ; fd
131         lea rbx,[rax+32]
132         push rbx                ; buffer
133         push qword [rax]        ; size
134         mov qword[rax+16],0
135         mov qword[rax+24],0
136         DOFORTH sys_read
137         pop rbx
138         mov rax,qword [rsp]
139         cmp rbx,0
140         jle p_read_stream_char.EOF
141         mov qword[rax+16],rbx
142         jmp p_read_stream_char.READ
143
144 p_read_stream_char.EOF:
145         mov qword [rsp],-1
146         popr rsi
147         next
148
149 p_read_stream_char.CHAR:
150         inc qword [rax+24]
151         add rcx,32
152         mov qword [rsp],0
153         mov bl,[rax+rcx]
154         mov byte [rsp],bl
155         popr rsi
156         next
157
158 ;;; ========================================
159 ;;; Input handling
160
161         WORD p_pad,'PAD',dovariable
162         ;; A buffer for holding a word
163         rb 1024
164
165         WORD p_read_word,'READ-WORD',fasm
166         ;; ( stream -- char* length )
167         ;; Read next word from the given stream into the PAD
168         pushr rsi
169         pop rax
170         push qword p_pad_DFA
171         push qword 0
172         push rax
173
174 p_read_word_skipblanks: 
175         FORTH
176         dq p_dup
177         dq p_read_stream_char
178         ENDFORTH
179         pop rbx
180         cmp bl,0
181         jl p_read_word_nomore
182         cmp bl,' '
183         jle p_read_word_skipblanks
184
185 p_read_word_readword:
186         ;; ( buffer length stream )
187         mov rax,qword [rsp+16]
188         mov rcx,qword [rsp+8]
189         mov [rax+rcx],bl
190         inc qword [rsp+8]
191         FORTH
192         dq p_dup
193         dq p_read_stream_char
194         ENDFORTH
195         pop rbx
196         cmp bl,0
197         jl p_read_word_nomore
198         cmp bl,' '
199         jg p_read_word_readword
200
201 p_read_word_nomore:
202         pop rax
203         popr rsi
204         next
205
206         WORD p_double_quote,'"',fasm ;; " (fool emacs)
207         ;; ( -- char* n )
208         ;; Scan to double quote in stream buffer, putting the string on PAD
209         pushr rsi
210         push p_pad_DFA
211         push 0
212 p_double_quote_loop:    
213         DOFORTH p_stdin, p_read_stream_char
214         pop rax
215         cmp rax,0
216         jl p_double_quote_endstream
217         cmp rax,'"'             ; " (fool emacs)
218         je  p_double_quote_endquote
219         lea rdi,[p_pad_DFA]
220         add rdi,qword [rsp]
221         stosb
222         inc qword [rsp]
223         jmp p_double_quote_loop
224 p_double_quote_endquote:
225 p_double_quote_endstream:
226         popr rsi
227         next
228
229         WORD p_tell,'TELL',fasm
230         ;; ( chars* n -- )
231         ;; Write n bytes from chars* to stdout
232         pushr rsi
233         pop rbx
234         pop rax
235         push 1
236         push rax
237         push rbx
238         DOFORTH sys_write
239         pop rax
240         popr rsi
241         next
242
243         WORD p_emit,'EMIT',fasm
244         ;; ( c -- )
245         ;; Write byte to stdout
246         pushr rsi
247         mov rax,rsp
248         push 1
249         push rax
250         push 1
251         DOFORTH sys_write
252         pop rax                 ; ignore return value
253         pop rax                 ; drop input data
254         popr rsi
255         next
256
257         WORD p_nl,'NL',dovalue
258         ;; ( -- c )
259         ;; Pushes a newline character on the stack
260         dq 10
261
262         WORD p_sp,'SP',dovalue
263         ;; ( -- c )
264         ;; Pushes a space character on the stack
265         dq 10
266
267         WORD p_digits,'DIGITS',dovariable
268         db '0123456789abcdef'
269
270         WORD p_dot,'.',fasm
271         ;; ( v -- )
272         ;; Print TOP value as unsigned BASE integer
273         pushr rsi
274         mov rax,qword [rsp]
275         cmp rax,0
276         jge p_dot_positive
277         cmp qword [p_base_DFA],10
278         jne p_dot_positive
279         push '-'
280         DOFORTH p_emit
281         mov rax,qword [rsp]
282         neg rax
283 p_dot_positive:
284         xor rdx,rdx
285         div qword [p_base_DFA]  ; rdx:rax / BASE => q=rax, r=rdx
286         mov qword [rsp],rdx 
287         cmp rax,0
288         je p_dot_remainder
289         push rax
290         DOFORTH p_dot
291 p_dot_remainder:
292         pop rdx
293         xor rax,rax
294         mov al,[p_digits_DFA+rdx]
295         push rax
296         DOFORTH p_emit
297         popr rsi
298         next