26171e6f9d35157cfe1e58b6cd56f81a8d400754
[vvhitespace] / stdlib / stdio.pvvs
@ (c) 2020 Aaron Taylor <ataylor at subgeniuskitty dot com>
@ See LICENSE.txt file for copyright and license details.
#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
NSNTSSSTSSN | JMP > 1000100
NSSVSTSSSTSSSSSSSSSTN | Mark: 01000100 00000001
SNN | DROP
NTN | RTS
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ 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
NTSSTSSSTSTSSSSSSSTN | BRZ > 01000101 00000001
TNSS | Print character
SSSTN | Push +1
TSSS | ADD
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)
@ Catch -(2^63) as a special case since its absolute value will overflow
@ a twos-complement 64-bit word.
SNS | DUP
SSTTSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSN | -(2^63)
TSST | SUBTRACT
NTSSTSSSSTTSSSSSSTSN | BRZ > 01000011 00000010
@ No special case applies. Prepare for computation by converting the number
@ to absolute value and preparing a string on the 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
@ Replace the number on the stack with its decimal ASCII representation.
NSSVSTSSSSTTSSSSSSTSN | BRZ > 01000011 00000010
SNN | DROP
A"-9223372036854775808"
NSNSTSSSSTTSSSSSSSTN | JMP > 01000011 00000001
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ 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
SSSTTTSTSSN | 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
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
#endif