home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Monster Media 1994 #1
/
monster.zip
/
monster
/
PROG_GEN
/
FORTH_86.ZIP
/
CELCIUS.WLK
< prev
next >
Wrap
Text File
|
1993-12-09
|
11KB
|
314 lines
4th_86 version 4.01 CELCIUS.WLK page 1
( November 1993 - 4th_86 version 4.01 - MFB )
While the functional source CEL4.4TH is provided -- this note
leads you through the process of developing the code yourself.
Let's suppose we want to print on screen a table comparing
Celsius and Fahrenheit temperatures. This is in fact the first example
in Kernighan & Richie's book "The C Programming Language".
The first step is to create a file on disk to develop the code in.
We don't want to type code in [ as with a BASIC interpreter ] directly
from keyboard to memory and risk losing it all if a bug in the code
"blows up" the system.
Let's name the file CEL.4TH [ **not** CEL4.4TH which is already
on disk ]. We will need to use the version of 4th_86 which contains
floating point routines -- 4th_86FP.COM
Fire up 4th_86FP and then type [ in upper or lower case - it
doesn't matter which ]
using cel.4th
: strt ;
redit
You should now have left 4th_86 and be in your editor with a blank
screen. Start to enter some code
forget strt
: strt ;
off redefine
on printload
using cel.4th
[ redundant here -- but it can be useful
in case of mishap ]
To make life simple at the initial stages -- let's create storage
locations for the variables we may need -- and define any constants we
may need. Once it is working we can "clean it up" and maybe get rid of a
lot of the intermediate storage -- as well as speed things up a bit.
32 const lower ( lower value of Fahrenheit range )
220 const upper ( higher value of Fahrenheit range )
15 const step ( incrememnt between adjacent table
values )
All the above are 16 bit [ single precision ] integers. They are also
decimal by default.
If we had wanted double precision we could have written ,32 ,const lower
4th_86 version 4.01 CELCIUS.WLK page 2
If we had wanted floating point we'd have written 32.0 ,const lower --
because floating point numbers are stored in double precision format.
Although our answers will be floating point -- we chose the input
parameters as integer because we need a DO -- LOOP construct -- or a
REPEAT -- WHILE -- ENDWHILE construct and we can not do that other than
in integer steps.
The first thing we must do therefore is define a word which will convert
single precision integer values into floating point values. Let's call
this word SFLOAT
word 1
%%%%%%
: sfloat double float ;
The words double and float are built into 4th_86.
Now comes the salient benefit of Forth as a language. We have defined
our first word in building a pyramid -- we must test -- ie debug it to
make sure it works BEFORE we ever go on to define other words or use this
one as a "building brick".
type 32 sfloat f. [ note that f. means print the top stack
value as a floating point number ]
Let's try something more critical
type 22 sfloat 7 sfloat f/ f.
Of course we didn't get any answers -- because we aren't in 4th_86. We're
in the editor.
Exit from the editor and you should see the file load into 4th_86
displaying the text -- and printing the answers to the last two "direct"
statements.
We can now type in further debug tests
3.14159 7 sfloat f* f.
If we are satisfied that SFLOAT works properly we can carry on and
define another word which uses it.
type REDIT and you should be back in the editor
4th_86 version 4.01 CELCIUS.WLK page 3
We want to multiply our fahrenheit values by 5 and divide by 9 --
after we have subtracted 32 from each one. Clearly it would be wasteful
to have to calculate 5 divided by 9 for every entry. We want to do it
once -- and store the answer as a constant. The answer will not be an
integer even though the Fahrenheit values are integers. So -- let's
decide to use SFLOAT to convert the fahrenheit values to floating point
-- calculate 5.0 divided by 9.0 as floating point and subtract 32.0 as
floating point.
DATA[ 0 ] fahr ( single precision integer variable )
DATA[ 0.0 ] celsius ( float variable )
DATA[ 0.0 ] scle ( float variable equal to 5.0 / 9.0 ]
word 2
%%%%%%%
: SSCLE 5.0 9.0 f/ scle ,! ;
F/ is floating point divide
,! is a double precision ( or floating point ) store.
We don't want to get involved in a DO .. LOOP construct at this stage.
Let's stick to one single fahrenheit value and see if we can get the
correct centigrade value from it.
But first let's exit the editor again to test SSCLE
when you are back in 4th_86 with your source loaded,
type SSCLE ( which should load the value of 5.0 / 9.0 into SCLE )
and then type SCLE ,@ f. to make sure we have actually stored
the
correct quotient
Now return to the editor with REDIT and let's defibe a word CALCULATE
word 3
%%%%%%
: CALCULATE fahr @ sfloat
32.0 f-
scle ,@ f*
celsius ,! ;
To test this we exit the editor again an type something such as
212 fahr ! calculate celsius ,@ f.
which should print on screen the answer 100.00
now REDIT back to the editor again.
4th_86 version 4.01 CELCIUS.WLK page 4
It's bad Forth programming to write very complicated and lengthy
definitions. What we should strive for is lots of short simple [ but
meaningful ] words that we build together into more complicated
consttructs. Let's therefore take care of incrementing FAHR at each point
in the loop
word 4
%%%%%%%
: INFAH fahr @ step + fahr ! ;
Probably no need to test this one immediately -- let's define
another word and then do a test.
word 5
%%%%%%%
: ANS tab tab fahr @ .
tab tab celsius ,@ f. crlf ;
The words TAB and CRLF are in fact part of 4th_86 vocabulary
word 6
%%%%%%
: CEL4 sscle ( to calculate and store 5.0 / 9.0 )
lower fahr ! ( initial value )
repeat
upper fahr @ >= ( test for upper limit )
while ( not >= upper limit )
calculate ( evalauate celsius value and store )
ans ( print out two values on one line )
infah ( increment for next loop )
endwhile
lower fahr ! ( just to be tidy )
;
Now is the time to exit the editor and test CEL4. It should print out
the required table of values. If it doesn't we'll have to work back and
check ANS and INFAH.
If that still fails we'll have to break CEL4 down into smaller
sub-words for testing --- or use the DEBUG and TRACE facilities 4th_86
provides.
All we have to add now is routines to print a heading and format
the display the way we want it.
4th_86 version 4.01 CELCIUS.WLK page 5
Revision of code
================
It was inefficient to store the loop values in FAHR and CELSIUS,
and almost immediately retrieve them again for incrementing and/or
printing. It would have been faster and neater to keep them in memory --
specifically stored on the stack.
This is one of the most difficult aspects of Forth for beginners -
- to know at each step just what remains on the stack -- how deep in the
parameter you want at any given time is -- and how to get it to the top
of the stack when you want to use it. This needs stack manipulation words
such as SWAP, ROT, OVER, DUP etc.
Not only is it difficult for the programmer -- it makes the code
extremely difficult to read when you find complicated stack manipulations
and aren't really sure just what is being "retrieved" or thrown away as
redundant.
By using named storage locations in the above code we have avoided
this issue.
Notice also that we used Reverse Polish Notation without really
being aware of the alleged "problem" it causes.
22 sfloat 7 sfloat f/ f. is a good example.
The value 22 is inserted first -- and THEN sfloat is called to
convert it from integer to float. This leaves 22.0 on the stack as the
numerator for the following f/
The value of 7 is then inserted -- and converted to 7.0 by sfloat.
This leaves 7.0 on the top of the stack [ TOS ] and 22.0 next on the
stack [ NOS ]. Each of these is a double precision value, so four 16-bit
values are stored on the stack.
Next the word F/ [ floating point divide ] is called and this
operates on the 22.0 and 7.0 to produce 3.14159 as the result of 22.0 /
7.0.
Then the word F. is called to print this value -- leaving the stack
empty.
4th_86 version 4.01 CELCIUS.WLK page 6
Stack Depth
===========
You may have noticed a highlighted digit to the left of the 4th86
prompt. This is the "depth" of the stack -- the number of 16 bit entries
it holds at any given time. Repeat each step of the above 22 / 7
calculation and watch how this depth indicator changes.
Type DEBUG and repeat the calculation again. You should now have a
display of the actual numeric stack contents at each stage of the
calculation. DEBUG is a toggle -- on and off.
As n alternative you can use the word DS [ standing for Display
Stack ] at any time to see the stack contents.
Effect of error messages
========================
If an error message is produced -- all files opened by the
offending definition are closed; any definition in progress is cancelled;
and the stack is cleared.
A very useful method of clearing the stack therefore is simply to
type in garbage such as asdjaisud and hit return.