Learn from these smart tips and hints about Forth programming. These
tips are not guaranteed to work for you, but hopefully you'll learn a
thing or two.
If you commonly work with arrays in Forth, here's a simple array notation that you might find useful.
Then I create an index operator starting with the } symbol, usually followed by a letter or short descriptor that describes the type of array being indexed. Something like }n or }name. So a reference to an array element would look like this:
for the 6th element in the array. The operator simply leaves the address of the desired element on the stack. For example, lets say I was using a 40 character max length for my name array, and a standard counted string could be stored in each 40 character field. Then the index operator definition would look like this:
I always load a small dictionary that extends the language when I'm working, and when I run my programs. In that extended dictionary I define a number of commonly used indexing operators, like }c to index character array elements, } to index cell array elements, }f to index floating point array elements, and }" to indicate counted string array elements. See if the idea doesn't work for you. For me it makes my Forth code seem easier to read, when the array work looks much like that in any other computer language.
I program in both a forth I wrote years ago, and gforth. In both of these I took advantage of the extensibility of the language to create a simple programing environment that provides the ease of use of the old block file system, even when working with forth within another operating system (like Linux).
1 text ( get the file name into pad)
4 (edit) c! ( reset the length of the edit command, including blank)
pad count (edit) count + swap cmove ( append file name to command)
pad c@ (edit) c@ + (edit) c! ( set the total length of the cmd)
Next, I created a simple edit command named ed. Simply typing ed puts me in edit mode, and when I exit I can try out the code. Simple, but very handy and effective. The ed command looks like this:
: ed ( -- ) (edit) count system ; ( tell system to run edit command)
This is the code for gforth. About the only thing you might need to do for your forth is to create the text word (it just uses word and copies here to pad), and replace system with whatever command lets you pass a string to the operating system.
Return To Index
Title: An Easy Reload Command For Gforth
From web browsing I've noticed that others who've tried gforth have been a bit puzzled on how to avoid getting all the redefined messages when re-compiling modified code. I dealt with the problem by creating an open word that stores my desired program code file in an edit string, and a reload string. Then I created a reload word that loads an empty.fs file (which forgets all my compiled code), then reloads my program file. The empty.fs file looks like this:
I needed a string to hold the file name I was working on
create (reload) 80 allot
The open command, described in the previous hint, also has this:
: open ( -- )
pad (reload) pad c@ 1+ cmove
The reload command looks like this:
: reload ( -- )
s" empty.fs" included
(reload) count included
In use, I enter gforth including my extended dictionary that has the text word, the open, word, the reload word, and many other words I find useful. Then I enter the open word followed by the program file I want to work on. After each editing sequence, I simply type reload to forget and re-compile my code for testing. Edit, then reload, then test.
If you don't have a text word, it looks like this:
: text ( mark -- ) \ gather following text till mark and put into pad
word count dup >r pad 1+ swap cmove r> pad c!
Return To Index
Title: Local Variables
This is my weigh-in on the use of local variables in Forth. I have quite a bit of experience using Forth in that I've used it both at home and on the job for over 20 years. Even so, I'm sure that many Forth experts would consider my code to be sub-optimal quality.
But I have created some pretty functional code that has been used for years and has served well, so I figure I can weigh in as well as the next guy. To be honest, I've been a bit disconnected from the Forth community for some time, having used mostly a version of Forth of my own making. Creating my own version wasn't an exercise or act of vanity, but the solution for the need of a version of Forth that could give full floating point support. To that end, I wrote a version of Forth using the c language, and patterned it after the Forth 79 standard.
Since Forth is so extensible, I've been able to solve my problems nicely with that version for all these years, so I haven't paid much attention to where Forth was going. Recently I've been trying to get caught up a bit by working with the GNU gforth language. I've written a review of my experiences with gforth, which you can read at the Review of Gforth page. Since working with gforth, I've discovered that the ANSI Forth standard has a model for local variables in Forth. Since I've programmed in a number of other languages at least as much as I have with Forth, I found the local variables to be very helpful. I also found when doing some reading that a number of Forth versions have added some implementation of local variables at least a decade ago.
I ran some performance tests with gforth to see how the use of local variable performed compared with other methods of Forth coding. I used a simple test, the object of which was to pass 3 variables (call them a, b, and c) to a word, and have the word compute and return the sum of products ab+bc+ac. This was enough of a problem to make a bit of stack juggling necessary if no variables were used. The results from performing each method the same thousands of times are shown in the following table:
|Solution Method||Solution Time
|Using Stack Operations||9 seconds
|Using Global Variables||15 seconds
|Using Global Values||19 seconds
|Using Local Values||19 seconds
The reference in the table to global variables refers to the classic Forth variables that one must fetch and store. The Global values refers to the Forth values that use the => operator to replace the value. As you can see, while there is a bit of overhead to using local variables vs using only stack operations, it isn't terribly costly, and is about the same cost as using Global variables.
I used gforth to write a program that loads star catalogs. The program lets
me select objects to view, and tells me where the point my telescope in order
to view the objects. The program has about 50 words or routines in it, and I
found that only two of the routines were clumsy enough that local variables
helped keep them readable and maintainable. Putting that into perspective, it
suggests that even though there is a small time cost in using local variables
vs doing stack gymnastics, a typical programmer will probably only need or use
local variables in a small percentage of routines, making the tradeoff of code
readability vs efficiency a very tolerable tradeoff.
In my general work, I don't use GNU Forth that often. I actually use an
old Forth compiler I built by studying a FIG Forth manual. I altered the
code just a bit to more resemble F79, as the programming documentation I liked
referenced F79. I created my version of Forth with a C compiler, specifically
so that I could add floating point support. I've used the system for years.
A couple of years ago after reading some suggestions about local variables,
I added a simple local variable method to my Forth compiler.
My simple system uses a couple of additional stacks in the C code that hold
local and floating point values. A couple of routines keep track of the
starting point in these stacks for Forth words that declare the need for local
variables. At the end of these words a locals release word is required to
restore the locals stack pointer to its previous level. In this way, each Forth
word declaring need for locals is using a different area of the locals stack.
When I say
required, I mean pairs checks for it as it would a
then for each if. The locals pointers are similar to the return
stack pointer used by the general Forth compiler.
The locals stack pointer is only used when locals are needed and released.
In my brain-dead, simplistic approach, the locals always have the same names,
n0 through n5 for integer locals, and f0 through f5 for floating point. I use
comment statements at the point of declaration to show what the generic names
actually relate to. The following is an example of use:
: sumprod ( a b c -- ab+bc+ac)
3 locals ( n0=a, n1=b, n2=c) \ declare need for 3 locals
n0 n1 * n1 n2 * + n0 n2 * + \ do the math
locals-end \ release locals
In the above example above, the locals declaration moves the locals
stack pointer up past any previous declaration point and pops 3 values from the
stack and puts them in local variables n0, n1, and n2. The locals-end
declaration moves the locals pointer back to the previous value. In this way,
each reference to the n0 ... variables points to the current word's
The floating point version uses flocals to declare need for
locals, and flocals-end to release the support. The scope of the
locals is between the declaration and release, so words referenced within
this scope also have access to the same locals, unless they declare need
for their own locals.
To thumb one's nose completely at the use of local variables seems to
suggest to me that developers of other languages like c, perl, scheme, or
whatever, have had no good ideas whatsoever, since they all make great use of
local variables. I don't find that an acceptable point of view, and have found
something quite clever about nearly every computer language I've ever studied.
So my view is that one should consider using local variables anytime that
stack operations in a word definition become unwieldy. If factoring a complex
word down into a few simpler words is relatively obvious, then factoring is
probably a better approach, and will likely create faster code. But at least
for me, sometimes I find too much time disappearing while I fumble with
factoring. In those instances, using a few local variables lets me quickly get
back to working on the rest of my program. And as my star catalog program
suggests, generally only a few words in each program seem well suited for local
So I say -- why not.
Return To Index
Title: Speedup Programming With Local Variables
Of late, I've been using a modified form of a Forth coding technique that I learned long ago when using Forth on microcomputer projects. In that time honored approach, I would write an application entirely in high-level Forth code so that I could minimize development time. Then I would examine the program and identify words that were frequently referenced, such as within loops. These words were then coded in Forth assembly code to make them more efficient. With this approach, a very fast running program could be created even though only a few words were actually written in Forth assembly. The procedure worked well because words called often within loops do perhaps 90% of the actual work. Just optimizing these few words could make a huge difference in execution speed of a program.
Most of my programming nowadays is not on microcomputer projects, but on creating utilities for my desktop. I still write many of these utilities in Forth for a couple of reasons. One, I enjoy coding in Forth. Two, compared to most scripting languages, the Forth engine is very small, about 1/10 the size of perl, for example. So Forth produces fast running code compared to most scripting languages, and loads very quickly, making it a nice utility scripting language.
Since I don't work much with microprocessors at the current time, I don't delve into the Forth assembly language very often. But I do find the assembly optimization concept still useful. In my application of the old optimization approach, I create my first draft by making copious use of local variables, using them whenever a stack manipulation sequence or factoring procedure isn't obvious. This lets me create readable, functional code quickly.
Then, I examine the code and identify words that are called frequently. I then work to factor these words so that I can eliminate the use of local variables. In this way, only high level (infrequently called) words carry the overhead of local variables. By only doing the extra work on a handful of frequently called words, I keep the programming time manageable. The final result is code that is created quickly, and code that is readable, maintainable, and runs fast.
I recently ran some tests to understand the costs of using local variables
in my home-grown Forth language. I found that the difference in time between
local variables and global variables is nil. But there is a measurable
difference in local variables and stack operators. My results showed what in
retrospect is an obvious solution: just don't use local variables (if possible)
within inner loops. If a local variable value is needed within an inner loop,
put it on the stack before entering the loop and use stack operators to work
with it. This simple adjustment virtually negates any speed loss of using
This follows along the old advice about looking for bottlenecks in code and
converting those bottlenecks into assembly. That generally involves only
programming an inner loop or so in assembly, as the inner loops are where all
the work is done. With my particular Forth I don't have the assembler option,
but I do find that using local variables isn't a time issue as long as I avoid
referencing them (and global variables for that matter) within inner loops --
similar reasoning as pertains to the advice about assembly language
Return To Index