Since version 0.6.0 FFL uses the ANS stack notation.
Stack parameters input to and output from a word are described by: ( stack: before -- after) where stack specifies which stack is used. The code for the control-flow-stack is C:, for the return-stack it is R: and for the float stack F:. If no stack identifier is present in the notation, the data stack is used.
The before info represents the stack parameter data types before execution of the word and after represents them after execution. The top of the stack is to the right. The following symbols are used in before and after:
Symbol | Data type |
---|---|
flag | flag |
true | true flag |
false | false flag |
char | character |
n | signed number |
+n | non-negative number |
u | unsigned number |
x | unspecified cell |
xt | execution token |
addr | address |
a-addr | aligned address |
c-addr | character-aligned address |
d | double-cell signed number |
+d | double-cell non-negative number |
ud | double-cell unsigned number |
xd | unspecified cell pair |
i*x, j*x, k*x | any data type |
r | float number |
As an addition to this table the FFL variables on the stack are represented by the three alphabetic characters of the defining module. For example the stack notation of the sh1-finish word, used in the Starting chapter is: ( sh1 -- u1 u2 u3 u4 u5 ). This word expects a sh1 variable on stack and returns five unsigned numbers. The FFL variables are actually aligned addresses (a-addr).
It is possible that a word returns different stack parameters after execution. This is described by after1 | after2.
If a word has both compile time as run time behaviour, this is described by ( before1 -- after1 ; before2 -- after2 ). The stack parameters before1 and after1 specifies stack behaviour during compilation time and before2 and after2 during run time.
A few words in the FFL parse text during compilation. Those words use the following syntax: ( before "parsed-text-abbreviation" -- after ). The parsed-text-abbreviation uses the following specifications:
Abbreviation | Description |
---|---|
<char> | the char marking the end of the parsed string |
<chars> | zero or more chars |
<space> | a delimiting space character |
<spaces> | zero or more spaces |
<quote> | a delimiting double quote |
<paren> | a delimiting right parenthesis |
<eol> | a delimiting end of line |
ccc | arbitrary characters, excluding the delimiter character |
name | a token delimited by space |
There are two different type of words in the FFL: general use words and library words.
The general words perform small, general actions. They use normal, descriptive names. Exampes are nil<>, #bits/byte, begin-stringtable and so on.
The name of the library words start with a prefix, followed by a special character and ends with a descriptive name. The prefix is equal to the module name. The special character is one of the following:
Char | Description |
---|---|
% | this word returns the size of the module variable, for example: sh1% |
. | this word is an enumeration, variable, value, constant of defer in the module, for example: sh1.version |
+ | this word expects no module variables on the stack, for example: frc+multiply |
- | this word expects one module variable on the stack, for example: sh1-update |
^ | this word expects two module variables on the stack, for example: str^move |
The descriptive name specifies the action that the word performs on the optional stack parameters. Some special characters are used for abbreviations:
Char | Description |
---|---|
? | the word performs a check and will return a boolean flag, for example: str-index? |
@ | the word fetches the state of an internal variable, for example: dtm-day@ |
! | the word stores the state of an internal variable, for example: dtm-day! |
+ | the word performs an addition or incrementation, for example: dti-seconds+ |
- | the word performs an subtraction or decrementation, for example: dti-seconds- |
( ) | the word performs an action on the internal state, for example: str-(free) |
Due to historical reasons there are two groups of words that do not follow this naming convention. Those are module-name-create and module-name-new. Based on the name you should expect that those words expect a module variable on the stack, but actually they don't. So they should be named module-name+create and module-name+new, but again for historical reasons they are not.