GreatBookEForthLINUX EN v1 3
GreatBookEForthLINUX EN v1 3
Author
• Marc PETREMANN
Page 1
Contents
Introduction........................................................................................................5
Translation help........................................................................................................5
Why program in FORTH language on eForth Linux?............................................6
Preamble..................................................................................................................6
Boundaries between language and application............................................................6
What is a FORTH word?............................................................................................7
A word is a function?.................................................................................................7
FORTH language compared to C language..................................................................8
What FORTH allows you to do compared to the C language.....................................9
But why a stack rather than variables?.................................................................10
Are you convinced?.............................................................................................10
Are there any professional applications written in FORTH?.........................................10
Install eForth on Linux......................................................................................12
Prerequisites...........................................................................................................12
Install eForth Linux on Linux....................................................................................13
Launch eForth Linux................................................................................................13
A real 64-bit FORTH with eForth Linux..............................................................15
Values on the data stack..........................................................................................15
Values in memory................................................................................................15
Word processing depending on data size or type...................................................16
Conclusion..............................................................................................................17
Editing and managing source files for eForth Linux..........................................19
Text file editors.......................................................................................................19
Storage on GitHub...............................................................................................19
Edit files for eForth Linux from Windows...............................................................20
Creation and management of FORTH projects with Netbeans.....................................21
Create an eForth project with Netbeans................................................................21
Some good practices...............................................................................................23
Executing the contents of a file by eForth Linux........................................................24
The Linux file system.........................................................................................26
Handling files......................................................................................................26
Organize and compile your files with eForth Linux.....................................................27
Organize your files..............................................................................................27
Chaining of files..................................................................................................28
Conclusion..............................................................................................................29
Comments and debugging.................................................................................30
Write readable FORTH code.....................................................................................30
Source code indentation......................................................................................31
Comments..............................................................................................................32
Stack comments..................................................................................................32
Meaning of stack parameters in comments...........................................................33
Word Definition Word Comments.........................................................................33
Page 2
Textual comments...................................................................................................34
Comment at the beginning of the source code......................................................34
Diagnostic and tuning tools......................................................................................35
The decompiler...................................................................................................35
Memory dump.....................................................................................................35
Data stack monitor..............................................................................................36
Perform unit tests...................................................................................................37
Creating and using assert(...................................................................................37
Dictionary / Stack / Variables / Constants........................................................39
Expand Dictionary...................................................................................................39
Dictionary management.......................................................................................39
Stacks and reverse Polish notation...........................................................................40
Handling the parameter stack..............................................................................41
The Return Stack and Its Uses.................................................................................41
Memory usage........................................................................................................42
Variables.............................................................................................................42
Constants...........................................................................................................42
Pseudo-constant values.......................................................................................43
Basic tools for memory allocation.........................................................................43
Local variables with eForth Linux......................................................................45
Introduction............................................................................................................45
The fake stack comment..........................................................................................45
Action on local variables..........................................................................................46
Data structures for eForth Linux.......................................................................49
Preamble................................................................................................................49
Tables in FORTH.....................................................................................................49
One-dimensional 64-bit data array........................................................................49
Words for table definitions...................................................................................50
Read and write in a table.....................................................................................50
Management of complex structures..........................................................................51
Real numbers with eForth Linux.......................................................................53
The real ones with eForth Linux...............................................................................53
Real number accuracy with eForth Linux...............................................................53
Real constants and variables................................................................................54
Arithmetic operators on real numbers...................................................................54
Mathematical operators on real numbers..............................................................54
Logical operators on real numbers........................................................................55
Integer ↔ real transformations............................................................................55
Displaying numbers and character strings........................................................57
Change of numerical base........................................................................................57
Definition of new display formats.............................................................................58
Displaying characters and character strings...............................................................60
String variables.......................................................................................................62
Text variable management word code..................................................................62
Adding character to an alphanumeric variable.......................................................64
Page 3
Delayed action words........................................................................................66
Definition and usage of words with defer..................................................................66
Setting a Forward Reference................................................................................67
A practical case.......................................................................................................68
Word Creation Words........................................................................................70
Using does>...........................................................................................................70
Color management example.................................................................................71
Example, writing in pinyin....................................................................................72
Processing UTF8 characters...............................................................................74
UTF8 encoding........................................................................................................74
Retrieve the UTF8 character code entered using the keyboard...............................75
Displaying UTF8 characters from their code..........................................................76
Encoding from UTF8 character code point.................................................................77
Re-encoding by recursion....................................................................................78
Generate a UTF8 character table..........................................................................79
Detailed content of eForth Linux vocabularies..................................................82
Version v 7.0.7.15...................................................................................................82
FORTH...............................................................................................................82
ansi....................................................................................................................83
asm....................................................................................................................83
editor.................................................................................................................84
graphics..............................................................................................................84
graphics/internals................................................................................................84
httpd..................................................................................................................84
internals.............................................................................................................84
posix..................................................................................................................85
sockets...............................................................................................................85
tasks..................................................................................................................85
telnetd................................................................................................................85
termios...............................................................................................................85
web-interface......................................................................................................85
x11.....................................................................................................................86
Page 4
Introduction
Since 2019, I manage several websites dedicated to FORTH language development for
ARDUINO and ESP32 boards, as well as the eForth web version:
• ARDUINO : https://arduino-forth.com/
• ESP32 : https://esp32.arduino-forth.com/
• eForth web : https://eforth.arduino-forth.com/
These sites are available in two languages, French and English. Every year I pay for
hosting the main site arduino-forth.com.
It will happen sooner or later – and as late as possible – that I will no longer be able to
ensure the sustainability of these sites. The consequence will be that the information
disseminated by these sites disappears.
This book is the compilation of content from my websites. It is distributed freely from a
Github repository. This method of distribution will allow greater sustainability than
websites.
Incidentally, if some readers of these pages wish to contribute, they are welcome:
• to suggest chapters ;
• to report errors or suggest changes;
• to help with the translation...
Translation help
Google Translate allows you to translate texts easily, but with errors. So I'm asking for
help to correct the translations.
In practice, I provide the chapters already translated in the LibreOffice format. If you want
to help with these translations, your role will simply be to correct and return these
translations.
Correcting a chapter takes little time, from one to a few hours.
To contact me : petremann@arduino-forth.com
Page 5
Why program in FORTH language on eForth Linux?
Preamble
I have been programming in FORTH since 1983. I stopped programming in FORTH in
1996. But I have never stopped monitoring the evolution of this language. I resumed
programming in 2019 on ARDUINO with FlashForth then
ESP32forth.
I am co-author of several books concerning the FORTH langage :
• Introduction au ZX-FORTH (ed Eyrolles - 1984 -
ASIN:B0014IGOXO)
• Tours de FORTH (ed Eyrolles - 1985 - ISBN-13: 978-
2212082258)
• FORTH pour CP/M et MSDOS (ed Loisitech - 1986)
• TURBO-Forth, manuel d'apprentissage (ed Rem CORP - 1990)
• TURBO-Forth, guide de référence (ed Rem CORP - 1991)
Programming in the FORTH language was always a hobby until 1992 when the manager
of a company working as a subcontractor for the automobile industry contacted me. They
had a concern for software development in C language. They needed to order an industrial
automaton.
The two software designers of this company programmed in C language: TURBO-C from
Borland to be precise. And their code couldn't be compact and fast enough to fit into the
64 kilobytes of RAM memory. It was 1992 and flash memory type expansions did not
exist. In these 64 KB of RAM, we had to fit MS-DOS 3.0 and the application!
For a month, C language developers had been twisting the problem in all directions, even
reverse engineering with SOURCER (a disassembler) to eliminate non-essential parts of
executable code.
I analyzed the problem that was presented to me. Starting from scratch, I created, alone,
in a week, a perfectly operational prototype that met the specifications. For three years,
from 1992 to 1995, I created numerous versions of this application which was used on the
assembly lines of several automobile manufacturers.
Page 6
• an interpreter and executable source code: BASIC, PHP, MySQL, JavaScript, etc...
The application is contained in one or more files which will be interpreted whenever
necessary. The system must permanently host the interpreter running the source
code;
• a compiler and/or assembler: C, Java, etc. Some compilers generate native code,
that is to say executable specifically on a system. Others, like Java, compile
executable code on a virtual Java machine.
The FORTH language is an exception. It integrates :
• an interpreter capable of executing any word in the FORTH language
• a compiler capable of extending the dictionary of FORTH words
With the FORTH language, the essential principle is that we do not create an application.
In FORTH, we extend the dictionary! Each new word you define will be as much a part of
the FORTH dictionary as all the words pre-defined when FORTH starts. Example:
: typeToLoRa ( -- )
0 echo ! \ disable display echo from terminal
['] serial2-type is type
;
: typeToTerm ( -- )
['] default-type is type
-1 echo ! \ enable display echo from terminal
;
We create two new words: typeToLoRa and typeToTerm which will complete the
dictionary of pre-defined words.
A word is a function?
Yes and no. In fact, a word can be a constant, a variable, a function... Here, in our
example, the following sequence :
: typeToLoRa ...code... ;
Page 7
In FORTH, as in C language, you can use any word already defined in the definition of a
new word.
Yes, but then why FORTH rather than C?
I was expecting this question.
In C language, a function can only be accessed through the main function main(). If this
function integrates several additional functions, it becomes difficult to find a parameter
error in the event of a malfunction of the program.
On the contrary, with FORTH it is possible to execute - via the interpreter - any word pre-
defined or defined by you, without having to go through the main word of the program.
The FORTH interpreter is immediately accessible on eForth Linux.
The compilation of programs written in FORTH language is carried out in the ESP32 card
and not on the PC. There is no edit→Link→compile→Run cycle. Example:
: >gray ( n -- n' )
dup 2/ xor \ n' = n xor ( 1 time right shift logic )
;
This definition is executable immediatly. The FORTH interpreter/compiler will parse the
stream and compile the new word >gray.
In the definition of >gray, we see the sequence dup 2/ xor. To test this sequence,
simply type it in the terminal. To execute >gray, simply type this word in the terminal,
preceded by the number to transform.
Page 8
Here is the initialization of registers in C langage :
void setup() {
// Timer1 module configuration
TCCR1A = 0;
TCCR1B = 0; // Disable Timer1 module
TCNT1 = 0; // Set Timer1 preload value to 0 (reset)
TIMSK1 = 1; // enable Timer1 overflow interrupt
}
Page 9
But why a stack rather than variables?
The stack is a mechanism implemented on almost all microcontrollers and
microprocessors. Even the C language leverages a stack, but you don't have access to it.
Only the FORTH language gives full access to the data stack. For example, to make an
addition, we stack two values, we execute the addition, we display the result: 2 5 + .
displays 7.
It's a little destabilizing, but when you understand the mechanism of the data stack, you
greatly appreciate its formidable efficiency.
The data stack allows data to be passed between FORTH words much more quickly than
by processing variables as in C language or any other language using variables.
Page 10
This same RTX2000 processor was used for the Philae probe which attempted to land on a
comet.
The choice of the FORTH language for professional applications turns out to be interesting
if we consider each word as a black box. Each word must be simple, therefore have a
fairly short definition and depend on few parameters.
During the debugging phase, it becomes easy to test all the possible values processed by
this word. Once made perfectly reliable, this word becomes a black box, that is to say a
function in which we have absolute confidence in its proper functioning. From word to
word, it is easier to make a complex program reliable in FORTH than in any other
programming language.
But if we lack rigor, if we build gas plants, it is also very easy to get an application that
works poorly, or even to completely crash FORTH!
Good programming.
Page 11
Install eForth on Linux
eForth Linux is a very powerful version for Linux system. eForth Linux works on all recent
versions of Linux, including in a Linux virtual environment.
Prerequisites
You must have a working Linux system:
installed on a computer using Linux as the only operating system;
If you only have a computer running Windows 10 or 11, you can install Linux in the WSL 1
subsystem.
Windows Subsystem for Linux allows developers to run a GNU/Linux environment
(including most utilities, applications, and command-line tools) directly on Windows,
without modification and without overloading a machine, traditional virtual or a dual-boot
configuration.
The advantage of installing a Linux distribution in WSL allows you to have a Linux version
available in command mode in a few seconds. Here, Ubuntu is accessible from the
Windows file system and launches with a single click :
Page 12
Install eForth Linux on Linux
If you launch Ubuntu (or any other version of Linux), you will find yourself in your user
directory by default. We start by accessing to usr/bin directory :
cd /usr/bin
We will now download the version of the ueForth Linux binary file :
either from the home page of Brad NELSON's ESP32forth site:
https://esp32forth.appspot.com/ESP32forth.html
either from the eforth Google storage repository:
https://eforth.storage.googleapis.com/releases/archive.html
In the list of proposed files, copy the web link mentioning Linux:
https://eforth.storage.googleapis.com/releases/ueforth-7.0.7.15.linux
The download will automatically drop the file into the previously selected folder. If you
took the link above, you end up with a file named ueforth-7.0.7.15.linux in this folder.
We rename this file with the mv command :
mv ueforth-7.0.7.15.linux ueforth
We check that everything went well with a simple dir ue* command.
We still have one last manipulation to perform, making this file executable by the Linux
system :
sudo chmod 755 ueforth
And it's done ! eForth Linux can now be used from any Linux directory.
Page 13
Figure 2: eForth Linux is active
You can now test eForth and program your first applications in FORTH language.
PLEASE NOTE : this eForth version handles integers in 64-bit format. It's easy to check:
cell. \ display: 8
Or a dimension of 8 bytes for integers. This warning is essential if you are using FORTH
code written for 16 or 32 bit versions.
Good programming.
Page 14
A real 64-bit FORTH with eForth Linux
Eforth Linux is a real 64-bit FORTH. What does it mean?
The FORTH language favors the manipulation of integer values. These values can be
literal values, memory addresses, register contents, etc.
If we stack another value, it will also be stacked. The previous value will be pushed down
one position :
45
Our two 64-bit integer values are added together and the result is dropped onto the stack.
To display this result, we will use the word .:
. \ display 80
Unlike the C language, we do not define an int8 or int16 or int32 or int64 type.
With Eforth Linux, an ASCII character will be designated by a 64-bit integer, but whose
value will be bounded [32..255]. Example :
67 emit \ display C
Values in memory
eForth Linux allows you to define constants and variables. Their content will always be in
64-bit format. But there are situations where that doesn't necessarily suit us. Let's take a
simple example, defining a Morse code alphabet. We only need a few bytes :
• one to define number of marks in Morse code character
• one or more bytes for Morse code marks
create mA ( -- addr )
2 c,
char . c, char - c,
Page 15
create mB ( -- addr )
4 c,
char - c, char . c, char . c, char . c,
create mC ( -- addr )
4 c,
char - c, char . c, char - c, char . c,
Here we define only 3 words, mA, mB and mC. In each word, several bytes are stored. The
question is: how will we retrieve the information in these words ?
The execution of one of these words deposits a 64-bit value, a value which corresponds to
the memory address where we stored our Morse code information. It is the word c@ that
we will use to extract the Morse code from each letter :
mA c@ . \ display 2
mB c@ . \ display 4
The first byte placed on the stack will be used to manage a loop to display the code of a
character in Morse code :
: .morse ( addr -- )
dup 1+ swap c@ 0 do
dup i + c@ emit
loop
drop
;
mA .morse \ display .-
mB .morse \ display -...
mC .morse \ display -.-.
There are plenty of certainly more elegant examples. Here we show a way to manipulate
8-bit values, our bytes, while operating these bytes on a 64-bit stack.
For all programmers, this way of doing things is THE STANDARD! So how would FORTH
do this example in PHP?
: bread s" Baked bread" ;
: price s" 2.30" ;
bread type s" : " type price type
Page 16
\ display Baked bread: 2.30
Here, the word type tells us that we have just processed a character string.
Where PHP (or any other language) has a generic function and a parser, FORTH
compensates with a single data type, but adapted processing methods which inform us
about the nature of the data processed.
Here is an absolutely trivial case for FORTH, displaying a number of seconds in HH:MM:SS
format:
: :##
# 6 base !
# decimal
[char] : hold
;
: .hms ( n -- )
<# :## :## # # #> type
;
4225 .hms \ display: 01:10:25
Conclusion
FORTH has no data typing. All data passes through a data stack. Each position in the stack
is ALWAYS a 64-bit integer!
That's all there is to know.
Purists of hyper-structured and verbose languages, such as C or Java, will certainly cry
heresy. And here, I will allow myself to answer them : why do you need to type your
data ?
Because it is in this simplicity that the power of FORTH lies : a single stack of data with an
untyped format and very simple operations.
And I'm going to show you what many other programming languages can't do, define new
definition words :
: morse: ( comp: c -- | exec -- )
create
c,
does>
dup 1+ swap c@ 0 do
dup i + c@ emit
loop
drop space
Page 17
;
2 morse: mA char . c, char - c,
4 morse: mB char - c, char . c, char . c, char . c,
4 morse: mC char - c, char . c, char - c, char . c,
mA mB mC \ display .- -... -.-.
Here, the word morse: has become a definition word, in the same way as constant or
variable...
Because FORTH is more than a programming language. It is a meta-language, that is to
say a language to build your own programming language....
Page 18
Editing and managing source files for eForth Linux
As with the vast majority of programming languages, source files written in FORTH
language are in simple text format. The extension of files in FORTH language is free:
txt generic extension for all text files;
Storage on GitHub
GitHub 2website is, along with SourceForge 3, one of the best places to store source
files.
On GitHub, you
can share a
2 https://github.com/
3 https://sourceforge.net/
Page 19
On GitHub , you can manage project forks . You can also make certain parts of your
projects confidential. Above are the branches in the flagxor/ueforth projects:
Once Ubuntu is active, move the mouse pointer out of the WSL window. You return
to the Windows environment. Open Windows File Manager.
in the left pane, click Linux ;
Page 20
Figure 7: Linux files visible from Windows
select the file to edit. For the example, we will open autoexec.fs ;
If you use an IDE, like Netbeans, here is how to configure this IDE to integrate your
eForth Linux development projects.
all eForth Linux source files are saved in the ueforth directory
New Project window , select Categories: PHP and in Projects: PHP Application
with Existing Sources
Page 21
Figure 8: création projet PHP
In the Name and Location → Sources Folder field , enter the path to the eForth
Linux source files
ueforth folder from Windows, launch File Explorer. At the bottom right, click Ubuntu .
Then click on the folders:
home → userName → ueforth
In the navigation bar, at the top, you must find the path to the ueforth folder. Place the
mouse pointer in this banner. Copy the path:
Paste this path into the Netbeans field described above. Finish creating the new project in
Netbeans. You can now find all the files of your project in Netbeans:
Page 22
Figure 10: the new project is operational
Now any editing, creating, modifying or deleting a file from Netbeans is immediately
reflected in your ueforth project folder on Linux.
documentation directory to store files in the format of your choice, related to the
project documentation;
Page 23
Figure 11: exemple de nommage de fichiers source Forth
myApp.fs for your project definitions. Choose a fairly explicit file name. For
example, to manage your game, take the name game-commands.fs .
If you have correctly installed ueforth , its launch may be followed by the name of the
source file to execute. On Linux:
cd ueforth
ueforth UTF8.fs
Page 24
Figure 12: executing a file when launching ueforth
Linux logs all system commands, even after shutting down the PC and restarting it. It is
therefore very easy to restart project processing with just a few presses of the up arrow
key .
In summary, provided you have a Linux version accessible from Windows WSL2 , you
edit the source files with Netbeans from Windows. And you process project files from
Linux.
If you are in a full Linux environment , the manipulations are not very different. To launch
ueforth, you will need to open a command window in Linux.
Page 25
The Linux file system
eForth Linux integrates the essential components for accessing Linux system files.
To compile the contents of a source file, here the dumpTool.fs file in the tools folder ,
edited by gedit , type:
include /tools/dumpTool.fs
The word include is an eForth dictionary word.
ls \ display :
.
..
autoexec.fs
blocks.fb
ueforth.bin
tools
ok
Here we see the tools folder . Eforth Linux does not use syntax highlighting like Linux
does. To see the contents of this tools subfolder , type:
ls tools\display:
ls tools
.
..
dumpTool.fs
There is no option to filter file names or pseudo directories.
Handling files
To completely delete a file, use the word rm followed by the name of the file to be
deleted. Here we want to delete the myTest.fs file which was created and is no longer
used:
rm myTest.fs\display:
ok
To rename a file, use the word mv . For example, we want to rename a myTest.txt file :
mv myTest.txt myTest.fs
ls\display:
.
..
autoexec.fs
blocks.fb
Page 26
myTest.fs
tools
cp myTest.fs testColors.fs
ls\display:
.
..
autoexec.fs
blocks.fb
myTest.fs
testColors.fs
tools
To see the contents of a file, use the word cat :
cat autoexec.fs
\ displays contents of autoexec.fs
To save the contents of a string to a file, save the contents of the string with dump-file :
We will not dwell on these manipulations which can also be carried out from Linux or a
source text editor.
The following explanations are given as advice only. They come from a certain experience
and aim to facilitate the development of large applications with eForth Linux.
All source files for your project are on your computer in the Linux environment. It is
advisable to have a subfolder dedicated to this project. For example, you are working on a
game named rubik, so you create a directory named rubik .
Editing files on a computer is carried out with any text file editor, gedit under Linux.
In these source files, do not use any characters not included in the ASCII code characters.
Some extended codes can disrupt program compilation.
Page 27
Let's start from our rubik directory on our computer.
The first file we will create in this directory will be the main.fs file . This file will contain
the calls to load all the other files of our application under development.
In the development phase, the contents of this main.fs file will be loaded from a
RUBIK.fs file placed in the same folder as eForth and containing this:
cd rubik
s" main.fs" included
This causes the contents of our main.fs file to be executed . Loading of other files will
be executed from this main.fs file . Here we load the config.fs file of which here is an
extract:
0 value MAX_DEPTH
3 constant CUBE_SIZE
config.fs file we will put all the constant values and various global parameters used by
the other files.
Chaining of files
Each file can call a file with the word included . Here is an example of a file hierarchy
included in this way:
Page 28
Figure 14: enchaînement de fichiers
Here, eForth calls a first file. Even if it is feasible, it is not recommended to create cascade
sequences. Prefer a succession of loading files from main.fs. Example :
DEFINED? --tempusFugit [if] forget --tempusFugit [then]
create --tempusFugit
s" strings.fs" included
s" RTClock.fs" included
s" clepsydra.fs" included
s" config.fs" included
s" dispTools.fs" included
In this succession of files, we use the strings.fs file . This is a so-called tool file . It is the
copy of a fairly general use file whose content extends the FORTH dictionary.
By working with a copy of the original file, you can make corrections or improvements
without risking altering the operation of the code in the original file. If these modifications
are consolidated, we can transfer them to the original file.
For each FORTH source code file, date the versions. This will allow you to find the
chronology of code modifications.
Conclusion
Files saved in Linux system are available permanently. If you access a Linux version in a
WSL2 management system from Windows, these files will also be accessible to the
Windows file system.
Page 29
Comments and debugging
There is no IDE4 to manage and present code written in FORTH language in a structured
way. At worst you use an ASCII text editor, at best a real IDE and text files:
edit or wordpad on Windows
This code will be perfectly compiled by eForth Linux. But will it remain understandable in
the future if it needs to be modified or reused in another application?
There is no rule. The main thing is that you can easily reread your FORTH code. However,
computer programmers in FORTH language have certain habits:
constants in uppercase characters LOTTO_NUMBERS_IN_GRID
Page 30
And what about naming FORTH words in a language other than English? Here again, only
one rule: total freedom ! Be careful though, eForth Linux does not accept names written
in alphabets other than the Latin alphabet. However, you can use these alphabets for
comments:
: .date \ Плакат сегодняшней даты
….coded… ;
Or
: .date \海報今天的日期
….coded… ;
If the code processed in a control structure is sparse, the FORTH code can be compacted:
: inGrid? { n gridPos -- fl }
0 { fl } gridPos getGridAddr
for aft
getNumber n =
if -1 to fl then
then
next
drop fl
;
Page 31
This is often the case with case of endof endcase structures ;
: socketError ( -- )
errno dup
case
2 of ." No such file " endof
5 of ." I/O error " endof
9 of ." Bad file number " endof
22 of ." Invalid argument " endof
endcase
. quit
;
Comments
Like any programming language, the FORTH language allows the addition of comments in
the source code. Adding comments has no impact on the performance of the application
after compiling the source code.
In FORTH language, we have two words to delimit comments:
the word ( must be followed by at least one space character. This comment is
completed by the character ) ;
the word \ must be followed by at least one space character. This word is followed
by a comment of any size between this word and the end of the line.
The word ( is widely used for stack comments. Examples:
dup ( n -- nn)
swap ( n1 n2 -- n2 n1)
drop ( n --)
emit ( c -- )
Stack comments
As we have just seen, they are marked by ( and ) . Their content has no effect on the
FORTH code during compilation or execution. So we can put anything between ( and ) .
As for the stack comments, we will remain very concise. The -- sign symbolizes the
action of a FORTH word. The indications before -- correspond to the data placed on the
data stack before the execution of the word. The indications after -- correspond to the
data left on the data stack after execution of the word. Examples :
words ( -- ) means that this word does not process any data on the data stack;
emit ( c -- ) means that this word processes data as input and leaves nothing
on the data stack ;
bl ( -- 32 ) means that this word does not process any input data and leaves
the decimal value 32 on the data stack;
There is no limitation on the amount of data processed before or after execution of the
word. As a reminder, the indications between ( and ) are only there for information.
Page 32
Meaning of stack parameters in comments
To begin with, a small but very important clarification is necessary. This is the size of the
data on stack. With eForth Linux, the stack data takes up 8 bytes. So these are integers in
64-bit format. So what do we put on the data stack? With eForth Linux, it will ALWAYS
be 64 BIT DATA ! An example with the c word! :
create myDelemiter
0 c,
64 myDelimiter c! ( c addr -- )
Here, the parameter c indicates that we stack an integer value in 64-bit format, but
whose value will always be included in the interval [0..255].
The standard parameter is always n . If there are several integers, we will number them:
n1 n2 n3 , etc.
But it is much less explicit than the previous version. Here are some symbols that you will
see throughout the source codes:
addr indicates a literal memory address or delivered by a variable;
Page 33
here \ leave current dictionnary pointer on stack
0 c, \ initial lenght data is 0
does>
dup 1+ swap c@
\ send a data array to SSD1306 connected via I2C bus
sendDatasToSSD1306
;
on the left, the action part when the definition word is executed, prefixed by comp:
on the right the action part of the word that will be defined, prefixed with exec:
At the risk of insisting, this is not a standard. These are only recommendations.
Textual comments
They are indicated by the word \ followed by at least one space character and
explanatory text:
\ store at <WORD> addr length of datas compiled beetween
\ <WORD> and here
: ;endStream ( addr-var len ---)
dup 1+ here
swap - \ calculate cdata length
\ store c in first byte of word defined by streamCreate:
swap c!
;
These comments can be written in any alphabet supported by your source code editor:
\ 儲存在 <WORD> addr 之間編譯的資料長度
\ <WORD> 和這裡
: ;endStream ( addr-var len ---)
dup 1+ here
swap - \ 計算 cdata 長度
\ 將 c 儲存在由 StreamCreate 定義的字的第一個位元組中:
swap c!
;
Page 34
\ Copyright: Marc PETREMANN
\ Author: Marc PETREMANN
\ GNU General Public License
\ **************************************
All this information is at your discretion. They can become very useful when you come
back to the contents of a file months or years later.
To conclude, do not hesitate to comment and indent your source files in FORTH language.
The decompiler
In a conventional compiler, the source code is transformed into executable code
containing the reference addresses to a library equipping the compiler. To have executable
code, you must link the object code. At no time can the programmer have access to the
executable code contained in his library with the resources of the compiler alone.
With eForth Linux, the developer can decompile their definitions. To decompile a word,
simply type see followed by the word to decompile:
: C>F ( øC --- øF) \ Conversion Celsius in Fahrenheit
9 5 */ 32 +
;
see c>f
\ display:
: C>F
9 5 */ 32 +
;
Memory dump
Sometimes it is desirable to be able to see the values that are in memory. The word dump
accepts two parameters: the starting address in memory and the number of bytes to
display:
create myDATAS 01 c, 02 c, 03 c, 04 c,
hex
myDATAS 4 dump \ displays :
3FFEE4EC 01 02 03 04
Page 35
Data stack monitor
The contents of the data stack can be displayed at any time using the word .s . Here is
the definition of the word .DEBUG which exploits .s :
variable debugStack
: debugOn ( -- )
-1 debugStack !
;
: debugOff ( -- )
0 debugStack !
;
: .DEBUG
debugStack @
if
cr ." STACK: " .s
key drop
then
;
To use .DEBUG, simply insert it in a strategic place in the word to be debugged:
\ example of use:
: myTEST
128 32 do
i .DEBUG
emit
loop
;
Here, we will display the contents of the data stack after execution of word i in our do
loop . We activate the focus and run myTEST :
debugOn
myTest
\ displays:
\ STACK: <1> 32
\ 2
\ STACK: <1> 33
\ 3
\ STACK: <1> 34
\ 4
\ STACK: <1> 35
\ 5
\ STACK: <1> 36
\ 6
\ STACK: <1> 37
\ 7
\ STACK: <1> 38
When debugging is enabled by debugOn , each display of the contents of the datastack
pauses our do loop. Run debugOff so that the myTEST word executes normally.
Page 36
Perform unit tests
eForth has the word assert allowing you to carry out tests. The best place to use this word
is in a tests.fs file. Example :
$1234 100div nip $34 = assert
$1234 100div drop $12 = assert
Here, we test the word 100div which leaves the quotient and the remainder of the
division by 256 (100 in hexadecimal) on the stack. The test should leave a true or false
value on the stack. If the test returns a null value, assert generates an ERROR
message.
Here is another example using assert :
$0080 bytesToUTF8 $c280 = assert
$0544 bytesToUTF8 $d584 = assert
$a894 bytesToUTF8 $eaa294 = assert
Here, we test the word bytesToUTF8. This word comes from code currently under
development. The values to test come from the online UTF8 documentation. These three
lines allow you to instantly test bytesToUTF8 with several typical cases. If the word does
not generate the expected result, assert will report that there is a test error.
The gForth code has been adapted to display the incorrect content. Here is the source
code for this version:
-1 value ASSERT_LEVEL
variable assert-start
: assert( ( -- )
tib >in @ + assert-start !
ASSERT_LEVEL 0= if
POSTPONE (
then
; immediate
: ) ( fl -- )
Page 37
0= if
cr ." ASSERT : "
assert-start @
tib >in @ + over - 1- type
-1 throw
then
; immediate
Next, we have an assert-start variable. This variable is used to store the location of
assert( in the interpretation chain processed by eForth.
The word ) tests the Boolean flag. If it is zero, it generates an error message and displays
the code after assert( which is causing the test error.
If you are on a development project, here is an example of typical file chaining in main.fs
:
s" gray.fs" included
s" assert.fs" included
s" tests.fs" included
The gray.fs file contains FORTH code currently being developed and fine-tuned. The
assert.fs file contains the assert( code. Finally, our tests.fs file contains the battery of
tests to be performed on the definitions currently being developed.
So, with a simple main.fs include sequence, the code under development is compiled,
then it is instantly tested through the unit tests written in tests.fs.
The word assert( was written to display nothing if the tests were executed successfully.
This development strategy with unit testing allows you to quickly detect code errors if you
modify a definition that is subject to unit testing.
Page 38
Dictionary / Stack / Variables / Constants
Expand Dictionary
Forth belongs to the class of woven interpretive languages. This means that it can
interpret commands typed on the console, as well as compile new subroutines and
programs.
The Forth compiler is part of the language and special words are used to create new
dictionary entries (i.e. words). The most important are : (start a new definition) and ;
(finishes the definition). Let's try this by typing :
: *+ * + ;
What happened? The action of : is to create a new dictionary entry named *+ and switch
from interpretation mode to compilation mode. In compile mode, the interpreter searches
for words and, rather than executing them, installs pointers to their code. If the text is a
number, instead of pushing it onto the stack, eFORTH Linux constructs the number in the
dictionary space allocated for the new word, following special code that puts the stored
number on the stack each time the word is executed. The execution action of *+ is
therefore to sequentially execute the previously defined words * and +.
Word ; is special. It is an immediate word and it is always executed, even if the system
is in compile mode. Which makes ; is twofold. First, it installs code that returns control to
the next external level of the interpreter, and second, it returns from compilation mode to
interpretation mode.
Now let's try this new word :
decimal 5 6 7 *+ . \ display 47 ok<#,ram>
This example illustrates two main work activities in Forth : adding a new word to the
dictionary, and trying it as soon as it has been defined.
Dictionary management
The word forget followed by the word to delete will remove all dictionary entries you
have made since that word :
: test1 ;
: test2 ;
: test3 ;
forget test2 \ delete test2 and test3 in dictionnary
Page 39
Stacks and reverse Polish notation
Forth has an explicitly visible stack that is used to pass numbers between words
(commands). Using Forth effectively forces you to think in terms of the stack. This can be
difficult at first, but as with anything, it gets much easier with practice.
In FORTH, The pile is analogous to a pile of cards with numbers written on them.
Numbers are always added to the top of the stack and removed from the top of the stack.
Eforth Linux integrates two stacks: the parameter stack and the return stack, each
consisting of a number of cells that can hold 64-bit numbers.
The FORTH input line :
decimal 2 5 73 -16
+ - *
.
Note that eForth Linux conveniently displays the stack elements when interpreting each
line and that the value of -16 is displayed as a 64-bit unsigned integer. Furthermore, the
Page 40
word . consumes data value -104, leaving the stack empty. If we execute . on the now
empty stack, the external interpreter aborts with a stack pointer error STACK UNDERFLOW
ERROR.
The programming notation where the operands appear first, followed by the operator(s) is
called Reverse Polish Notation (RPN).
-16 73 5 2 2
73 5 73 5 2
5 2 2 73 5
2 73
presented below.
Page 41
To store on the return stack, use >r to move the top of the parameter stack to the top of
the return stack. To retrieve a value, r> moves the top value from the return stack back to
the top of the parameter stack. To simply remove a value from the top of the return stack,
there is the word rdrop. The word r@ copies the top of the return stack back into the
parameter stack.
Memory usage
In eForth Linux, 64-bit numbers are fetched from memory to the stack by the word @
(fetch) and stored from the top to memory by the word ! (store). @ expects an address on
the stack and replaces the address with its contents. ! expects a number and an address
to store it. It places the number in the memory location referenced by the address,
consuming both parameters in the process.
Unsigned numbers that represent 8-bit (byte) values can be placed in character-sized
characters. memory cells using c@ and c!.
create testVar
cell allot
$f7 testVar c!
testVar c@ . \ display 247
Variables
A variable is a named location in memory that can store a number, such as the
intermediate result of a calculation, off the stack. For example :
variable x
creates a storage location named x, which executes leaving the address of its storage
location at the top of the stack :
x . \ display address
Constants
A constant is a number that you would not want to change while a program is running.
The result of executing the word associated with a constant is the value of the data
remaining on the stack.
\ define VSPI pins
19 constant VSPI_MISO
23 constant VSPI_MOSI
18 constant VSPI_SCLK
Page 42
05 constant VSPI_CS
Pseudo-constant values
A value defined with value is a hybrid type of variable and constant. We set and
initialize a value and it is invoked as we would a constant. We can also change a value like
we can change a variable.
decimal
13 value thirteen
thirteen . \ display: 13
47 to thirteen
thirteen . \ display: 47
The word to also works in word definitions, replacing the value following it with whatever
is currently at the top of the stack. You need to be careful that to is followed by a value
defined by value and not something else.
When executed, the word graphic-array stacks the address of the first entry.
Page 43
We can now access the memory allocated to graphic-array using the fetch and store
words explained earlier. To calculate the address of the third byte assigned to graphic-
array we can write graphic-array 2 +, remembering that the indices start at 0.
30 graphic-array 2 + c!
graphic-array 2 + c@ . \ display 30
Page 44
Local variables with eForth Linux
Introduction
The FORTH language processes data primarily through the data stack. This very simple
mechanism offers unrivaled performance. Conversely, following the flow of data can
quickly become complex. Local variables offer an interesting alternative.
Here, the comment ( u1 u2 -- sum carry ) has absolutely no action on the rest of the
FORTH code. This is pure commentary.
When preparing a complex definition, the solution is to use local variables framed by {
and } . Example :
: 2OVER { a b c d }
a b c d a b
;
The words { and } are similar to the words ( and ) but do not have the same effect at all.
Codes placed between { and } are local variables. The only constraint: do not use variable
names that could be FORTH words from the FORTH dictionary. We might as well have
written our example like this :
: 2OVER { varA varB varC varD }
varA varB varC varD varA varB
;
Each variable will take the value of the data stack in the order of their deposit on the data
stack. here, 1 goes into varA, 2 into varB, etc.:
--> 1 2 3 4
ok
1 2 3 4 --> 2over
ok
1 2 3 4 1 2 -->
Page 45
Our fake stack comment can be completed like this :
: 2OVER { varA varB varC varD -- varA varB varC varD varA varB }
The characters following -- have no effect. The only point is to make our fake comment
look like a real stack comment.
We assign a value to a local variable with the word to or +to to increment the content of
a local variable. In this example, we add a local variable result initialized to zero in the
code of our word:
: a+bEXP2 { varA varB -- (a+b)EXP2 }
0 { result }
varA varA * to result
varB varB * +to result
varA varB * 2 * +to result
result
;
Here is a final example, the definition of the word um+ which adds two unsigned integers
and leaves the sum and the overflow value of this sum on the data stack:
\ add two unsigned integers, leaves sum and carry on the stack
: um+ { u1 u2 -- sum carry }
0 { sum }
Page 46
cell for
aft
u1 $100 /mod to u1
u2 $100 /mod to u2
+
cell 1- i - 8 * lshift +to sum
then
next
sum
u1 u2 + abs
;
Page 47
else emit
then
loop
loop
myBASE base ! \ restore current base
cr cr
;
forth
The use of local variables greatly simplifies data manipulation on stacks. The code is more
readable. Note that it is not necessary to pre-declare these local variables, it is enough to
designate them when using them, for example: base @ { myBASE }.
WARNING: if you use local variables in a definition, no longer use the words >r and r>,
otherwise you risk disrupting the management of local variables. Just look at the
decompilation of this version of DUMP to understand the reason for this warning:
: dump cr cr s" --addr--- " type
s" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ------chars-----" type
2dup + >R SWAP >R -4 local@ 16 / 16 * >R 16 / 1+ >R base @ >R
hex -8 local@ 0 (do) -20 local@ R@ 16 * + cr
<# # # # # 45 hold # # # # #> type space space
16 0 (do) -28 local@ j 16 * R@ + + CA@ <# # # #> type space 1 (+loop)
0BRANCH rdrop rdrop space 16 0 (do) -28 local@ j 16 * R@ + + CA@ DUP 32 < OVER 127 > OR
0BRANCH DROP 46 emit BRANCH emit 1 (+loop) 0BRANCH rdrop rdrop 1 (+loop)
0BRANCH rdrop rdrop -4 local@ base ! cr cr rdrop rdrop rdrop rdrop rdrop ;
Page 48
Data structures for eForth Linux
Preamble
Eforth Linux is a 64-bit version of the FORTH language. Those who have practiced FORTH
since its beginnings have programmed with 16-bit versions. This data size is determined
by the size of the elements deposited on the data stack. To find out the size in bytes of
the elements, you must execute the word cell. Running this word for ESP32forth :
cell . \ display 8
The value 8 means that the size of the elements placed on the data stack is 8 bytes, or
8x8 bits = 64 bits.
With a 16-bit FORTH version, cell will stack the value 2. Likewise, if you use a 32-bit
version, cell will stack the value 4.
Tables in FORTH
Let's start with fairly simple structures : tables. We will only discuss one- or two-
dimensional arrays.
We can factor the access code to the desired value by defining a word which will calculate
this address :
: temp@ ( index -- value )
cell * temperatures + @
;
0 temp@ . \ display 34
2 temp@ . \ display 42
Page 49
You will notice that for n values stored in this table, here 6 values, the access index must
always be in the interval [0..n-1].
In our example, we store 6 values between 0 and 255. It is easy to create a variant of
array to manage our data in a more compact way :
: arrayC ( comp: -- | exec: index -- addr )
create
does>
+
;
arrayC myCTemps
21 c, 32 c, 45 c, 44 c, 28 c, 12 c,
0 myCTemps c@ . \ display 21
5 myCTemps c@ . \ display 12
With this variant, the same values are stored in four times less memory space.
In our example, the array contains 6 elements. With eForth Linux, there is enough
memory space to process much larger arrays, with 1,000 or 10,000 elements for example.
It's easy to create multi-dimensional tables. Example of a two-dimensional array :
63 constant SCR_WIDTH
16 constant SCR_HEIGHT
create mySCREEN
SCR_WIDTH SCR_HEIGHT * allot \ allocate 63 * 16 bytes
Page 50
mySCREEN SCR_WIDTH SCR_HEIGHT * bl fill \ fill this memory with 'space'
Here, we define a two-dimensional table named mySCREEN which will be a virtual screen of
16 rows and 63 columns.
Simply reserve a memory space which is the product of the dimensions X and Y of the
table to use.
Here, we define the YMDHMS structure. This structure manages the >year >month >day
>hour >min and >sec pointers.
The sole purpose of the YMDHMS word is to initialize and group the pointers in the complex
structure. Here is how these pointers are used :
create DateTime
YMDHMS allot
Page 51
DateTime .date
We defined word DateTime as simple table of 6 consecutive cells each 32 bits. Access to each
cell is with specific pointer. We can redefine our structure YMDHMS with i8 pointers to bytes.
structures
struct cYMDHMS
ptr field >year
i8 field >month
i8 field >day
i8 field >hour
i8 field >min
i8 field >sec
create cDateTime
cYMDHMS allot
: .cDate ( date -- )
>r
." YEAR: " r@ >year @ . cr
." MONTH: " r@ >month c@ . cr
." DAY: " r@ >day c@ . cr
." HH: " r@ >hour c@ . cr
." MM: " r@ >min c@ . cr
." SS: " r@ >sec c@ . cr
r> drop
;
cDateTime .cDate \ displays:
\ YEAR: 2022
\ MONTH: 3
\ DAY: 21
\ HH: 22
\ MM: 36
\ SS: 15
In this cYMDHMS structure, we kept the year in 32-bit format and reduced all other values
to 8-bit integers. We see, in the .cDate code, that the use of pointers allows easy access
to each element of our complex structure.…
Page 52
Real numbers with eForth Linux
If we test the operation 1 3 / in FORTH language, the result will be 0.
It's not surprising. Basically, eForth Linux only uses 64-bit integers via the data stack.
Integers offer certain advantages:
speed of processing;
impossible results for simple division calculations, like our 1/3 example;
pi f. \ display 3.141592
4 set-precision
pi f. \ display 3.1415
The limit precision for processing real numbers with eForth Linux is six decimal places :
Page 53
12 set-precision
1.987654321e f. \ display 1.987654668777
If we reduce the display precision of real numbers below 6, the calculations will still be
carried out with a precision to 6 decimal places.
fvariable intensity
170e 12e F/ intensity SF! \ I=P/U --- P=170w U=12V
intensity SF@ f. \ display 14.166669
ATTENTION: all real numbers pass through the real number stack . In the case of a real
variable, only the address pointing to the real value passes through the data stack.
The word SF! stores a real value at the address or variable pointed to by its memory
address. Executing a real variable places the memory address on the classic data stack.
The word SF@ stacks the real value pointed to by its memory address.
Page 54
FCOS (r1 -- r2) Calculates the cosine of an angle expressed in radians.
FSINCOS (r1 -- rcos rsin) calculates the cosine and sine of an angle expressed in
radians.
Some examples :
2e 3e f** f. \ display 8.000000
2e 4e f** f. \ display 16.000000
10e 1.5e f** f. \ display 31.622776
pi 4e f/
FSINCOS f. f. \ display 0.707106 0.707106
pi 2e f/
FSINCOS f. f. \ display 0.000000 1.000000
Page 55
35 S>F
F. \ display 35.000000
Page 56
Displaying numbers and character strings
Change of numerical base
FORTH does not process just any numbers. The ones you used when trying the previous
examples are single-precision signed integers. These numbers can be processed in any
number base, with all number bases between 2 and 36 being valid :
255 HEX. DECIMAL \displays FF
You can choose an even larger numerical base, but the available symbols will fall outside
the alpha-numeric set [0..9,A..Z] and risk becoming inconsistent.
The current numerical base is controlled by a variable named BASE and whose content
can be modified. So, to switch to binary, simply store the value 2 in BASE . Example:
2 BASE !
and type DECIMAL to return to the decimal numeric base.
ESP32forth has two pre-defined words allowing you to select different numerical bases:
DECIMAL to select the decimal numeric base. This is the numerical base taken by
default when starting ESP32forth;
HEX to select the hexadecimal numeric base.
Page 57
VARIABLE RANGE_BASE \ RANGE-BASE variable definition
BASE @ RANGE_BASE ! \ storage BASE contents in RANGE-BASE
HEX FF 10 + . \ displays 10F
RANGE_BASE @ BASE ! \ restores BASE with contents of RANGE-BASE
In a definition : , the contents of BASE can pass through the return stack :
: OPERATION ( ---)
BASE @ >R \ stores BASE on back stack
HEX FF 10 + . \ operation of the previous example
R> BASE ! ; \ restores initial BASE value
WARNING : the words >R and R> cannot be used in interpreted mode. You can only use
these words in a definition that will be compiled.
#S is equivalent to a succession of # ;
#> completes a format definition and leaves on the stack the address and length of
the string containing the number to display.
These words can only be used within a definition. Example, either to display a number
expressing an amount denominated in euros with the comma as a decimal separator :
: .EUROS ( n ---)
<# # # [char] , hold #S #>
type space ." EUR" ;
1245 .euros
Execution examples:
Page 58
At runtime, a display format sequence deals exclusively with signed or unsigned 32-bit
integers. The concatenation of the different elements of the string is done from right to
left, i.e. starting with the least significant digits.
Here is a more complex example demonstrating the compactness of FORTH. This involves
writing a program converting any number of seconds into HH:MM:SS format:
:00 ( ---)
DECIMAL # \ insert digit unit in decimal
6 BASE ! \ base 6 selection
# \ insert digit ten
[char] : HOLD \ insertion character :
DECIMAL ; \ return decimal base
: HMS ( n ---) \ displays number seconds format HH:MM:SS
<# :00 :00 #S #> TYPE SPACE ;
Execution examples :
Another example, to define a program converting a single precision decimal integer into
binary and displaying it in the format bbbb bbbb bbbb bbbb:
: FOUR-DIGITS ( ---)
# # # # 32 HOLD ;
: AFB ( n ---) \ format 4 digits and a space
BASE @ >R \ Current database backup
2 BASE ! \ Binary digital base selection
<#
4 0 DO \ Format Loop
FOUR-DIGITS
LOOP
#> TYPE SPACE \ Binary display
R> BASE ! ; \ Initial digital base restoration
Execution example :
Page 59
DECIMAL 12 AFB \ displays 0000 0000 0000 0110
HEX 3FC5 AFB \ displays 0011 1111 1100 0101
Another example is to create a telephone diary where one or more telephone numbers are
associated with a surname. We define a word by surname :
: .## ( ---)
# # [char] . HOLD ;
: .TEL ( d ---)
CR <# .## .## .## .## # # #> TYPE CR ;
: WACHOWSKI ( ---)
0618051254 .TEL ;
WACHOWSKI \ displays: 06.18.05.12.54
This calendar, which can be compiled from a source file, is easily editable, and although
the names are not classified, the search is extremely fast.
65 EMIT \ displays A
The displayable characters are in the range 32..255. Codes between 0 and 31 will also be
displayed, subject to certain characters being executed as control codes. Here is a
definition showing the entire character set of the ASCII table:
variable #out
: #out+! ( n -- )
#out +! \ increment #out
;
: (.) ( n -- a l )
DUP ABS <# #S ROT SIGN #>
;
: .R ( n l -- )
>R (.) R> OVER - SPACES TYPE
;
: ASCII-SET ( ---)
cr 0 #out !
128 32
DO
I 3 .R SPACE \ displays character code
4 #out+!
I EMIT 2 SPACES \ displays character
3 #out+!
#out @ 77 =
IF
CR 0 #out !
THEN
Page 60
LOOP ;
Running ASCII-SET displays the ASCII codes and characters whose code is between 32
and 127. To display the equivalent table with the ASCII codes in hexadecimal, type HEX
ASCII-SET:
hex ASCII-SET
20 21 ! 22 " 23 # 24 $ 25 % 26 & 27 ' 28 ( 29 ) 2A *
2B + 2C , 2D - 2E . 2F / 30 0 31 1 32 2 33 3 34 4 35 5
36 6 37 7 38 8 39 9 3A : 3B ; 3C < 3D = 3E > 3F ? 40 @
41 A 42 B 43 C 44 D 45 E 46 F 47 G 48 H 49 I 4A J 4B K
4C L 4D M 4E N 4F O 50 P 51 Q 52 R 53 S 54 T 55 U 56 V
57 W 58 X 59 Y 5A Z 5B [ 5C \ 5D ] 5E ^ 5F _ 60 ` 61 a
62 b 63 c 64 d 65 e 66 f 67 g 68 h 69 i 6A j 6B k 6C l
6D m 6E n 6F o 70 p 71 q 72 r 73 s 74 t 75 u 76 v 77 w
78 x 79 y 7A z 7B { 7C | 7D } 7E ~ 7F ok
Character strings are displayed in various ways. The first, usable in compilation only,
displays a character string delimited by the character " (quote mark):
A character string can also be compiled by the word s" and delimited by the character "
(quotation mark):
Page 61
String variables
Alpha-numeric text variables do not exist natively in ESP32forth. Here is the first attempt
to define the word string :
\ define a strvar
: string ( comp: n --- names_strvar | exec: --- addr len )
create
dup
c, \ n is maxlength
0 c, \ 0 is real length
allot
does>
2 +
dup 1 - c@
;
A character string variable is defined like this:
16 string strState
Here is how the memory space reserved for this text variable is organized:
\ define a strvar
: string ( n --- names_strvar )
create
dup
, \ n is maxlength
0 , \ 0 is real length
allot
does>
cell+ cell+
Page 62
dup cell - @
;
\ Example:
\ : s1
\ s" this is constant string" ;
\ 200 string test
\ s1 test $!
Page 63
\ work only with strings. Don't use with other arrays
: input$ ( addr len -- )
over swap maxlen$ nip accept
swap cell - !
;
Creating an alphanumeric character string is very simple :
64 string myNewString
Here we create an alphanumeric variable myNewString which can contain up to 64
characters.
s" This is a very long string, with more than 64 characters. It can't store
complete"
myNewString $!
myNewString type
\ displays: This is a very long string, with more than 64 characters. It
can
32 string AT_BAND
s" AT+BAND=868500000" AT_BAND $! \ set frequency at 865.5 Mhz
$0a AT_BAND c+$!
$0d AT_BAND c+$! \ add CR LF code at end of command
The memory dump of the contents of our alphanumeric variable AT_BAND confirms the
presence of the two control characters at the end of the string:
Page 64
2 string $crlf
$0d $crlf c+$!
$0a $crlf c+$!
Page 65
Delayed action words
Deferred action words are defined by the definition word defer. To understand the
mechanisms and the interest in exploiting this type of word, let's look in more detail at the
functioning of the internal interpreter of the FORTH language.
Any definition compiled by : (colon) contains a sequence of coded addresses
corresponding to the code fields of the words previously compiled. At the heart of the
FORTH system, the word EXECUTE accepts as parameters these code field addresses,
addresses which we abbreviate by cfa for Code Field Address. Every FORTH word has a
cfa and this address is used by the internal FORTH interpreter :
' <word>
\ drops the cfa of <word> onto the data stack
Example:
' WORDS
\ stacks the WORDS cfa.
From this cfa , known as the only literal value, the execution of the word can be carried
out with EXECUTE:
' WORDS EXECUTE
\ executes WORDS
Of course, it would have been easier to type WORDS directly . From the moment a cfa is
available as the only literal value, it can be manipulated and notably stored in a variable :
variable vector
' WORDS vector !
vector @ .
\ displays cfa of WORDS stored in vector variable
This is a similar mechanism that is exploited by the execution part of the defer definition
word. To simplify, defer creates a header in the dictionary, like a variable or
constant, but instead of simply dropping an address or value on the stack, it starts
execution of the word whose cfa was stored in the parametric area of the word defined
by defer .
Page 66
defer vector
' words is vector
Executing vector causes the word whose cfa was previously assigned to be executed:
vector \ exécute words
A word created by defer is used to execute another word without explicitly calling on
that word. The main interest of this type of word lies above all in the possibility of
modifying the word to be executed:
' page is vector
vector now executes page and no longer words.
This time word2 compiled without errors. It is not necessary to assign a cfa to the
vectorized execution word word2 . It is only after the definition of (word2) that the
parameter area of word2 is updated. After assignment of the vectorized execution word
word2 , word1 will be able to execute the content of its definition without error. The
exploitation of words created by defer in this situation must remain exceptional.
Page 67
A practical case
You have an application to create, with displays in two languages. Here is a clever way by
exploiting a word defined by defer to generate text in French or English. To begin, we will
simply create a table of days in English:
:noname s" Saterday" ;
:noname s" Friday" ;
:noname s" Thursday" ;
:noname s" Wednesday" ;
:noname s" Tuesday" ;
:noname s" Monday" ;
:noname s" Sunday" ;
: in-ENGLISH
['] ENdayNames is dayNames ;
: in-FRENCH
['] FRdayNames is dayNames ;
Here are now the words to manage these two tables:
: _getString { array length -- addr len }
array
swap cell *
+ @ execute
length ?dup if
min
then
;
10 value dayLength
: getDay ( n -- addr len ) \ n interval [0..6]
Page 68
dayNames dayLength _getString
;
Here's what running getDay does :
: .dayList { size -- }
size to dayLength
7 0 do
i getDay type space
loop
;
in-ENGLISH 3 .dayList cr \ display : Sun Mon Tue Wed Thu Fri Sat
in-FRENCH 1 .dayList cr \ display : D L M M J V S
In the second line, we only display the first letter of each day of the week.
In this example, we leverage defer to simplify programming. In web development, we
would use templates to manage multilingual sites. In FORTH, we simply move a vector in
a delayed action word. Here we only manage two languages. This mechanism can easily
be extended to other languages, because we have separated the management of text
messages from the purely application part.
Page 69
Word Creation Words
FORTH is more than a programming language. It's a meta-language. A meta-language is a
language used to describe, specify or manipulate other languages.
With eForth Linux, we can define the syntax and semantics of programming words beyond
the formal framework of basic definitions.
We have already seen the words defined by constant , variable , value . These
words are used to manage digital data.
In the Data Structures for eForth Linux chapter, we also used the word create. This word
creates a header allowing access to a data area stored in memory. Example :
create temperatures
34, 37, 42, 36, 25, 12,
Here, each value is stored in the parameters area of the word temperatures with the
word ,.
With eForth Linux, we will see how to customize the execution of words defined by
create.
Using does>
However, there is a combination of "CREATE" and "DOES>" keywords, which are often used
together to create custom words (vocabulary words) with specific behaviors.
Here's how it generally works in Forth:
CREATE : this keyword is used to create a new data space in the eForth Linux
dictionary. It takes one argument, which is the name you give your new word;
DOES> : this keyword is used to define the behavior of the word you just created
with CREATE . It is followed by a block of code that specifies what the word should
do when encountered during program execution.
Together it looks something like this:
forth
CREATE my-new-word
\ code to execute when encountering my-new-word
DOES>
;
When the word my-new-word is encountered in the FORTH program, the code specified
in the does>... ; will be executed.
\ define a register, similar as constant
: defREG:
create ( addr1 -- <name> )
Page 70
,
does> ( -- regAddr )
@
;
Here, we define the definition word defREG: which has exactly the same action as
constant . But why create a word that recreates the action of a word that already exists?
$3FF44004 constant DB2INSTANCE
or
$3FF44004 defREG: DB2INSTANCE
are similar. However, by creating our registers with defREG: we have the following
advantages:
a more readable eForth Linux source code. We easily detect all the constants
naming an ESP32 register;
we leave ourselves the possibility of modifying the does> part of defREG:
without then having to rewrite the lines of code which would not use defREG:
Here is a classic case, processing a data table:
\ definition word for one dimension arrays
:array (comp: -- <name> | exec: index <name> -- addr)
create
does>
swap cell * +
;
array temperatures
21 , 32 , 45 , 44 , 28 , 12 ,
0 temperatures @ . \ display 21
5 temperatures @ . \ display 12
The execution of temperatures must be preceded by the position of the value to extract
in this table. Here we only get the address containing the value to extract.
Page 71
$00 color: setBLACK
$ff color: setWHITE
Running the word setBLACK or setWHITE greatly simplifies the eForth Linux code.
Without this mechanism, one of these lines would have had to be repeated regularly :
$00 currentCOLOR !
Or
$00 constant BLACK
BLACK currentCOLOR !
To find the UTF8 code of a Chinese character, copy the Chinese character, from Google
Translate for example. Example :
Good Morning --> 早安 (Zao an)
Copy 早 and go to PuTTy terminal and type :
key key key \ followed by key <enter>
paste the character 早. eForth Linux should display the following codes:
230 151 169
Page 72
For each Chinese character, we will use these three codes as follows:
169 151 230 chinese: Zao
137 174 229 chinese: Year
Use :
Zao An \ display 早安
Admit that programming like this is something other than what you can do in C language.
No?
Page 73
Processing UTF8 characters
It was while carrying out some character entry tests on the keyboard that a small problem
appeared. If we do this:
key \ and press a key, push 97 on stack
So far everything is normal. But on the keyboard, we also have, in France on AZERTY
keyboard, accented characters and certain characters like € . Let's try key again and try
to recover the code for this character:
key
€
ok
226 --> ��
ERROR: �� NOT FOUND!
The first code retrieved has the value 226. but there are two other codes which disrupt
the FORTH interpreter. Let's see this solution:
key key key
€
ok
226 130 172
Oh…?!?!? Three codes?
UTF8 encoding
Let's take the three codes 226 130 172 in hexadecimal: E2 82 AC . If we do this:
$e2 emit
eForth Linux has some problems displaying characters with an ASCII code greater than
127. If we repeat this test with eForth Windows, the same word dispChars displays this:
!"#$%&'()*+,-./0123456789:;<=>?
@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~Çüéâäàåçêëèï
Page 74
îìÄÅÉæÆôöòûùÿÖÜø£Ø×ƒáíó úñѪº¿®¬½¼¡«»░▒▓ │┤ÁÂÀ©╣║╗╝¢
¥┐└┴┬├─┼ãÃ╚╔╩╦╠═╬¤ðÐÊËÈıÍÎÏ┘┌█▄¦Ì▀ÓßÔÒõ ÕµþÞÚÛÙýݯ´ ±‗¾¶§÷¸°¨·¹³²■ ok
For characters whose ASCII code is in the range [32..127], the characters are identical.
For characters with an ASCII code greater than 127 (7F in hexadecimal), eForth Linux
cannot display valid characters.
To display the € character in eForth Linux, we have simple solutions:
: .eur ( -- )
." €" ;
Or
: .€ ( -- )
." €" ;
Or
: .eur ( -- )
226 emit 130 emit 172 emit ;
But we do not resolve the problem of characters whose ASCII code is greater than 127. To
resolve this problem, we must look at UTF8 encoding, the one used by eForth Linux.
For all codes greater than $7F, the first most significant bits determine the number of
bytes encoding a UTF8 character. Let's return to our character € . The first code that
comes up when executing key is $E2. In binary: 111 00010 . Here we have three bits at
1. This means that the € character is coded on 3 bytes.
Let's test with the UTF8 character 𭫷 . An execution of key brings up code 240, in binary:
1111 0000 . We have 4 bits at 1. The character 𭫷 is coded over four bytes.
if the code is greater than 127, we slide this code 1 bit to the left, then we test bit
b7. If this bit is 1 we re-execute key .
Page 75
Here is the code capable of entering any UTF8 character:
0 value keyUTF8
: toKeyUTF8 ( c -- )
keyUTF8 8 lshift or to keyUTF8
;
The word toKeyUTF8 receives an 8-bit keyboard code and concatenates it with the
contents of the keyUTF8 value . The idea is to recover the UTF8 encoding into a single
final numeric value.
\ execute key recursively
: getKeys ( n -- )
1 lshift dup $80 and \ test if bit b7 is not null
if recurse \ re-execute xkey
else drop then \ otherwise, drop n
key toKeyUTF8 \ and execute key 1 or may times
;
The word getkeys processes the code returned by the first execution of key . It
performs a one-byte shift to the left and tests bit b7 (sequence 1 lshift dup $80 and
). If this bit is 1, the word is re-executed ( if recurse sequence ).
Recursion allows you to control the number of iterations of getKeys without requiring
complex loops and tests. The recursion stops as soon as a bit b7 is 0. The recursion exit
takes place after then . The word getKeys will execute the sequence key toKeyUTF8
as many times as there are recursive calls.
\ key version for UTF8 characters
: ukey
key to keyUTF8
keyUTF8 $7F > if \ if 1st key code > $7F
keyUTF8 1 lshift getKeys \ execute xkey
then
keyUTF8
;
The word ukey can now replace the word key to retrieve the UTF8 code of any character
in the UTF8 character set:
hex
ukey . \ paste € and <enter>, display : E282AC
Page 76
;
RP@ 1 type code sequence strictly limits the display of a single-byte code character. This
hex E282AC emit sequence will not work. Likewise :
: uemit
>R RP@ 4 type rdrop
;
\ hex e282ac uemit display : ��� ok
The problem comes from the order of the bytes of a digital value. A memory dump of the
stack gives this:
--addr--- 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ------chars-----
0802-00FA 00 00 00 00 00 00 AC 82 E2 00 00 00 00 00 08 01 ......���......
In conclusion, with ukey and uemit , we now have words allowing us to process non-
ASCII characters. So, with a Greek keyboard:
hex
ukey \ press key Σ display : CEA3
uemit \ display Σ
Page 77
point.
Example: U+00E9 for the character e .
The problem, as you have already understood, is that you cannot do hex e9 emit with
eForth Linux.
To have the correct UTF8 encoding sequence b1-b0 (for byte1 byte0), you must switch
the two most significant bits of byte e9 to b1. We cut e9 like this:
hex
e9 40 /mod
Which leaves us on the stack of data r and q resulting from the execution of /mod , or in
our example the values 29 and 3 . To transform this into a two-byte value, we then
execute:
100 * +
Which now leaves us on the data stack with the hexadecimal value 329 .
Which leaves us with the final c3a9 code , which is now usable with uemit :
c3a9 uemit \ display char : é
Re-encoding by recursion
In the sequence n 40 /mod , we recover at each iteration a remainder and a quotient.
When an iteration gives a zero quotient, we stop. This lends itself wonderfully to
processing by recursion:
$40 constant BYTE_DIVISOR
Page 78
;
The word mod40Recombine splits the value n into rq pairs . If q is equal to 0, we exit
the recursion after then and we execute $100 * + as many times as was cut.
It remains to apply a mask based on the size of the re-encoded code point. Here are the
limit values for two, three, or four byte encodings:
$8000 constant LIMIT_2_BYTES
$10000 constant LIMIT_3_BYTES
$200000 constant LIMIT_4_bytes
For each of these limit values, here are the masks to apply:
$C080 constant MASK_2_BYTES
$E08080 constant MASK_3_BYTES
$F0808080 constant MASK_4_BYTES
And finally, here is the word bytesToUTF8 which applies the madque adapted to the size
of the code point number:
: bytesToUTF8 ( n -- n' )
>r
r@ LIMIT_2_BYTES < if
r> mod40Recombine
MASK_2_BYTES OR
exit
then
r@ LIMIT_3_BYTES < if
r> mod40Recombine
MASK_3_BYTES OR
exit
then
r@ LIMIT_4_BYTES < if
r> mod40Recombine
MASK_4_BYTES OR
exit
then
abort" UTF8 conversion failed"
;
There are certainly ways to make it more elegant. This definition has the merit of working.
As input, we stack the code point to be re-encoded. As output, we obtain the UTF8 code
usable by uemit .
Page 79
\ CR only if i MOD = 0
: cr? ( i -- )
1+ LINE_LIMIT mod
0= if
cr
then
;
The word cr? executes a newline if the display reaches n columns. The word .######
displays a 6-digit n value. Finally here is the display loop:
: utf8Set { start stop -- }
base @ { currentBase }
hex
stop 1+ start do
i .######
space
i bytesToUTF8 uemit
2 spaces
i cr?
loop
currentBase base !
;
Here is the definition to display the UTF8 character table of the Greek and Coptic
character set:
: greekAndCopt ( -- )
$370 $3ff utf8Set
;
Page 80
Figure 15: table of Greek and Coptic characters
The numbers indicate the code point of each character. Here, we see for example that the
character φ has the code point 3D5.
In conclusion, what is it for?
First, it helps to understand UTF8 encoding.
Then, we can take inspiration from part of this code to count the number of characters.
Example :
s" nb: φ"
\ display :
134495848 6
Page 81
Detailed content of eForth Linux vocabularies
Eforth Linux provides numerous vocabularies:
FORTH is the main vocabulary;
certain vocabularies are used for internal mechanics for eForth Linux, such as
internals , asm…
Here you will find the list of all the words defined in these different vocabularies. Some
words are presented with a colored link:
is an ordinary FORTH word;
is definition word;
marks a control structure;
is a deferred execution word;
is a word defined by constant , variable or value ;
marks a vocabulary.
FORTH vocabulary words are displayed in alphabetical order. For other vocabularies, the
words are presented in their display order.
Version v 7.0.7.15
FORTH
- -rot , ; : :noname !
? ?do ?dup . ." .s '
(local) [ ['] [char] [ELSE] [IF] [THEN]
] { }transfer @ * */ */MOD
/ /mod # #! #> #fs #s
#tib + +! +loop +to < <#
<= <> = > >= >BODY >flags
>flags& >in >link >link& >name >params >R
>size 0< 0<> 0= 1- 1/F 1+
2! 2@ 2* 2/ 2drop 2dup 4*
4/ abort abort" abs accept afliteral aft
again ahead align aligned allocate allot also
AND ansi argc argv ARSHIFT asm assert
at-xy base begin bg BIN binary bl
blank block block-fid block-id buffer bye c,
C! C@ CASE cat catch cd CELL
Page 82
cell/ cell+ cells char CLOSE-DIR CLOSE-FILE cmove
cmove> CONSTANT context copy cp cr CREATE
CREATE-FILE current decimal default-key default-type default-use
defer DEFINED? definitions DELETE-FILE depth DLSYM do
DOES> DROP dump dump-file DUP echo editor
else emit empty-buffers ENDCASE ENDOF erase
evaluate EXECUTE EXIT extract F- f. f.s
F* F** F/ F+ F< F<= F<>
F= F> F>= F>S F0< F0= FABS
FATAN2 fconstant FCOS fdepth FDROP FDUP FEXP
fg file-exists? FILE-POSITION FILE-SIZE fill
FIND fliteral FLN FLOOR flush FLUSH-FILE FMAX
FMIN FNEGATE FNIP for forget form FORTH
forth-builtins FOVER FP! FP@ fp0 free
FROT FSIN FSINCOS FSQRT FSWAP fvariable graphics
handler here hex hld hold httpd I
if IMMEDIATE include included included? internals invert
is J K key key? L! latestxt
leave list literal load loop ls LSHIFT
max min mkdir mod ms ms-ticks mv
n. needs negate nest-depth next nip nl
NON-BLOCK normal octal OF ok only open-blocks
OPEN-DIR OPEN-FILE OR order OVER pad page
PARSE pause PI posix postpone precision previous
prompt pwd quit r" R@ R/O R/W
R> r| r~ rdrop READ-DIR READ-FILE recurse
refill remaining remember RENAME-FILE repeat REPOSITION-FILE
required reset resize RESIZE-FILE restore revive rm
rmdir rot RP! RP@ rp0 RSHIFT s"
S>F s>z save save-buffers scr sealed
see set-precision set-title sf, SF! SF@
SFLOAT SFLOAT+ SFLOATS sign SL@ sockets SP!
SP@ sp0 space spaces start-task startswith? startup:
state str str= streams structures SW@ SWAP
task tasks telnetd terminate termios then throw
thru tib to touch transfer transfer{ type
u. U/MOD UL@ UNLOOP until update use
used UW@ value VARIABLE visual vlist vocabulary
W! W/O web-interface while words WRITE-FILE
x11 XOR z" z>s
ansi
terminal-restore terminal-save show hide scroll-up scroll-down clear-to-eol
bel esc
asm
end-code code, code4, code3, code2, code1, callot chere reserve code-at
code-start
Page 83
editor
a r d e wipe p n l
graphics
poll wait flip window window heart vertical-flip viewport scale translate
}g g{ screen>g box color pressed? pixel height width event last-char last-key
mouse-y mouse-x RIGHT-BUTTON MIDDLE-BUTTON LEFT-BUTTON FINISHED TYPED RELEASED
PRESSED MOTION EXPOSED RESIZED IDLE internals
graphics/internals
update-event pending-key? update-key update-mouse image-resize EVENT-MASK
keybuffer-used keybuffer keybuffer-size xevent xevent-type image gc window-handle
root-window white black screen-depth xvisual colormap screen display raw-heart
heart-ratio heart-initialize cmax! cmin! heart-end heart-start heart-size
heart-steps heart-f raw-box g> >g gp gstack hline ty tx sy sx key-state!
key-state key-count backbuffer
httpd
notfound-response bad-response ok-response response send path method hasHeader
handleClient read-headers completed? body content-length header crnl= eat
skipover skipto in@<> end< goal# goal strcase= upper server client-cr client-emit
client-read client-type client-len client httpd-port clientfd sockfd body-read
body-1st-read body-chunk body-chunk-size chunk-filled chunk chunk-size
max-connections
internals
errno CALLCODE CALL0 CALL1 CALL2 CALL3 CALL4 CALL5 CALL6 CALL7 CALL8 CALL9
CALL10 CALL11 CALL12 CALL13 CALL14 CALL15 DOFLIT S>FLOAT? fill32 'heap
'context 'latestxt 'notfound 'heap-start 'heap-size 'stack-cells 'boot
'boot-size 'tib 'argc 'argv 'runner 'throw-handler NOP BRANCH 0BRANCH DONEXT
DOLIT DOSET DOCOL DOCON DOVAR DOCREATE DODOES ALITERAL LONG-SIZE S>NUMBER?
'SYS YIELD EVALUATE1 'builtins internals-builtins autoexec boot-set-title
e' @line grow-blocks use?! common-default-use block-data block-dirty clobber
clobber-line include+ path-join included-files raw-included include-file
sourcedirname sourcefilename! sourcefilename sourcefilename# sourcefilename&
starts../ starts./ dirname ends/ default-remember-filename remember-filename
restore-name save-name forth-wordlist setup-saving-base 'cold park-forth
park-heap saving-base crtype cremit cases (+to) (to) --? }? ?room scope-create
do-local scope-clear scope-exit local-op scope-depth local+! local! local@
<>locals locals-here locals-area locals-gap locals-capacity ?ins. ins.
vins. onlines line-pos line-width size-all size-vocabulary vocs. voc. voclist
voclist-from see-all >vocnext see-vocabulary nonvoc? see-xt ?see-flags
see-loop see-one indent+! icr see. indent mem= ARGS_MARK -TAB +TAB NONAMED
BUILTIN_FORK SMUDGE IMMEDIATE_MARK dump-line ca@ cell-shift cell-base cell-mask
#f+s internalized BUILTIN_MARK zplace $place free. boot-prompt raw-ok [SKIP]'
[SKIP] ?stack sp-limit input-limit tib-setup raw.s $@ digit parse-quote
leaving, leaving )leaving leaving( value-bind evaluate&fill evaluate-buffer
Page 84
arrow ?arrow. ?echo input-buffer immediate? eat-till-cr wascr *emit *key
notfound last-vocabulary voc-stack-end xt-transfer xt-hide xt-find& scope
posix
FNDELAY F_SETFL fcntl CLOCK_BOOTTIME_ALARM CLOCK_REALTIME_ALARM CLOCK_BOOTTIME
CLOCK_MONOTONIC_COARSE CLOCK_REALTIME_COARSE CLOCK_MONOTONIC_RAW
CLOCK_THREAD_CPUTIME_ID
CLOCK_PROCESS_CPUTIME_ID CLOCK_MONOTONIC CLOCK_REALTIME timespec clock_gettime
0777 SIGPIPE SIGBUS SIGKILL SIGINT SIGHUP SIG_IGN SIG_DFL EPIPE EAGAIN
d0=ior d0<ior 0=ior 0<ior stdin-key stdout-write O_NONBLOCK O_APPEND O_TRUNC
O_CREAT O_RDWR O_WRONLY O_RDONLY MAP_ANONYMOUS MAP_FIXED MAP_PRIVATE PROT_EXEC
PROT_WRITE PROT_READ PROT_NONE SEEK_END SEEK_CUR SEEK_SET stderr stdout
stdin errno .d_name .d_type readdir closedir opendir getwd rmdir mkdir
chdir signal usleep realloc sysfree malloc rename unlink mprotect munmap
mmap waitpid wait fork sysexit fsync ftruncate lseek write read close creat
open sign-extend shared-library sysfunc sofunc calls dlopen 'dlopen RTLD_NOW
RTLD_LAZY
sockets
sockaccept ip. ip# ->h_addr ->addr! ->addr@ ->port! ->port@ sockaddr l,
s, bs, SO_REUSEADDR SOL_SOCKET sizeof(sockaddr_in) AF_INET SOCK_RAW SOCK_DGRAM
SOCK_STREAM gethostbyname recvmsg recvfrom recv sendmsg sendto send setsockopt
poll sockaccept connect listen bind socket
tasks
main-task .tasks task-list
telnetd
server broker-connection wait-for-connection connection telnet-key
telnet-type telnet-emit broker client-len client telnet-port clientfd
sockfd
termios
termios-key termios-key? pending form winsize sizeof(winsize) TIOCGWINSZ
normal-mode raw-mode termios! termios@ VMIN VTIME TCSAFLUSH _ECHO ICANON
.c_cc[] .c_lflag new-termios old-termios sizeof(termios) delay-mode nodelay-mode
ioctl tcsetattr tcgetattr
web-interface
server webserver-task do-serve handle1 serve-key serve-type handle-input
handle-index out-string output-stream input-stream out-size webserver index-html
index-html#
Page 85
x11
GenericEvent MappingNotify ClientMessage ColormapNotify SelectionNotify
SelectionRequest SelectionClear PropertyNotify CirculateRequest CirculateNotify
ResizeRequest GravityNotify ConfigureRequest ConfigureNotify ReparentNotify
MapRequest MapNotify UnmapNotify DestroyNotify CreateNotify VisibilityNotify
NoExpose GraphicsExpose Expose KeymapNotify FocusOut FocusIn LeaveNotify
EnterNotify MotionNotify ButtonRelease ButtonPress KeyRelease KeyPress
xevent# OwnerGrabButtonMask ColormapChangeMask PropertyChangeMask FocusChangeMask
SubstructureRedirectMask SubstructureNotifyMask ResizeRedirectMask
StructureNotifyMask
VisibilityChangeMask ExposureMask KeymapStateMask ButtonMotionMask
Button5MotionMask
Button4MotionMask Button3MotionMask Button2MotionMask Button1MotionMask
PointerMotionHintMask PointerMotionMask LeaveWindowMask EnterWindowMask
ButtonReleaseMask ButtonPressMask KeyReleaseMask KeyPressMask xmask NoEventMask
xexposure xconfigure xmotion xkey xbutton xany bool time win xevent-size
NULL ZPixmap XYPixmap XYBitmap XFillRectangle XSetBackground XSetForeground
XDrawString XSelectInput XPutImage XNextEvent XMapWindow XLookupString
XFlush XDestroyImage XDefaultVisual XDefaultDepth XCreateSimpleWindow XCreateImage
XCreateGC XCheckMaskEvent XRootWindow XDefaultScreen XDefaultColormap
XScreenOfDisplay
XDisplayOfScreen XWhitePixel XBlackPixel XOpenDisplay xlib
Page 86
Lexical index
allot.......................................43 fvariable................................53 struct......................................50
ansi........................................82 graphics.................................83 structures...............................50
asm........................................82 HEX......................................56 tasks.......................................84
assert.....................................37 HOLD...................................57 telnetd....................................84
BASE....................................56 httpd......................................83 termios...................................84
BINARY...............................56 include...................................26 type........................................17
c!...........................................42 internals.................................83 value......................................43
c@.........................................42 is............................................66 variable..................................42
cat..........................................27 lshift......................................75 web-interface.........................84
constant.................................42 mv.........................................26 x11.........................................85
create...............................43, 69 posix......................................84 ;.............................................39
DECIMAL............................56 r@..........................................41 :.............................................39
defer......................................66 r>...........................................41 :noname.................................67
delete file...............................26 rdrop......................................41 .s................................................
DOES>..................................69 recurse...................................75 ..........................................36
dump.....................................35 rm..........................................26 #.............................................57
editor.....................................83 S"...........................................60 #>..........................................57
fconstant................................53 see.........................................35 #S..........................................57
files list..................................26 SF!.........................................53 <#..........................................57
forget.....................................39 SF@......................................53 >r...........................................41
FORTH..................................81 sockets...................................84
FORTH word..........................7 SPACE..................................60
Page 87