TutorialPart2

Repetition

We left the last tutorial being able to add new commands to Forth and being able to do some simple outputs for numbers and text. In this one we're exploring the next step up in programming: repetition. Unlike every-day life, if you want to do things multiple times you have to actually do them multiple times. On a computer you can get it to do it for you. There's a number of ways you can explore this.

Firstly, you can wrap commands inside commands. Try this (assuming you have hi from the last tutorial still defined):

: hi5 hi hi hi hi hi ;

: hi25 hi5 hi5 hi5 hi5 hi5 ;

hi25 Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World!Hello World! OK

This works a lot like the way you'd cut and paste text to replicate it: Select All, Copy, Paste, Paste, Paste, Paste, Paste etc. Except here, you only use up something like 30 bytes of memory. However, this method is quite rigid in use and besides, there's no space between the messages.

A more flexible way is to repeat something a known number of times and in Forth this is done using two commands: do and loop. do expects the programmer to provide two numbers, which determine how many times to repeat, and loop handles the repetition itself, jumping back to just after its matching do until there's no more repeats. So, try this:

: doingHi 25 0 do hi space loop ;

doingHi Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! Hello World! OK

So, this new command repeats hi 25 times as you can see and with a space in between each "Hello World!". In Forth the number of repetitions are maintained using an internal counter, which in this case starts at 0 (because the second number was a 0). We can retrieve the counter when we're inside the loop using the command i , which is short for index, so if we try this example:

: countTen 10 0 do i . loop ;

countTen 0 1 2 3 4 5 6 7 8 9 ok

We can see that it starts counting at 0 and ends, perhaps surprisingly, at 9 not 10. However, if you count the number of times i is displayed, you'll see that it's 10 - it's repeated the loop 10 times. do expects two numbers, but they don't have to be entered inside our new command. So, we can make our counter a bit more flexible by removing the limit from the command itself and typing it in when we need it.

: countUp 0 do i . loop ;

100 countUp 0 1 2 3 4 5 ... 98 99 ok

So, then you can try much larger numbers: 1000 countUp and 10000 countUp. You can see that FIGnition is pretty fast, certainly compared with any early 80s 8-bit computer running Forth, displaying 1000 numbers in about a second!

Predetermined repetitions are handy in many situations. For example, we can slow the computer down simply by creating empty loops.

: delay 0 do loop ;

: countSlow 0 do i . 10000 delay loop ;

10 countSlow 0 (pause) 1 (pause) 2 (pause) ... 9 (pause) ok

Although the do loop in delay doesn't repeat anything, it still slows the computer down because Forth still has to do the counting. FIGnition has a built-in command, pause if you want to delay for a specific time in 50ths of a second (60ths of a second for NTSC FIGnitions). Executing 50 pause pauses for a second, and -50 pause pauses for a second or until you press a key.

In Forth we can combine arithmetic and loops to quickly achieve number patterns. For example, in Maths classes we come across triangle numbers which are calculated as 1, 1+2, 1+2+3, 1+2+3+4 etc. We can easily mimic this in Forth:

: triNum 0 do i + loop ;

0 1 triNum . 0 ok

0 2 triNum . 1 ok

0 3 triNum . 3 ok

Here, the first number we enter is the starting sum, because + needs 2 numbers and the following number is the number of repetitions. Anyway, after 3 I got bored typing it all out. But a-ha, I then realised I can wrap triNum in a loop to make it print out a whole lot of them!

: triNums 0 do 0 i triNum . loop ;

6 triNums 0 0 1 3 6 10 ok

Weird, the first two are both 0, but the rest seem like proper triangle numbers. I wonder how many it can calculate?

Conditional Loops

The next easiest type of repetition is the conditional loop, where you want the computer to keep doing something until it detects a particular situation, called a condition in programming-speak, and then you continue. In Forth this is achieved using the commands begin and until. For example, we can create a simple typewriter program with this:

: typer begin key dup emit 13 = until ;

typer <enter>

Nothing happens at first. But if you continue to type some letters they get displayed until you press <enter> again.

typer <exe> OK, let's see how this program works! <enter> ok

OK, let's see how the program works! The command key waits for you to press a key, and it causes Forth to remember the code for the key as though you'd typed the code in directly. For example, if you press 'A', key remembers the number 65. You can try this directly:

key . A 65 ok

dup duplicates the last number remembered, so it's as though you typed in the same number twice: 65 65. Again, since this is Forth you can try it immediately:

123 65 dup . 65 ok

. 65 ok

. 123 ok

emit uses the most recent number; treats it as a key code and displays the letter, number or symbol corresponding to it. In this case it would use the most recent 65 and display 'A'.

= tests whether the two most recently remembered numbers are equal. It's like an arithmetic command, using up those two numbers and returning a result: -1 for true or 0 for false.

until repeats from it's begin if the result was false. In this case, 65 isn't 13, so it will repeat. 13 happens to be the key code for <enter>, so typer will stop when you press <enter>.

So the way typer works is that it waits for you to press a key and then remembers the key code. It duplicates that number and emits it as a character (so you see what you typed); after that FIGnition is back to remembering one copy of the key you pressed; it compares that with 13 (which is the <enter> key) using 13 =  and goes back round the loop if the comparison wasn't true using until. The upshot is that it keeps displaying every key you type until you press <enter>.

In the next tutorial we'll explore the memory!

Notes:

#1 If you're new to programming, it probably doesn't help much to know that i is short for index. It's a common convention in maths and programming though. What it refers to is the act of using your index finger to point to successive items; you might be pointing to days marked out on a calendar or determining if you have enough coins for a bus ride or counting clothes you need to pack in a suitcase. In turn, index is a Latin word which means indicate and also means forefinger.

#2

In this tutorial we've deliberately only covered the basics about loops. There's a few other words you will find useful from time to time:

i' (with the apostrophe after the i) results in the loop limit being displayed (the first number provided for the do command).

leave is a command which sets the current counter to the loop limit - this means you can finish looping early, because the next loop command won't loop round for another.

begin ... while .. repeat is an alternative to begin .. until. Instead of testing to see if we want to repeat the code at the end of a loop, it's sometimes better to test at the beginning, because you might not want it to run the loop at all!