First draft of a real README for the VVS stdlib.
[vvhitespace] / stdlib / stdio.pvvs
CommitLineData
48f88489
AT
1@ (c) 2020 Aaron Taylor <ataylor at subgeniuskitty dot com>
2@ See LICENSE.txt file for copyright and license details.
3
8bed3ccd
AT
4#ifndef VVS_STDLIB_STDIO
5#define VVS_STDLIB_STDIO
6
7@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 8@ Name:
b8b65c17 9@ printstackstring (1000100)
8bed3ccd 10@ Description:
bb21580a 11@ Prints a null-terminated string from the stack.
8bed3ccd
AT
12@ Call Stack:
13@ null-terminator (ASCII '\0')
14@ char n
15@ ...
16@ char 2
17@ char 1 <-- TOS
18@ Return Stack:
19@ <empty>
20@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
b8b65c17 21NSSVTSSSTSSN | Mark: 1000100 (print string from stack)
32c440bf 22SNS | DUP
b8b65c17 23NTSSTSSSTSSSSSSSSSTN | BRZ > 01000100 00000001
32c440bf 24TNSS | Print character
b8b65c17
AT
25NSNTSSSTSSN | JMP > 1000100
26NSSVSTSSSTSSSSSSSSSTN | Mark: 01000100 00000001
32c440bf
AT
27SNN | DROP
28NTN | RTS
29
8bed3ccd 30@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 31@ Name:
b8b65c17 32@ printheapstring (1000101)
8bed3ccd 33@ Description:
bb21580a 34@ Prints a null-terminated string from the heap.
8bed3ccd
AT
35@ Call Stack:
36@ pointer to first character <-- TOS
37@ Return Stack:
38@ <empty>
39@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
b8b65c17 40NSSVTSSSTSTN | Mark: 1000101 (print string from heap)
32c440bf
AT
41SNS | DUP
42TTT | LOAD
43SNS | DUP
b8b65c17 44NTSSTSSSTSTSSSSSSSTN | BRZ > 01000101 00000001
32c440bf
AT
45TNSS | Print character
46SSSTN | Push +1
47TSSS | ADD
b8b65c17
AT
48NSNTSSSTSTN | JMP > 1000101
49NSSVSTSSSTSTSSSSSSSTN | Mark: 01000101 00000001
32c440bf
AT
50SNN | DROP
51SNN | DROP
52NTN | RTS
8bed3ccd 53
3625ff3a 54@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 55@ Name:
23d17247 56@ printstacknumber (1001)
3625ff3a 57@ Description:
bb21580a 58@ Prints 'number' from the stack in sign-magnitude format.
3625ff3a
AT
59@ Leading zeros are suppressed.
60@ Call Stack:
bb21580a 61@ number <-- TOS
3625ff3a
AT
62@ Return Stack:
63@ <empty>
64@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
23d17247 65NSSVTSSTN | Mark: 1001 (print number from stack)
3625ff3a 66SNS | DUP
149f16fd
AT
67NSTTSSSSTSN | JSR > 1000010 (printstacknumbersign)
68NSTTSSSSTTN | JSR > 1000011 (printstacknumbermagnitude)
3625ff3a
AT
69NTN | RTS
70
71@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 72@ Name:
ae1f85a1 73@ printstacknumbersign (1000010)
3625ff3a 74@ Description:
bb21580a 75@ Prints the sign of 'number' from the stack.
3625ff3a 76@ Call Stack:
bb21580a 77@ number <-- TOS
3625ff3a
AT
78@ Return Stack:
79@ <empty>
80@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
ae1f85a1
AT
81NSSVTSSSSTSN | Mark: 1000010 (print sign of number from stack)
82NTTSTSSSSTSSSSSSSSTN | BMI > 01000010 00000001
3625ff3a 83SSSTSTSTTN | PUSH ASCII '+'
ae1f85a1
AT
84NSNSTSSSSTSSSSSSSTSN | JMP > 01000010 00000010
85NSSVSTSSSSTSSSSSSSSTN | Mark: 01000010 00000001
3625ff3a 86SSSTSTTSTN | PUSH ASCII '-'
ae1f85a1 87NSSVSTSSSSTSSSSSSSTSN | Mark: 01000010 00000010
3625ff3a
AT
88TNSS | PUTC
89NTN | RTS
90
91@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 92@ Name:
ae1f85a1 93@ printstacknumbermagnitude (1000011)
3625ff3a 94@ Description:
bb21580a 95@ Prints the magnitude of 'number' from the stack.
3625ff3a 96@ Call Stack:
bb21580a 97@ number <-- TOS
3625ff3a
AT
98@ Return Stack:
99@ <empty>
100@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
bb21580a 101#include <math.pvvs>
ae1f85a1 102NSSVTSSSSTTN | Mark: 1000011 (print magnitude of number from stack)
3625ff3a 103
acd78c53
AT
104@ Catch -(2^63) as a special case since its absolute value will overflow
105@ a twos-complement 64-bit word.
106SNS | DUP
107SSTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSN | -(2^63)
108TSST | SUBTRACT
109NTSSTSSSSTTSSSSSSTSN | BRZ > 01000011 00000010
110
111@ No special case applies. Prepare for computation by converting the number
112@ to absolute value and preparing a string on the stack.
113NSTTSSSTN | JSR > 10001 (absolute value)
3625ff3a
AT
114SSSSN | PUSH ASCII '\0'
115SNT | SWAP
116
117@ Pick off one digit on each pass through this loop.
ae1f85a1 118NSSVSTSSSSTTSSSSSSSSN | Mark: 01000011 00000000
3625ff3a
AT
119SNS | DUP
120
121@ Mod-off a digit, convert to ASCII, store on stack as part of the string.
122SSSTSTSN | PUSH +10
123TSTT | MODULO
124SSSTTSSSSN | PUSH ASCII '0'
125TSSS | ADD
126SNT | SWAP
127
128@ Divide down to next digit and keep looping if number != 0 yet.
129SSSTSTSN | PUSH +10
130TSTS | DIVIDE
131SNS | DUP
ae1f85a1
AT
132NTSSTSSSSTTSSSSSSSTN | BRZ > 01000011 00000001
133NSNSTSSSSTTSSSSSSSSN | JMP > 01000011 00000000
3625ff3a
AT
134
135@ Print the string we have built on the stack.
ae1f85a1 136NSSVSTSSSSTTSSSSSSSTN | Mark: 01000011 00000001
3625ff3a 137SNN | DROP
45abb94e 138NSTTSSSTSSN | JSR > 1000100 (print string from stack)
3625ff3a
AT
139NTN | RTS
140
acd78c53
AT
141@ Replace the number on the stack with its decimal ASCII representation.
142NSSVSTSSSSTTSSSSSSTSN | BRZ > 01000011 00000010
143SNN | DROP
144A"-9223372036854775808"
145NSNSTSSSSTTSSSSSSSTN | JMP > 01000011 00000001
146
23d17247
AT
147@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
148@ Name:
149@ printf
150@ Description:
151@ If printing a static string (i.e. no substitutions), pass
152@ 'number of substitutions' as 0, immediately followed by 'string word 1'.
153@ If printing a string from the heap instead of stack, pass an empty string
154@ on the stack followed by a pointer to the first word of the
155@ null-terminated string on the heap.
156@ For example:
157@ pointer
158@ ASCII '\0'
159@ substitution n
160@ <remainder of call stack is unchanged>
6cb31a3e
AT
161@ Maximum substitutions determined by upper heap limit in stackrotate and
162@ stackrotatereverse subroutines.
23d17247
AT
163@ Call Stack:
164@ ACSII '\0'
165@ string word n
166@ ...
167@ string word 1
168@ substitution n
169@ ...
170@ substitution 1
171@ number of substitutions <-- TOS
172@ Return Stack:
173@ <empty>
174@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
149f16fd 175#include <stack.pvvs>
23d17247
AT
176NSSVTSSSN | Mark: 1000 (printf)
177
23d17247
AT
178@ If the stack contains an empty string (i.e. just an ASCII '\0'), the next
179@ word is a pointer we must use to load the string from the heap.
6cb31a3e 180@ This will leave the stack looking exactly like the example call stack above.
23d17247
AT
181@ Do the test this way so we can keep the code inline.
182SNS | DUP
6cb31a3e
AT
183SSSTSN | PUSH 2
184TSSS | ADD
185NSTTTSSN | JSR > 1100 (deepdup)
23d17247
AT
186SSTTN | PUSH -1
187TSSN | MULTIPLY
188NTTSSSSTSSSSSSSSSSTN | BMI > 00001000 00000001
6cb31a3e
AT
189SNS | DUP
190SSSTSN | PUSH 2
191TSSS | ADD
192NSTTSTTN | JSR > 1011 (stackrotatereverse)
23d17247
AT
193SNN | DROP
194SNS | DUP
6cb31a3e
AT
195SSSTSN | PUSH 2
196TSSS | ADD
197NSTTSTTN | JSR > 1011 (stackrotatereverse)
198NSTSSSSTSSSTSSSTTSSN | JSR > 00001000 10001100 (printf_deepslurp)
23d17247
AT
199
200@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
201@ The rest of printf parses a string according to the following information.
202@ ASCII '\ ':
203@ ASCII '\ ': putchar '\ '
204@ ASCII '%': putchar '%'
205@ ASCII 'n': putchar '\n'
206@ ASCII 't': putchar '\t'
207@ ASCII '%':
208@ ASCII 'c': (print character)
209@ ASCII 's': (print string)
210@ ASCII 'd': (print decimal digit)
211@ ASCII 'u': (print abs(integer), w/o sign)
212@ ASCII 'i': (print integer w/sign)
213@ ASCII '\0':
214@ cleanup and exit
215@ default:
216@ putchar
217@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
218
219@@@@@@@@@@@@@@@@@@@@
6cb31a3e 220@ The next block tests the char against all possible level 1 branches (see above).
23d17247
AT
221@ If there is a match, execution jumps to the appropriate level 2 branch label.
222@ If no match is found, print the character and move on.
223@@@@@@@@@@@@@@@@@@@@
224NSSVSSSSTSSSSSSSSSSTN | Mark: 00001000 00000001
6cb31a3e
AT
225@ Move the next character of the string to TOS.
226NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
23d17247
AT
227@ TOS is an ASCII '\ '. Jump to process the possible level 2 branches.
228SNS | DUP
229SSSTSTTTSSN | PUSH ASCII slash
230TSST | SUBTRACT
231NTSSSSSTSSSSSSSSSTSN | BRZ > 00001000 00000010
232@ TOS is an ASCII '%'. Jump to process the possible level 2 branches.
233SNS | DUP
234SSSTSSTSTN | PUSH ASCII '%'
235TSST | SUBTRACT
236NTSSSSSTSSSSSSSSSTTN | BRZ > 00001000 00000011
237@ TOS is an ASCII "\0". Jump to clean-up-and-exit.
238SNS | DUP
239NTSSSSSTSSSSSSSSSSSN | BRZ > 00001000 00000000
240@ TOS is a normal character. Print it and loop again.
241TNSS | PUTC
242NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
243
244@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
245@ Level 2 - ASCII '\ ' - Escapes
246@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
247
248@@@@@@@@@@@@@@@@@@@@
249@ The level 1 match was an ASCII '\ '.
250@ Now look for level 2 matches that trigger a character substitution (n -> newline, etc).
251@ If no matches are found, print the character directly (e.g. "\%" -> '%')
252@ When finished, loop back to testing level 1 branches.
253@@@@@@@@@@@@@@@@@@@@
254NSSVSSSSTSSSSSSSSSTSN | Mark: 00001000 00000010
255SNN | DROP
6cb31a3e
AT
256@ Move the next character of the string to TOS.
257NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
23d17247
AT
258@ Check for ASCII '\n'
259SNS | DUP
260SSSTTSTTTSN | PUSH ASCII 'n'
261TSST | SUBTRACT
262NTSSSSSTSSSSSSSSTSSN | BRZ > 00001000 00000100
263@ Check for ASCII '\t'
264SNS | DUP
08a3a286 265SSSTTTSTSSN | PUSH ASCII 't'
23d17247
AT
266TSST | SUBTRACT
267NTSSSSSTSSSSSSSSTSTN | BRZ > 00001000 00000101
268@ No substitution necessary. Print literally.
269TNSS | PUTC
270NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
271
272@@@@@@@@@@@@@@@@@@@@
273@ These are utility labels to output the appropriate non-printable ASCII character.
274@ After output, they loop back to testing level 1 branches.
275@@@@@@@@@@@@@@@@@@@@
276
277@ Print a newline and loop for the next character.
278NSSVSSSSTSSSSSSSSTSSN | Mark: 00001000 00000100
279SNN | DROP
280SSSTSTSN | PUSH ASCII '\n'
281TNSS | PUTC
282NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
283
284@ Print a horizontal tab and loop for the next character.
285NSSVSSSSTSSSSSSSSTSTN | Mark: 00001000 00000101
286SNN | DROP
287SSSTSSTN | PUSH ASCII '\t'
288TNSS | PUTC
289NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
290
291@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
292@ Level 2 - ASCII '%' - Substitutions
293@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
294
295@@@@@@@@@@@@@@@@@@@@
296@ The level 1 match was an ASCII '%'.
297@ Now look for level 2 matches that trigger a substitution.
298@ When finished, loop back to testing level 1 branches.
299@@@@@@@@@@@@@@@@@@@@
300NSSVSSSSTSSSSSSSSSTTN | Mark: 00001000 00000011
301SNN | DROP
6cb31a3e
AT
302@ Move the next character of the string to TOS.
303NSTSSSSTSSSTSSSTSTTN | JSR > 00001000 10001011 (next char to TOS)
23d17247
AT
304@ Check for ASCII 'c' - Print character
305SNS | DUP
306SSSTTSSSTTN | PUSH ASCII 'c'
307TSST | SUBTRACT
308NTSSSSSTSSSSSSSSTTSN | BRZ > 00001000 00000110
309@ Check for ASCII 's' - Print string
310SNS | DUP
311SSSTTTSSTTN | PUSH ASCII 's'
312TSST | SUBTRACT
313NTSSSSSTSSSSSSSSTTTN | BRZ > 00001000 00000111
314@ Check for ASCII 'd' - Print decimal digit
315SNS | DUP
316SSSTTSSTSSN | PUSH ASCII 'd'
317TSST | SUBTRACT
318NTSSSSSTSSSSSSSTSSSN | BRZ > 00001000 00001000
319@ Check for ASCII 'u' - Print unsigned number
320SNS | DUP
321SSSTTTSTSTN | PUSH ASCII 'u'
322TSST | SUBTRACT
323NTSSSSSTSSSSSSSTSSTN | BRZ > 00001000 00001001
324@ Check for ASCII 'i' - Print signed number
325SNS | DUP
326SSSTTSTSSTN | PUSH ASCII 'i'
327TSST | SUBTRACT
328NTSSSSSTSSSSSSSTSTSN | BRZ > 00001000 00001010
329@ Unrecognized substitution specifier.
330@ For now, silently consume it and continue.
331@ Do not increment the substitution counter.
332@ TODO: Is this really what I want to do here?
333SNN | DROP
334NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
335
336
337@@@@@@@@@@@@@@@@@@@@
338@ These are utility labels to call the appropriate type of output subroutine.
6cb31a3e
AT
339@ After output, they decrement the substition counter and loop back to testing
340@ level 1 branches.
23d17247
AT
341@@@@@@@@@@@@@@@@@@@@
342
343@ Print a character
344NSSVSSSSTSSSSSSSSTTSN | Mark: 00001000 00000110
345SNN | DROP
6cb31a3e 346SNT | SWAP
23d17247 347TNSS | PUTC
6cb31a3e
AT
348SSSTN | PUSH 1
349TSST | SUBTRACT
23d17247
AT
350NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
351@ Print a string
352NSSVSSSSTSSSSSSSSTTTN | Mark: 00001000 00000111
353SNN | DROP
6cb31a3e 354SNT | SWAP
23d17247 355NSTTSSSTSTN | JSR > 1000101 (print string from heap)
6cb31a3e
AT
356SSSTN | PUSH 1
357TSST | SUBTRACT
23d17247
AT
358NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
359@ Print a decimal digit
360NSSVSSSSTSSSSSSSTSSSN | Mark: 00001000 00001000
361SNN | DROP
6cb31a3e 362SNT | SWAP
23d17247 363TNST | PUTDIGIT
6cb31a3e
AT
364SSSTN | PUSH 1
365TSST | SUBTRACT
23d17247
AT
366NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
367@ Print an unsigned integer
368NSSVSSSSTSSSSSSSTSSTN | Mark: 00001000 00001001
369SNN | DROP
6cb31a3e 370SNT | SWAP
23d17247 371NSTTSSSSTTN | JSR > 1000011 (print magnitude of number from stack)
6cb31a3e
AT
372SSSTN | PUSH 1
373TSST | SUBTRACT
23d17247
AT
374NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
375@ Print a signed integer
376NSSVSSSSTSSSSSSSTSTSN | Mark: 00001000 00001010
377SNN | DROP
6cb31a3e 378SNT | SWAP
23d17247 379NSTTSSTN | JSR > 1001 (print number from stack)
6cb31a3e
AT
380SSSTN | PUSH 1
381TSST | SUBTRACT
23d17247
AT
382NSNSSSSTSSSSSSSSSSTN | JMP > 00001000 00000001
383
384@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
385@ These are misc labels associated with the printf function.
386@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
387
6cb31a3e
AT
388@ Found an ASCII "\0" when processing the format string. Clean up and exit.
389NSSVSSSSTSSSSSSSSSSSN | Mark: 00001000 00000000
390SNN | DROP
2da74194 391SNN | DROP
6cb31a3e
AT
392NTN | RTS
393
394@ Move the next string character to TOS.
395@ Stack should look like the printf call stack, with num-of-subs at TOS.
396NSSVSSSSTSSSTSSSTSTTN | Mark: 00001000 10001011 (next char to TOS)
397SNS | DUP
398SSSTSN | PUSH 2
23d17247 399TSSS | ADD
6cb31a3e 400NSTTSTTN | JSR > 1011 (stackrotatereverse)
23d17247
AT
401NTN | RTS
402
6cb31a3e
AT
403@ Slurps a string from the heap to the stack, storing it behind the substitutions.
404@ Call Stack:
405@ substitution n
406@ ...
407@ substitution 1
408@ number of substitutions <-- TOS
409@ pointer to string
410@ Return Stack:
411@ ACSII '\0'
412@ string word n
413@ ...
414@ string word 1
415@ substitution n
416@ ...
417@ substitution 1
418@ number of substitutions <-- TOS
419@ TODO: This, along with a deepspew, should probably be stdlib routines.
420NSSVSSSSTSSSTSSSTTSSN | Mark: 00001000 10001100 (printf_deepslurp)
421SNS | DUP
422@ Advance a duplicate copy of the pointer until it points to the null-terminator.
423NSSVSSSSTSSSTSSSTTSTN | Mark: 00001000 10001101
424SNS | DUP
425TTT | LOAD
426NTSSSSSTSSSTSSSTTTSN | BRZ > 00001000 10001110
427SSSTN | PUSH 1
428TSSS | ADD
429NSNSSSSTSSSTSSSTTSTN | JMP > 00001000 10001101
430@ Load a character to the stack on each pass through this loop.
431NSSVSSSSTSSSTSSSTTTSN | Mark: 00001000 10001110
432SNS | DUP
433TTT | LOAD
434SSSTSSN | PUSH 4
435NSTTTSSN | JSR > 1100 (deepdup)
436SSSTSSN | PUSH 4
437TSSS | ADD
438NSTTSTSN | JSR > 1010 (stackrotate)
439@ Test for end of loop.
440SNS | DUP
441SSSTTN | PUSH 3
442NSTTTSSN | JSR > 1100 (deepdup)
443TSST | SUBTRACT
444NTSSSSSTSSSTSSSTTTTN | BRZ > 00001000 10001111
445@ Decrement pointer to end of string, loop again.
446SSSTN | PUSH 1
447TSST | SUBTRACT
448NSNSSSSTSSSTSSSTTTSN | JMP > 00001000 10001110
449@ Clean up and return.
450NSSVSSSSTSSSTSSSTTTTN | Mark: 00001000 10001111
451SNN | DROP
23d17247
AT
452SNN | DROP
453NTN | RTS
454
8bed3ccd 455#endif