--Andrew Sieber
absi...@eos.ncsu.edu
> 1 CONSTANT IDENTITY
> to create a constant labeled IDENTITY with value of 1, I would suggest
> 1 S" IDENTITY" CONSTANT
But change the name to protect the innocent. Following INCLUDE
and INCLUDED leads to CONSTANT and CONSTANTED, which is pretty bad,
so you're going to have to use some imahination.
Virtually,
Bruce R. McFarling, Newcastle, NSW
ec...@cc.newcastle.edu.au
>A (possibly) better solution would be to have a common word, with a
>common delimiter, to parse the input stream, dynamically allocate memory
>for a counted string, and store a pointer to that counted string on the
>stack. Words such as CREATE, VARIABLE, and so on can then expect ALL of
>their arguments from the stack, including the pointer to the string,
>rather than having to parse the input stream themselves. For example,
>whereas traditional Forth would use
>1 CONSTANT IDENTITY
>to create a constant labeled IDENTITY with value of 1, I would suggest
>1 S" IDENTITY" CONSTANT
>to do the same thing.
This kind of factoring is IMHO one step too far. Forth already has the
reputation of being a write-only language and you want to make it a little
worse. As a matter of fact, why don't we drop VARIABLE and simply write:
CREATE MYVAR 1 CELLS ALLOT
No! These words are just created to make Forth a little more readable. I even
added: STRING and ARRAY in 4tH:
: STRING CREATE CHARS ALLOT ;
: ARRAY CREATE CELLS ALLOT ;
10 ARRAY MYARRAY
20 STRING MYSTRING
There are excellent tools in Forth to parse that identifier or string. No need
to change it for just some extra factoring.
Hans
================
"First make it work, then improve it."
Visit our website! http://visitweb.com/hansoft
*** Home of the 4tH compiler! ***
This is actually a very clear and unambiguous statement of the behavior
of defining words: they are preceded by numeric arguments, if any, and
followed immediately by the name of the word being defined. The name
isn't considered "an argument"; it is a syntactic element in the
defining process.
> A (possibly) better solution would be to have a common word, with a
> common delimiter, to parse the input stream, dynamically allocate memory
> for a counted string, and store a pointer to that counted string on the
> stack....
This sounds like a rather complex solution to a non-problem.
> This idea also has the benefit that words such as CREATE can more easily
> be used within colon definitions, since the traditional method of only
> reading the input stream to obtain the name of the word to create makes
> the use of CREATE in a colon definition a pain in the butt (at least as
> far as I'm aware), unless you happen to WANT to get the name from the
> run-time input stream (which isn't necessarily the case).
You must have an unusual perception of what CREATE and other defining
words are for. I don't recall encountering a single situation in which
this normal behavior has been viewed as a "pain in the butt". In
teaching newcomers to Forth, however, (which I do often!) we often find
surprise at this behavior because what they are trying to do is make
local variables. There is a different syntax in ANS Forth, supported by
many systems, for making local variables if that is what you want. But
we recommend learning to program well without local variables first, in
order to know when to use them effectively.
> I am curious what the experienced Forth programmers here have to say
> about this. If this particular topic has already been discussed to
> death, I apologize; I've not seen any discussion about it. I would also
> be interested to know if someone has already implemented this type of
> behavior in a Forth system.
Well, the topic crops up about once a year, but it can't be considered
"talked to death" so long as someone still wants to discuss it!
Cheers,
Elizabeth
--
===============================================
Elizabeth D. Rather (US & Canada) 800-55-FORTH
FORTH Inc. +1 310-372-8493
111 N. Sepulveda Blvd. Fax: +1 310-318-7130
Manhattan Beach, CA 90266
http://www.forth.com
"Forth-based products and Services for real-time
applications since 1973."
===============================================
> An idea for the modification of the behavior of CREATE and strings:
> Traditional Forth has several words which parse the input stream; ." and
> CREATE and CONSTANT and VARIABLE and .( and several others all parse the
> input stream, with various terminating delimiters, including quote,
> space, and right parenthesis. Some of them, such as CONSTANT and
> VARIABLE, take arguments on the left (from the stack), AND on the right
> (from the input stream).
> A (possibly) better solution would be to have a common word, with a
> common delimiter, to parse the input stream, dynamically allocate memory
> for a counted string, and store a pointer to that counted string on the
> stack. Words such as CREATE, VARIABLE, and so on can then expect ALL of
> their arguments from the stack, including the pointer to the string,
> rather than having to parse the input stream themselves. For example,
I follow you, until the dynamically allocation part. That is not essential.
In tForth and now in iForth one can set/reset a USER variable so that CREATE
takes its argument from the stack: ( c-addr u -- ). If I'm not mistaken,
Win32Forth and / or F-PC have this same feature. In practice I've used
this possibility only twice in many hundreds of programs. So I would say it
is not essential, merely "elegant", or "natural". Incidentally, you didn't
forget that : FOO bar ; should become S" FOO" : bar ;, didn't you?
> whereas traditional Forth would use
> 1 CONSTANT IDENTITY
> to create a constant labeled IDENTITY with value of 1, I would suggest
> 1 S" IDENTITY" CONSTANT
> to do the same thing. The word S" would parse the input stream up to
> the delimiting quote, and place a pointer to a newly allocated location
> in memory (the "heap") that contains the string IDENTITY. CONSTANT
Could it be that you don't know that the word S" already exists in ANS
Forth, and that it (probably) is implemented as you suggest?
> would then get both the value and name for the constant from stack
> arguments, rather than having to parse the input stream itself.
> CONSTANT (or whatever component of CONSTANT, probably CREATE) would of
> course have to complain somehow if the string did not contain a valid
> identifier (ie. the string has spaces, or linefeeds, etc). It would
> also have to free the heap memory that S" used to create the string. S"
> should read the input stream literally; if there are carriage returns,
> multiple spaces, or tabs, it should treat those the same as any other
Already taken care of by the existing CREATE and S"
> characters. Of course, there needs to be a corresponding word SI" that
> is defined as
> : SI" S" LITERAL ; IMMEDIATE
SLITERAL
> for use in colon definitions in which a string is needed from the input
> stream at compile time rather than run time. The word ". could be
> defined to take the string pointer on the top of the stack and print out
> the string that it points to, then deallocate the string. So
> : HELLO SI" HELLO" ". ;
HELLO HELLO wouldn't work then. Besides, if you really want it, do
: HELLO S" HELLO" TYPE ; in ANS Forth.
A far more annoying problem in Forth is that you can't escape delimiter
characters inside string. So ." Hello, ""brave, new"" world!" doesn't
work.
> would be the same as a traditional
> : HELLO ." HELLO" ;
[..]
> I am curious what the experienced Forth programmers here have to say
> about this. If this particular topic has already been discussed to
> death, I apologize; I've not seen any discussion about it. I would also
It regularly pops up, so it's time it gets its place in the FAQ.
> be interested to know if someone has already implemented this type of
> behavior in a Forth system.
-marcel
<http://www.iaehv.nl/users/mhx/>
On 1998-02-06 han...@geocities.com said:
:This kind of factoring is IMHO one step too far. Forth already has
:the reputation of being a write-only language and you want to make
:it a little worse.
agreed.
:As a matter of fact, why don't we drop VARIABLE and simply write:
indeed, why don't we just drop VARIABLE completely, drop variables as a
concept, add function composition, add closures, add objects, and make
forth a pure functional language? that'd be much more fun. ;>
[8< 8< <-- scissors, not frowneys]
-- Communa -- lisard AT zetnet DOT co DOT uk (no spam, we're allergic)
wasted views - that's all they see blue hot blood guilt optic nerve
Net-Tamer V 1.08X - Test Drive
>A far more annoying problem in Forth is that you can't escape delimiter
>characters inside string. So ." Hello, ""brave, new"" world!" doesn't
>work.
This ought to be possible. Here's a first sketch in that direction:
: (."" ( caN lenN ... ca0 len0 N+1 -- )
0 DO TYPE LOOP ;
: ."" ( "chars" """ -- )
1 >R BEGIN
[CHAR] " PARSE
SOURCE >IN @ TUCK > WHILE
CHARS + C@ [CHAR] " = WHILE
1+ R> 1+ >R 1 >IN +!
REPEAT
THEN
R@ 0 DO POSTPONE SLITERAL LOOP
R> POSTPONE LITERAL
POSTPONE (."" ;
I haven't tested this. I haven't generalized it. It should be easy to
do this with any delimiter and for many uses for the strings. The
question is, do we get enough value from the result to be worth the
complication?
>In article <6bfoek$9u5$1...@news.IAEhv.nl>,
> m...@iaehv.iaehv.nl (Marcel Hendrix) wrote:
>>A far more annoying problem in Forth is that you can't escape delimiter
>>characters inside string. So ." Hello, ""brave, new"" world!" doesn't
>>work.
>This ought to be possible. Here's a first sketch in that direction:
Of course it's possible, everything we need can be added. What "annoys" me
(this means "I never encountered the case where it would have been bad for
ME" :-) is that standard words like ( .( ." S" and C" are not specified to
allow it. It does appear to me that if PARSE and WORD are changed to allow
escaping, BL WORD will act weird.
What I did in iForth is to define .~ and S~ as alternatives for .( ." and S".
In fact, there is a USER "CHAR that contains the delimiter for all words that
seem to use CHAR " . Of course there are strings that contain both CHAR " and
CHAR ~ , but they are very rare.
> : (."" ( caN lenN ... ca0 len0 N+1 -- )
> 0 DO TYPE LOOP ;
> : ."" ( "chars" """ -- )
> 1 >R BEGIN
> [CHAR] " PARSE
> SOURCE >IN @ TUCK > WHILE
> CHARS + C@ [CHAR] " = WHILE
> 1+ R> 1+ >R 1 >IN +!
> REPEAT
> THEN
> R@ 0 DO POSTPONE SLITERAL LOOP
> R> POSTPONE LITERAL
> POSTPONE (."" ;
> I haven't tested this. I haven't generalized it. It should be easy to
With an additional IMMEDIATE it works for me. Of course, in
real systems we only want a single string and a single TYPE.
> do this with any delimiter and for many uses for the strings. The
> question is, do we get enough value from the result to be worth the
> complication?
What speaks against more functionality? The runtime overhead could be made
zero. The compile time overhead and the larger compiler are a disadvantage
for small, self-compiling, 8 or 16-bit systems. But most small systems are
target compiled nowadays.
Why it hasn't been in Forth from the start? It must have been a conscious
decision to leave it out.
-marcel
Here are examples of CONSTANT, CODE words and ' : ' definitions
taken from StoicBas.STC
% DEFINE COMMONLY USED CONSTANTS
0 '0 CONSTANT
1 '1 CONSTANT
% DUPLOCATE TOP OF STACK
'DUP CODE< H POP, H PUSH, PUSH JMP, >
% DUPLICATE TOP - 1
'OVER CODE< 2 H LXI, SP DAD, @PUSH JMP, >
% OUTPUT N BYTES STARTING AT ADDRESS AT TOP - 1; N AT TOP
'TYPE : OVER + SWAP UDO I B@ TYO ULOOP ;
STOIC used transient compilation for its outer interpreter. The syntax
you suggest may have been more natural in this environment.
The strange thing is that I find it harder to read than putting the
defining word at the beginning of the line as in FORTH.
--
Bill Powell. ( MIME, UU )
Atherstone, Warks., CV9 3AR. | Tel: +44 1827-718 945
<whpo...@iee.org> | Fax: -714 884
>How about just using CHAR in the definition instead of [CHAR] " ?
>
>: $ CHAR PARSE SLITERAL ; IMMEDIATE
>: ... $ "Hello World" ;
>: .... $ 'Hello "brave, new" World!' ;
>
>This works for any character string, so long as you don't want to
>include the _entire_ character set!
Two things, 1) SLITERAL is an immediate word so you need to POSTPONE
it in the above case. So change the definition of $ to:
: $ CHAR PARSE POSTPONE SLITERAL ; IMMEDIATE
And 2) CHAR parses a "name" (and then returns the value of name's
first char on the stack) so it'd parse the whole of "Hello World"
which you don't want. Just change its usage to:
: aa $ " Hello World" ;
or
: bb $ ' Hello "brave, new" World!' ;
and then
aa type bb type \ or whatever
I very much like this solution though - great one! It's the best and
simplest solution I've seen to this problem of throwing quotes and
other characters in your strings.
l8r, Ben Hoyt ben...@clear.net.nz
> Jonah Thomas <jeth...@ix.netcom.com> wrote Re: Postfix CREATE
> >In article <6bfoek$9u5$1...@news.IAEhv.nl>,
> > m...@iaehv.iaehv.nl (Marcel Hendrix) wrote:
> >>A far more annoying problem in Forth is that you can't escape delimiter
> >>characters inside string. So ." Hello, ""brave, new"" world!" doesn't
> >>work.
> >This ought to be possible. Here's a first sketch in that direction:
> Of course it's possible, everything we need can be added. What "annoys" me
> (this means "I never encountered the case where it would have been bad for
> ME" :-) is that standard words like ( .( ." S" and C" are not specified to
> allow it. It does appear to me that if PARSE and WORD are changed to allow
> escaping, BL WORD will act weird.
How about just using CHAR in the definition instead of [CHAR] " ?
: $ CHAR PARSE SLITERAL ; IMMEDIATE
: ... $ "Hello World" ;
: .... $ 'Hello "brave, new" World!' ;
This works for any character string, so long as you don't want to
include the _entire_ character set!
--
Jack Brien
Prove all things - hold fast to that which is good (1 Thessalonians 5:21)
www.users.zetnet.co.uk/aborigine/forth.htm
Home of the FIG UK website
>How about just using CHAR in the definition instead of [CHAR] " ?
>: $ CHAR PARSE SLITERAL ; IMMEDIATE
>: ... $ "Hello World" ;
>: .... $ 'Hello "brave, new" World!' ;
>This works for any character string, so long as you don't want to
>include the _entire_ character set!
That looks good, and it's similar to something Wil Baden does.
You'd need an extra space using CHAR
: ... $ " Hello World" ;
CHAR takes the whole next word and throws away everything but the first
character. It might be nice to have it just take one character, to be
like KEY , but that isn't the way it works. It's easy to add 1CHAR
: 1CHAR ( -- char )
BEGIN
SOURCE >IN @ > 0= WHILE
DROP REFILL 0= ABORT" can't refill buffer"
REPEAT
SOURCE DROP >IN @ CHARS + C@
1 >IN +!
;
but that adds another word, when by using careful spaces we can get by
with the standard word.
If you don't mind the possibility of getting garbage when the input buffer
is empty, you can make it simpler:
: 1CHAR ( -- char )
SOURCE DROP >IN @ CHARS + C@ 1 >IN +! ;
And you can use it to define CHAR
: CHAR ( -- char )
BEGIN 1CHAR DUP BL = WHILE DROP REPEAT \ get first nonblank char
BL PARSE 2DROP ; \ remove rest of word
or
: CHAR ( -- char )
BL SKIP 1CHAR BL PARSE 2DROP ;
> Win32Forth and / or F-PC have this same feature. In practice I've used
> this possibility only twice in many hundreds of programs. So I would say it
> is not essential, merely "elegant", or "natural". Incidentally, you didn't
> forget that : FOO bar ; should become S" FOO" : bar ;, didn't you?
Actually I did forget.
> Could it be that you don't know that the word S" already exists in ANS
> Forth, and that it (probably) is implemented as you suggest?
The core wordset version of the Ans S" puts the string in the
dictionary, and I have to delete it manually if I want it gone after
using it. The file wordset version uses a buffer to store the string as
I want, but this buffer is overwritten by subsequent uses of S".
> > for use in colon definitions in which a string is needed from the input
> > stream at compile time rather than run time. The word ". could be
> > defined to take the string pointer on the top of the stack and print out
> > the string that it points to, then deallocate the string. So
> > : HELLO SI" HELLO" ". ;
>
> HELLO HELLO wouldn't work then. Besides, if you really want it, do
> : HELLO S" HELLO" TYPE ; in ANS Forth.
I'm probably missing something obvious, but I don't see why HELLO HELLO
wouldn't work.
> It regularly pops up, so it's time it gets its place in the FAQ.
I would also like to see it in the FAQ.
--Andrew
> > A (possibly) better solution would be to have a common word, with a
> > common delimiter, to parse the input stream, dynamically allocate memory
> > for a counted string, and store a pointer to that counted string on the
> > stack....
>
> This sounds like a rather complex solution to a non-problem.
OK I'll concur that for this simplistic example, Forth's default
behavior is better. Better to use infix where's its convenient rather
than try to force the use of postfix _everywhere_.
But I stand by my statement below about the un-dynamicness of CREATE.
> > This idea also has the benefit that words such as CREATE can more easily
> > be used within colon definitions, since the traditional method of only
> > reading the input stream to obtain the name of the word to create makes
> > the use of CREATE in a colon definition a pain in the butt (at least as
> > far as I'm aware), unless you happen to WANT to get the name from the
> > run-time input stream (which isn't necessarily the case).
>
> You must have an unusual perception of what CREATE and other defining
> words are for. I don't recall encountering a single situation in which
> this normal behavior has been viewed as a "pain in the butt". In
> teaching newcomers to Forth, however, (which I do often!) we often find
> surprise at this behavior because what they are trying to do is make
> local variables. There is a different syntax in ANS Forth, supported by
> many systems, for making local variables if that is what you want. But
> we recommend learning to program well without local variables first, in
> order to know when to use them effectively.
My goal isn't the creation of local variables with CREATE. I agree,
that would be a rather warped thing to do. I use the stacks for
temporary variables, and am aware that there's a locals wordset for the
times that I have too many temporary variables to handle efficiently on
the stack.
As a hypothetical situation, I'm writing a program that lets me
experiment with data structures that I can define arbitrarily at
runtime. I define a structure, enter in data and define search and
sort, etc. routines to act on that data structure. While I'm writing
the program, I already know that several structures that I'm going to
want to play with include arrays, and singly and doubly linked lists. I
write in the code to make these structures with CREATE statements, and
define search, sort, insert data and delete data routines for these
structures, and then when I compile and run the program I can create an
instance of one of these types and put some data in it, and run the
search and sort, etc. routines and time how long it takes to complete.
But then what happens if I want a binary tree? One option would be to
exit the program, load the source code, enter in code to create the
binary tree and search and sort it, and compile the program and re-run
it, and I would then have the binary tree option available to test.
However if I want to be able to do this at runtime then I need to be
able to write code that will create a defining word on the fly, using a
string that I supply at runtime for a name (eg. "BINARY-TREE", that will
create binary trees. The standard version of CREATE only takes the name
argument from the input stream at compile time, and since I don't know,
at compile time, the name of the structure that I want, the standard
version of CREATE will not suffice. The difference is between having a
static set of data structures to choose from, defined at compile time,
and having a dynamic, expandable set of data structures that I can
define at runtime. An example (though perhaps not the best one) would
be a operating system kernel that I've written that stores a process
table in memory as an array in which data about new processes are
appended to the end of the array. When I want to delete a process, I
have to remove it from the process table and collapse the entire array
to fill in the hole that I've created by deleting the process. Then a
buddy of mine sees this horrendous way of doing things and enlightens me
to the wonderful world of linked lists, which would be more efficient
that my array for the process table. The problem is that my kernel is
busy running important tasks that I can't shut down long enough to put
the new kernel in place. If I had written the kernel to allow dynamic
changing of the data structure used to hold process information, I
wouldn't have this problem. Of course in this particular example I
would hope that I wouldn't be so stupid as to create an inefficient
kernel to begin with, but in other applications it might be practical to
not only change the data structures on the fly, but create new types of
data structures on the fly.
Yes, I do have an unusual perception of what CREATE is for. Forth is
wonderfully dynamic at compile time, but no more so than any other
language at run time. Have you ever heard of anyone writing a C++
program that defines new classes on the fly, while the program is
running? Neither have I heard of the analogue being done in Forth. But
I want to be able to do it.
--Andrew
On 1998-02-12 absi...@eos.ncsu.edu said:
:I don't see how it's a syntactic element any more so than the "3"
:in "2 + 3" is a syntactic element of the infix addition operator.
:If I say "CREATE ME", "ME" is an argument to CREATE that specifies
:the name to be given to the new defining word. Sure it looks
:pretty to say "CREATE ME", but that's not postfix.
no, it's prefix. it's also easier to do it that way - you need WORD for
" anyway so why not reuse it? and using a prefix character (eg.
'this CREATE
) complicates the parser too much. (well, what moore considered too much
anyway.)
:OK I'll concur that for this simplistic example, Forth's default
:behavior is better. Better to use infix where's its convenient
:rather than try to force the use of postfix _everywhere_.
precisely.
:But I stand by my statement below about the un-dynamicness of
:CREATE.
erm, but create is supposed to be undynamic. the whole point about
dynamic structures is that they are (a) anonymous and (b) ambiguously
referred to. static structures usually aren't either - indeed, can't be
in something like Oberon. and it's for creating those kind of
definitions that CREATE is used. you want dynamic allocation, write a
MALLOC - don't try to make CREATE dynamic, it doesn't need it.
(we aren't saying that forth couldn't use some kind of dynamic
definition that's as flexible as static - just that it's not what CREATE
gets used for.)
:As a hypothetical situation, I'm writing
:a program that lets me experiment with data structures that I can
:define arbitrarily at runtime. I define a structure, enter in data
:and define search and sort, etc. routines to act on that data
:structure. While I'm writing the program, I already know that
:several structures that I'm going to want to play with include
:arrays, and singly and doubly linked lists. I write in the code to
:make these structures with CREATE statements, and define search,
:sort, insert data and delete data routines for these structures,
:and then when I compile and run the program I can create an
:instance of one of these types and put some data in it, and run the
:search and sort, etc. routines and time how long it takes to
:complete.
erm... you sound as if you mean an object-oriented variant of forth,
which is quite a bit beyond even MALLOC. multiple CFAs at least.
however, perhaps you would care to restructure your program so that it
makes use of the Forth dictionary and outer interpreter routines. then
use the commands you have just defined to play around. when you're done,
just FORGET the whole lot. what's the problem? forth should be like lisp
here, no compile/runtime distinction.
:But then what happens if I want a binary tree? One
:option would be to exit the program, load the source code, enter in
:code to create the binary tree and search and sort it, and compile
:the program and re-run it, and I would then have the binary tree
:option available to test. However if I want to be able to do this
:at runtime then I need to be able to write code that will create a
:defining word on the fly, using a string that I supply at runtime
:for a name (eg. "BINARY-TREE", that will create binary trees. The
:standard version of CREATE only takes the name argument from the
:input stream at compile time, and since I don't know, at compile
:time, the name of the structure that I want, the standard version
:of CREATE will not suffice.
you really do wish to add a defining word...? well, you'll have to
supply a bit more than just this - eg. code to do those definitions,
code to do the searching and sorting... and you're going to wish you
*had* used the facilities forth gave you gratis. :>
:The difference is between having a
:static set of data structures to choose from, defined at compile
:time, and having a dynamic, expandable set of data structures that
:I can define at runtime.
as we said, though - compile time *is* run time in forth. why shoot
yourself in the foot?
:An example (though perhaps not the best
:one) would be a operating system kernel that I've written that
:stores a process table in memory as an array in which data about
:new processes are appended to the end of the array. When I want to
:delete a process, I have to remove it from the process table and
:collapse the entire array to fill in the hole that I've created by
:deleting the process.
since you can make it a fixed size array, keep a bitmap of the free
process slots, and know that it won't exhaust your memory like dynamic
allocation can - we'd have to admit that you'd chosen a pretty contrived
example. :>
:Then a buddy of mine sees this horrendous
:way of doing things and enlightens me to the wonderful world of
:linked lists, which would be more efficient that my array for the
:process table. The problem is that my kernel is busy running
:important tasks that I can't shut down long enough to put the new
:kernel in place. If I had written the kernel to allow dynamic
:changing of the data structure used to hold process information, I
:wouldn't have this problem.
ok, but remember you'd also need to rewrite every single word that deals
with such things. DEFER comes in handy here, since those words will be
precompiled and a real bugger to replace in everything that calls them.
:Of course in this particular example I
:would hope that I wouldn't be so stupid as to create an inefficient
:kernel to begin with, but in other applications it might be
:practical to not only change the data structures on the fly, but
:create new types of data structures on the fly. Yes, I do have an
:unusual perception of what CREATE is for.
a perception which, with all due respect, you have failed to state
clearly.
:Forth is wonderfully
:dynamic at compile time, but no more so than any other language at
:run time. Have you ever heard of anyone writing a C++ program that
:defines new classes on the fly, while the program is running?
:Neither have I heard of the analogue being done in Forth. But I
:want to be able to do it.
define running. even if you have a command loop that works in a
completely different way to INTERPRET, there's no harm in adding an
'escape' mode that takes you right back there, so you can happily type
in
DEFER NIL
: BINARY-TREE CREATE NIL , ( left) NIL , ( right) , ( node) ;
: LEFT-LINK ;
: RIGHT-LINK CELL+ ;
: NODE 2 CELLS + ;
: FOLLOW @ ;
NIL BINARY-TREE (NIL)
' (NIL) => NIL
QUERY BINARY-TREE PROCESS
' COLLECT NEW-PROCESS PROCESS LEFT-LINK !
..
: SEARCH ( thing tree - addr|NIL) ...
and then go back to your running program and play around. *that* you
can't do in c++.
-- Communa (together) we remember... we'll see you falling
you know soft spoken changes nothing to sing within her...
> Marcel Hendrix wrote:
>> I follow you, until the dynamically allocation part. That is not essential.
>> In tForth and now in iForth one can set/reset a USER variable so that CREATE
>> takes its argument from the stack: ( c-addr u -- ). If I'm not mistaken,
> I don't like state-smart words.
Do you mean STATE-smart (which CREATE isn't) or state-smart?
>> Could it be that you don't know that the word S" already exists in ANS
>> Forth, and that it (probably) is implemented as you suggest?
> The core wordset version of the Ans S" puts the string in the
> dictionary, and I have to delete it manually if I want it gone after
> using it. The file wordset version uses a buffer to store the string as
> I want, but this buffer is overwritten by subsequent uses of S".
Actually, the Standard suggests that some Forths will allow the use of
several of these transient strings. It is of course your option to use
a minimal Forth, but I would not recommend it if language experiments
are what you're after.
>> > for use in colon definitions in which a string is needed from the input
>> > stream at compile time rather than run time. The word ". could be
>> > defined to take the string pointer on the top of the stack and print out
>> > the string that it points to, then deallocate the string. So
>> > : HELLO SI" HELLO" ". ;
>>
>> HELLO HELLO wouldn't work then. Besides, if you really want it, do
>> : HELLO S" HELLO" TYPE ; in ANS Forth.
> I'm probably missing something obvious, but I don't see why HELLO HELLO
> wouldn't work.
You aren't suggesting that HELLO allocates a new string, copies "HELLO"
into it from code space, prints the string, and deallocates the temporary
(I hope)? Maybe you should explain it some more (if you want me to understand
it).
-marcel
[ snipped an awful lot ]
> Yes, I do have an unusual perception of what CREATE is for. Forth is
> wonderfully dynamic at compile time, but no more so than any other
> language at run time. Have you ever heard of anyone writing a C++
> program that defines new classes on the fly, while the program is
> running?
No. But I can write a Forth interpreter in C++ and then ...
> Neither have I heard of the analogue being done in Forth.
As Forth is an interpreter, actually you are doing this all of the time.
Typing ": ccon create c, does> c@ ; 3 ccon bar 4 ccon fuubar" is defining
a class and instantiating 2 objects.
Are you by chance mixing up 4tH and Forth?
If you want Forth itself to write Forth programs, the above can be written
S" : ccon CREATE C, DOES> C@ ; 3 ccon bar 4 ccon fuubar" EVALUATE . The
input specification is generated using string operators (or CMOVE and
CHAR in a pinch). You don't need a postfix CREATE to do it, that should
be considered a style or user interface issue (actually a postfix
Forth makes trouble for EVALUATE because of embedded quotes).
> But
> I want to be able to do it.
There is nothing wrong with that. The proper phrase, however, is "I want to
learn how to do it."
E.g. GRAY <http://www.complang.tuwien.ac.at/projects/forth.html> lets you
define completely new languages on the fly and will execute code written
in it if you order it to, all in pass. Extreme enough?
-marcel
> That looks good, and it's similar to something Wil Baden does.
( Thanks for the reference, JET. I think that it's unfortunate that
`[CHAR]` and `CHAR` don't simply get the next character, but
it's tolerable.
This is what I have in the Tool Belt.
)
CREATE SBUF 80 CHARS ALLOT
: S ( char "ccc<char>" -- caddr u )
CHAR PARSE ( str len)
0 >R
BEGIN DUP WHILE
R@ 80 < NOT ABORT" Maximum String Length Exceeded. "
OVER C@ ( str len char)
DUP [CHAR] ^ = IF
DROP 1 /STRING OVER C@ 64 XOR
THEN
R> DUP 1+ >R CHARS SBUF + C! ( str len)
1 /STRING
REPEAT 2DROP
SBUF R> STATE @ IF POSTPONE SLITERAL THEN
; IMMEDIATE
(
If "ccc" doesn't contain `"` or `^` then `S " ccc"` is the same as
`S" ccc"`. But I can admonish --
: WARNING S | Just say "No".| TYPE ;
and include control chars --
: CRLF S " ^M^J" TYPE ;
`^?` will give the delete character.
--
Wil Baden Costa Mesa, California
)
--END--