Linux Goodies

In Pursuit Of The Perfect O/S

Home Page Go To Small Telescope Astronomy Writing and Sci Fi humorous science shirt,comical science shirt,funny science shirt,zany science shirt,humorous math shirt,comical math shirt,Pi shirt,Pi day shirt,zany math shirt,funny linux shirt,comical linux shirt,linux nerd shirt,humorous linux shirt,computer geek shirt

Forth Programming Tips And Tricks For Linux Users

Home

Linux General Info
Migrating from Windows
Programming Languages
Making Documents
Linux on an Old Laptop
Linux User Survey

Linux Astronomy
Kstars Planetarium
Stellarium Planetarium
Xephem Planetarium

Window Manager Reviews
Dwm
Fluxbox
FVWM
Idesk
Icewm
Ratpoison
Window Maker

Linux Hints and Tips
Linux App Hints
Linux Distro Hints
Forth Programming Hints

Linux Lite Apps
MtPaint

Linux Language Reviews
Gforth Review
Linux Matrix Languages
Euler Math Toolbox Review
Octave Language Review
PDL Language Review
R Language Review
Scilab Language Review
Tela Language Review
Yorick Language Review

Linux Virtual Machines
Virtual Machine Intro
Qemu Review
Vbox Review
VMware Review
VM File Sharing
Freedos in DOSEMU
Freedos in QEMU

Linux Distro Reviews
Antix Review
Puppy Linux Review
  Puppy On Flash
  Frugal Puppy

Product Reviews
All Products

Favorite Sites
Science T-shirts
Math T-shirts
Computer T-shirts
Climate Change T-shirts
Science Posters
Digital Art Posters
Witty T-shirts
Bowling T-shirts
Free Craft Howto's
Building a Dobsonian Telescope


Linux Programming Tips, Hints, And Tricks



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.

Hints Index

A Simple Array Notation For Forth
A Simple Forth Programming Environment
An Easy Reload Command For Gforth
Local Variables
Speedup Programming With Local Variables


Title: A Simple Array Notation For Forth

If you commonly work with arrays in Forth, here's a simple array notation that you might find useful.

I name my arrays with a trailing { symbol, like

create names{ element_size nelements * allot

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:

name{ 5 }n

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:

: }n ( adr n -- nthadr ) 40 * + ;

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.

Return To Index


Title: A Simple Forth Programming Environment

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).

I created a character array in each that had the word vim, including a trailing space and an allocation for enough additional characters to hold a file name. It looks like this:

create (edit) ," vim " 80 allot

Then I created a word called open that lets me enter a file name, which it appends to the (edit) word. It looks like this:

: open ( -- )
  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:

[IFDEF] empty
empty
[ENDIF]
marker empty
init-included-files

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 ( -- )
1 text
pad (reload) pad c@ 1+ cmove
;

The reload command looks like this:

: reload ( -- )
s" empty.fs" included
(reload) count included
;

It 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 MethodSolution Time
Using Stack Operations9 seconds
Using Global Variables15 seconds
Using Global Values19 seconds
Using Local Values19 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.

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 variable use.

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.

Return To Index