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