RetroForth is not -- nor is it intended to be -- ANS compliant. This tutorial is based on the one by Phil Burk of SoftSynth.com but has been substantially altered in order to reflect RetroForth rather than pForth or any other Forth.


Table of Contents

The intent of this tutorial is to provide a series of experiments that will introduce you to the major concepts of Forth as implemented in RetroForth. It is only a starting point. Feel free to deviate from the sequences I provide. A free form investigation that is based on your curiosity is probably the best way to learn any language. Forth is especially well adapted to this type of learning. If you are only interested in learning ANS Forth, there are other tutorials which will serve your purpose better.

In the tutorials, I will print the things you need to type in monospaced font, and indent them. RetroForth is case-sensitive, unlike some other Forths; so the words which are built-in must be entered as shown, but words you create can be any combination of case you prefer.

At the end of each line, press the RETURN (or ENTER) key; this causes RetroForth to interpret what you've entered. You might also note that RetroForth doesn't prompt you with ok like most other Forths do.


Forth Syntax


Forth has one of the simplest syntaxes of any computer language. In fact, it might be said it has no syntax at all! What minimal syntax it has can be summed up as follows: "Forth code is a bunch of words with spaces between them." This is even simpler than English! Each word is equivalent to a function or subroutine in a language like 'C'. "Words" are executed in the order they appear in the code. The following statement, for example, could appear in a Forth program: Notice that WAKE.UP has a dot between the WAKE and UP. The dot has no particular meaning to the Forth compiler. I simply used a dot to connect the two words together to make one word, and to make that word easier for a human to read. Forth word's names can use any combination of letters, numbers, or punctuation. We will encounter words with names like: These are all called words. The word $%%-GL7OP is a legal Forth name, although not a very good one. It is up to the programmer to name words in a sensible manner. In general, Forth (and RetroForth in particular) give the programmer ultimate freedom to make whatever design decisions are appropriate, and does not get in the way of making bad decisions.

Now it is time to start RetroForth and begin experimenting. One of Forth's greatest strengths is its interactive, immediate nature.


Stack Manipulation


The Forth language is based on the concept of a stack. Imagine a stack of blocks with numbers on them. You can add or remove numbers from the top of the stack. You can also rearrange the order of the numbers. Forth uses several stacks. The data stack is the one used for passing data between Forth words so we will concentrate our attention there. The return stack is another Forth stack that is primarily for internal system use but is often used to store temporary values. In this tutorial, when we refer to the "stack," we will be referring to the data stack. For reference, we'll call the return stack "RS".

The stack is initially empty. Start up RetroForth, and notice you are greeted by something like:

RetroForth Release 8 :: http://www.retroforth.org :: Build 912
The interpreter is now awaiting your command. Let's start by putting some numbers on the stack. Type in: Excellent! Now print the number on top of the stack using the Forth word ' . ', which is pronounced "dot". This is a hard word to write about in a manual because it is just a single period.

Enter: .

You should see the last number you entered, 9182, printed. RetroForth has a very handy word for showing you what's on the stack. It is .s , which is pronounced "dot S". The name was constructed from "dot" for print, and "S" for stack. If you enter:

you will see your numbers 23 7, in a list. The number at the far right is the one on top of the stack. Notice that 9182 is not on the stack. The word ' . ' removes the number on top of the stack before printing it. In contrast, '.s' leaves the stack untouched.

Forth uses the stack to hold data being operated on, and it uses the stack to pass data from word to word. Essentially, a word takes whatever it needs from the stack, and puts whatever its results are on the stack. This is a very powerful aspect of Forth, but one which requires practice to understand. It also means that documenting what each word does to the stack is important and useful.

The standard technique for documenting the effect words have on the stack is by means of a stack diagram. Stack diagrams begin with a left-parenthesis, contain the "stack-effect diagram", and end with a right-parenthesis. In Forth, parentheses indicate a comment, and everything between them is ignored. So while you could put whatever you like between parentheses and treat them as ordinary comments, the usual use of parentheses is for stack-comments. For example, the stack-digram for the word 'dot' which we used before, would be:

. ( n -- )
That is to say, ' . ' takes one word off the stack (the 'n') and puts nothing on the stack. In other words, it consumes the top stack item (hereafter called TOS).

In the examples that follow, you do not need to type in the comments. When you are programming, of course, liberal use of comments and stack diagrams may make your code more readable and maintainable. Besides the parenthesis, you may use the vertical-bar character | as comment to end-of-line. In other words, anything after the | on that line is ignored:

Between examples, you may wish to clear the stack. If you enter reset, the stack will be cleared. Since the stack is central to Forth, it is important to be able to alter it easily. Let's look at some more words that manipulate the stack. Enter:

You will notice that there are two copies of 777 on the stack. The word dup duplicates TOS. This is useful when you want to use the TOS and still have a copy. The stack diagram for DUP would be:
DUP ( n -- n n )
Another useful word is swap. Enter: The stack should have 7 23 now. The stack diagram for swap would be:
swap ( a b -- b a )
Now enter: You should see 23 7 23 . The word over causes a copy of the second item on the stack to leapfrog over the first. Its stack diagram would be:

over ( a b -- a b a )

Here is another commonly used Forth word:

drop ( a -- )

Can you guess what we will see if we enter:

Another handy word for manipulating the stack is rot. Enter: The stack diagram for rot is, therefore:

rot ( a b c -- b c a )

You have now learned the more important stack manipulation words. You will see these in almost every Forth program. I should caution you that if you see too many stack manipulation words being used in your code then you may want to reexamine and perhaps reorganize your code. You will often find that you can avoid excessive stack manipulations by using variables, which will be discussed later. It is also likely that factoring your code -- that is, breaking it into smaller words -- may help reduce the stack juggling.

I have included the stack diagrams for some other useful stack manipulation words. Try experimenting with them by putting numbers on the stack and calling them to get a feel for what they do. Again, the text in parentheses is just a comment and need not be entered.

2drop ( a b c -- a )
2dup ( a b -- a b a b )
nip ( a b c -- a c )
tuck ( a b -- b a b )
-rot ( a b c -- c a b )

    Arithmetic


    Simply moving numbers around on a stack can be a lot of fun. Eventually, however, you'll want to do something useful with them. This section describes how to perform arithmetic operations in Forth.

    The Forth arithmetic operators work on the numbers currently on top of the stack. If you want to add the top two numbers together, use the Forth word + , pronounced "plus". Enter:

    This style of expressing arithmetic operations is called Reverse Polish Notation, or RPN. It will already be familiar to those of you with HP calculators. In the following examples, I have put the algebraic equivalent representation in a comment.

    Some other arithmetic operators are - * / . Enter:

    One thing that you should be aware of is that when you are doing division with integers using / , the remainder is lost. Enter: This is true in all languages on all computers. Later we will examine /mod and mod which do give the remainder.

    Defining a New Word


    It's now time to write a small program in Forth. You can do this by defining a new word that is a combination of words we have already learned. Let's define and test a new word that takes the average of two numbers.

    We will make use of two new words, : ( "colon"), and ; ("semicolon") . These words start and end a typical Forth definition. Enter:

    Congratulations! You have just written a Forth program. Let's look more closely at what just happened. The colon told Forth to add a new word to its list of words. This list is called the Forth dictionary. The name of the new word will be whatever name follows the colon. Any Forth words entered after the name will be compiled into the new word. This continues until the semicolon is reached which finishes the definition.

    Let's test this word by entering:

    Once a word has been defined, it can be used to define more words. Let's write a word that tests our word.. Enter: Try combining some of the words you have learned into new Forth definitions of your choice. If you promise not to be overwhelmed, you can get a list of the words that are available for programming by entering: Don't worry, only a small fraction of these will be used directly in yourprograms.

    More Arithmetic


    When you need to know the remainder of a divide operation. /mod will return the remainder as well as the quotient, whereas mod will only return the remainder. Enter:

    negate ( a -- -a )
    << ( a n -- (a<<n) )
    >> ( a n -- (a>>n) )

    Convert Algebraic Expressions to Forth

    How do we express complex algebraic expressions in Forth? For example: 20 + (3 * 4)?

    To convert this to Forth you must order the operations in the order of evaluation. In Forth, therefore, this would look like:

    Evaluation proceeds from left to right in Forth so there is no ambiguity. Compare the following algebraic expressions and their Forth equivalents: (Do not enter these!) If any of these expressions puzzle you, try entering them one word at a time, while viewing the stack with .s

        Character Input and Output


        Because Forth is not a typed language, the numbers on top of the stack can represent anything. The top number might be how many blue whales are left on Earth or your weight in kilograms. It might also be an ASCII character. Try entering the following: You should see the word "Hi" appear. 72 is an ASCII 'H' and 105 is an 'i'. emit takes the number on the stack and outputs it as a character. To get the ASCII value of a character, prepend the character with a single-quote. Enter: The use of the single-quote character is a bit unusual. It tells the RetroForth interpreter that the character that follows should be converted to the ASCII code representing it, rather than being considered a word. There are other such modifiers in RetroForth which can make inputting numbers simpler:

        'a Gives 97, the ASCII value of 'a'
        %1100 Gives 12, or 1100 binary
        $ff 255, or hexadecimal FF
        &010 8, or octal 10
        #123 123 - decimal 123

        Using emit to output character strings would be very tedious. Luckily there is a better way. Enter:

        The word ." , pronounced "dot quote", will take everything up to the next quotation mark and print it to the screen. Make sure you leave a space after the first quotation mark. When you want to have text begin on a new line, you can issue a carriage return using the word cr . Enter: You can emit a blank space with space . In other Forths one may output more than one space with the word spaces. Let's write one for RetroForth: Notice that the new word we created, spaces, uses a "loop construct". The word repeat starts a series of words which will be run repeatedly. The word until subtracts one from TOS; if it's not zero then it jumps back to just after the repeat. We'll see more of these kinds of words later on.

        For character input, Forth uses the word key which corresponds to the word emit for output. key waits for the user to press a key then leaves its value on the stack. Try the following.

        [Note: On some computers, the input if buffered so you will need to hit the ENTER key after typing your character.]

        Compiling from Files


        With a plugin from the library, RetroForth can read from ordinary text files so you can use any editor that you wish to write your programs. To load this plugin do:

        Sample Program

        Enter into your file, the following code.

        Now save the file to disk as 'test.f'.

        The text following the | character is treated as a comment. Note that in ANS Forth, this would be the \ character. If you were writing in Basic, the equivalent would be "REM". In C it would be /* .... */, and in C++ it would be // ... The text between parentheses is also a comment.

        Using this file is trivial:

        The word include means to read in and interpret words from a file, rather than from the keyboard. After the file has been read, input returns to the keyboard.

        If you have a big project that needs lots of files, you can have a file that will load all the files you need. It is also possible to write blockfiles, but that is beyond the scope of this tutorial.


        Variables


        Forth does not rely as heavily on the use of variables as other compiled languages. This is because values normally reside on the stack. There are situations, of course, where variables are required. To create a variable, use the word variable as follows: This created a variable named MY-VAR . A space in memory is now reserved to hold its 32-bit value. The word VARIABLE is what's known as a "defining word" since it creates new words in the dictionary. Now enter: The number you see is the address, or location, of the memory that was reserved for MY-VAR. To store data into memory you use the word ! , pronounced "store". It looks like an exclamation point, but to a Forth programmer it is the way to write 32-bit data to memory. To read the value contained in memory at a given address, use the Forth word @ , pronounced "fetch". Try entering the following: This sets the variable MY-VAR to 513 , then reads the value back and prints it. You can also create a variable and set its value at the same time: The stack diagrams for these words follows:

        @ ( addr -- val )
        ! ( val addr -- )
        variable ( [name] -- )
        variable: ( val [name] -- )

        Imagine you are writing a game and you want to keep track of the highest score. You could keep the highest score in a variable. When you reported a new score, you could check it against the highest score. Try entering this code in a file as described in the previous section:

        Save the file to disk, then load this code using the include word. Test your word as follows: The Forth words @ and ! work on 32-bit quantities. Some Forths are "16-bit" Forths. They fetch and store 16-bit quantities. Forth has some words that will work on 8 and 16-bit values. c@ and c! work on characters which are usually for 8-bit bytes. The 'c' stands for "Character" since ASCII characters are 8-bit numbers.

        A word of warning about fetching and storing to memory: You have now learned enough about Forth to be dangerous. The operation of a computer is based on having the right numbers in the right place in memory. You now know how to write new numbers to any place in memory. Since an address is just a number, you could, but shouldn't, enter:

        The 253000 would be treated as an address and you would set that memory location to 73. I have no idea what will happen after that, maybe nothing. This would be like firing a rifle through the walls of your apartment building. You don't know who or what you are going to hit. Since you share memory with other programs including the operating system, you could easily cause the computer to behave strangely, even crash. Don't let this bother you too much, however. Crashing a computer, unlike crashing a car, does not hurt the computer. You just have to reboot. The worst that could happen is that if you crash while the computer is writing to a disk, you could lose a file. That's why we make backups. This same potential problem exists in any powerful language, not just Forth. This might be less likely in BASIC, however, because BASIC protects you from a lot of things, including the danger of writing powerful programs.

        Constants


        If you have a number that is appearing often in your program, it's recommended you define it as a "constant." We do this just like defining a word. Enter: We just defined a word called MAX_CHARS that returns the value on the stack when it was defined. It cannot be directly changed unless you edit the program and recompile. Using constant can improve the readability of your programs and reduce some bugs. Imagine if you refer to the number 128 very often in your program, say 8 times. Then you decide to change this number to 256. If you globally change 128 to 256 you might change something you didn't intend. If you change it by hand you might miss one, especially if your program occupies more than one file. Using constant will make it easy to change. The code that results is equally as fast and small as putting the numbers in directly. I recommend defining a constant for almost any number used more than two or three times.

        Logical Operators


        These next two sections are concerned with decision making. This first section deals with answering questions like "Is this value too large?" or "Does the guess match the answer?". The answers to questions like these are either TRUE or FALSE. Generally Forth uses a 0 to represent FALSE and a -1 to represent TRUE. TRUE and FALSE have been capitalized because they are defined as Forth constants in most Forths (but not in RetroForth). Most Forths have a word = which takes the two top values and produces either FALSE or TRUE. RetroForth doesn't, but it's trivial to add them to RetroForth:

        Now try:

        You will notice that the first line printed a 0, or FALSE, and the second line a -1, or TRUE. The equal sign in Forth is used as a question, not a statement. It asks whether the top two items on the stack are equal. It does not set them equal. In other Forths you could ask other questions that you can ask, like < or >. RetroForth doesn't have these words (or =) because they are almost always coupled with an "if" statement. RetroForth therefore has special forms of "if", which are used directly with a condition. In California, the drinking age for alcohol is 21. You could write a simple word now to help bartenders. Enter: Here you are introduced to the if/;;/then structure of Forth conditional statements. Other useful "if" constructs are:

        <if If second stack item is less than TOS
        =if Two top stack items are equal
        <>if Top two stack items are not equal
        ;; Exit the current word


        Loops


        We've mentioned one of the "looping constructs" before. Now we'll examine them more closely. RetroForth has a completely different set of loop constructs than ANS Forth, so you'll want to pay attention.

        Most loops begin with the word repeat. The first kind of loop is between repeat ... until. This loops until a condition is true. Try this:

        This word will count down from N to zero. The second type of loop RetroForth has is an "unconditional" loop, repeat ... again. This keeps going until you break out of it, perhaps by using ;; or pressing Ctrl-C :

        Consider the following word for doing character graphics. Enter:

        RetroForth also has a for ... next construct similar to ANS Forth. It is used like this:

        If you type looper you will see 10 lines, starting with "Iteration #10".

        Text Input and Output


        You learned earlier how to do single character I/O. This section concentrates on using strings of characters. RetroForth has several varieties of strings, and it is good to know when to use each type.

        The "normal" string is a Forth string, consisting of an address,count pair. That is, it is represented on the stack by an address which points to the start of the character data, and a count of characters. In stack diagrams it is often listed as ( a n -- ). To create such a string, you may use a double-quote character, " . That word parses until if finds another double-quote, and then it puts the address, count on the stack. Inside a colon-definition, it compiles a reference to that string data so that at runtime, the string data will appear on the stack.

        The word type seen above, prints out the Forth string on top of the stack.

        The second type of string supported by RetroForth is the "ASCIIZ" string. That is, a string which is terminated by a NUL byte (ASCII-ZERO). These are the native strings for C, and both Windows and Linux API functions expect such strings. Use the word zt to temorarily convert a Forth string to an ASCIIZ string.

        When using " inside a colon-definition, the strings will be compiled to a separate area which by default is 8K in size. So any "compiled" string will be physically separate from the "temporary" string area, and there is no danger of overwriting them (unless you have a bug in your code...). If you try to compile more than 8K of string data, RetroForth will likely crash. You can allocate mores space by doing: here st0 ! xxxx allot where xxxx is the amount of memory to allocate.


        Changing Numeric Base


        Our numbering system is decimal, or "base 10." This means that a number like 527 is equal to (5*100 + 2*10 + 7*1). The use of 10 for the numeric base is a completely arbitrary decision. It no doubt has something to do with the fact that most people have 10 fingers (including thumbs). The Babylonians used base 60, which is where we got saddled with the concept of 60 minutes in an hour. Computer hardware uses base 2, or "binary". A computer number like 1101 is equal to (1*8 + 1*4 + 0*2 + 1*1). If you add these up, you get 8+4+1=13 . A 10 in binary is (1*2 + 0*1), or 2. Likewise 10 in any base N is N .

        Forth makes it very easy to explore different numeric bases because it can work in any base. Try entering the following:

        Another useful numeric base is hexadecimal. which is base 16. One problem with bases over 10 is that our normal numbering system only has digits 0 to 9. For hex numbers we use the letters A to F for the digits 10 to 15. Thus the hex number 3E7 is equal to (3*256 + 14*16 + 7*1). Try entering: A variable called base is used to keep track of the current numeric base. The words hex , decimal , and binary work by changing this variable. You can change the base to anything you want. As mentioned before, certain modifier characters allow you to enter decimal, hex, binary or octal (base 8) numbers no matter what the current base is. Try: You are now in base 7 . When you fetched and printed the value of BASE, it said 10 because 7, in base 7, is 10.