SuperFORTH Strings

Anything QL Software or Programming Related.
Post Reply
tcat
Super Gold Card
Posts: 633
Joined: Fri Jan 18, 2013 5:27 pm
Location: Prague, Czech Republic

SuperFORTH Strings

Post by tcat »

Hi,

I was thinking about strings, how they work etc. I looked at this site
http://www.forth.com/starting-forth/sf11/sf11.html and read the tutorial
for beginners. My definition of strings below, not perfect, but it DOES>
things, it's fun :-)

Code: Select all

( Definitions CHAR, [CHAR] )
( Takes a char from the input stream )
( leaves ASCII value on the stack )
: CHAR BL WORD 1+ C@ ; : [CHAR] CHAR ; IMMEDIATE

( Create string )
: S"       ( S" ..." --- adr n )
  [CHAR] " LITERAL WORD DUP COUNT PAD SWAP CMOVE
  C@ PAD SWAP ;

( Create string variable ) 
: STRING   ( n "name" --- adr n )
  CREATE DUP , HERE SWAP DUP ALLOT BLANK
         DOES> DUP 2+ SWAP @ ;

( Move string , ad1 +1..+n1 ->  ad2 +1.. )
: $MOVE    ( ad1 n1 ad2 n2  --- )
  2DUP BLANK ROT MIN CMOVE ;

( Print string )
: $.       ( ad n --- )
  -TRAILING CR TYPE ;

( Compare two strings )
( n=0 equal, n>0 str1>str2, n<0 str1<str2 )
VARIABLE ?SL             ( ? same lengths )
: $COMPARE         ( ad1 n1 ad2 n2  --- n )
  ROT 2DUP - NEGATE ?SL ! MIN
  0 DO 2DUP I + C@ SWAP I + C@ - DUP
  0 <> IF 0 LEAVE ELSE DROP THEN LOOP
  0= IF ROT ROT 2DROP NEGATE ELSE DROP ?SL @ THEN ;

( Fetch a CHAR at string positon m )
: $C@          ( m ad n --- ch )
  ROT 1 MAX MIN SWAP + 1- C@ ;

( Stores a CHAR to string positon m )
: $C!          ( ch m ad n --- )
  ROT 1 MAX MIN SWAP + 1- C! ;

( Some short hand definitions )
: $BL BLANK ; : $! $MOVE ; : $= $COMPARE ; : C. EMIT ;

( Test, create strings [15] and [20] chars long )
15 STRING GREET  20 STRING INGS

( Test, strings are empty on creation )
GREET $. INGS $.

( Test, move string [11] -> GREET [15] )
( Print GREET )
S" HELLO THERE" GREET $MOVE
GREET $.

( Test, move string [24] -> INGS [20] )
( Print INGS )
S" PLEASED TO MEET YOU! ..." INGS $!
INGS $.

( Test, move GREET [15] -> INGS [20] )
( Print INGS )
GREET INGS $!
INGS $.

( Test, put 'x' to GREET at postion 10 )
( Print GREET )
CHAR x 10 GREET $C!
GREET $.

( Test, get chars at position 1,10 from INGS )
1 INGS $C@ CR C.
10 INGS $C@ C.

( Test, compare GREET, INGS )
GREET INGS $= CR .

( Test, compare < > = ) 
3 STRING TEST CR
S" ABC" TEST $!
S" ABC" TEST $= .
S" ABCD" TEST $= .
S" AB" TEST $= .
S" ABD" TEST $= .
S" ABB" TEST $= .

( Test, blank INGS )
( Print INGS )
INGS $BL
INGS $.

( Test, blank GREET )
( Print GREET )
S"  " GREET $!
GREET $.


END_FILE


I have it also in a single block :-)
Super FORTH Strings
Super FORTH Strings
FTH-strings.png (5.3 KiB) Viewed 3311 times
Tom
Last edited by tcat on Thu Dec 31, 2015 8:37 am, edited 1 time in total.


User avatar
programandala.net
Chuggy Microdrive
Posts: 74
Joined: Mon Dec 13, 2010 12:41 pm
Location: Spain
Contact:

Re: SuperFORTH Strings

Post by programandala.net »

tcat wrote:Hi,

I was thinking about strings, how they work etc. I looked at this site
http://www.forth.com/starting-forth/sf11/sf11.html and read the tutorial
for beginners. My definition of strings below, not perfect, but it DOES>
things, it's fun :-)
Nice work, Tom! SuperForth provides words to define and manipulate strings, but they use counted strings, not the more versatile format of address and length, found in modern Forth. So while you learn Forth you are updating SuperForth as well :)


Marcos Cruz (programandala.net)
User avatar
programandala.net
Chuggy Microdrive
Posts: 74
Joined: Mon Dec 13, 2010 12:41 pm
Location: Spain
Contact:

Re: SuperFORTH Strings

Post by programandala.net »

tcat wrote:
: CHAR BL WORD 1+ C@ ;
: [CHAR] CHAR ; IMMEDIATE
[/code]
By the way, you forgot to compile the character in `[CHAR]`:

Code: Select all

: [CHAR]  CHAR [COMPILE] LITERAL ; IMMEDIATE
Also, `s"` would be more useful (and standard) if you make it immediate and state-smart, so at run-time it will return the address, while at compile-time it will compile the string (and a previous word, to fetch it at run-time)... Forth is so flexible that things seems complicated at first sight, but they aren't :)


Marcos Cruz (programandala.net)
tcat
Super Gold Card
Posts: 633
Joined: Fri Jan 18, 2013 5:27 pm
Location: Prague, Czech Republic

Re: SuperFORTH Strings

Post by tcat »

Marco,

Thank you, with this definition of [CHAR], I can simplify the definition of S" ... leaving out LITERAL here, that is the part I was missing.

Code: Select all

: S"       ( S" ..." --- adr n )
  [CHAR] " WORD DUP COUNT PAD SWAP CMOVE
  C@ PAD SWAP ;
S" redefinition ... I will deal with later (A) I believe using PAD can save memory, while the purpose of S" ... might really be a temporary storage right before the assignment to a real string variable (B) I am not too sure how to do it, will need to try and learn first.

I also tried S*FTH built-in strings, I quite like the implementation of READ" and INPUT", also its complex vocabulary for string manipulation and slicing.

I wanted to define my own set of words, mainly to learn and usderstand better, while I found this very insteresting question when trying to search for the END_FILE word in the input stream.

Code: Select all


( create two IDENTICAL counted strings on stack )
: TEST ." 123" ; 
' TEST >BODY 2+
DUP

( compare strings, n=0 FALSE not equal, n=-1 TRUE equal ) 
( ad1 ad2 --- n)
$=

( print the result )
.
-1 

Now the interesting part, under uQLx emulator it returns -1 TRUE equal, on the real QL it returns 0 FALSE not equal. In fact it considers the first string less $< than its second copy.

????

Tom


User avatar
programandala.net
Chuggy Microdrive
Posts: 74
Joined: Mon Dec 13, 2010 12:41 pm
Location: Spain
Contact:

Re: SuperFORTH Strings

Post by programandala.net »

tcat wrote:

Code: Select all

: S"       ( S" ..." --- adr n )
I suggest using standard notation for representing the input stream in stack
effects, and also strings:

Code: Select all

: S"       ( "ccc<quote>" --- c-addr u )
I myself use a different convention I find clearer:

Code: Select all

: S"       ( "text<quote>" --- ca len )
tcat wrote: (A) I believe using PAD can save memory, while the purpose of S" ... might really be a temporary storage right before the assignment to a real string variable (B) I am not too sure how to do it, will need to try and learn first.
`pad` is not intended to be used by the system, but only by the programmer. I recommend an alternative storage for temporary strings, for example, to store two strings, so `s"` will overwrite always the old one.

You can also try a circular string buffer. You can adapt some of my implementations:

http://programandala.net/en.program.csb8.html
http://programandala.net/en.program.csb2.html
http://programandala.net/en.program.sbuffer.html

Anyway, I'm afraid this thread is becoming quite non-QL-specific :) , so I suggest we discuss the low-level Forth details in the Forth email list.


Marcos Cruz (programandala.net)
tcat
Super Gold Card
Posts: 633
Joined: Fri Jan 18, 2013 5:27 pm
Location: Prague, Czech Republic

Re: SuperFORTH Strings

Post by tcat »

Hi,

I just wish to share some conclusion about S*FTH strings, as there was some work done at Forth email list.

COMPARE ( $= $== ... ) uses UT.CSTR vectored utlity to compare strings, that have to be aligned and padded on word boundary. I suspect that UT.CSTR compares strings by words rather than by bytes, but not sure.

This works very fast and well with S*FTH strings having MAX_LEN byte, but may fail if used on strings right from the input stream e.g. BL WORD, QUERY etc., as they may not always appear on even address.

LOCATE is safe to use to search even for strings in the input stream, although not as fast.

Code: Select all

( string compare using LOCATE )
: $$= ( ad1 ad2 --- flag )
2DUP C@ SWAP C@ = ROT ROT 1 0 LOCATE NEGATE AND ;
: $$== ( ad1 ad2 --- flag )
2DUP C@ SWAP C@ = ROT ROT 1 1 LOCATE NEGATE AND ;
Or better still, Input (file) stream can be easilly scanned with INPUT word along with S*FTH strings, rather than with QUERY BL WORD, etc.


Cheers
Tom


Post Reply