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