add parsing for binary, octal, and hexadecimal literals

This commit is contained in:
Jesse D. McDonald 2020-10-24 14:12:30 -05:00
parent f89a98e0b0
commit 59ed031ca4
1 changed files with 52 additions and 16 deletions

View File

@ -74,6 +74,8 @@ LATEST ' BOOTSTRAP-GET-ORDER DEFER!
\ Decrement the array size and increment the address by the same amount \ Decrement the array size and increment the address by the same amount
: /STRING ( c-addr u1 u2 -- c-addr+u2 u1-u2 ) TUCK - -ROT + SWAP ; : /STRING ( c-addr u1 u2 -- c-addr+u2 u1-u2 ) TUCK - -ROT + SWAP ;
\ Semantically equivalent to "1 /STRING"
: 1/STRING ( c-addr u -- c-addr+1 u-1 ) 1- SWAP 1+ SWAP ;
\ Standard (ANS FORTH) THROW code assignments (-255 ... -1) \ Standard (ANS FORTH) THROW code assignments (-255 ... -1)
-1 CONSTANT EXCP-ABORT -1 CONSTANT EXCP-ABORT
@ -929,6 +931,51 @@ CREATE LEAVE-ORIG 0 ,
LOOP LOOP
2DROP R> SIGNUM ; 2DROP R> SIGNUM ;
\ True if n1 >= n2 && n1 <= n3, false otherwise
: WITHIN ( n1|u1 n2|u2 n3|u3 -- flag )
OVER - -ROT - U>= ;
\ Convert a character to lowercase or uppercase, respectively
: TO-LOWER ( ch1 -- ch2 )
DUP [CHAR] A [CHAR] Z WITHIN IF [ CHAR a CHAR A - ] LITERAL + THEN ;
: TO-UPPER ( ch1 -- ch2 )
DUP [CHAR] a [CHAR] z WITHIN IF [ CHAR a CHAR A - ] LITERAL - THEN ;
\ If ch is a digit (any base) return the value in range [0, 36) and TRUE
\ Otherwise just return FALSE
: >DIGIT ( ch -- u TRUE | FALSE )
DUP [CHAR] 0 [CHAR] 9 WITHIN IF [CHAR] 0 - TRUE EXIT THEN
DUP [CHAR] A [CHAR] Z WITHIN IF [ CHAR A 10 - ] LITERAL - TRUE EXIT THEN
DUP [CHAR] a [CHAR] z WITHIN IF [ CHAR a 10 - ] LITERAL - TRUE EXIT THEN
DROP FALSE ;
\ Convert a string in the given base to an unsigned double-cell number
\ Stop at the end of the string or when the next character is not valid for the base
\ Return the double-cell number and the remainder of the string
: >NUMBER-BASE ( c-addr1 u1 base -- ud c-addr2 u2 )
>R 0 0 2SWAP
BEGIN
DUP 0= IF RDROP EXIT THEN
OVER C@ >DIGIT 0= IF RDROP EXIT THEN
DUP R@ U>= IF RDROP DROP EXIT THEN
>R 1/STRING 2SWAP 2R@ DROP 0 D* R> 0 D+ 2SWAP
AGAIN ;
: >NUMBER ( c-addr1 u1 -- ud c-addr2 u2 )
DUP 0= IF 0 0 2SWAP EXIT THEN
OVER C@ [CHAR] 0 = IF
1/STRING
DUP 0= IF 0 0 2SWAP EXIT THEN
OVER C@ TO-UPPER CASE
[CHAR] B OF 1/STRING 2 ENDOF
[CHAR] X OF 1/STRING 16 ENDOF
8 SWAP
ENDCASE
ELSE
10
THEN
>NUMBER-BASE ;
\ Copy the bootstrap SOURCE values into variables to allow changing the input buffer \ Copy the bootstrap SOURCE values into variables to allow changing the input buffer
CREATE INPUT-BUFFER SOURCE 2, CREATE INPUT-BUFFER SOURCE 2,
@ -1765,22 +1812,11 @@ CREATE TIB-LEFTOVER-BYTES 0 ,
: PARSENUMBER ( c-addr u -- n TRUE | c-addr u FALSE ) : PARSENUMBER ( c-addr u -- n TRUE | c-addr u FALSE )
DUP 0= IF FALSE EXIT THEN DUP 0= IF FALSE EXIT THEN
2>R 2R@ DROP C@ [CHAR] - = 0 2DUP OVER C@ [CHAR] - = DUP >R IF
( S: neg-flag accum ) ( R: c-addr u ) 1/STRING DUP 0= IF 2DROP RDROP FALSE EXIT THEN
OVER IF R@ 1 = IF 2DROP 2R> FALSE EXIT THEN THEN THEN
OVER 2R@ ROT IF 1- SWAP 1+ SWAP THEN >NUMBER DUP 0<> IF 2DROP 2DROP RDROP FALSE EXIT THEN
( S: neg-flag accum c-addr' u' ) ( R: c-addr u ) 2DROP 2NIP DROP R> IF NEGATE THEN TRUE ;
BEGIN ?DUP WHILE
OVER -ROT 2>R C@ [CHAR] 0 -
( S: neg-flag accum digit ) ( R: c-addr u c-addr' u' )
DUP 9 U> IF DROP 2DROP 2RDROP 2R> FALSE EXIT THEN
SWAP 10 * + 2R>
( S: neg-flag accum' c-addr' u' ) ( R: c-addr u )
1- SWAP 1+ SWAP
REPEAT
( S: neg-flag accum c-addr' ) ( R: c-addr u )
2RDROP DROP SWAP IF NEGATE THEN
TRUE ;
\ Read a word, number, or string and either execute it or compile it \ Read a word, number, or string and either execute it or compile it
\ The stack effect depends on the input and the current value of STATE \ The stack effect depends on the input and the current value of STATE