[comp.lang.forth] Forth in C

putko@tolsun.oulu.fi (Heikki Putkonen) (01/07/88)

This may sound crazy, but I would need a forth interpreter which is
programmed in C. If you have an idea where I could find one, could
you please reply by e-mail (or send source).

	Heikki Putkonen, SUN-adm.                    (putko@oulu.fi)
	University of Oulu
	Institute of Data Processing Science
	Linnanmaa
	SF-90570 OULU 57
	Finland
 	


Newsgroups: comp.languages.forth
Subject: forth in c
Expires: 
References: 
Sender: Heikki I Putkonen 
Reply-To: putko@tolsun.UUCP (Heikki Putkonen)
Followup-To: 
Distribution: world
Organization: University of Oulu, Finland
Keywords: 
This may sound crazy, but I would need a forth interpreter which is
programmed in C. If you have an idea where I could find one, could
you please reply by e-mail (or send source).

	Heikki Putkonen, SUN-adm.                    (putko@oulu.fi)
	University of Oulu
	Institute of Data Processing Science
	Linnanmaa
	SF-90570 OULU 57
	Finland
 	

wmb@SUN.COM (Mitch Bradley) (11/07/89)

> I only need one hack to make this work: I need to be able to
> take the address of a label, i. e.

Sorry, you lose.  It can't be done in portable C.  Labels don't have
visible addresses.  Their scope is entirely contained within the enclosing
subroutine.

What you are suggesting is the first thing that I thought of doing when
I was writing C Forth 83, but I had to give up on that implementation
strategy.  The two options that I know of are indirect subroutine calls
(relatively slow) and a big switch with an integer selector (which is what
C Forth 83 uses).

Mitch

daemon@ucbvax.BERKELEY.EDU (11/07/89)

> I only need one hack to make this work: I need to be able to
> teke the address of a label, i. e.

Sorry, you lose. $It can't be done in portable C.  Labels don't heve
visible addresses.  Their scope is entirely contained within the enclosing
subroutine.

What you are suggesting is the fmrst thing that I thought of doing when
I was writing C Forth 83, but I had to give up on that implementation
strategy.  The two options that I know of are indirect subroutine calls
(relativel} slow) and a big switch with an integer selector (which is what
C Forth 83 uses).

Mitch

ir230@sdcc6.ucsd.edu (john wavrik) (11/10/89)

kurtl@fai.fai.com (Kurt Luoto) writes:

>  ..............               Some might call it a toy implementation,
> but it gave me the ability to exploit the power of Forth on a machine that 
> otherwise only had C.  I did "real work" with it, stuff that helped save 
> time and effort on my projects.  Does that qualify it for non-toyness? 

> Now I'm an assembly hacker at heart and, having done realtime/embedded 
> systems programming for most of my career, I can appreciate the need for 
> efficiency and machine-level access for many applications.  But I don't make 
> the mistake of assuming that all applications are like this.

   There are two things at issue here: the definition of "toy" and the reason 
that an assembly language implementation is desirable for Forth. Let me deal 
with the second issue first. 

   Because Forth is close to the architecture of the host processor (and 
includes an assembler) it does have the advantages Kurt Luoto notes (it is 
good for projects which require machine-level access and for projects which 
require efficiency). But it is a mistake to assume that these are the primary 
reasons for implementing Forth in the traditional way (using a little 
assembly language and a lot of Forth). Traditional Forth implementation is so 
simple that it is easy to add new features to the language -- new primitives, 
control structures, data types, etc.  What would you like:  quadruple 
precision integers?  complex numbers as a primitive data type?  graphics?  
strings?  local variables?  arithmetic of sets?  A construct  "IF:  COND1 
COND2 COND3 ... DO:"  that tests for a conjunction but will stop testing as 
soon as a condition fails?  redirection of I/O?  It is one thing to say that a 
professional compiler writer can build these things into a language -- quite 
another to say a language allows such things to be added by typical users. 

    The ability of a USER to add to a language almost anything one could 
conceive of is a rare attribute. It is this extraordinary degree of control 
(rather than the use of stacks and RPN) that characterizes Forth -- and it 
comes from the simplicity and accessibility of Forth implementation. Forth 
(when implemented traditionally) is more than just a rather small interactive 
stack-based language with Reverse Polish Syntax.  

    To make matters more concrete, suppose a Forth implementation lacks 
certain primitive words involving double precision numbers (D+, D-, */, */MOD, 
etc.), lacks a desired feature (like access to the OS timer) and has some 
errors in the implementation of one or two primitives. A typical Forth 
programmmer using a traditional Forth system can readily add the words (they 
have short definitions in assembly language), provide the features, and fix 
the bugs. 

   How is one to characterize a Forth implementation that does not allow a 
user the ability to add new primitives to the language?  Or to tap features of 
hardware and OS to do such simple things as adding a timer or redirecting 
output to a printer or file?  By imbedding Forth in another language this is 
exactly the situation that seems to be produced. New primitives cannot be 
added (or existing ones modified) from within the Forth environment without 
knowledge of how the program and compiler handle register assignments and 
stacks. They only can be added outside the Forth environment by someone who 
knows the implementation language and has access to (and understands) the 
source code for the implementation (most likely the implementor and not the 
user).

   Most people never miss what they don't know exists -- so it is no surprise 
that people who come to Forth from other languages will accept a version of 
Forth which is as static and rigid as a 'C' compiler. To someone accustomed to 
compiled languages, an interactive environment can be quite an experience -- 
and there is no doubt that even a limited version of Forth can do useful 
things. To call something "toy" does not mean that it is not useful -- it 
means that, in comparison to a non-toy version, it lacks both important 
characteristics and the means for obtaining them. (Thus a soap-box racer is a 
"toy" car, but a child is not a "toy" adult). Forth would be a "toy" language 
were it not for its ability (at least in traditional implementations) to 
accept important features as optional add-ons and to support almost unlimited 
modification. 

   Let me emphasize again that it is not speed or the ability to do hardware 
control applications that is the main argument for the traditional 
implementation of Forth. It is the resulting simplicity and accessibility of 
the implementation -- making the language malleable, allowing a user to 
exercise a high degree of control and to add powerful features as options. 

   One of my differences of opinion with my friends who speak Forth as a 
second language is how to best introduce Forth to speakers of their first 
language. Their idea is to package Forth in a form that natives will find 
familiar and comfortable (even if it means giving them the "look and feel" 
without some of the substance). My idea is to confront new people with a 
version of Forth that challenges rather than supports pre-conceived notions 
about programming languages. I want them to meet Forth on its own terms. 


                                                  John J Wavrik 
             jjwavrik@ucsd.edu                    Dept of Math  C-012 
                                                  Univ of Calif - San Diego 
                                                  La Jolla, CA  92093 

kurtl@fai.UUCP (Kurt Luoto) (11/14/89)

In article <4969@sdcc6.ucsd.edu> ir230@sdcc6.ucsd.edu (john wavrik) writes:
>
>   There are two things at issue here: the definition of "toy" and the reason 
>that an assembly language implementation is desirable for Forth.  [...]
>
> [...]  To call something "toy" does not mean that it is not useful -- it 
>means that, in comparison to a non-toy version, it lacks both important 
>characteristics and the means for obtaining them. (Thus a soap-box racer is a 
>"toy" car, but a child is not a "toy" adult).    [...]

I'll accept this as a working definition of a "toy" language implementation.

>   Let me emphasize again that it is not speed or the ability to do hardware 
>control applications that is the main argument for the traditional 
>implementation of Forth. It is the resulting simplicity and accessibility of 
>the implementation -- making the language malleable, allowing a user to 
>exercise a high degree of control and to add powerful features as options. 
>
>   One of my differences of opinion with my friends who speak Forth as a 
>second language is how to best introduce Forth to speakers of their first 
>language. Their idea is to package Forth in a form that natives will find 
>familiar and comfortable (even if it means giving them the "look and feel" 
>without some of the substance). My idea is to confront new people with a 
>version of Forth that challenges rather than supports pre-conceived notions 
>about programming languages. I want them to meet Forth on its own terms. 
>
>                                                  John J Wavrik 

As one who learned Forth long before learning C, I agree that it is well
worth the time invested for a programmer in any language to learn Forth
from a traditional implementation.  And I agree that Forth's simplicity,
malleability, and extensibility are some of its essential qualities. I'm
still not convinced that a C-implementation of Forth necessarily abrogates
these qualities.

In the case study from my last posting, I had to consider C to be the
practical replacement for assembly language.  In the actual case, this was
imposed by the system's vendor.  Some users might even prefer to
use C instead of a machine's assembly languagea.  Reasons might include
    
    -- portability
    -- lack of vendor supplied assembly support
    -- easy to add in existing C code as Forth primitives
    -- familiarity

Forth programmers (users) may still add new functionality (control structures,
double precision or floating point packages, etc) by writing their code
in terms of high-level Forth words.  Of course, these implementations
will usually be less efficient.  For users who are familiar with C,
there is no problem extending or modifying a C-implementation of Forth
by adding new primitives at the C-language level.  

Now adding new Forth primitives at the C-language level is usually not done
(if not impossible) during an interactive session.  The new primitives may
be viewed as "second-class citizens" among Forth words, since their imple-
mentation is in the C source rather than in the Forth source, and adding
them requires recompiling the Forth interpreter.

So, are C implementations of Forth simple, malleable and extensible?  Yes.
Can low-level primitives be added to a C-Forth implementation as easily
as in a traditional implementation?  No, C implementations are a tad more
cumbersome.  Does this additional difficulty mean C-implementations of
Forth are only toy implementations?  I suppose this is where our
difference of opinion lies.
-- 

----------------
Kurt W. Luoto     kurtl@fai.com   or   ...!sun!fai!kurtl

bouma@cs.purdue.EDU (William J. Bouma) (11/14/89)

In article <4969@sdcc6.ucsd.edu> ir230@sdcc6.ucsd.edu (john wavrik) writes:
>
>   There are two things at issue here: the definition of "toy" and the reason 
>that an assembly language implementation is desirable for Forth. Let me deal 
>with the second issue first. 
>
>   Because Forth is close to the architecture of the host processor (and 
>includes an assembler) it does have the advantages Kurt Luoto notes (it is 
>good for projects which require machine-level access and for projects which 
>require efficiency). But it is a mistake to assume that these are the primary 
>reasons for implementing Forth in the traditional way (using a little 
>assembly language and a lot of Forth). Traditional Forth implementation is so 
>simple that it is easy to add new features to the language -- new primitives, 
>control structures, data types, etc.  What would you like:  quadruple 
>precision integers?  complex numbers as a primitive data type?  graphics?  
>strings?  local variables?  arithmetic of sets?  A construct  "IF:  COND1 
>COND2 COND3 ... DO:"  that tests for a conjunction but will stop testing as 
>soon as a condition fails?  redirection of I/O?  It is one thing to say that a 
>professional compiler writer can build these things into a language -- quite 
>another to say a language allows such things to be added by typical users. 
>
>    The ability of a USER to add to a language almost anything one could 
>conceive of is a rare attribute. It is this extraordinary degree of control 
>(rather than the use of stacks and RPN) that characterizes Forth -- and it 
>comes from the simplicity and accessibility of Forth implementation. Forth 
>(when implemented traditionally) is more than just a rather small interactive 
>stack-based language with Reverse Polish Syntax.  


    I fail to see what all this has to do with implementing forth in
    assembly language? I see no reason a forth interpreter written in
    any other language could not be made to behave identically to one
    written in assembly! You have given here no arguments to convince
    me otherwise. There are several reasons to write forth in assembly,
    speed, access to hardware, or limited memory. But ease of programming,
    as the above seems to imply, is not a valid reason.
 
    Also, I have to disagree with the rest of what was said because the
    main thing that distinguishes forth from other languages is the 
    parameter stack. Other languages (yes, even C) provide means to 
    build new data types using structures. One can build new operations
    by writing functions. A language which does not allow the user to add
    to it would not be very useful!


>    To make matters more concrete, suppose a Forth implementation lacks 
>certain primitive words involving double precision numbers (D+, D-, */, */MOD, 
>etc.), lacks a desired feature (like access to the OS timer) and has some 
>errors in the implementation of one or two primitives. A typical Forth 
>programmmer using a traditional Forth system can readily add the words (they 
>have short definitions in assembly language), provide the features, and fix 
>the bugs. 


    The thing that bothers me about this is that you seem to be implying
    that the user knows the host assembly language? If not, then what is
    the difference between having your forth core written in assembly, or
    having it written in basic? Speed!


>   How is one to characterize a Forth implementation that does not allow a 
>user the ability to add new primitives to the language?


    I wouldn't call it forth, and probably wouldn't call it a language.


>                                                        Or to tap features of 
>hardware and OS to do such simple things as adding a timer


    I'd call that a "high level" language! 8^)


>                              By imbedding Forth in another language this is 
>exactly the situation that seems to be produced. New primitives cannot be 
>added (or existing ones modified) from within the Forth environment without 
>knowledge of how the program and compiler handle register assignments and 
>stacks.


   Why not? What do registers have to do with it? If you are writing from
   "within the forth environment" you are writing forth, right? Then why
   does it matter what that forth was written in?


>   Let me emphasize again that it is not speed or the ability to do hardware 
>control applications that is the main argument for the traditional 
>implementation of Forth. It is the resulting simplicity and accessibility of 
>the implementation -- making the language malleable, allowing a user to 
>exercise a high degree of control and to add powerful features as options. 


   When is it simpler to write in assembly language? When one knows the
   assembly language. When is it more accessible to write in lisp? When
   one knows lisp. When is it simpler and more accessible to write in
   forth? I would like the answer to that to be the obvious, rather than
   when one knows forth AND knows the language/machine that forth was
   written in!

-- 
Bill <bouma@cs.purdue.edu>  ||  ...!purdue!bouma 

cep4478@ultb.UUCP (C.E. Piggott) (11/14/89)

I have been watching this for quite some time, and trying to follow and
learn (and I think it's working, too)...but I've got some questions.

For one, let's say you've got a FORTH written in C.  If you want to
create something and make it a primitive (for example, let's say that
you want the word CWEMIT to emit a letter in morse code - [grin] ).

From what I gather from the conversation at hand:

- In a FORTH FORTH, CWEMIT will never be a primitive.

- In an ASSEMBLY-based FORTH (is this what "traditional" means to you
		guys?), CWEMIT is a primitive if it's implemented in
		assembler.

- In a C FORTH, it will only be a primitive if CWEMIT is written in C
		(useable in FORTH)



Believe it or not, I'm a beginner here for the second time ... I used
to play with forth many, many, many years ago on Apple ]['s -- even
wrote a few BBS's (when they were popular) and a neat little text
editor.

The funny thing is that now, after having received the FORMAL education
in software engineering (iterative approach: pascal, modula/2, and
lots and lots of C - plus all the usual crap), I find FORTH to be
much more difficult to deal with - the concepts behind it are much
clearer now, but the actual quirkiness of it while at the console are
a little tougher for me.  I'm no slouch, mind you, would R.I.T. let
slouch through the works?!?  (Hmmf.)

Just a few thoughts; hoping perhaps if I make myself known as a poor
college student, somebody will feel sorry for me and mail me a book
they don't need any more. (smiley face optional, here)

Thanks guys, I'm really enjoying this newsgroup, esp. due to the
high quality of articles and low amount of QRM.

				Christopher Piggott, ARS: N2JGW

P.S. Phil, I am cep4478@ultb.isc.rit.edu

rs0@beach.cis.ufl.edu (Bob Slaughter) (11/14/89)

In article <8630@medusa.cs.purdue.edu> bouma@cs.purdue.EDU
 (William J. Bouma) writes:
> 
>    Also, I have to disagree with the rest of what was said because the
>    main thing that distinguishes forth from other languages is the 
>    parameter stack. Other languages (yes, even C) provide means to 
>    build new data types using structures. One can build new operations
>    by writing functions. A language which does not allow the user to add
>    to it would not be very useful!

It isn't really the parameter stack, but the extensibility of Forth
that makes it special.  Fortran has function capability and such, but
let me see you add a CASE structure to Fortran, or a WHILE-NEXT to a
standard version of the language the way you can with Forth.  Heck, C
is even in the same boat, but it comes with all the flow-control
structures I need already, but if it didn't, I'd be stuck.  It isn't
the ability to create new data types, primitives, or the stack; it is
the ability to use the language to make a better language that makes
Forth unique.

>-- 
>Bill <bouma@cs.purdue.edu>  ||  ...!purdue!bouma 


--
*     Bob Slaughter                           *  This space for rent       *
*     InterNet#1:  rs0@beach.cis.ufl.edu      *    Call 1-800-FOR-RENT     *
*     InterNet#2:  Haldane@Pine.Circa.Ufl.Edu *   Model Railroading        *
*     Bitnet:      Haldane@UFPine             *          is Fun!!          *

bouma@cs.purdue.EDU (William J. Bouma) (11/15/89)

In article <21215@uflorida.cis.ufl.EDU> rs0@beach.cis.ufl.edu (Bob Slaughter) writes:
>It isn't really the parameter stack, but the extensibility of Forth
>that makes it special.  Fortran has function capability and such, but
>let me see you add a CASE structure to Fortran, or a WHILE-NEXT to a
>standard version of the language the way you can with Forth.  Heck, C
>is even in the same boat, but it comes with all the flow-control
>structures I need already, but if it didn't, I'd be stuck.  It isn't
>the ability to create new data types, primitives, or the stack; it is
>the ability to use the language to make a better language that makes
>Forth unique.

   No, I still claim it is the parameter stack that is the major 
   difference between forth and other languages. Granted, in C or
   fortran it is ugly to write a function that behaves like a control
   structure. But one can do it. You must remember that the means to
   "extend the language" here are functions. As an example, here is
   what you could do to make a case statement in C:
  
   case(key, switches, n, functions)
   int key, n, switches[], (*functions[])();
   {
       int i;
       for (i = 0; i < n; i++)
           if (key == switches[i]) {
                (functions[i])();
                break;
           }
   }

   If you want to take away the 'for' statement, I can make a function
   that does the same thing from 'if' and 'goto'.

   Forgetting about C, what makes forth different from common-lisp? In
   CL one has an interpreter, and can create new control structures on
   a whim. Further, they look exactly like the rest of the language,
   just as they do in forth. Forth is definitely not unique as a 
   language in being extensible.
-- 
Bill <bouma@cs.purdue.edu>  ||  ...!purdue!bouma 

sabbagh@acf5.NYU.EDU (sabbagh) (11/16/89)

In article <8637@medusa.cs.purdue.edu> bouma@cs.purdue.EDU (William J. Bouma) writes:
>   [stuff deleted]
>   Forgetting about C, what makes forth different from common-lisp? In
>   CL one has an interpreter, and can create new control structures on
>   a whim. Further, they look exactly like the rest of the language,
>   just as they do in forth. Forth is definitely not unique as a 
>   language in being extensible.

The _major_ difference between forth and Common Lisp, from a language
design point of view, is that Forth has a parameter stack and LISP does
not (so I seem to agree with you). In LISP terms, this implies that
the arguments to a procedure are evaluated _before_ the procedure is
evaluated; in LISP the procedure definition (i.e., def vs. defun vs.
ndefun, etc.) determines the evaluation its arguments.

There are, hwoever, operational differences, namely that Forth is
_smaller_ than common Lisp and was originally designed to accomplish
different things.  This makes it a lower level language in some
ways.

To add to the "Forth written in C debate" I wish to point out that,
in UNIX, it is not _possible_ to write Forth (in either C _or_
assembler !!!) that can allow the user to write definitions in the
native machine language (ie.e., assembler).  THis is because the
the "text space" (the segment of memory that holds the executable
code image) is defined to be _read-only_.  There may be a way
around this if you achieved a sufficiently high level of UNIX wizardry
and have the right priviledges :-).


Hadil G. Sabbagh
E-mail:		sabbagh@csd27.nyu.edu
Voice:		(212) 998-3285
Snail:		Courant Institute of Math. Sci.
		251 Mercer St.
		New York,NY 10012

186,282 miles per second -- it's not just a good idea, it's the law!

peter@ficc.uu.net (Peter da Silva) (11/16/89)

In article <930@acf5.NYU.EDU> sabbagh@acf5.UUCP () writes:
> To add to the "Forth written in C debate" I wish to point out that,
> in UNIX, it is not _possible_ to write [a FORTH assembler] because
> the "text space" [is] _read-only_.

Not in *all* UNIX implementations and all models. Just in 'pure code' models.
Now a particular UNIX may not support impure code, but that's a different
matter. The grandaddy of them all, PDP-11 UNIX, certainly did. And I did run
Forth with a Forth assembler on it.
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.hackercorp.com>.
 'U`  --------------  +1 713 274 5180.
"*Real* wizards don't whine about how they paid their dues"
	-- Quentin Johnson quent@atanasoff.cs.iastate.edu

toma@tekgvs.LABS.TEK.COM (Tom Almy) (11/17/89)

In article <930@acf5.NYU.EDU> sabbagh@acf5.UUCP () writes:
>In article <8637@medusa.cs.purdue.edu> bouma@cs.purdue.EDU (William J. Bouma) writes:
>>   [stuff deleted]
>>   Forgetting about C, what makes forth different from common-lisp? In
>>   CL one has an interpreter, and can create new control structures on
>>   a whim. Further, they look exactly like the rest of the language,
>>   just as they do in forth. Forth is definitely not unique as a 
>>   language in being extensible.
>
>The _major_ difference between forth and Common Lisp, from a language
>design point of view, is that Forth has a parameter stack and LISP does
>not (so I seem to agree with you). In LISP terms, this implies that
>the arguments to a procedure are evaluated _before_ the procedure is
>evaluated; in LISP the procedure definition (i.e., def vs. defun vs.
>ndefun, etc.) determines the evaluation its arguments.

In Common Lisp, there are a handfull (good analogy?) of special forms that
the evaluator knows about. All other functions get their arguments evaluated,
just like Forth. Common Lisp macros (defmacro) get their arguments unevaluated,
but macros execute at compile time (when the lisp compiler is used) and may
be executed at compile time (execution of defun) or runtime in uncompiled 
functions. Macros have no real equivalent in Forth, although immediate
words come close.

The implementation of the Lisp interpreter can certainly use a parameter
stack to hold the evaluated arguments of pending functions. I have seen
implementations that do this. Of course, the parameter stack is not user
accessable, as it is in Forth.

I view the major difference between Forth and (Common or any other) Lisp
is that in Lisp program and data have the same representation, while
Forth takes the traditional approach of treating them separately. In that
respect, PostScript has more in common with Lisp than Forth because you
treat blocks of code as data. If Forth treated code as data, a much purer
postfix function implementation would be possible. 

Imagine that the words { and } delimit a code literal. This would mean that:

{ 3 4 + . }

would leave the address of threaded code block performing "3 4 + ." on
the stack.  If we were to then execute EXECUTE, "7" would be printed.

Now lets define a new conditional "IF" statement in terms of traditional
Forth operation:

: POSTFIX_IF  ( boolean_expression false_code true_code -- )
    ROT IF  NIP ELSE DROP THEN EXECUTE ;

Then we could say:

   4 3 > { ." Not greater" } { ." Greater" }  POSTFIX_IF

which would bear a strong similarity to Common Lisp:

  (IF (> 4 3) (princ "Greater") (princ "Not greater"))

(BTW, IF is one of the special forms in Common Lisp)

>To add to the "Forth written in C debate" I wish to point out that,
>in UNIX, it is not _possible_ to write Forth (in either C _or_
>assembler !!!) that can allow the user to write definitions in the
>native machine language (ie.e., assembler).

Not true! I modified the PDP-11 fig-Forth to run under PDP-11 Unix, and
have a copy of Kit Peak Unix (for the VAX), both allowing CODE words.
I also brought up several 68000 Forths under Unix. There may be hardware
constraints on specific machines coupled with poor Unix implentation
decisions that would make it impossible, but it is not too likely --
if the implementation rules out Forth it is also ruling out Lisp!

Tom Almy
toma@tekgvs.labs.tek.com
Standard Disclaimers Apply

wmb@SUN.COM (Mitch Bradley) (11/17/89)

> >To add to the "Forth written in C debate" I wish to point out that,
> >in UNIX, it is not _possible_ to write Forth (in either C _or_
> >assembler !!!) that can allow the user to write definitions in the
> >native machine language (ie.e., assembler).

> Tom Almy adds...
> Not true! ...
> There may be hardware constraints on specific machines coupled with
> poor Unix implentation decisions that would make it impossible,
> but it is not too likely --

All of my assembly language Unix Forth implementations have an interactive
assembler.  My C Forth 83 implementation, which runs under Unix and many
other operating systems, does not come with an assembler, but some customers
have written interactive assemblers which run under C Forth 83 and
assemble code for their particular machine.  (To do so requires knowledge
of the particular C compiler's register allocation, but that information
is easily obtained by disassembling the compiled code.)

I have only heard of one instance where an interactive assembler was
not routinely possible.  That was on a Unix machine which did not allow
the execution of machine instructions from the data segment.  Even on
that machine, there may have been some magic linker incantation which
would have relaxed the restriction, but I did not look at the machine
personally, so I can't say for sure.


> if the implementation rules out Forth it is also ruling out Lisp!

I'm not sure how this statement follows.  One can certainly implement either
Forth or LISP in such a way that code and data are kept strictly separate.
Generating machine code "on the fly" may be a particularly efficient
way to interpret or compile LISP, but it is not the only way.

Even in a FIG-Forth-style Forth implementation, user-defined words
Forth words are mostly "pure data".  The exceptions are obviously CODE words,
and perhaps not-so-obviously DOES> clauses.  DOES> clauses can certainly be
implemented without compiling machine code on-the-fly.

Mitch

marc@noe.UUCP (Marc de Groot) (11/17/89)

I wrote, about double indirect threaded Forth in C:
>> I only need one hack to make this work: I need to be able to
>> take the address of a label, i. e.

Mitch Bradley replied:
>What you are suggesting is the first thing that I thought of doing when
>I was writing C Forth 83, but I had to give up on that implementation
>strategy.  The two options that I know of are indirect subroutine calls
>(relatively slow) and a big switch with an integer selector (which is what
>C Forth 83 uses).

Here's a third way to do it that I just tried.  Thanks to Bob Kelley
(sequent!rjk) who gave me the idea.

I use the asm("..."); pseudo-op to assemble an indirect branch instruction.
This turns into some very efficient code, even with my awful pcc-derived
80286 C compiler.  This, of course, is "non-portable" in that it is
implementation-dependent.  On the other hand, the actual amount of effort
necessary to port this to another environment is minimal.  It's tantalizing...

^Marc

/*
 * Prototype Forth interpreter which REALLY uses a double-indirect jump.
 * Note that it is assumed that sizeof(cell) == sizeof(void *)
 */
typedef short cell;	/* typedef long cell for 32-bit pointers */
#include <setjmp.h>
jmp_buf jbuf;
#define NPRIMS	3	/* Number of primitives */
#define NSTK	50	/* Number of elements in each stack */
#define NDICT	50	/* Number of cells in the dictionary */
#define ONE	0
#define	DROP	1
#define	BRANCH	2
void *primaddr[NPRIMS];	/* Array of addresses of primitive code */
int naddr;		/* Subscript into primaddr[] */
cell stk[NSTK];		/* Parameter stack */
cell rstk[NSTK];	/* Return stack */
cell dict[NDICT];	/* The dictionary */

main()
{
	void **ip;	/* The interpreter pointer */
	void *w;	/* A scratch register used by next */
	cell *sp;	/* The stack pointer */
	cell *rp;	/* The return stack pointer */

	naddr = -1;
	setjmp(jbuf);	/* entry() inside the loop below calls longjmp() */

	/* This loop initializes the array primaddr[] with the addresses
	 * of primitive code.  The switch statement contains all of the code
	 * for primitives in the system.
	 */
	while (++naddr < NPRIMS) {
		switch(naddr) {
		case ONE:	entry(); *--sp = 1; goto next;
		case DROP:	entry(); sp++; goto next;
		case BRANCH:	entry(); ip += (cell)*ip; goto next;
		}
	}

	/* Now that the prim addrs are initialized, we build the
	 * equivalent of a colon definition's parameter field
	 * in the dictionary.
	 */
	 dict[0] = (cell)primaddr[ONE];		/* addr of "1" */
	 dict[1] = (cell)primaddr[DROP];	/* addr of "drop" */
	 dict[2] = (cell)primaddr[BRANCH];	/* addr of "branch" */
	 dict[3] = (cell)(-6);			/* branch offset */

	 /* Now we initialize Forth's registers */
	 ip = (void **)dict;		/* Point IP at the : def we built */
	 sp = &stk[NSTK];		/* Init param stack pointer */
	 rp = &rstk[NSTK];		/* Init return stack pointer */

	/* Here's the inner interpreter */
next:	w = *ip++;			/* W <- CFA */
next1:	asm("	jmp	*%ax");		/* JMP [W] */
}

entry()
{
	int i;
	primaddr[naddr] = (void *)(&i)[1];
	longjmp(jbuf, 1);
}
-- 
Marc de Groot (KG6KF)                   These ARE my employer's opinions!
Noe Systems, San Francisco
UUCP: uunet!hoptoad!noe!marc
Internet: marc@kg6kf.AMPR.ORG

koopman@a.gp.cs.cmu.edu (Philip Koopman) (11/18/89)

In article <717@noe.UUCP>, marc@noe.UUCP (Marc de Groot) writes:
> Here's a third way to do it that I just tried.  Thanks to Bob Kelley
> (sequent!rjk) who gave me the idea.
> 
> I use the asm("..."); pseudo-op to assemble an indirect branch instruction.
> This turns into some very efficient code, even with my awful pcc-derived
> 80286 C compiler.  This, of course, is "non-portable" in that it is
> implementation-dependent.  On the other hand, the actual amount of effort
> necessary to port this to another environment is minimal.  It's tantalizing...

How much faster did it go?  The PCC compilers I've seen tend to
use an indirect jump table to implement case statements, which
isn't that far away from what you're doing.  Did you measure
enough speed improvement to be worthwhile?  Does your C compiler
us jump tables?

-- Phil

marc@noe.UUCP (Marc de Groot) (11/22/89)

In article <7026@pt.cs.cmu.edu> koopman@a.gp.cs.cmu.edu (Philip Koopman) writes:
>In article <717@noe.UUCP>, marc@noe.UUCP (Marc de Groot) writes:
>> I use the asm("..."); pseudo-op to assemble an indirect branch instruction.
>> This turns into some very efficient code, even with my awful pcc-derived
>> 80286 C compiler.
>How much faster did it go?  The PCC compilers I've seen tend to
>use an indirect jump table to implement case statements, which
>isn't that far away from what you're doing.  Did you measure
>enough speed improvement to be worthwhile?  Does your C compiler
>us jump tables?
Yes, my C compiler does use jump tables.  No, I did not actually time
it.  I looked at a disassembly of the code.  My token-threaded Forth
has the dictionary in an array of short.  That means that every
reference into the dictionary requires a left-shift of the subscript
and adding the dictionary's base address before fetching.  Then it
sets up the arguments for the jump through the table.  The indirect-
threaded code that I posted does not need to do this and uses
considerably fewer instructions.

^M


>
>-- Phil


-- 
Marc de Groot (KG6KF)                   These ARE my employer's opinions!
Noe Systems, San Francisco
UUCP: uunet!hoptoad!noe!marc
Internet: marc@kg6kf.AMPR.ORG

vandys@sequent.com (04/18/91)

I'm looking for better options for a Forth implementation in C to port to
my UNIX box.  I'm aware of cforth in the uunet archives, but it really
doesn't really do it for me, as it has 16 bit integers only, requires
blockfiles, upper case dictionary only, etc.  I'm wondering if anyone has
implemented a richer environment, better integrated with the rest of the
UNIX environment.

						Thanks,
						Andy Valencia
						vandys@sequent.com