From b6bea2cfd080c66a11074dd47484711482a2907a Mon Sep 17 00:00:00 2001 From: Aaron Taylor Date: Thu, 12 Mar 2020 21:50:47 -0700 Subject: [PATCH] Added 'atoi' to stdlib. --- stdlib/README.md | 1 + stdlib/convert.pvvs | 88 +++++++++++++++++++++++++++++++++++++ stdlib_tests/7001_atoi.pvvs | 59 +++++++++++++++++++++++++ stdlib_tests/vv_test.py | 1 + 4 files changed, 149 insertions(+) create mode 100644 stdlib/convert.pvvs create mode 100644 stdlib_tests/7001_atoi.pvvs diff --git a/stdlib/README.md b/stdlib/README.md index 40b9f4a..eb92964 100644 --- a/stdlib/README.md +++ b/stdlib/README.md @@ -63,6 +63,7 @@ header comment for each function to learn the call and return stack. 101100 ----- rshift (logic.pvvs) 101101 ----- lshift (logic.pvvs) 110xxx - conversion functions + 110000 ----- atoi (convert.pvvs) 111xxx - debug functions 111000 ----- dump heap (debug.pvvs) 111001 ----- dump stack (debug.pvvs) diff --git a/stdlib/convert.pvvs b/stdlib/convert.pvvs new file mode 100644 index 0000000..e20c809 --- /dev/null +++ b/stdlib/convert.pvvs @@ -0,0 +1,88 @@ +#ifndef VVS_STDLIB_CONVERT +#define VVS_STDLIB_CONVERT + +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@ Name: +@ atoi (110000) +@ Description: +@ Convert null-terminated ASCII string to integer. +@ Result is negative if leading character is a hyphen ('-'). +@ Result is positive if leading character is a plus sign ('+') or number. +@ Excluding the sign, parsing halts on the first non-numeric ASCII character. +@ Since all possible return values are valid, this subroutine simply returns +@ zero if no parseable number was found. Any stronger validity checks are the +@ responsibility of the caller. Similarly, no overflow checks are performed. +@ In addition to returning the parsed integer, also returns a pointer to the +@ first character after the parsed integer. +@ Call Stack: +@ pointer to first character <-- TOS +@ Return Stack: +@ integer +@ pointer to last parsed character <-- TOS +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#include +#include +NSSVTTSSSSN | Mark: 110000 (atoi) + +@ Check the first character and create a 'sign' flag on the stack. +@ Update the pointer to point to the first numeric character. +SNS | DUP +TTT | LOAD +SSSSSTSTTSTN | PUSH 45 (ASCII '-') +TSST | SUBTRACT +NTSSSTTSSSSSSSSSSSSN | BRZ > 00110000 00000000 (found_minus_sign) +SNS | DUP +TTT | LOAD +SSSSSTSTSTTN | PUSH 43 (ASCII '+') +TSST | SUBTRACT +NTSSSTTSSSSSSSSSSSTN | BRZ > 00110000 00000001 (found_plus_sign) +NSNSSTTSSSSSSSSSSTSN | JMP > 00110000 00000010 (found_digit) +NSSVSSTTSSSSSSSSSSSTN | Mark: 00110000 00000001 (found_plus_sign) +SSSTN | PUSH +1 +TSSS | ADD +NSSVSSTTSSSSSSSSSSTSN | Mark: 00110000 00000010 (found_digit) +SSSTN | PUSH +1 (sign_flag) +SNT | SWAP +NSNSSTTSSSSSSSSSSTTN | JMP > 00110000 00000011 (done_with_sign_flag) +NSSVSSTTSSSSSSSSSSSSN | Mark: 00110000 00000000 (found_minus_sign) +SSSTN | PUSH +1 +TSSS | ADD +SSTTN | PUSH -1 (sign_flag) +SNT | SWAP +NSSVSSTTSSSSSSSSSSTTN | Mark: 00110000 00000011 (done_with_sign_flag) + +@ Create an accumulator on the TOS. +SSSSN | PUSH 0 (accumulator) + +@ Main loop examines string one character at a time, building result in accumulator. +@ TOS> accumulator, string_ptr, sign_flag +NSSVSSTTSSSSSSSSSTSSN | Mark: 00110000 00000100 (atoi:main_loop) +SSSTSN | PUSH +2 +NSTTTSSN | JSR > 1100 (deepdup) +TTT | LOAD +SNS | DUP +NSTTSSSSTN | JSR > 100001 (isdigit) +NTSSSTTSSSSSSSSSTSTN | BRZ > 00110000 00000101 (found_end_of_number) +SSSSSTTSSSSN | PUSH 48 (ASCII '0') +TSST | SUBTRACT +SNT | SWAP +SSSTSTSN | PUSH 10 +TSSN | MULTIPLY +TSSS | ADD +SNT | SWAP +SSSTN | PUSH 1 +TSSS | ADD +SNT | SWAP +NSNSSTTSSSSSSSSSTSSN | JMP > 00110000 00000100 (atoi:main_loop) + +@ Clean up and return +@ TOS> character, accumulator, string_ptr, sign_flag +NSSVSSTTSSSSSSSSSTSTN | Mark: 00110000 00000101 (found_end_of_number) +SNN | DROP +SSSTTN | PUSH 3 +NSTTSTTN | JSR > 1011 (stackrotatereverse) +TSSN | MULTIPLY +SNT | SWAP +NTN | RTS + +#endif diff --git a/stdlib_tests/7001_atoi.pvvs b/stdlib_tests/7001_atoi.pvvs new file mode 100644 index 0000000..c4ea625 --- /dev/null +++ b/stdlib_tests/7001_atoi.pvvs @@ -0,0 +1,59 @@ +A"42" +SSSTSSSSSN | PUSH 32 (address) +SSSTSN | PUSH 2 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +A"+42" +SSSTSSSSSN | PUSH 32 (address) +SSSTTN | PUSH 3 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +A"-42" +SSSTSSSSSN | PUSH 32 (address) +SSSTTN | PUSH 3 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +A"+" +SSSTSSSSSN | PUSH 32 (address) +SSSTN | PUSH 1 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +A"-" +SSSTSSSSSN | PUSH 32 (address) +SSSTN | PUSH 1 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +A"" +SSSTSSSSSN | PUSH 32 (address) +SSSSN | PUSH 0 (count) +NSTTTTTTN | JSR > 11111 (spew) +SSSTSSSSSN | PUSH 32 (address) +NSTTTSSSSN | JSR > 110000 (atoi) +SNN | DROP +NSTTTTTSTN | JSR > 111101 (debug:printsignednumber) + +NNN | DIE + +#include +#include +#include diff --git a/stdlib_tests/vv_test.py b/stdlib_tests/vv_test.py index 4ec6a81..045f81c 100755 --- a/stdlib_tests/vv_test.py +++ b/stdlib_tests/vv_test.py @@ -50,6 +50,7 @@ tests = [ ['6007_printf_staticheapstring', '', 'test'], ['6008_printf_escapedstackstring', '', '\\%\t\n'], ['6009_printf_substitutedstackstring', '', 'Atest142+42'], + ['7001_atoi', '', '+42+42-42+0+0+0'], ] for test in tests: -- 2.20.1