Sunday, June 14, 2009

Primary ColorForth Chapter 2

First some housekeeping:

Since Starting Forth is based on traditional Forth, there are some examples that won't work out of the box on ColorForth. Most of the required words can be easily implemented such as spaces back in chapter 1. Some words already exist but are not available in interactive mode because they have only been defined in the macro wordlist. I will define definitions needed for the Starting Forth examples as we go along. Alternatively here are the new definitions together.

/mod ab-qr /mod ;
mod ab-r mod ;
swap ab-ba swap ;
over ab-aba over ;
rot abc-bca push swap pop swap ;
2swap abcd-cdab push rot rot pop rot rot ;
2dup ab-abab over over ;
2over abcd-abcdab push push 2dup pop pop 2swap ;
2drop ab- drop drop ;

Forth Arithmetic -- Calculator Style

Starting Forth identifies the four fundamental arithmetic instructions in traditional Forth are +, -, *, and /. ColorForth has +, * and /. You might be wondering what happened to -. It is a macro that returns the one's complement (the same as invert in ANS Forth). This corresponds to the way - is used in Charles Moore's MISC processors since MuP21. You can still subtract by adding the negative. For constants just use the negative value. For variables or calculated results you can get the negative using NEGATE.

Starting Forth then gives several examples of postfix math. Note as mentioned in chapter 2, in ColorForth you don't need to use
. in interactive mode except as a shortcut for drop. You can also clear the entire stack using c. ColorForth continuously displays the parameter stack in the lower left of the screen. Try the following:

17 5 +
7 8 *
3 4 +
500 -300 +
5 6 *
20 4 /
c


An example of adding multiple numbers:

17 20 + 132 + 3 + 9 + .

Converting infix expressions to postfix (quizzie 2-a)

Here is a little trick I learned as a computer science undergraduate. Fully parenthesize your expression and move all operators to the end of the corresponding parenthesis. Examples:

c(a + b) => (c*(a+b)) => (c(a b)+)* => c a b + *

a*b/100 => ((a * b)/100) => ((a b)*100)/ => a b * 100 /

Try the following on your own:

(3a - b)/4 + c

(a + 1)/4

x(7x + 5)

Forth Arithmetic -- Definition Style

The next examples are for converting from yards or feet to inches. We know 1 yard = 36 inches and 1 foot = 12 inches. Here is the conversion code:

yards-inches 36 * ;
feet-inches 12 * ;

Usage example:

10 yards-inches
2 feet-inches

If we always want results to be in inches, we can define:

yards 36 * ;
feet 12 * ;
inches ;

to get the phrase

10 yards 2 feet + 9 inches +

Now perhaps you want to be able to use singular or plural words for better readability. Starting Forth used the following code:

: yard yards ;
: foot feet ;
: inch ;

That has the undesiable effect of adding an extra word call just for the sake of readability. ColorForth can do the same without the overhead using fall through factoring. The same definition can have multiple entry points. So in ColorForth you can define:

yard
yards 36 * ;
foot
feet 12 * ;
inch
inches ;

Note that yard and yards, foot and feet, inch and inches all point to the same memory location.

Now let's consider the earlier example of adding 5 numbers together.

17 20 + 132 + 3 + 9 +

The same thing could be accomplished by moving the
+'s to the end.

17 20 132 3 9 + + + +


Changing this to a definition we get:

5sum + + + + ;

Now say if in the same program sometimes we needed to add 5 numbers together and sometimes we needed to add 3? We could use fall through factoring here.

5sum + +
3sum + + ;

This time
5sum and 3sum point to different locations in memory. If you call 5sum it does the first 2 additions and then "falls through" to the remaining 2 additions in 3sum. If you call 3sum it just does the required 2 additions and returns.

An equation for another definition:

(a + b) * c

In postfix:

a b + c *

Alternatively we could say:

c * (a + b)

In postfix:

c a b + *

from which we can write the definition:

solution + * ;

It's a good time to point out that in Forth it's sometimes better to re-write an equation to make it easier to manipulate on the parameter stack. Here is the same code as a word problem:

If a jet plane flies at an average air speed of 600 mph and if it flies with a tail wind of 25 mph, how far will it travel in five hours?

If we define:

flight-dist + * ;

we could enter
5 600 25 flight-dist and get 3125 on the top of the stack.

Try it with different values, including head winds (negative values).


The Division Operators

The basic division in ColorForth (and traditional Forth as well) is /. This is an interger operator which discards the remainder.

22 5 /

This leaves 4 on the stack. There are two other division operators,
mod and /mod. By default they are in the macro wordset and only available during compilation. However they can be compiled to the Forth wordset.

mod ab-r mod ; returns the remainder
/mod ab-qr /mod ; returns quotient and remainder

Testing
/mod interactively: 22 4 /mod leaves 2 5 on the stack.

We can define a word quarters that takes a number of quarters and calculates the dollars and leftover quarters.

126 load q 0 quarters ones 0 ones
quarters 4 /mod . q .s . ones .s ;
go show blank text 22 quarters ;

Test
mod interactively: 22 4 mod leaves 2 on the stack.

Stack Manipulation

Swap

As the name suggests, this word takes the top too numbers on the stack and swaps them. Again this word is only in the macro wordlist. To use it interactively:

swap swap ;

Testing this interactively:
1 2 swap leaves 2 1 on the stack.

Dup

Dup takes the top number on the stack and duplicates it.
2 dup leaves 2 2 on the stack.

You can use dup to square a number.
4 dup * leaves 16 on the stack.

Over

Over is defined only in the macro wordlist. To use it interactively define:

over over ;

Over takes the second item on the stack and copies it to the top of the stack.

Testing it interactively,
1 2 over leaves 1 2 1 on the stack.

Thus the expression

a * (a + b)

can be written as:

over * +

Rot

Rot is in traditional Forth but is not by default defined in ColorForth. However defining it is simple. It requires a the words
push and pop. These words manipulate the second stack called the "return stack". Starting Forth doesn't cover this until another chapter. Basically push takes the top number from the parameter stack and moves it to the return stack. pop does the opposite. Using them rot is defined as:

rot push swap pop swap ;

Rot takes the 3rd item on the stack and rotates it to the top.

Testing it interactively:
1 2 3 rot leaves 2 3 1 on the stack.

Say if you wanted to evaluate the expression
ab - bc. First factor out the b's.

b*(a - c)

Now starting with
c b a on the stack we can use rot - *.

Drop

Drop, as its name suggests, drops the top item on the stack. Testing interactively:
1 2 drop leaves 1 on the stack.

Note: Look ma! No .s. Starting Forth mentions at this point that .s can be used to display the stack non destructively. But ColorForth shows the stack in interactive mode at the bottom left of the screen. Thus .s is not needed and not defined. Hence I can use .s is ColorForth for printing strings.

Stack Manipulation and Math Definitions (Quizzie 2-c)

1. Write a phrase which flips three items on the stack, leaving the middle number in the middle; that is:

a b c ==> c b a

Answer:
swap rot

2. Write a phrase that does what
over does, without using over.

Answer:
swap dup rot rot

3. Write a definition called
-rot, which rotates the top three stack items in the opposite direction from rot; that is:

a b c ==> c a b


Answer: -rot rot rot ;

Write definitions for the following:

4. (n+1) / n

Answer: 2c4 dup 1 + swap / ;

5. x(7x + 5)

Answer: 2c5 dup 7 * 5 + * ;

6.
9a2 - ba

a(9a - b)

Answer:
2c6 over 9 * swap - * ;

Playing Doubles

Many early Forths ran on 16 bit computers. As such "double" words, which allowed 32 bit math, were very important. ColorForth was initially written for a 32 bit computer and thus does not implement double words. However double stack manipulation words are not difficult to write.

2swap abcd-cdab push rot rot pop rot rot ;
2dup ab-abab over over ;
2over abcd-abcdab push push 2dup pop pop 2swap ;
2drop ab- drop drop ;

Problems -- Chapter 2

1. What's the difference between DUP DUP and 2DUP?

2. Write a phrase which will reverse the order of the top four items on the stack; that is,

( 1 2 3 4 -- 4 3 2 1 )

Answer:
reverse swap 2swap swap ;

3. Write a definition called 3DUP which will duplicate the top three numbers on the stack; for example,

Answer:
3dup abc-abcabc dup 2over rot ;

Write definitions for the following infix equations, given the stack effects shown:
4. a2 + ab + c ( c a b -- result )

a(a + b) + c

Answer:
prob4 over + * + ;

5. (a-b) / (a+b) ( a b -- result ) [answer]

Answer:
prob5 2dup - -rot + / ;

6. Write a set of words to compute prison sentences for hardened criminals such that the judge can enter:

CONVICTED-OF ARSON HOMICIDE TAX-EVASION ok
WILL-SERVE 35 years ok

or any series of crime beginning with the word CONVICTED-OF and ending with WILL-SERVE. Use these sentences

HOMICIDE 20 years
ARSON 10 years
BOOKMAKING 2 years
TAX-EVASION 5 years

Answer:

126 load years 0 years
convicted-of 0 ;
homicide 20 + ;
arson 10 + ;
bookmaking 2 + ;
tax-evasion 5 + ;
will-serve . years .s ;
ok show blank text convicted-of homicide arson tax-evasion will-serve ;

7. You're the inventory programmer at Maria's Egg Ranch. Define a word called EGG.CARTONS which expects on the stack the total number of eggs laid by the chickens today and prints out the number of cartons that can be filled with a dozen each, as well as the number of left-over eggs.

126 load cartons 0 cartons eggs 0 eggs
egg.cartons e-cr 12 /mod . cartons .s . eggs .s ;
ok show blank text 55 egg.cartons ;

Fall through factoring

The idea is that you can have multiple entry points to the same word. Here's an example. Say if you needed code for shifting right twice (4 *) and shifting right3 times (8 *). You could code that without factoring as:

4* 2* 2* ;
8* 2* 2* 2* ;

You could also code it using traditional factoring as:

4* 2* 2* ;
8* 2* 4* ;

Using fall through factoring that becomes:

8* 2*
4* 2* 2* ;

With fall through factoring 8* doesn't have the overhead of having to call 4*, but you still get the code density benefit of having 4* factored out. Fall through factoring can also be used to increase code readability without added overhead. Consider the example from Starting Forth chapter 2.

: YARDS 36 * ;
: FEET 12 * ;
: INCHES ;

: YARD YARDS ;
: FOOT FEET ;
: INCH INCHES ;

The only reason for yard, foot and inch is readability. Here is the same result using fall through factoring.

yard
yards 36 * ;
foot
feet 12 * ;
inch
inches ;

Note that there is now no overhead for yard, foot, or inch being their own separate words. Each word is a separate label for the same code address. In traditional Forth the words yard, foot and inch all have the overhead of making a call to their plural versions. Some traditional Forths have a word alias that can give a similar result as this last example, but that's not standard.

Saturday, June 13, 2009

Typing ColorForth 4.1

Well I thought I had done my last post on "typing ColorForth" at version 4.0. That version does everything I want. However it doesn't quite do it the way I wanted it to. I took code I found on the web that types comment text to the screen, modified it to use yellow "immediate" mode for accessing variables, and then factored the word ".s" (stype in the original version) using inline macros. At least I thought I was using inline macros. The reason is that I wanted to make it clear what .s does. Again the code from the original stype.

stype 1 + dup @ dup 15 and select stype ;

Anyone who understands ColorForth's tail recursion feature can tell what
stype ; does. And select is explained in the shadow block comments. But what does 1 + dup @ dup 15 and do? Not obvious is it? 1 + dup @ dup increments then retrieves from the string address. 15 and gets the tag value. You can factor that out those two phrases as "nextw" and "tag", but that doesn't do anything for code density in this case because the words are only used once yet you still have the penalty (albeit small) of the extra call.

So I thought about trying to inline it using
cyan words. My thought was that I could define the words inside the macro wordlist and then use them as cyan words in the normal forth wordlist and everything would be inlined. I'd get the readability improvement from factoring without the overhead.

On retrospect I believe my understanding of cyan words was not right.
Cyan should be used inside macro wordlist and not the forth wordlist. I believe the result of using cyan for a word defined as a macro is that a call was inserted instead of inline code.

Now I'm not sure if this is right either. But there is a better way to get the results I want. One of the key features of ColorForth is fall through factoring. The idea is that you can have multiple entry points to the same word. Using fall through factoring I can rewrite
.s as this:

select jump rest done done done done done done done done norm cap caps done done done done ;
.s
nextw 1 + dup @ dup
tag f and select .s ;

I can now document nextw and tag in the corresponding shadow block. Again, the entire code.

+first 0 +rest 0
type space fffffff0 and unpack +first @ + emit
rest unpack if +rest @ + emit rest ; then drop drop ;
done drop drop pop drop ;
norm 0 +first ! 0 +rest ! type ;
cap 48 +first ! 0 +rest ! type ;
caps 48 +first ! 48 +rest ! type ;
select jump rest done done done done done done done done norm cap caps done done done done ;
.S
nextw 1 + dup @ dup
tag f and select .s ;

And the shadow block:

type w display one 32-bit word of text
rest w finish typing a word
done aw drop addr and word and return from stype
norm normal text
cap text starts with a capital
caps all caps
select wt handle word according to tag
.s a display contiguous white text
nextw a get next word and increment address
tag n get tag field from word. used by select.

The usage remains the same. "Hello World" in 2 lines of ColorForth.

126 load hello 0 Hello World, I speak ColorForth
ok show blank text hello .s ;

Note: This will probably be the last version of Typing ColorForth (at least I hope so). It does (almost*) everything I want it to do as is as efficient and readable as I can make it. To the critics (well meaning I'm sure) who don't understand why I was doing this, please look at the rest of the Primary ColorForth tutorial. Doing all of the examples in Starting Forth by looking up codes and "emitting" them would be an unecessary pain in the butt. And yes, I could just type in "Hello World" on a blank screen, but that would not be flexible enough for what I'm doing.

(* There is one other thing I'd like to do. The current version sticks in an extra space before typing anything. Sometimes this throws the formatting off. But I'm going to quibble about that...for now.)

Wednesday, June 3, 2009

Primary ColorForth Chapter 1

As mentioned in the intro, Primary ColorForth is loosely based on Starting Forth. You can follow along in it for this tutorial series either with a hardcopy version or online.

Starting Forth chapter 11 starts by describing a way of organizing work by defining useful tasks and giving them a name, then grouping tasks together into larger tasks and naming them.

It gives the example of an embedded washing machine program which we will explore.


Washing Machine Example

Here is the top level washing machine program in ColorForth.

washer wash spin rinse spin ;

In ColorForth red words signify the start of a new definition. So
washer is the new procedure. The ";" represents the call return. Green words are ones that have already been defined and are compiled into the new definition. Note that unlike traditional Forth words cannot be defined from the command line. All words must be defined in the editor. Then the block containing the source text must be loaded. For example, to define new words in block 22 you would use 22 edit, then to compile then you would use 22 load.

Let's look at the definition of
rinse.

rinse fill agitate drain ;

And now the definition of
fill.

fill faucets open till-full faucets close ;

The definition includes "things" (faucets) and verbs (open and close). The word "till-full" represents a delay loop. After the faucets "open" the word waits "till-full" before they "close".

Every word must be defined before it can be compiled into a definition, so
fill must be compiled before rinse and rinse must be compiled before washer.

fill faucets open till-full faucets close ;
rinse fill agitate drain ;
washer wash spin rinse spin ;

This system is just an example. For a real system the definitions for open, close, faucets, till-full, agitate, drain and spin would all have to be defined. At some point it would be direct machine code to activate stepper motors, read sensors etc.

Putting On a Show

Forth was originally designed around a TTY display model. But ColorForth uses a GUI display, albeit one that is MUCH simpler than MS Windows, X-Windows or MacIntosh. So getting things displayed on the screen is a bit tricker than traditional Forth, but simpler than raw programming of most GUI operating system. The ColorForth word
show creates a display task using the words following it.

Consider this definition.

ok show text 93 emit keyboard ;

This creates a new definition
ok that draws a "*" at the top left corner of the screen. The word text moves the cursor to the top left of the screen and sets the drawing color to white. The word emit takes a number off the stack and draws the corresponding charecter. It's the same as emit in traditional Forth. Note that the character set is different from ASCII. You can look up the characters in a code map, or you can use the command icons. The word keyboard redraws the keyboard and stack.

Chapter 1 of Starting Forth builds up an example on how to draw the letter "F" as a large character using "ASCII art". Here is a walkthrough of that example using colorForth.

First we need to define the word
spaces which is built into traditional Forth.

spaces for space next ;

Note ColorForth uses
for...next for its counted loop structure. Using spaces with what we learned earlier we can code the following:

spaces for space next ;
ok show text 15 spaces 93 emit ;

Notice when we run this, the word
spaces doesn't erase the text already on the screen, but just moves the star over. That's another example of how graphical CF is different from TTY TF.

Now let's define
star as it's own word.

spaces for space next ;
star 93 emit ;
go show text 15 spaces star ;

Moving sections of code into their own definitions is called factoring. Factoring is used to increase readability and/or code density.

The next words define the "F" using combinations of the above defined words. Note that "cr" stands for "carriage return". That simply moves the cursor to the next line.

side star spaces star ;
margin cr 30 spaces ;
blip margin star ;
bar margin 5 stars ;
f bar blip bar blip blip cr ;
ok show text f keyboard ;

After loading the block containing these words and typing
ok from the command line a large "F" will be displayed on the screen.

Hello World from ColorForth

The next Starting Forth example is a variation on the venerable "Hello World" program. This particular program has cause some needless controvery and confusion over the years. Sure you
emit each character one at a time, but that's not the most readable solution nor the most flexible. ColorForth can type blocks of text just like traditional Forth. And since ColorForth is extensible, just like traditional Forth is extensible, you extend it to where you can do a program like "Hello World" in just two lines.

First you have to understand how text is stored in the ColorForth editor. ColorForth doesn't store ASCII characters in bytes. Instead it packs several characters in one 32 bit word using Shannon encoding, eabling it to store 5 to 7 characters plus a color token in one word. ColorForth includes a word
unpack for decompressing such words. We have already discussed red and green words. ColorForth uses white words for comments. Comments can be as all lowercase, all upper case, or mixed case. So one way to display a block of text is to store it as comments in a Forth block, put that address on the stack, and then unpack and properly display the words until a non comment word is reached. Here is the code to set this up:

+first 0 +rest 0
type space fffffff0 and unpack +first @ + emit
rest unpack if +rest @ + emit rest ; then drop drop ;
done drop drop pop drop ;
norm 0 +first ! 0 +rest ! type ;
cap 48 +first ! 0 +rest ! type ;
caps 48 +first ! 48 +rest ! type ;
select jump rest done done done done done done done done norm cap caps done done done done ;
.s
nextw 1 + dup @
tag dup 15 and select .s ;

That may look like a lot, but realize that you can load this block whenever you need it or you can even have it load automatically when ColorForth boots. Here is an example of its usage (assuming the code was stored in block 126).

126 load s 0 Hello world, I speak ColorForth
ok show text s .s ;

Note that magenta words like
s define variables. Variables in ColorForth point to the blocks where they are defined as opposed to the dictionary. So s is being used here to point to the comment block of text we want to type.

Run-time Versus Compile-time Versus Edit Time

Starting Forth then goes into a discussion about "run time versus compile time". This is a good time (no pun intended) to go into the other color states in ColorForth. We've already gone over how
red defines a new word and how green compiles a previously defined word into a new definition. Green words are executed at run time. There are also yellow words that are executed at compile time. Consider the "hello world" example given earlier.

126 load s 0 Hello world, I speak ColorForth
ok show text s .s ;

Note the phrase
126 load. This will load the text display code in block 126 as soon as the current block is loaded. You don't have to wait until ok is run. Also note that the acess to the variable s is in yellow too. A variable is really just a name for an address. Why wait until run time to look up the address? Why not look it up at compile time and compile the address directly into the code? Accessing variables as yellow words instead of green ones accomplishes that. In fact that is the preferred way.

Another way to use yellow words are with constants. When a constant is coded in yellow its value is compiled into the code on the yellow to green transition. This is also true for calculations that are done in yellow. Using the earlier "big F" exampe:

side star spaces star ;
margin cr 30 spaces ;
blip margin star ;
bar margin 5 stars ;
f bar blip bar blip blip cr ;
ok show text f keyboard ;

Yellow words can also be used to do calculations that can be determined at compile time such as calculations based on a constant.

Cyan words are used to create inline macros.

The Dictionary

ColorForth, like traditional Forth, stores definitions in a dictionary. One difference is the way ColorForth handles numbers. In traditional Forth the interpreter first looks in the dictionary find a word and if it's not found it checks to see if it is a number. The ColorForth editor handles numbers differently. So the compiler never has to check to see if something is really a number.

The Stack: Forth's Worksite for Arithmetic

If you are already familiar with Forth (or with HP scientific calculators) you know you to use the stack. If not here's a brief overview. Everytime a number is entered it is pushed on the stack. Forth arithmetic words will take numbers off the stack, do some operation with them, and return the results to the stack. To do 3 + 4 you must first push the 3 and the 4 to the stack then execute the "+" word.

3 4 +

Note that the current state of the stack is shown on the bottom left of the screen. If you use the dot command
. by itself all you will notice is that one number drops off. In traditional Forth . displays the top number on the stack. If you use . inside of a show word you get the traditional result.

go show 3 4 + . ;

Problems

Problem 1-1: Define a word called gift that, when executed, will type out the name of some .gift, a word .giver that prints out a person's name, and a word .thanks that prints out something like this:

Dear Stephanie, Thanks for the bookends.

Solution:

gift 0 bookends. giver 0 Stephanie, dear 0 Dear thank 0 Thanks for the
.gift gift .s ;
.giver giver .s ;
.thank thank .s ;
.dear dear .s ;
thanks show black screen text .dear .giver .thank .gift ;

Alternatively:

gift 0 bookends. giver 0 Stephanie, dear 0 Dear thank 0 Thanks for the
thanks show black screen text dear .s giver .s thank .s gift .s ;

Problem 1-2: Define a word
tenless that takes a number on the stack, substracts 10, and returns the answer on the stack. (Hint: You can use +.) Be sure to include stack effects.

Solution

tenless n-n' -10 + ;

Problem 1-3: After entering the words in Problems 1-1, enter a new definition for
.giver to print someone else's name, then without redefining thanks, execute thanks again. Can you explain why thanks still prints out the first giver's name?

Solution

gift 0 bookends. giver 0 Stephanie, dear 0 Dear thank 0 Thanks for the
.gift gift .s ;
.giver giver .s ;
.thank thank .s ;
.dear dear .s ;
thanks .dear .giver .thank .gift ; giver 0 Jill
.giver giver .s ;
go show black screen text thanks .giver ;

Alternatively:

gift 0 bookends. giver 0 Stephanie, dear 0 Dear thank 0 Thanks for the
thanks dear .s giver .s thank .s .gift .s ; giver 0 Jill
go show black screen text thanks giver .s ;


Whenever a new word is compiled it is appended to the end of the dictionary. The old definition isn't overwritten, but the interpreter starts at the newest definition and searches backwards so it doesn't find the older definition. However words that were defined using the old definition still work the same.