learnxinyminutes-docs/forth.html.markdown
ruv bf4a8e7c56 [forth/en] correct some mistakes, make better wording in some places
1. A variable size cannot be changed in Forth, see
https://forth-standard.org/standard/usage#subsubsection.3.3.3.3

2. `variable` shall not be used to create a variable to hold a floating-point number. Use `fvariable` instead.

3. In Forth, `i` is NOT equivalent to `r@`. Remove the corresponding sentence.

4. Add an example of using the return stack and `begin ... while ... repeat` loop.

5. Make `one-to-12` do what its name suggests.

6. Add a link to the Forth Standard.

7. Make some comments more consistent (e.g. instead of using the terms "item" and "element", use "item" throughout).

8. In some places, make comments more correct or detailed, briefly explain the stack diagrams.
2024-06-06 09:34:24 +04:00

8.1 KiB

language contributors filename
forth
Horse M.D.
http://github.com/HorseMD/
learnforth.fs

Forth was created by Charles H. Moore in the 70s. It is an imperative, stack-based language and programming environment, being used in projects such as Open Firmware. It's also used by NASA.

Note: This article focuses predominantly on the Gforth implementation of Forth, but most of what is written here should work elsewhere.

\ This is a comment
( This is also a comment but it's usually used when defining words )

\ --------------------------------- Precursor ----------------------------------

\ All programming in Forth is done by manipulating the data stack (more
\ commonly just referred to as "the stack").
5 2 3 56 76 23 65    \ ok

\ Those numbers get added to the stack, from left to right.
.s    \ <7> 5 2 3 56 76 23 65 ok

\ In Forth, everything is either a word or a number.
\ A word is a named definition, that is something like a function/subprogram.

\ ------------------------------ Basic Arithmetic ------------------------------

\ Arithmetic works by manipulating parameters on the stack.
\ (in fact most words requiring parameters)
5 4 +    \ ok

\ `.` pops the top parameter from the stack and prints it as a signed number:
.    \ 9 ok

\ More examples of arithmetic:
6 7 * .        \ 42 ok
1360 23 - .    \ 1337 ok
12 12 / .      \ 1 ok
13 2 mod .     \ 1 ok

99 negate .    \ -99 ok
-99 abs .      \ 99 ok
52 23 max .    \ 52 ok
52 23 min .    \ 23 ok

\ ----------------------------- Stack Manipulation -----------------------------

\ Naturally, as we work with the stack, we'll want some useful methods:

3 dup -          \ duplicate the top item (1st now equals 2nd): 3 - 3
2 5 swap /       \ swap the top with the second item:           5 / 2
6 4 5 rot .s     \ rotate the top 3 items:                      4 5 6
4 0 drop 2 /     \ remove the top item (don't print to screen): 4 / 2
1 2 3 nip .s     \ remove the second item (similar to drop):    1 3

\ ---------------------- More Advanced Stack Manipulation ----------------------

1 2 3 4 tuck   \ duplicate the top item below the second item:     1 2 4 3 4 ok
1 2 3 4 over   \ duplicate the second to the top:                  1 2 3 4 3 ok
1 2 3 4 2 roll \ *move* the item at that position to the top:      1 3 4 2 ok
1 2 3 4 2 pick \ *duplicate* the item at that position to the top: 1 2 3 4 2 ok

\ When referring to stack indexes, they are zero-based.

\ ------------------------------ Creating Words --------------------------------

\ The `:` word sets Forth into compile mode until it sees the `;` word.
: square ( n -- n ) dup * ;    \ ok
5 square .                     \ 25 ok

\ "( n -- n )" above is a stack diagram.
\ A stack diagram shows the number and data types of the input and output stack parameters.
\ Data types are referred by their data type symbols.
\ The standard data type symbols are listed at https://forth-standard.org/standard/usage#table:datatypes

\ We can view what a word does too:
see square     \ : square dup * ; ok

\ -------------------------------- Conditionals --------------------------------

\ -1 == true, 0 == false. However, any non-zero value is usually treated as
\ being true:
42 42 =    \ -1 ok
12 53 =    \ 0 ok

\ `if` is a compile-only word. `if` <stuff to do> `then` <rest of program>.
: ?>64 ( n -- n ) dup 64 > if ." Greater than 64!" then ; \ ok
100 ?>64                                                  \ Greater than 64! ok
\ Note: the input parameter 100 remains on the stack.

\ Else:
: ?>64 ( n -- n ) dup 64 > if ." Greater than 64!" else ." Less than 64!" then ;
100 ?>64    \ Greater than 64! ok
20 ?>64     \ Less than 64! ok

\ ------------------------------------ Loops -----------------------------------

\ `?do` is also a compile-only word.
: myloop ( -- ) 5 0 ?do cr ." Hello!" loop ; \ ok
myloop
\ Hello!
\ Hello!
\ Hello!
\ Hello!
\ Hello! ok

\ `?do` expects two numbers on the stack: the end number (exclusive) and the
\ start number (inclusive).

\ We can get the value of the index as we loop with `i`:
: one-to-12 ( -- ) 13 1 do i . loop ;     \ ok
one-to-12                                 \ 1 2 3 4 5 6 7 8 9 10 11 12 ok

\ `do` works similarly, except if start and end are exactly the same it will
\ loop forever (until arithmetic underflow).
: loop-forever 1 1 do i square . loop ;     \ ok
loop-forever                                \ 1 4 9 16 25 36 49 64 81 100 ...

\ Change the "step" with `+loop`:
: threes ( n n -- ) ?do i . 3 +loop ;    \ ok
15 0 threes                             \ 0 3 6 9 12 ok

\ Indefinite loops with `begin` <stuff to do> <flag> `until`:
: death ( -- ) begin ." Are we there yet?" 0 until ;    \ ok

\ ---------------------------- Variables and Memory ----------------------------

\ Use `variable` to declare `age` to be a variable.
variable age    \ ok

\ Then we write 21 to age with the word `!`.
21 age !    \ ok

\ Finally we can print our variable using the "read" word `@`, which puts the
\ value to the stack, or use `?` that reads and prints it in one go.
age @ .    \ 21 ok
age ?      \ 21 ok

\ Constants are quite similar, except we don't bother with memory addresses:
100 constant WATER-BOILING-POINT    \ ok
WATER-BOILING-POINT .               \ 100 ok

\ ----------------------------------- Arrays -----------------------------------

\ Creating arrays is similar to variables, except we need to allocate more
\ memory to them.

\ You can use `create` and `3 cells allot` to create an array that's 3 cells long:
create mynumbers 3 cells allot    \ ok

\ Initialize all the values to 0
mynumbers 3 cells erase    \ ok

\ Alternatively we could use `fill`:
mynumbers 3 cells 0 fill

\ or we can just skip all the above and initialize with specific values:
create mynumbers 64 , 9001 , 1337 , \ ok (the last `,` is important!)

\ ...which is equivalent to:

\ Manually writing values to each index:
64 mynumbers 0 cells + !      \ ok
9001 mynumbers 1 cells + !    \ ok
1337 mynumbers 2 cells + !    \ ok

\ Reading values at certain array indexes:
0 cells mynumbers + ?    \ 64 ok
1 cells mynumbers + ?    \ 9001 ok

\ We can simplify it a little by making a helper word for manipulating arrays:
: of-arr ( n n -- n ) cells + ;    \ ok
mynumbers 2 of-arr ?               \ 1337 ok

\ Which we can use for writing too:
20 mynumbers 1 of-arr !    \ ok
mynumbers 1 of-arr ?       \ 20 ok

\ ------------------------------ The Return Stack ------------------------------

\ The return stack may be used to temporary hold parameters while
\ executing other words, e.g. in indefinite loops.

\ `>r` ( x -- ) moves the top paramenter from the data stack to the return stack
\ `r>` ( -- x ) moves the top paramenter from the return stack to the data stack
\ `r@` ( -- x ) copies the top paramenter from the return stack to the data stack

: myloop ( -- ) 5 >r 0  begin ( n ) dup r@ u< while  dup . 1+ repeat  drop r> drop ;    \ ok
myloop \ 0 1 2 3 4 ok

\ In some Forth systems the return stack can be used in interpretation state:
5 6 4 >r swap r> .s    \ 6 5 4 ok

\ NOTE: Because Forth uses the return stack for word pointers,  `>r` should
\ always be followed by `r>`.

\ ------------------------- Floating Point Operations --------------------------

\ Most Forths tend to eschew the use of floating point operations.
8.3e 0.8e f+ f.    \ 9.1 ok

\ Usually we simply prepend words with 'f' when dealing with floats:
fvariable myfloatingvar   \ ok
4.4e myfloatingvar f!     \ ok
myfloatingvar f@ f.       \ 4.4 ok

\ --------------------------------- Final Notes --------------------------------

\ Typing a non-existent word will empty the stack. However, there's also a word
\ specifically for that (Gforth-specific):
clearstack

\ This word can be defined as
: clearstack ( i*x -- ) depth 0 ?do drop loop ;

\ Clear the screen:
page

\ Loading Forth files:
\ s" forthfile.fs" included
\ or:
\ include forthfile.fs

\ You can list every word that's in Forth's dictionary (but it's a huge list!):
\ words

\ Exiting Gforth:
\ bye

##Ready For More?