fcl/README.md

278 lines
6.9 KiB
Markdown
Raw Normal View History

2021-06-19 20:58:54 +02:00
# FCL - Forth Calculator's Language
FCL is the programming language of an Android app called Forth Calculator. It is a Forth dialect with optional local variables, complex data structures, quotations and Java interoperability.
```forth
2021-06-20 11:12:48 +02:00
: fib ( n -- n* ) -> n ( local variable )
0 1 { 2dup + } n times ; ( quotation )
2021-06-19 20:58:54 +02:00
```
2021-06-19 21:08:32 +02:00
Besides all the high-level features, FCL supports the traditional Forth programming structures and uses the same compilation model (compile/interpret mode, dictionary, immediate words, etc.) as traditional Forth systems.
## The Syntax
2021-06-19 21:23:08 +02:00
The syntax is a superset of the Forth language. In FCL there are literal syntax for creaing Lists `[ 1 2 3 ]`, Maps `#[ 'key' 'value' ]#`, Quotations `{ dup + }` and Strings `'Hello World'`.
2021-06-19 21:21:35 +02:00
2021-06-20 00:12:10 +02:00
## Low-level control structures
2021-06-19 21:21:35 +02:00
2021-06-20 15:43:21 +02:00
FCL supports the traditional Forth conditionals and loops.
2021-06-19 21:33:31 +02:00
General form of `if else then`.
```forth
<bool> if <consequent> else <alternative> then
```
For example:
```forth
2021-06-20 13:32:53 +02:00
: max ( n n -- n )
2021-06-19 21:33:31 +02:00
2dup < if nip else drop then ;
10 100 max . \ prints 100
```
2021-06-19 21:34:21 +02:00
The `else` part is optional.
2021-06-19 21:33:31 +02:00
```forth
2021-06-19 21:35:24 +02:00
: abs ( n -- n )
dup 0 < if -1 * then ;
2021-06-19 21:33:31 +02:00
-10 abs . \ prints 10
```
#### Case statement
FCL supports switch-case like flow control logic as shown in the following example.
```forth
2021-06-20 13:32:53 +02:00
: day ( n -- s )
2021-06-19 21:33:31 +02:00
case
2021-06-20 13:32:53 +02:00
1 of 'Monday' endof
2 of 'Tuesday' endof
3 of 'Wednesday' endof
4 of 'Thursday' endof
5 of 'Friday' endof
6 of 'Saturday' endof
7 of 'Sunday' endof
2021-06-19 21:33:31 +02:00
drop 'Unknown'
endcase ;
````
#### Count-controlled loops
The `limit` and `start` before the word `do` defines the number of times the loop will run.
```forth
<limit> <start> do <loop-body> loop
```
2021-06-20 15:43:21 +02:00
*DO* loops iterate through integers by starting at *start* and incrementing until you reach the *limit*. The word *i* pushes the loop index onto the stack. In a nested loop, the inner loop may access the loop variable of the outer loop by using the word *j*.
2021-06-19 21:33:31 +02:00
For example:
```forth
5 0 do i . loop \ prints 0 1 2 3 4
```
It is important to understand the implementation details of this loop. `DO` loops store the loop index on the return stack. You can break the semantics of *i* and *j* if you use the return stack to store temporary data. Exiting from the loop requires clearing up the return stack by using the `unloop` word.
#### Condition-controlled loops
##### until loop
```forth
begin <loop-body> <bool> until
```
The *begin*...*until* loop repeats until a condition is true. This loop always executes at least one time.
For example:
```forth
: countdown ( n -- )
begin
2021-06-20 13:33:59 +02:00
dup .
1-
dup 0 <
2021-06-19 21:36:46 +02:00
until
2021-06-19 21:33:31 +02:00
drop ;
5 countdown \ prints 5 4 3 2 1 0
```
##### while loop
```forth
2021-06-20 01:03:39 +02:00
begin <bool-exp> while <loop-body> repeat
2021-06-19 21:33:31 +02:00
```
For example:
```forth
: countdown ( n -- )
begin
dup 0 >=
while
dup . 1-
repeat
drop ;
5 countdown \ prints 5 4 3 2 1 0
```
Control structres are compile time words with no interpretation semantics.
2021-06-19 21:08:32 +02:00
## Locals
2021-06-19 21:43:27 +02:00
```
: example ( a b -- n )
-> b -> a 42 -> c 0 => d
a b + c * d !
d @ ;
```
There are two types of locals in FCL. Local constant `->` and local variable `=>`.
2021-06-19 21:49:40 +02:00
`-> a` loads the top of the stack into the local, called `a`.
2021-06-19 21:43:27 +02:00
2021-06-19 21:49:40 +02:00
`a` pushes the value of the local.
2021-06-19 21:43:27 +02:00
2021-06-19 21:49:40 +02:00
`=> b` loads the top of the stack into the local variable, called `b`.
2021-06-19 21:43:27 +02:00
2021-06-19 21:49:40 +02:00
`b` pushes the reference of the local. `b @` pushes the value of the local.
The `->` and `=>` words can be used anywhere within a word, including loop bodies and quotations. You can initialize a local (`0 -> a`) within the word or use the data that was supplied on the call site (`-> a`).
```
: count-even ( n -- c )
-> n 0 => count
n 0 do
i 2 /mod -> quotient -> remainder
remainder 0 = if
count inc
then
loop
count @ ;
```
2021-06-19 21:08:32 +02:00
2021-06-19 22:02:49 +02:00
### Implementation notes
2021-06-19 23:58:24 +02:00
Local variable support is implemented in FCL itself. Locals are stored in a parameter stack. Both `->` and `=>` are immediate parsing words. They have both runtime and compilation semantics. They compile an inline *lookup word* within the enclosing word. At runtime they load the top of the stack into the proper location of the parameter stack. At runtime, the *lookup word* gets the value (or the reference) from the parameter stack and pushes it onto the data stack.
## Quotations
```forth
2021-06-20 11:06:41 +02:00
{ dup * } \ creates a quotation
2021-06-19 23:58:24 +02:00
```
A quotations is an anonymous word that contain a snippet of code and its evaluation is delayed until it's called (with `yield`).
```forth
{ 'hello world' . } \ quotation pushes its address to the data stack
yield \ calls the quotation
```
```forth
{ 'hello' . } 10 times
```
A quotation can access to local variables of the enclosing word and have its own local variables as well.
```forth
: tst ( -- n )
0 => sum
[ 1 2 3 4 5 ] { -> item sum @ item + sum ! } each
sum @ ;
```
2021-06-20 15:43:21 +02:00
Local variables are lexically scoped. If the quotation is called by another word, the `sum` still denotes the variable that was defined in the quotation's context.
2021-06-19 23:58:24 +02:00
Quotations don't act as lexical closures however. The parameter stack is unwinded after the enclosing function is returned.
### Implementation notes
The quotation code is compiled into the enclosing word and bypassed by a jump. At runtime the quotation pushes its address as well as a stack frame to the stack. The word `yield` calls the address like a normal word and sets the parameter stack pointer to the quotation's stack frame.
2021-06-19 22:02:49 +02:00
2021-06-19 21:08:32 +02:00
## List
2021-06-20 00:04:35 +02:00
A list is a dynamic, ordered data structed.
2021-06-19 22:02:49 +02:00
`<list>` \ creates a new empty list
`<list> dup 1 add` \ creates an empty list and adds *1* to it.
`[ 1 2 3 ]` \ creates a list with 3 elements.
2021-06-20 00:04:35 +02:00
Lists are java.util.ArrayList instances and garbage collected automatically by the host language.
2021-06-19 22:02:49 +02:00
2021-06-19 21:43:27 +02:00
## Maps
2021-06-20 00:04:35 +02:00
Maps contain key value pairs.
2021-06-19 22:02:49 +02:00
`<map>` \ creates a new empty map
`<map> dup 'key1' 'value1' put` \ creates an empty map and puts *'key1' => 'value1'* into it.
`#[ 'key1' 'value1' ]#` \ same as above
2021-06-20 00:04:35 +02:00
Lists are java.util.LinkedHashMap instances and garbage collected automatically by the host language.
## Collection operations
```forth
2021-06-20 00:05:21 +02:00
\ iterets through the list and calls the quotation on each element
[ 1 2 3 4 ] { . } each
2021-06-20 00:04:35 +02:00
```
```forth
2021-06-20 00:05:21 +02:00
\ selects only the odd items from the list [ 1 3 ]
[ 1 2 3 4 ] { odd? } filter
2021-06-20 00:04:35 +02:00
```
```forth
2021-06-20 00:05:21 +02:00
\ transforms the list to a new list that contain the squares of the original items [ 1 4 9 16 ]
[ 1 2 3 4 ] { dup * } map
2021-06-20 00:04:35 +02:00
```
```forth
2021-06-20 00:57:32 +02:00
1 5 .. \ creates a range from 1 to 5
2021-06-20 00:04:35 +02:00
```
2021-06-19 22:02:49 +02:00
2021-06-20 01:02:09 +02:00
```forth
10 1 -2 ... \ creates a range from 10 downto 2 by 2
```
2021-06-20 00:09:53 +02:00
```forth
\ adds 5 to the end of the list
[ 1 2 3 4 ] dup 5 add
```
```forth
\ prepends 0 to the beginning of the list
[ 1 2 3 4 ] dup 0 prep
```
```forth
[ 1 2 3 ] size \ gets the size of the list
```
```forth
[ 1 2 3 4 ] 2 at \ gets the second item of the list ( indexing is zero based )
```
```forth
alist clear \ removes all items from the list
```
2021-06-20 01:12:05 +02:00
## High level control structures
Quotations combined with the collection API offers some high level control structures.
```forth
1 .. 10 {
dup * .
} each
```
2021-06-20 00:09:53 +02:00
2021-06-19 21:08:32 +02:00
## HTTP