Forth for bloody beginners

1 the virtual Forth environment

  • use a modern Browser (Firefox, Chrome, Brave etc)
  • URL: https://free.forth-schulung.de:9090/system/terminal
  • User: forth
  • Password: forth-oct-2020
  • Select a unique name for your Forth environment. For example use your first and last name without spaces. If you need to reconnect to the system, please use the same name again.

2 Intro into Forth

2.1 Why Forth?

Forth is interactive

2.2 Why Forth?

Forth is lightweight

2.3 Why Forth?

  • Forth is available on many OS and machines (microcontroller, small and large computer)
  • … it is easy to re-use knowledge
  • … since more than 50 years

2.4 Why Forth?

  • Forth is extendable and does not age
  • … missing functions can always be added
  • … Multitasking, OOP, functional programming, …

3 Forth Crashkurs

3.1 A short intro into Forth

  • Syntax:
    • a Forth word is a sequence of characters separated by whitespace
    • a word is the functional unit of a Forth system (like a function or procedure in other languages)
  • valid Forth words
    • wort
    • !@#$%^&*()
    • 1234567890
    • BLIT

3.2 Forth-Syntax

  • the Forth syntax is very simple
    • words are separated by whitespace …
    • … end will be evaluated from left to right
  • Entries evaluate either to executable Forth words or numbers
    • … and that's it

3.3 Safety

  • Important: Forth only has the safey nets that the deveoper creates
    • e.g. none in the usual case
  • Forth does not stand in the way of the developer

3.4 What is Forth?

  • an ultimative expandable programming environment
  • almost no rules, no syntax
  • full control of the language and the system

3.5 Stack

  • Forth uses a stack to pass parameters between words
    • a number that has been entered will be pushed to the stack
  • the stack is a FIFO storage memory
  • The word .s prints the content of the stack
1 2 3 .s

3.6 "." (Dot)

  • The word . print the value of the top most number on the stack
1 2 3 . . . [RTN]

3.7 Arithmetic

  • The arithmetic operators +, -, *, / and mod work on the topmost stack elements (Postfix)
2 2 + . [RTN]
2 1 - . [RTN]
7 3 mod . [RTN]

3.8 Aritthmetic 2

  • there is no need for parantheses, the evaluation order is always clear from the order of words
3 4 + 5 * .
3 4 5 * + .

3.9 Stack comments

  • Stack comments in parantheses are for humans reading the code
    • will be ignored by the parser
    • document the input and output parameter of a word
  • example
. ( n -- )
+ ( n n - n )

3.10 SWAP

  • swap exchanges to two values on the top of stack (TOS)
SWAP ( x y -- y x )

3.11 DUP

  • dup creates a copy (duplicate) of the topmost stack entry
DUP ( x -- x x )

3.12 OVER

  • over creates a copy of the 2nd stack element and places it on the top
OVER ( x1 x2 - x1 x2 x1 )

3.13 ROT

  • rot rotates the 3 topmost stack entries
ROT ( x1 x2 x3 -- x2 x3 x1 )

3.14 -ROT

  • -rot rotates the topmost 3 stack elements (reverse)
-ROT ( x1 x2 x3 -- x3 x1 x2 )

3.15 Comments

\ comment until the end of the line
( comment until the closing parenthesis ) .s
.( this comment will be printed when the code is evaluated )
  • \, ( and .( are normal Forth words and need to be separated by whitespace

3.16 Marker

  • marker is a simple way to remove unwanted word definitions
  • marker can be defined at any location
  • when the marker is executed, all words defined after the marker will be purged
marker --mymarker--

3.17 creating new words

  • word definitions are equivalent to functions in other languages
: square ( n -- n^2 ) dup * ;

5 square .

7 square .

3.18 creating new words (2)

  • : starts a definition
  • square is the name of the new words
  • the comment documents the stack changes
  • the words dup * will not be executed but compiled into the body of the new word
: square ( n -- n^2 ) dup * ;

3.19 creating new words (3)

  • there is no difference between words that come with a Forth system and defined words
: times-three ( n -- n^3 ) dup square * ;

-5 times-three .

: times-four ( n -- n^4 ) square square ;

3 zur-vierten .

3.20 overwriting words

  • if a word is defined that has the same name as an existing word, the new word will hide the older word
  • new definitions will use the new code, existing definitions will still use the old code
: * + ;

5 square . [RTN] 25

5 5 * . [RTN] 10

3.21 WORDS

  • the command words lists all defined words of the forth system
WORDS ( -- )

3.22 Variables

VARIABLE ccc ( -- )
  • defines a variable with the name ccc

3.23 Variables (2)

VARIABLE AMOUNT [RTN]
AMOUNT ( -- addr )
  • puts the memory address of the variable on the stack

3.24 ! (STORE)

! ( x addr -- )
  • stores the value of x into the memory addr
200 AMOUNT !
  • stores the value 200 into the variable AMOUNT

3.25 @ (FETCH)

@ ( addr -- x )
  • reads the value from memory location addr on the stack
AMOUNT @ . [RTN] 200
  • reads the value from variable AMOUNT and prints the value on the stack

3.26 Memory access

  • @, !, +! work with variables or with any memory location, like a pointer in "C" or "PEEK" and "POKE" in BASIC

3.27 control structures

  • control structures can be used in definitions, not in the interactive mode. This is an example for an IF control statement
: abs ( n1 -- +n2 )
	dup 0 < if
		negate then ;
5 abs .
-5 abs .

3.28 control structures (2)

  • if takes a flag from the stack. If it is not zero ("true"), the following code will be executes, or the code jumps to the follwoing then or else code
  • < comares the two topmost stack elements and produces a flag
1 2 < .
2 1 < .
1 1 < .

3.29 control structures (3)

  • additional logical comparison words are =, >, <>, <=, >= (not all combinations are in the Forth standards, but can be easily created when missing from you Forth system)

3.30 control structures (4)

  • The else part is optional
: min ( n1 n2 -- n )
	2dup < if
		drop
	else
		nip
	then ;
  • Remark: the stack comment of 2dup is ( n1 n2 -- n1 n2 n1 n2 )

3.31 logical operators

  • a true-Flag has all bits set, a false flag has no bit set (logical 0) (F83/ANSI Forth):
hex true u. decimal true . false .
  • Remark: all values other than 0 are logic true

3.32 logical operators (2)

  • the words AND, OR, XOR and 0= and INVERT can be used as logical operators. AND, OR, XOR and INVERT work bitwise, they need well formed flags to product valid flags
1 2 and .
1 2 or .
1 3 xor .
1 invert .

3.33 logical operators (3)

  • 0= takes any value and produces a well formed flag
1 0= .
  • to create a well formed flag from any value, use 0<>:
1 0<> .

3.34 logical operators (4)

  • the property all bit set for a well formed true can be used to prevent the use of IF
: foo ( n1 -- n2 ) 0= if 14 else 0 then ;
0 foo .
1 foo .
  • the same code without IF
: foo ( n1 -- n2 ) 0= 14 and ;
0 foo .
1 foo .

3.35 loops

  • this loop is an endless one
: endless ( -- )
  0 begin
    dup . 1+
again ;

endless
  • BEGIN macht nichts (zur Laufzeit), AGAIN springt zurueck zum BEGIN.

3.36 loops (2)

  • a while loop that will exit once a false flag is produced sieht so aus:
: log2 ( +n1 -- n2 )
 2 / 0 begin
    over 0>
 while
    1+ swap 2 / swap
repeat nip ;

7 log2 .
8 log2 .
  • WHILE consumes a flag; is it a 0 (false) the code branches past REPEAT. REPEAT jumps back to BEGIN, similar to AGAIN above.

3.37 loops (4)

?DO takes two values from the stack ( n1 n2 -- ) and executes the code between ?DO and LOOP n1-n2 times. The loop counter can be placed in the stack with the Forth word I

: fac ( n -- n! )
  1 swap 1+ 1 ?do
    i *
  loop ;

5 fac .

7 fac .

3.38 I/O

  • the word emit prints an ASCII/UTF-8 char on the screen
97 emit
char A emit
  • char reads the next character from the input stream an places the ascii value on the stack

3.39 memory

  • memory can be allocated with allot
variable storage 20 cells allot
  • This code creates a word with the name storage that places it's address on the stack when executed. The word allot allocates additional 20 cells in addition to the one cell allocated by variable

3.40 memory (2)

  • address calculation can be used to access the memory locations
3 memory 5 cells + !
  • the word cells defines the word size of the CPU architecture
: cells 2 * ;  ( 8/16 bit CPU )
: cells 4 * ;  ( 32bit CPU )
: cells 8 * ;  ( 64bit CPU )

3.41 ' (TICK)

` ccc ( -- xt )
  • searches the Forth word ccc and places it's execution token (xt) on the stack
execute ( xt -- ?? )
  • executes the word that is referenced by the execution token xt. Inside a word definition the word ['] must be used to get the 'xt' from the word next in the source code

3.42 talking to the OS

  • in GNU/Forth the word set-dir changes the current path
s" ~" set-dir

3.43 executing a shell

  • in GNU/Forth, the word sh can be used to execute operating system commands on the shell
sh sh
  • executes an interactive bourne shell

3.44 start an editor

  • some Forth-Systems have build in source code editors. In GNU/Forth you can add a Forth editor from source code or execute a external editor from within Forth
: vi s" vi" system ;
  • this defines a new word vi that will execute the VI editor. The word system will send a string to execute to the operting system

3.45 load source code

  • the Forth word include will load source code from a file from disk
include mysource.4th

4 Example applications

4.1 factorize numbers

// print factors
:  factors  
   dup  2/  1+ 1 do 
      dup i mod 0= if 
       i swap then 
      loop ;

: .factors 
  factors begin 
     dup dup . 1 <> while 
	 drop 
     repeat drop cr ;

64 .factors
100 .factors
333 .factors

4.2 Fizz Buzz

// fizz buzz in Forth https://codereview.stackexchange.com/questions/56839/fizzbuzz-in-forth
// others: https://rosettacode.org/wiki/General_FizzBuzz#Forth
// more: https://www.reddit.com/r/Forth/comments/druotn/fizzbuzz_in_forth/
// Fizz Buzz https://en.wikipedia.org/wiki/Fizz_buzz

hex
1249 constant 3vec
0421 constant 5vec
4000 constant probe
3vec 5vec or constant 3or5vec
decimal

: bang
   cr 0 101 1
   do
      ?dup 0= if probe then
      3or5vec over and 0= if i . then
      3vec over and if ." fizz" then
      5vec over and if ." buzz" then
      1 rshift cr
   loop
   drop
;

4.3 Functions / Words as data

siehe Joel Spolsky: Can Your Programming Language Do This?

If your programming language requires you to use functors, you’re not getting all the benefits of a modern programming environment. See if you can get some of your money back.

The Forth developer can extend the Forth system (Compiler, Language) and any direction

4.3.1 Java Script Version

function reduce(fn, a, init) 
{ 
    var s = init; 
    for (i = 0; i < a.length; i++) 
	s = fn( s, a[i] ); 

    return s; 
} 

function sum(a) 
{ 
    return reduce( function(a, b){ return a + b; },  
		   a, 0 ); 
}

4.3.2 Forth Version

// words (xt) as arguments on the stack
// Donated  to the public domain, J.L. Bezemer 2014
// response to Joel's  article  "Can  Your  Programming   Language   Do   This?"
// https://www.joelonsoftware.com/2006/08/01/can-your-programming-language-do-this/

: reduce >r over r> execute
	 rot 0 ?do
	    >r r@  execute  r>
	 loop drop  ;

: sum  [: dup >r +! r> ;]
       [: 0 swap ! ;] reduce ;

variable  A
12 34 45 3 A sum ? cr