Question

I'm trying to store a string value into a variable. To define the variable, I use:

: define CREATE 0 , ;
define x

I can easily store an integer/float value to x using

10 x !

or

10.0e x f!

And to access it I use either @ or f@. Now I'm trying to store a string value:

s" hello world" x !

The problem with this is that it pushes two values to the stack (since it's a counted string) but x ! will only store the item on top, which is the length of the string. This is dangerous since the stack content might have been modified by the time x is referenced such that the address is not directly below the length (bad!), so type would fail. So my question is, is there a way to store both values (address and length) to x? Or is there a different data type/operand that would let me achieve this?

Any help is appreciated.

Was it helpful?

Solution

A lot of the things that you need to make this work are quite conveniently similar to what you have already.

You need a different version of define if you want to store two values in the things that you create with it;

: 2define create 0 , 0 , ;

Putting two at the start of a word is a convention that indicates it does the same thing as that word without the two but instead does it on double-cell things.

To use this you would write:

2define 2x
//Write something to 2x
s" Hello world!" 2x 2!
//Retrieve it and print
2x 2@ type

It is worth noting that the address that s" returns is not guaranteed to last the duration of the program and may be overwritten by a later use of s", to see a way to make a string variable that is guaranteed to last have a look at this answer https://stackoverflow.com/a/8748192/547299 (it is a bit long winded but there is a definition of a word called string which might be illustrative).

OTHER TIPS

Don't get stuck on "!". This is more efficient ...

: 2x S" Hello World!" ;

Also, define is not safe for floats, it could be

   : define CREATE 0 f, does> f@ ;
 \   3.1459e0 define pi
 \   pi f. 3.1459 ok

Gforth has a $! ( c-addr u addr -- ) word precisely for this purpose. Given a string and an address, it copies the string into a freshly ALLOCATEd space and stores the string at the address. If the address already has a string stored at it, that string will be FREEd.

So:

define x
s" hello world" x $!

x $@ type  \ hello world

You can also use fixed buffers with counted strings and words like PLACE and +PLACE , which have $!'s same stack picture. Equivalently to the above (although with a character limitation):

256 buffer: x
s" hello world" x place

x count type  \ hello world

s" !" x +place
x count type  \ hello world!

You can't store a string in a VARIABLE that is in the Forth sense. VARIABLE has at most space for 2 4 or 8 length strings dependant on the Forth. If you want to store a string you need a buffer. The buffer has to be at the least longer than the string (duh!) and the length of the string must be obligatory stored with it, to accomodate the normal meaning of string. Apart from ALLOCATE-ing a buffer of the correct size, you must do the following.

1024 CONSTANT SIZE \ Pray this is enough
CREATE BUFFER SIZE ALLOT
"AAP" BUFFER $! 

The quoted string is 2012 standard, leaving (address, length). $! is left as an exercise. ^H^H^H^H^H^H

: $! ( cs s -- ) 2DUP ! CELL+ SWAP CMOVE ; 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top