Updated #includes for stdlib.
[vvhitespace] / stdlib / stdio.pvvs
index d9184ad..54bb2ac 100644 (file)
-################################################################################
-# Description:
-#   This function prints a null-terminated string from the stack.
-# Call Stack:
-#   null-terminator (ASCII '\0')
-#   char n
-#   ...
-#   char 2
-#   char 1 <-- TOS
-# Return Stack:
-#   <empty>
-################################################################################
-NSSVTSSSN               | Mark: 1000 (print string from stack)
-SNS                     | DUP
-NTSSSSSTSSSSSSSSSSTN    | BRZ > 00001000 00000001
+#ifndef VVS_STDLIB_STDIO
+#define VVS_STDLIB_STDIO
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printstackstring (1000100)
+@ Description:
+@   Prints a null-terminated string from the stack.
+@ Call Stack:
+@   null-terminator (ASCII '\0')
+@   char n
+@   ...
+@   char 2
+@   char 1 <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+NSSVTSSSTSSN            | Mark: 1000100 (print string from stack)
+SNS                     | DUP
+NTSSTSSSTSSSSSSSSSTN    | BRZ > 01000100 00000001
 TNSS                    | Print character
 TNSS                    | Print character
-NSNTSSSN                | JMP > 1000
-NSSVSSSSTSSSSSSSSSSTN   | Mark: 00001000 00000001
+NSNTSSSTSSN             | JMP > 1000100
+NSSVSTSSSTSSSSSSSSSTN   | Mark: 01000100 00000001
 SNN                     | DROP
 NTN                     | RTS
 
 SNN                     | DROP
 NTN                     | RTS
 
-################################################################################
-# Description:
-#   This function prints a null-terminated string from the heap.
-# Call Stack:
-#   pointer to first character  <-- TOS
-# Return Stack:
-#   <empty>
-################################################################################
-NSSVTSSTN               | Mark: 1001 (print string from heap)
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printheapstring (1000101)
+@ Description:
+@   Prints a null-terminated string from the heap.
+@ Call Stack:
+@   pointer to first character  <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+NSSVTSSSTSTN            | Mark: 1000101 (print string from heap)
 SNS                     | DUP
 TTT                     | LOAD
 SNS                     | DUP
 SNS                     | DUP
 TTT                     | LOAD
 SNS                     | DUP
-NTSSSSSTSSTSSSSSSSTN    | BRZ > 00001001 00000001
+NTSSTSSSTSTSSSSSSSTN    | BRZ > 01000101 00000001
 TNSS                    | Print character
 SSSTN                   | Push +1
 TSSS                    | ADD
 TNSS                    | Print character
 SSSTN                   | Push +1
 TSSS                    | ADD
-NSNTSSTN                | JMP > 1001
-NSSVSSSSTSSTSSSSSSSTN   | Mark: 00001001 00000001
+NSNTSSSTSTN             | JMP > 1000101
+NSSVSTSSSTSTSSSSSSSTN   | Mark: 01000101 00000001
+SNN                     | DROP
+SNN                     | DROP
+NTN                     | RTS
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printstacknumber (1001)
+@ Description:
+@   Prints 'number' from the stack in sign-magnitude format.
+@   Leading zeros are suppressed.
+@ Call Stack:
+@   number  <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+NSSVTSSTN               | Mark: 1001 (print number from stack)
+SNS                     | DUP
+NSTTSSSSTSN             | JSR > 1000010 (printstacknumbersign)
+NSTTSSSSTTN             | JSR > 1000011 (printstacknumbermagnitude)
+NTN                     | RTS
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printstacknumbersign (1000010)
+@ Description:
+@   Prints the sign of 'number' from the stack.
+@ Call Stack:
+@   number  <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+NSSVTSSSSTSN            | Mark: 1000010 (print sign of number from stack)
+NTTSTSSSSTSSSSSSSSTN    | BMI > 01000010 00000001
+SSSTSTSTTN              | PUSH ASCII '+'
+NSNSTSSSSTSSSSSSSTSN    | JMP > 01000010 00000010
+NSSVSTSSSSTSSSSSSSSTN   | Mark: 01000010 00000001
+SSSTSTTSTN              | PUSH ASCII '-'
+NSSVSTSSSSTSSSSSSSTSN   | Mark: 01000010 00000010
+TNSS                    | PUTC
+NTN                     | RTS
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printstacknumbermagnitude (1000011)
+@ Description:
+@   Prints the magnitude of 'number' from the stack.
+@ Call Stack:
+@   number  <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <math.pvvs>
+NSSVTSSSSTTN            | Mark: 1000011 (print magnitude of number from stack)
+NSTTSSSTN               | JSR > 10001 (absolute value)
+
+SSSSN                   | PUSH ASCII '\0'
+SNT                     | SWAP
+
+@ Pick off one digit on each pass through this loop.
+NSSVSTSSSSTTSSSSSSSSN   | Mark: 01000011 00000000
+SNS                     | DUP
+
+@ Mod-off a digit, convert to ASCII, store on stack as part of the string.
+SSSTSTSN                | PUSH +10
+TSTT                    | MODULO
+SSSTTSSSSN              | PUSH ASCII '0'
+TSSS                    | ADD
+SNT                     | SWAP
+
+@ Divide down to next digit and keep looping if number != 0 yet.
+SSSTSTSN                | PUSH +10
+TSTS                    | DIVIDE
+SNS                     | DUP
+NTSSTSSSSTTSSSSSSSTN    | BRZ > 01000011 00000001
+NSNSTSSSSTTSSSSSSSSN    | JMP > 01000011 00000000
+
+@ Print the string we have built on the stack.
+NSSVSTSSSSTTSSSSSSSTN   | Mark: 01000011 00000001
+SNN                     | DROP
+NSTTSSSTSSN             | JSR > 1000100 (print string from stack)
+NTN                     | RTS
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Name:
+@   printf
+@ Description:
+@   If printing a static string (i.e. no substitutions), pass
+@     'number of substitutions' as 0, immediately followed by 'string word 1'.
+@   If printing a string from the heap instead of stack, pass an empty string
+@     on the stack followed by a pointer to the first word of the
+@     null-terminated string on the heap.
+@     For example:
+@         pointer
+@         ASCII '\0'
+@         substitution n
+@         <remainder of call stack is unchanged>
+@   Maximum substitutions determined by upper heap limit in stackrotate and
+@     stackrotatereverse subroutines.
+@ Call Stack:
+@   ACSII '\0'
+@   string word n
+@   ...
+@   string word 1
+@   substitution n
+@   ...
+@   substitution 1
+@   number of substitutions  <-- TOS
+@ Return Stack:
+@   <empty>
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+#include <stack.pvvs>
+NSSVTSSSN               | Mark: 1000 (printf)
+
+@ If the stack contains an empty string (i.e. just an ASCII '\0'), the next
+@ word is a pointer we must use to load the string from the heap.
+@ This will leave the stack looking exactly like the example call stack above.
+@ Do the test this way so we can keep the code inline.
+SNS                     | DUP
+SSSTSN                  | PUSH 2
+TSSS                    | ADD
+NSTTTSSN                | JSR > 1100 (deepdup)
+SSTTN                   | PUSH -1
+TSSN                    | MULTIPLY
+NTTSSSSTSSSSSSSSSSTN    | BMI > 00001000 00000001
+SNS                     | DUP
+SSSTSN                  | PUSH 2
+TSSS                    | ADD
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
+SNN                     | DROP
+SNS                     | DUP
+SSSTSN                  | PUSH 2
+TSSS                    | ADD
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
+NSTSSSSTSSSTSSSTTSSN    | JSR > 00001000 10001100 (printf_deepslurp)
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ The rest of printf parses a string according to the following information.
+@   ASCII '\ ':
+@       ASCII '\ ': putchar '\ '
+@       ASCII '%': putchar '%'
+@       ASCII 'n': putchar '\n'
+@       ASCII 't': putchar '\t'
+@   ASCII '%':
+@       ASCII 'c': (print character)
+@       ASCII 's': (print string)
+@       ASCII 'd': (print decimal digit)
+@       ASCII 'u': (print abs(integer), w/o sign)
+@       ASCII 'i': (print integer w/sign)
+@   ASCII '\0':
+@       cleanup and exit
+@   default:
+@       putchar
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+@@@@@@@@@@@@@@@@@@@@
+@ The next block tests the char against all possible level 1 branches (see above).
+@ If there is a match, execution jumps to the appropriate level 2 branch label.
+@ If no match is found, print the character and move on.
+@@@@@@@@@@@@@@@@@@@@
+NSSVSSSSTSSSSSSSSSSTN   | Mark: 00001000 00000001
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN    | JSR > 00001000 10001011 (next char to TOS)
+@ TOS is an ASCII '\ '. Jump to process the possible level 2 branches.
+SNS                     | DUP
+SSSTSTTTSSN             | PUSH ASCII slash
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSSTSN    | BRZ > 00001000 00000010
+@ TOS is an ASCII '%'. Jump to process the possible level 2 branches.
+SNS                     | DUP
+SSSTSSTSTN              | PUSH ASCII '%'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSSTTN    | BRZ > 00001000 00000011
+@ TOS is an ASCII "\0". Jump to clean-up-and-exit.
+SNS                     | DUP
+NTSSSSSTSSSSSSSSSSSN    | BRZ > 00001000 00000000
+@ TOS is a normal character. Print it and loop again.
+TNSS                    | PUTC
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Level 2 - ASCII '\ ' - Escapes
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+@@@@@@@@@@@@@@@@@@@@
+@ The level 1 match was an ASCII '\ '.
+@ Now look for level 2 matches that trigger a character substitution (n -> newline, etc).
+@ If no matches are found, print the character directly (e.g. "\%" -> '%')
+@ When finished, loop back to testing level 1 branches.
+@@@@@@@@@@@@@@@@@@@@
+NSSVSSSSTSSSSSSSSSTSN   | Mark: 00001000 00000010
+SNN                     | DROP
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN    | JSR > 00001000 10001011 (next char to TOS)
+@ Check for ASCII '\n'
+SNS                     | DUP
+SSSTTSTTTSN             | PUSH ASCII 'n'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSTSSN    | BRZ > 00001000 00000100
+@ Check for ASCII '\t'
+SNS                     | DUP
+SSSTSSTN                | PUSH ASCII '\t'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSTSTN    | BRZ > 00001000 00000101
+@ No substitution necessary. Print literally.
+TNSS                    | PUTC
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+@@@@@@@@@@@@@@@@@@@@
+@ These are utility labels to output the appropriate non-printable ASCII character.
+@ After output, they loop back to testing level 1 branches.
+@@@@@@@@@@@@@@@@@@@@
+
+@ Print a newline and loop for the next character.
+NSSVSSSSTSSSSSSSSTSSN   | Mark: 00001000 00000100
+SNN                     | DROP
+SSSTSTSN                | PUSH ASCII '\n'
+TNSS                    | PUTC
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+@ Print a horizontal tab and loop for the next character.
+NSSVSSSSTSSSSSSSSTSTN   | Mark: 00001000 00000101
+SNN                     | DROP
+SSSTSSTN                | PUSH ASCII '\t'
+TNSS                    | PUTC
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ Level 2 - ASCII '%' - Substitutions
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+@@@@@@@@@@@@@@@@@@@@
+@ The level 1 match was an ASCII '%'.
+@ Now look for level 2 matches that trigger a substitution.
+@ When finished, loop back to testing level 1 branches.
+@@@@@@@@@@@@@@@@@@@@
+NSSVSSSSTSSSSSSSSSTTN   | Mark: 00001000 00000011
+SNN                     | DROP
+@ Move the next character of the string to TOS.
+NSTSSSSTSSSTSSSTSTTN    | JSR > 00001000 10001011 (next char to TOS)
+@ Check for ASCII 'c' - Print character
+SNS                     | DUP
+SSSTTSSSTTN             | PUSH ASCII 'c'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSTTSN    | BRZ > 00001000 00000110
+@ Check for ASCII 's' - Print string
+SNS                     | DUP
+SSSTTTSSTTN             | PUSH ASCII 's'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSSTTTN    | BRZ > 00001000 00000111
+@ Check for ASCII 'd' - Print decimal digit
+SNS                     | DUP
+SSSTTSSTSSN             | PUSH ASCII 'd'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSTSSSN    | BRZ > 00001000 00001000
+@ Check for ASCII 'u' - Print unsigned number
+SNS                     | DUP
+SSSTTTSTSTN             | PUSH ASCII 'u'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSTSSTN    | BRZ > 00001000 00001001
+@ Check for ASCII 'i' - Print signed number
+SNS                     | DUP
+SSSTTSTSSTN             | PUSH ASCII 'i'
+TSST                    | SUBTRACT
+NTSSSSSTSSSSSSSTSTSN    | BRZ > 00001000 00001010
+@ Unrecognized substitution specifier.
+@ For now, silently consume it and continue.
+@ Do not increment the substitution counter.
+@ TODO: Is this really what I want to do here?
+SNN                     | DROP
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+
+@@@@@@@@@@@@@@@@@@@@
+@ These are utility labels to call the appropriate type of output subroutine.
+@ After output, they decrement the substition counter and loop back to testing
+@ level 1 branches.
+@@@@@@@@@@@@@@@@@@@@
+
+@ Print a character
+NSSVSSSSTSSSSSSSSTTSN   | Mark: 00001000 00000110
+SNN                     | DROP
+SNT                     | SWAP
+TNSS                    | PUTC
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+@ Print a string
+NSSVSSSSTSSSSSSSSTTTN   | Mark: 00001000 00000111
+SNN                     | DROP
+SNT                     | SWAP
+NSTTSSSTSTN             | JSR > 1000101 (print string from heap)
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+@ Print a decimal digit
+NSSVSSSSTSSSSSSSTSSSN   | Mark: 00001000 00001000
+SNN                     | DROP
+SNT                     | SWAP
+TNST                    | PUTDIGIT
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+@ Print an unsigned integer
+NSSVSSSSTSSSSSSSTSSTN   | Mark: 00001000 00001001
+SNN                     | DROP
+SNT                     | SWAP
+NSTTSSSSTTN             | JSR > 1000011 (print magnitude of number from stack)
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+@ Print a signed integer
+NSSVSSSSTSSSSSSSTSTSN   | Mark: 00001000 00001010
+SNN                     | DROP
+SNT                     | SWAP
+NSTTSSTN                | JSR > 1001 (print number from stack)
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSSSSSSSSTN    | JMP > 00001000 00000001
+
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+@ These are misc labels associated with the printf function.
+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+@ Found an ASCII "\0" when processing the format string. Clean up and exit.
+NSSVSSSSTSSSSSSSSSSSN   | Mark: 00001000 00000000
+SNN                     | DROP
+NTN                     | RTS
+
+@ Move the next string character to TOS.
+@ Stack should look like the printf call stack, with num-of-subs at TOS.
+NSSVSSSSTSSSTSSSTSTTN   | Mark: 00001000 10001011 (next char to TOS)
+SNS                     | DUP
+SSSTSN                  | PUSH 2
+TSSS                    | ADD
+NSTTSTTN                | JSR > 1011 (stackrotatereverse)
+NTN                     | RTS
+
+@ Slurps a string from the heap to the stack, storing it behind the substitutions.
+@ Call Stack:
+@   substitution n
+@   ...
+@   substitution 1
+@   number of substitutions  <-- TOS
+@   pointer to string
+@ Return Stack:
+@   ACSII '\0'
+@   string word n
+@   ...
+@   string word 1
+@   substitution n
+@   ...
+@   substitution 1
+@   number of substitutions  <-- TOS
+@ TODO: This, along with a deepspew, should probably be stdlib routines.
+NSSVSSSSTSSSTSSSTTSSN   | Mark: 00001000 10001100 (printf_deepslurp)
+SNS                     | DUP
+@ Advance a duplicate copy of the pointer until it points to the null-terminator.
+NSSVSSSSTSSSTSSSTTSTN   | Mark: 00001000 10001101
+SNS                     | DUP
+TTT                     | LOAD
+NTSSSSSTSSSTSSSTTTSN    | BRZ > 00001000 10001110
+SSSTN                   | PUSH 1
+TSSS                    | ADD
+NSNSSSSTSSSTSSSTTSTN    | JMP > 00001000 10001101
+@ Load a character to the stack on each pass through this loop.
+NSSVSSSSTSSSTSSSTTTSN   | Mark: 00001000 10001110
+SNS                     | DUP
+TTT                     | LOAD
+SSSTSSN                 | PUSH 4
+NSTTTSSN                | JSR > 1100 (deepdup)
+SSSTSSN                 | PUSH 4
+TSSS                    | ADD
+NSTTSTSN                | JSR > 1010 (stackrotate)
+@ Test for end of loop.
+SNS                     | DUP
+SSSTTN                  | PUSH 3
+NSTTTSSN                | JSR > 1100 (deepdup)
+TSST                    | SUBTRACT
+NTSSSSSTSSSTSSSTTTTN    | BRZ > 00001000 10001111
+@ Decrement pointer to end of string, loop again.
+SSSTN                   | PUSH 1
+TSST                    | SUBTRACT
+NSNSSSSTSSSTSSSTTTSN    | JMP > 00001000 10001110
+@ Clean up and return.
+NSSVSSSSTSSSTSSSTTTTN   | Mark: 00001000 10001111
 SNN                     | DROP
 SNN                     | DROP
 NTN                     | RTS
 SNN                     | DROP
 SNN                     | DROP
 NTN                     | RTS
+
+#endif