Question

I'm trying to append two strings in gforth, but I get some scary looking error messages.

While s" foo" s" bar" append type cr works fine, as soon as I start storing strings in variables or creating them from words, I get errors. For instance:

: make-string ( -- s )
    s" foo" ;

: append-print ( s s -- )
    append type cr ;

make-string s" bar" append-print

Running it produces the following error:

$ gforth prob1.fs -e bye
gforth(41572,0x7fff79cc2310) malloc: *** error for object 0x103a551a0: pointer being realloc'd was not allocated
*** set a breakpoint in malloc_error_break to debug

Abort trap: 6.

I'm well versed in C, so it seems pretty clear that I'm using Forth incorrectly! I suppose I need to learn something very basic about memory management in Forth.

Can anyone please explain what goes wrong here, and what I should do?

I also run into problems when I try to append a string that is stored in a variable:

variable foo
s" foo" foo !

foo s" bar " append type cr

This ends in a loop that I have to break:

$ gforth prob2.fs
foo��^C
in file included from *OS command line*:-1
prob2.fs:4: User interrupt
foo s" bar " append >>>type<<< cr
Backtrace:
$10C7C2E90 write-file

For reference, I'm using gforth 0.7.2 on Mac OS X. I would be very grateful for some good explanations on what's going on.

Update

I can see the definition of append:

see append
: append
  >l >l >l >l @local0 @local1 @local3 + dup >l resize throw >l @local4 @local0 @local3 + @local5
  move @local0 @local1 lp+!# 48 ; ok

So, it would seem I need to manage memory myself in Forth? If so, how?

Solution

Andreas Bombe provides the clue below. The final program that works would be

: make-string ( -- s )
  s" foo" ;

: append-print
  s+ type cr ;

make-string s" bar" append-print

Output is

$ gforth b.fs -e bye
foobar
Was it helpful?

Solution

append uses resize on the first string make space to append the second string. This requires that the string be allocated on the heap.

When you compile a string with s" into a word, it gets allocated in the dictionary. If you try resize (directly or indirectly through append) on that pointer you will get the error you see.

Normally s" has undefined interpretation semantics. Gforth defines its interpretation semantics for convenience as allocating the string on the heap. That's why it works (in gforth) as long as you don't compile it.

Edit:

I've found the definition of append, it's part of libcc.fs (a foreign function interface builder as it seems) and not a standard word. This is the definition in the source, more readable than the see decompile:

: append { addr1 u1 addr2 u2 -- addr u }
    addr1 u1 u2 + dup { u } resize throw { addr }
    addr2 addr u1 + u2 move
    addr u ;

Immediately before that is a definition of s+:

: s+ { addr1 u1 addr2 u2 -- addr u }
    u1 u2 + allocate throw { addr }
    addr1 addr u1 move
    addr2 addr u1 + u2 move
    addr u1 u2 +
;

As you can see this one allocates new memory space instead of resizing the first string and concatenates both strings into it. You could use this one instead. It is not a standard word however and just happens to be in your environment as an internal implementation detail of libcc.fs in gforth so you can't rely on it being available elsewhere.

OTHER TIPS

The usage of strings in Forth doesn't warrant dynamic allocation mostly and at least not in your example. You can get by nicely with buffers that you allocate yourself using ALLOT and some very simple words to manipulate them.

[ALLOT uses the data space (ANSI term) in an incremental fashion for adding words and buffers. It is not dynamic, you can't release an item without removing at the same time all items ALLOT-ted later. It is also simple. Do not confuse with ALLOCATE which is dynamic and is in a separate extension wordset]

You make a fundamental mistake in leaving out the specification of your append-buffer. It doesn't work, and we don't know how it is supposed to work!

In ciforth's an example could be:

 : astring S" foo" ;    

  CREATE buffer 100 ALLOT \ space for 100  chars 

  \ Put the first string in `buffer and append the second string.

  \ Also print the second string

 : append-print ( s s -- )

 type cr 2swap   

 buffer $!  

 buffer $+! ;   

 astring s" bar" append-print 

  bar OK \ answer

  buffer $@ TYPE 

  foobar OK \ answer

Other Forths have other non-standard words to manipulate simple strings. An excursion through malloc land is really not necessary. In the gforth documentation you can look up 'place' and find an equivalent family of words.

Also nowadays (Forth 2012) you can have strings like so "foo".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top