Big refactor of site.

This commit is contained in:
Brad Nelson
2021-02-12 00:20:53 -08:00
parent e93a62e0af
commit ca0cc67359
10 changed files with 1156 additions and 753 deletions

View File

@ -265,7 +265,7 @@ $(DEPLOY):
mkdir -p $@
$(DEPLOY)/app.yaml: $(ARDUINO)/ESP32forth-$(VERSION).zip \
site/index.html \
$(wildcard site/*.html) \
site/app.yaml \
site/eforth.go \
$(TARGETS) | $(DEPLOY)
@ -275,7 +275,14 @@ $(DEPLOY)/app.yaml: $(ARDUINO)/ESP32forth-$(VERSION).zip \
cp -r $(WINDOWS)/uEf32.exe $(DEPLOY)/static/uEf32-$(VERSION).exe
cp -r $(WINDOWS)/uEf64.exe $(DEPLOY)/static/uEf64-$(VERSION).exe
cp -r $(RES)/eforth.ico $(DEPLOY)/static/favicon.ico
cp -r site/static/* $(DEPLOY)/static/
cp -r site/*.sh $(DEPLOY)
cp -r site/*.go $(DEPLOY)
cp -r site/*.yaml $(DEPLOY)
sed 's/{{VERSION}}/$(VERSION)/g' site/index.html >$(DEPLOY)/index.html
sed 's/{{VERSION}}/$(VERSION)/g' site/ESP32forth.html >$(DEPLOY)/ESP32forth.html
sed 's/{{VERSION}}/$(VERSION)/g' site/windows.html >$(DEPLOY)/windows.html
sed 's/{{VERSION}}/$(VERSION)/g' site/linux.html >$(DEPLOY)/linux.html
cp site/internals.html $(DEPLOY)/
cp site/classic.html $(DEPLOY)/
cp -r site/.gcloudignore $(DEPLOY)

View File

@ -0,0 +1,524 @@
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>ESP32forth</title>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<div>
<h1>ESP32forth</h1>
<div class="menu">
<span class="picked"><a href="ESP32forth.html">ESP32forth</a></span>
<span><a href="linux.html">Linux</a></span>
<span><a href="windows.html">Windows</a></span>
<span><a href="internals.html">Internals</a></span>
<span><a href="classic.html">Classic</a></span>
</div>
<h2>Download</h2>
<p>
<a href="static/ESP32forth-{{VERSION}}.zip">ESP32forth-{{VERSION}}.zip</a>
- Single .ino file ready for installation
</p>
<p>
<a href="https://github.com/flagxor/eforth" target="_blank">http://github.com/flagxor/eforth</a>
- Complete Source Code (under ueforth/)
</p>
<h2>Install</h2>
<p>
Download the <a href="https://www.arduino.cc/en/software">Arduino IDE</a> for your platform.
</p>
<p>
Go to <b>File &gt; Preferences</b>.<br/>
Under <b>Additional Board Manager URLs</b> enter: <code>https://dl.espressif.com/dl/package_esp32_index.json</code>
</p>
<p>
Choose these options under Tools.
<ul>
<li><b>ESP32 Dev Module or similar (may work better with your particular board)</b>
<ul>
<li><b>Board:</b> ESP32 Dev Module</li>
<li><b>Partition Scheme:</b> No OTA (2M APP, 2M SPIFFS) <b>&larr; Non-default</b></li>
<small>
<li><b>Upload Speed:</b> 921600</li>
<li><b>CPU Frequency:</b> 240MHz</li>
<li><b>Flash Frequency:</b> 80MHz</li>
<li><b>Flash Mode:</b> QIO</li>
<li><b>Flash Size:</b> 4MB</li>
<li><b>Core Debug Level:</b> None</li>
<li><b>PSRAM:</b> Disabled</li>
</small>
</ul>
</li>
<li><b>ESP32-CAM</b>
<ul>
<li><b>Board:</b> AI Thinker ESP32-CAM</li>
</ul>
</li>
</ul>
</p>
<h2>ESP32forth Features</h2>
<h3>ESP32forth Specific Words</h3>
<h5>Null Terminated Strings</h5>
<p>
As null terminated strings are used throughout C interfaces,
their use is supported in Forth by way of several non-standard
words with the convention of using Z/z to refer to such strings
in names and stack comments.
</p>
<pre>
Z" ( "string" -- z ) Creates a null terminated string on the heap
Z&gt;S ( z -- a n ) Convert a null terminated string to a counted string
S&gt;Z ( a n -- z ) Conver a counted string string to null terminated (copies string to heap)
</pre>
<h5>Raw Strings</h5>
<p>
Raw strings are provided better support using a string
for the duration of the current command, without consuming heap memory.
</p>
<pre>
R" ( "string" -- a n ) Creates a temporary counted string
R| ( string| -- a n ) Creates a temporary counted string ending with |
</pre>
<h5>Utilities</h5>
<pre>
DUMP ( a n -- ) Dump a memory region
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h5>Vocabularies</h5>
<p>
µEforth uses a hybrid of Forth-79 and Forth-83 style vocabularies.
By default vocabularies chain to the vocabulary in which they were defined,
as in Forth-79. However, like Forth-83, <code>ALSO</code>
can be used to add vocabularies to a vocabulary stack of which
<code>CONTEXT @</code> is the first item.
The word <code>ONLY</code> clears the vocabulary stack, but as there is
no separate ONLY vocabulary, it also sets <code>CONTEXT</code>
to the <code>FORTH</code> vocabulary.
The word <code>SEALED</code> modifies the most recently defined vocabulary
such that it does not chain. Note, this must be done before words are added to it.
</p>
<pre>
VOCABULARY ( "name" ) Create a vocabulary with the current vocabulary as parent
FORTH ( -- ) Make the FORTH vocabulary the context vocabulary
DEFINITIONS ( -- ) Make the context vocabulary the current vocabulary
VLIST ( -- ) List the words in the context vocabulary (not chains)
WORDS ( -- ) List the words in the context vocabulary (including chains)
TRANSFER ( "name" ) Move a word from its current dictionary to the current vocabulary
Useful for "hiding" built-in words
ALSO ( -- ) Duplicate the vocabulary at the top of the vocabulary stack
ONLY ( -- ) Reset context stack to one item, the FORTH dictionary
Non-standard, as there's no distinct ONLY vocabulary
ORDER ( -- ) Print the vocabulary search order
SEALED ( -- ) Alter the last vocabulary defined so it doesn't chain
</pre>
<h5>Blocks</h5>
<pre>
USE ( "name" -- ) Use "name" as the blockfile, e.g. USE /spiffs/foo
OPEN-BLOCKS ( a n -- ) Open a file as the block file
LOAD ( n -- ) Evaluate a block
THRU ( a b -- ) Load blocks a thru b
LIST ( n -- ) List a block
BLOCK ( n -- a ) Get a 1024 byte block
BUFFER ( n -- a ) Get a 1024 byte block without regard to old contents
UPDATE ( -- ) Mark the last block modified
FLUSH ( -- ) Save and empty all buffers
EMPTY-BUFFERS ( -- ) Empty all buffers
SAVE-BUFFERS ( -- ) Save all buffers
SCR ( -- a ) Pointer to last listed block
</pre>
<h5>Block Editor</h5>
These words are available inside the <code>EDITOR</code> vocabulary.
<pre>
WIPE ( -- ) Blank out the current block
L ( -- ) List the current block
D ( n -- ) Delete a line in the current block
E ( n -- ) Clear a line in the current block
R ( n "text" -- ) Replace a line in the current block
A ( n "text" -- ) Add (insert) a line in the current block
P ( -- ) Move to the previous block
N ( -- ) Move to the next block
</pre>
<h5>Utilities</h5>
<pre>
SEE ( "name" -- ) Attempt to decompile a word
ECHO ( -- a ) -- Address of flag that determines if commands are echoed
</pre>
<h3>ESP32forth Opcodes</h3>
<p>
Because Arduino builds a statically linked image for flashing into ESP32 devices,
all C function bindings need to be explicitly added.
This is the current collection.
Typically to reduce confusion, function names have be preserved even through verbose.
In popular cases a shorted higher level name is provided.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino.template.ino">arduino.template.ino</a>.
</p>
<h5>Allocation</h5>
These words are inside the <code>internals</code> vocabulary.
<pre>
MALLOC ( n -- a | 0 ) System malloc
SYSFREE ( a -- ) System free
REALLOC ( a n -- a | 0 ) System realloc
</pre>
<h5>Serial</h5>
These words are inside the <code>Serial</code> vocabulary.
<pre>
Serial.begin ( baud -- ) Start serial port
Serial.end ( -- ) End serial port
Serial.available ( -- f ) Is serial data available
Serial.readBytes ( a n -- n ) Read serial bytes, return number gotten
Serial.write ( a n -- n ) Write serial bytes
Serial.flush ( -- ) Flush serial buffer
</pre>
<h5>Serial Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
SerialBT.new ( -- bt ) Allocate new BT object
SerialBT.delete ( bt -- ) Free BT object
SerialBT.begin ( localname ismaster bt -- f )
SerialBT.end ( bt -- )
SerialBT.available ( bt -- f )
SerialBT.readBytes ( a n bt -- n )
SerialBT.write ( a n bt -- n )
SerialBT.flush ( bt -- )
SerialBT.hasClient ( bt -- f )
SerialBT.enableSSP ( bt -- )
SerialBT.setPin ( z bt -- f )
SerialBT.unpairDevice ( addr bt -- f )
SerialBT.connect ( remotename bt -- f )
SerialBT.connectAddr ( addr bt -- f )
SerialBT.disconnect ( bt -- f )
SerialBT.connected ( timeout bt -- f )
SerialBT.isReady ( checkMaster timeout -- f ) Default checkMaster=false, timeout=0
</pre>
<h5>Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
esp_bt_dev_get_address ( -- a ) addr of 6 byte mac address
</pre>
<h5>GPIO</h5>
<pre>
pinMode ( pin mode -- ) Set GPIO pin mode
digitalWrite ( pin value -- ) Set GPIO pin state
analogRead ( pin -- n ) Analog read from 0-4095
</pre>
<h5>ledc</h5>
These words are inside the <code>ledc</code> vocabulary.
<pre>
ledcSetup ( channel freq resolution -- freq )
ledcAttachPin ( pin channel -- )
ledcDetachPin ( pin -- )
ledcRead ( channel -- n )
ledcReadFreq ( channel -- freq ) Get frequency (x 1,000,000)
ledcWrite ( channel duty -- )
ledcWriteTone ( channel freq ) Write tone frequency (x 1000)
ledcWriteNote ( channel note octave -- freq )
</pre>
<h5>Short GPIO Names</h5>
<pre>
pin ( value pin# -- ) Set GPIO pin value
adc ( pin# -- n ) Analog read pin, result 0-1023
</pre>
<h5>System</h5>
<pre>
MS ( n -- )
TERMINATE ( n -- ) Call system exit
</pre>
<h5>Files</h5>
<pre>
R/O ( -- mode )
R/W ( -- mode )
W/O ( -- mode )
BIN ( mode -- mode )
CLOSE-FILE ( fh -- ior )
OPEN-FILE ( a n mode -- fh ior )
CREATE-FILE ( a n mode -- fh ior )
DELETE-FILE ( a n -- ior )
WRITE-FILE ( a n fh -- ior )
READ-FILE ( a n fh -- n ior )
FILE-POSITION ( fh -- n ior )
REPOSITION-FILE ( n fh -- ior )
FILE-SIZE ( fh -- n ior )
</pre>
<h5>WiFi</h5>
These words are inside the <code>WiFi</code> vocabulary.
<pre>
WiFi.config ( ip dns gateway subnet -- ) Packaged a.b.c.d little-endian
Wifi.begin ( ssid-z password-z -- )
Wifi.disconnect ( -- )
WiFi.status ( -- n )
WiFi.macAddress ( a -- )
WiFi.localIP ( -- ip )
WiFi.mode ( mode -- ) WIFI_MODE_NULL WIFI_MODE_STA WIFI_MODE_AP WIFI_MODE_APSTA
WiFi.setTxPower ( powerx4 -- ) Set power x4
WiFi.getTxPower ( -- powerx4 ) Get power x4
</pre>
<h5>mDNS</h5>
<pre>
MDNS.begin ( name-z -- ) Start multicast dns
</pre>
<h5>SPIFFS</h5>
These words are inside the <code>SPIFFS</code> vocabulary.
<pre>
SPIFFS.begin ( format-on-fail path-z max-files -- f )
SPIFFS.end ( -- )
SPIFFS.format ( -- f )
SPIFFS.totalBytes ( -- n )
SPIFFS.usedBytes ( -- n )
</pre>
<h5>WebServer</h5>
These words are inside the <code>WebServer</code> vocabulary.
<pre>
WebServer.new ( port -- ws ) Allocate new webserver object
WebServer.delete ( ws -- ) Delete webserver object
WebServer.begin ( port ws -- )
WebServer.stop ( ws -- )
WebServer.on ( path-z xt ws -- ) Set up a web path handle callback
WebServer.handleClient ( ws -- ) Handle one client request
WebServer.hasArg ( z ws -- f ) By name
WebServer.arg ( z ws -- z ) By name
WebServer.argi ( n ws -- z ) By index
WebServer.argName ( n ws -- z) By index
WebServer.args ( ws -- n ) Number of args
WebServer.setContentLength ( n ws -- )
WebServer.sendHeader ( name-z value-z fist ws -- )
WebServer.send ( code mimetype data ws -- )
WebServer.sendContent ( z ws -- )
WebServer.method ( ws -- n ) GET / POST etc.
</pre>
<h5>Wire</h5>
These words are inside the <code>Wire</code> vocabulary.
<pre>
Wire.begin ( -- f )
Wire.setPins ( sda scl -- f )
Wire.setClock ( frequency -- )
Wire.getClock ( -- frequency )
Wire.setTimeout ( ms -- ) Default is 50ms
Wire.getTimeout ( -- ms )
Wire.lastError ( -- n )
Wire.getErrorText ( n -- z )
Wire.beginTransmission ( n -- )
Wire.endTransmission ( sendstop -- f )
Wire.requestFrom ( address quantity sendstop -- n )
Wire.writeTransmission ( addr a n sendstop -- err )
Wire.readTransmission ( addr a n sendstop acount -- err )
Wire.write ( a n -- n )
Wire.available ( -- f )
Wire.read ( -- ch )
Wire.peek ( -- ch )
Wire.busy ( -- f )
Wire.flush ( -- )
</pre>
<h5>Camera</h5>
These words are inside the <code>camera</code> vocabulary.
<pre>
esp_camera_init ( config -- f )
esp_camera_deinit ( -- f )
esp_camera_fb_get ( -- fb )
esp_camera_fb_return ( fb -- )
esp_camera_sensor_get ( -- sensor )
</pre>
<h5>SD_MMC</h5>
These words are inside the <code>SD_MMC</code> vocabulary.
<pre>
SD_MMC.begin ( mount mode1bit ) default mode1bit=false
SD_MMC.end ( -- )
SD_MMC.cardType ( -- n )
SD_MMC.totalBytes ( -- n )
SD_MMC.usedBytes ( -- n )
</pre>
<h3 id="webui">ESP32 WebUI</h3>
<p>
A terminal over the web can be activated.
Contact at port printed or via mDNS <a href="http://ueforth/">http://ueforth/</a>.
</p>
<pre>
webui ( network-z password-z -- )
</pre>
<p>Usage:</p>
<pre>
z" NETWORK-NAME" z" PASSWORD" webui
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino_server.fs">arduino_server.fs</a>.
</p>
<h3 id="autoexec">Autoexec.fs</h3>
<p>
The system will automatically attempt to mount SPIFFS filesystem at <code>/spiffs</code>.
It will then at start attempt to load <code>/spiffs/autoexec.fs</code>
</p>
<p>
One way this feature can be used to configure the Web UI to start by default.
When doing this, be sure to test your Web UI settings work well first.
</p>
<pre>
r| z" NETWORK-NAME" z" PASSWORD" webui | s" /spiffs/autoexec.fs" dump-file
</pre>
<p>
To remove a previously configured <code>autoexec.fs</code> you will need
to be able to reboot in a mode with Forth. One way to do this is to search
for the line in the .ino file that refers to <code>autoexec.fs</code>
and replace it with a different name. Then run the following:
</p>
<pre>
s" /spiffs/autoexec.fs" delete-file
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/autoboot.fs">autoboot.fs</a>.
</p>
<h3 id="adding_words">Adding Words</h3>
<p>
Adding words based on C functions can be done by editing the source code.
For ESP32forth <code>arduino.template.ino</code> is the appropriate place.
</p>
<p>
Because of the use of <a href="https://en.wikipedia.org/wiki/X_Macro">X-Macros</a> words can be
added in as little as one line. Locate the macro called <code>PLATFORM_OPCODE_LIST</code>
and add your words there.
</p>
<p>NOTE: Be careful to end each line with a \ so the macros will chain correctly.</p>
<p>
To add a word containing only letters, numbers, and underscore you can use <code>Y</code>.
</p>
<pre>
Y(MY_WORD123, c_function_to_call()) \
</pre>
<p>
If your word name contains other characters, instead use <code>X</code>.
You will need to make up an alternate name for the middle parameter.
It must contain only letters, numbers, and underscore.
The name is not used anywhere else, but must be unique.
</p>
<pre>
X("myword!", MY_WORD_BANG, c_function_to_call()) \
</pre>
<p>
Values from the data stack can be accessed via
the variables <code>tos</code> (Top of Stack) and
<code>sp</code> (Pointer to the rest of the stack).
The stack has the data type <code>cell_t</code>.
</p>
<p>
You can push a value of any type to the stack with the macro <code>PUSH</code>:
</p>
<pre>
Y(MY_WORD, PUSH calculate_magic_value()) \
</pre>
<p>
To simplify calling C functions, you can also refer to elements on the stack
with the types positional names:
</p>
<pre>
n10 n9 n8 n7 n6 n5 n4 n3 n2 n1 n0 - Access stack as cell_t integer values
c4 c3 c2 c1 c0 - Access stack as char* values
b4 b3 b2 b1 b0 - Access stack as uint8_t* byte values
a4 a3 a2 a1 a0 - Access stack as void* values
Examples:
void send_message(const char *message, int code);
...
X("send-message", SEND_MESSAGE, send_message(c1, n0)) \
</pre>
<p>
You can always replace the top item on the stack with <code>SET</code>:
</p>
<pre>
Y(DECODE, SET decode_func(n0)) \
</pre>
<p>
You can drop elements from the stack with <code>DROP</code>
or <code>DROPn(number)</code>.
You can nip elements from below top of the stack with <code>NIP</code>
or <code>NIPn(number)</code>.
Be aware that like <code>PUSH</code> this will cause stack indices to change.
</p>
<pre>
int my_cool_function(char *foo, int bar, uint8_t *baz);
...
Y(MY_FUNC, n0 = my_cool_function(c2, n1, b0); NIPn(2)) \
</pre>
<p>
Multiple C statements can be included in the code area of a word,
but care must be taken to generally avoid {}s.
If you find you need nesting, a separate function is recommended.
</p>
<p>
New variables can be declared in each word and are scoped to that word.
</p>
<pre>
Y(MY_WORD, cell_t foo = n0; DROP; char *x = c0; DROP; \
PUSH my_func(foo, x)) \
</pre>

View File

@ -18,6 +18,11 @@ handlers:
upload: index.html
secure: always
- url: /(.*).html
static_files: \1.html
upload: *.html
secure: always
- url: /static
static_dir: static
secure: always

62
ueforth/site/classic.html Normal file
View File

@ -0,0 +1,62 @@
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Classic EForth</title>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<h1>Classic EForth</h1>
<div class="menu">
<span><a href="ESP32forth.html">ESP32forth</a></span>
<span><a href="linux.html">Linux</a></span>
<span><a href="windows.html">Windows</a></span>
<span><a href="internals.html">Internals</a></span>
<span class="picked"><a href="classic.html">Classic</a></span>
</div>
<p>
EForth is a delightfully minimalist approach to Forth originated by Bill Muench and Dr. C. H. Ting.
</p>
<h2>Classic ESP32forth</h2>
<p>
ESP32forth - Version 6.3 for NodeMCU ESP32S - Tweaked for the Web
</p>
<ul>
<li><a href="static/ESP32forth-6.3.0.ino">ESP32forth-6.3.0.ino</a>
</ul>
<h3>Classic EForth Quirks</h3>
<p>
EForth exclusively uses <code>FOR..NEXT</code> in favor of <code>DO..LOOP</code>.
<a href="https://github.com/TG9541/stm8ef/wiki/eForth-FOR-..-NEXT">Details</a>
</p>
<p>
This construct has the odd property that it iterates one "extra" time for zero.
</p>
<pre>
: FOO 10 FOR R@ . NEXT ; FOO
10 9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
To permit a more ordinary loop the <code>AFT</code> word is used in the sequence
<code>FOR..AFT..THEN..NEXT</code>.
</p>
<pre>
: FOO 10 FOR ( 1st time only ) AFT R@ . THEN NEXT ; FOO
9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
The even more enigmatic <code>FOR..WHILE..NEXT..ELSE..THEN</code>
is used in place of <code>DO..LEAVE..LOOP</code>.
It allows a while condition to early out of a counted loop.
</p>

View File

@ -2,761 +2,21 @@
<head>
<meta charset="UTF-8">
<title>EForth</title>
<style>
body {
max-width: 800px;
}
h1 {
border-top: 3px solid #777;
background-color: #111;
color: #eee;
padding: 10px;
margin-top: 0;
}
h2 {
border-top: 2px solid #777;
background-color: #ccc;
padding: 10px;
}
h3 {
border-top: 1px solid #777;
background-color: #eee;
padding: 10px;
}
h5 {
margin: 2px;
}
</style>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<h1>EForth</h1>
<script>
window.location.replace('./ESP32forth.html');
</script>
<div class="menu">
<span><a href="ESP32forth.html">ESP32forth</a></span>
<span><a href="linux.html">Linux</a></span>
<span><a href="windows.html">Windows</a></span>
<span><a href="internals.html">Internals</a></span>
<span><a href="classic.html">Classic</a></span>
</div>
<p>
EForth is a delightfully minimalist approach to Forth originated by Bill Muench and Dr. C. H. Ting.
</p>
<h2>Downloads</h2>
<h3>µEforth</h3>
<p>
A reduced cross-platform EForth version
</p>
<ul>
<li><a href="static/ESP32forth-{{VERSION}}.zip">ESP32forth-{{VERSION}}.zip</a>
- <b>ESP32forth</b> Source Code <b>&larr; SVFIG & Forth2020 folks start here!</b>
<ul>
<li><b>ESP32 Dev Module or similar (may work better with your particular board)</b>
<ul>
<li><b>Board:</b> ESP32 Dev Module</li>
<li><b>Partition Scheme:</b> No OTA (2M APP, 2M SPIFFS) <b>&larr; Non-default</b></li>
<small>
<li><b>Upload Speed:</b> 921600</li>
<li><b>CPU Frequency:</b> 240MHz</li>
<li><b>Flash Frequency:</b> 80MHz</li>
<li><b>Flash Mode:</b> QIO</li>
<li><b>Flash Size:</b> 4MB</li>
<li><b>Core Debug Level:</b> None</li>
<li><b>PSRAM:</b> Disabled</li>
</small>
</ul>
</li>
<li><b>ESP32-CAM</b>
<ul>
<li><b>Board:</b> AI Thinker ESP32-CAM</li>
</ul>
</li>
</ul>
</li>
<li><a href="static/uEf32-{{VERSION}}.exe">uEf32-{{VERSION}}.exe</a> - Window 32-bit EXE µEforth</li>
<li><a href="static/uEf64-{{VERSION}}.exe">uEf64-{{VERSION}}.exe</a> - Window 64-bit EXE µEforth</li>
<li><a href="static/ueforth-{{VERSION}}.linux">ueforth-{{VERSION}}.linux</a> - Linux 64-bit Executable µEforth</li>
</ul>
<p>
<a href="https://github.com/flagxor/eforth" target="_blank">http://github.com/flagxor/eforth</a>
- Complete Source Code (under ueforth)
</p>
<h2>µEforth</h2>
<h3>µEforth Specific Words</h3>
<h5>Null Terminated Strings</h5>
<p>
As null terminated strings are used by virtually all platforms,
their use is supported in Forth by way of several non-standard
words with the convention of using Z/z to refer to such strings
in names and stack comments.
</p>
<pre>
Z" ( "string" -- z ) Creates a null terminated string on the heap
Z&gt;S ( z -- a n ) Convert a null terminated string to a counted string
S&gt;Z ( a n -- z ) Conver a counted string string to null terminated (copies string to heap)
</pre>
<h5>Raw Strings</h5>
<p>
Raw strings are provided better support using a string
for the duration of the current command, without consuming heap memory.
</p>
<pre>
R" ( "string" -- a n ) Creates a temporary counted string
R| ( string| -- a n ) Creates a temporary counted string ending with |
</pre>
<h5>Utilities</h5>
<pre>
DUMP ( a n -- ) Dump a memory region
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h5>Vocabularies</h5>
<p>
µEforth uses a hybrid of Forth-79 and Forth-83 style vocabularies.
By default vocabularies chain to the vocabulary in which they were defined,
as in Forth-79. However, like Forth-83, <code>ALSO</code>
can be used to add vocabularies to a vocabulary stack of which
<code>CONTEXT @</code> is the first item.
The word <code>ONLY</code> clears the vocabulary stack, but as there is
no separate ONLY vocabulary, it also sets <code>CONTEXT</code>
to the <code>FORTH</code> vocabulary.
The word <code>SEALED</code> modifies the most recently defined vocabulary
such that it does not chain. Note, this must be done before words are added to it.
</p>
<pre>
VOCABULARY ( "name" ) Create a vocabulary with the current vocabulary as parent
FORTH ( -- ) Make the FORTH vocabulary the context vocabulary
DEFINITIONS ( -- ) Make the context vocabulary the current vocabulary
VLIST ( -- ) List the words in the context vocabulary (not chains)
WORDS ( -- ) List the words in the context vocabulary (including chains)
TRANSFER ( "name" ) Move a word from its current dictionary to the current vocabulary
Useful for "hiding" built-in words
ALSO ( -- ) Duplicate the vocabulary at the top of the vocabulary stack
ONLY ( -- ) Reset context stack to one item, the FORTH dictionary
Non-standard, as there's no distinct ONLY vocabulary
ORDER ( -- ) Print the vocabulary search order
SEALED ( -- ) Alter the last vocabulary defined so it doesn't chain
</pre>
<h5>Blocks</h5>
<pre>
USE ( "name" -- ) Use "name" as the blockfile, e.g. USE /spiffs/foo
OPEN-BLOCKS ( a n -- ) Open a file as the block file
LOAD ( n -- ) Evaluate a block
THRU ( a b -- ) Load blocks a thru b
LIST ( n -- ) List a block
BLOCK ( n -- a ) Get a 1024 byte block
BUFFER ( n -- a ) Get a 1024 byte block without regard to old contents
UPDATE ( -- ) Mark the last block modified
FLUSH ( -- ) Save and empty all buffers
EMPTY-BUFFERS ( -- ) Empty all buffers
SAVE-BUFFERS ( -- ) Save all buffers
SCR ( -- a ) Pointer to last listed block
</pre>
<h5>Block Editor</h5>
These words are available inside the <code>EDITOR</code> vocabulary.
<pre>
WIPE ( -- ) Blank out the current block
L ( -- ) List the current block
D ( n -- ) Delete a line in the current block
E ( n -- ) Clear a line in the current block
R ( n "text" -- ) Replace a line in the current block
A ( n "text" -- ) Add (insert) a line in the current block
P ( -- ) Move to the previous block
N ( -- ) Move to the next block
</pre>
<h5>Utilities</h5>
<pre>
SEE ( "name" -- ) Attempt to decompile a word
ECHO ( -- a ) -- Address of flag that determines if commands are echoed
</pre>
<h3>ESP32 Arduino</h3>
<h4>ESP32 Arduino Opcodes</h4>
<p>
Because Arduino builds a statically linked image for flashing into ESP32 devices,
all C function bindings need to be explicitly added.
This is the current collection.
Typically to reduce confusion, function names have be preserved even through verbose.
In popular cases a shorted higher level name is provided.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino.template.ino">arduino.template.ino</a>.
</p>
<h5>Allocation</h5>
These words are inside the <code>internals</code> vocabulary.
<pre>
MALLOC ( n -- a | 0 ) System malloc
SYSFREE ( a -- ) System free
REALLOC ( a n -- a | 0 ) System realloc
</pre>
<h5>Serial</h5>
These words are inside the <code>Serial</code> vocabulary.
<pre>
Serial.begin ( baud -- ) Start serial port
Serial.end ( -- ) End serial port
Serial.available ( -- f ) Is serial data available
Serial.readBytes ( a n -- n ) Read serial bytes, return number gotten
Serial.write ( a n -- n ) Write serial bytes
Serial.flush ( -- ) Flush serial buffer
</pre>
<h5>Serial Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
SerialBT.new ( -- bt ) Allocate new BT object
SerialBT.delete ( bt -- ) Free BT object
SerialBT.begin ( localname ismaster bt -- f )
SerialBT.end ( bt -- )
SerialBT.available ( bt -- f )
SerialBT.readBytes ( a n bt -- n )
SerialBT.write ( a n bt -- n )
SerialBT.flush ( bt -- )
SerialBT.hasClient ( bt -- f )
SerialBT.enableSSP ( bt -- )
SerialBT.setPin ( z bt -- f )
SerialBT.unpairDevice ( addr bt -- f )
SerialBT.connect ( remotename bt -- f )
SerialBT.connectAddr ( addr bt -- f )
SerialBT.disconnect ( bt -- f )
SerialBT.connected ( timeout bt -- f )
SerialBT.isReady ( checkMaster timeout -- f ) Default checkMaster=false, timeout=0
</pre>
<h5>Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
esp_bt_dev_get_address ( -- a ) addr of 6 byte mac address
</pre>
<h5>GPIO</h5>
<pre>
pinMode ( pin mode -- ) Set GPIO pin mode
digitalWrite ( pin value -- ) Set GPIO pin state
analogRead ( pin -- n ) Analog read from 0-4095
</pre>
<h5>ledc</h5>
These words are inside the <code>ledc</code> vocabulary.
<pre>
ledcSetup ( channel freq resolution -- freq )
ledcAttachPin ( pin channel -- )
ledcDetachPin ( pin -- )
ledcRead ( channel -- n )
ledcReadFreq ( channel -- freq ) Get frequency (x 1,000,000)
ledcWrite ( channel duty -- )
ledcWriteTone ( channel freq ) Write tone frequency (x 1000)
ledcWriteNote ( channel note octave -- freq )
</pre>
<h5>Short GPIO Names</h5>
<pre>
pin ( value pin# -- ) Set GPIO pin value
adc ( pin# -- n ) Analog read pin, result 0-1023
</pre>
<h5>System</h5>
<pre>
MS ( n -- )
TERMINATE ( n -- ) Call system exit
</pre>
<h5>Files</h5>
<pre>
R/O ( -- mode )
R/W ( -- mode )
W/O ( -- mode )
BIN ( mode -- mode )
CLOSE-FILE ( fh -- ior )
OPEN-FILE ( a n mode -- fh ior )
CREATE-FILE ( a n mode -- fh ior )
DELETE-FILE ( a n -- ior )
WRITE-FILE ( a n fh -- ior )
READ-FILE ( a n fh -- n ior )
FILE-POSITION ( fh -- n ior )
REPOSITION-FILE ( n fh -- ior )
FILE-SIZE ( fh -- n ior )
</pre>
<h5>WiFi</h5>
These words are inside the <code>WiFi</code> vocabulary.
<pre>
WiFi.config ( ip dns gateway subnet -- ) Packaged a.b.c.d little-endian
Wifi.begin ( ssid-z password-z -- )
Wifi.disconnect ( -- )
WiFi.status ( -- n )
WiFi.macAddress ( a -- )
WiFi.localIP ( -- ip )
WiFi.mode ( mode -- ) WIFI_MODE_NULL WIFI_MODE_STA WIFI_MODE_AP WIFI_MODE_APSTA
WiFi.setTxPower ( powerx4 -- ) Set power x4
WiFi.getTxPower ( -- powerx4 ) Get power x4
</pre>
<h5>mDNS</h5>
<pre>
MDNS.begin ( name-z -- ) Start multicast dns
</pre>
<h5>SPIFFS</h5>
These words are inside the <code>SPIFFS</code> vocabulary.
<pre>
SPIFFS.begin ( format-on-fail path-z max-files -- f )
SPIFFS.end ( -- )
SPIFFS.format ( -- f )
SPIFFS.totalBytes ( -- n )
SPIFFS.usedBytes ( -- n )
</pre>
<h5>WebServer</h5>
These words are inside the <code>WebServer</code> vocabulary.
<pre>
WebServer.new ( port -- ws ) Allocate new webserver object
WebServer.delete ( ws -- ) Delete webserver object
WebServer.begin ( port ws -- )
WebServer.stop ( ws -- )
WebServer.on ( path-z xt ws -- ) Set up a web path handle callback
WebServer.handleClient ( ws -- ) Handle one client request
WebServer.hasArg ( z ws -- f ) By name
WebServer.arg ( z ws -- z ) By name
WebServer.argi ( n ws -- z ) By index
WebServer.argName ( n ws -- z) By index
WebServer.args ( ws -- n ) Number of args
WebServer.setContentLength ( n ws -- )
WebServer.sendHeader ( name-z value-z fist ws -- )
WebServer.send ( code mimetype data ws -- )
WebServer.sendContent ( z ws -- )
WebServer.method ( ws -- n ) GET / POST etc.
</pre>
<h5>Wire</h5>
These words are inside the <code>Wire</code> vocabulary.
<pre>
Wire.begin ( -- f )
Wire.setPins ( sda scl -- f )
Wire.setClock ( frequency -- )
Wire.getClock ( -- frequency )
Wire.setTimeout ( ms -- ) Default is 50ms
Wire.getTimeout ( -- ms )
Wire.lastError ( -- n )
Wire.getErrorText ( n -- z )
Wire.beginTransmission ( n -- )
Wire.endTransmission ( sendstop -- f )
Wire.requestFrom ( address quantity sendstop -- n )
Wire.writeTransmission ( addr a n sendstop -- err )
Wire.readTransmission ( addr a n sendstop acount -- err )
Wire.write ( a n -- n )
Wire.available ( -- f )
Wire.read ( -- ch )
Wire.peek ( -- ch )
Wire.busy ( -- f )
Wire.flush ( -- )
</pre>
<h5>Camera</h5>
These words are inside the <code>camera</code> vocabulary.
<pre>
esp_camera_init ( config -- f )
esp_camera_deinit ( -- f )
esp_camera_fb_get ( -- fb )
esp_camera_fb_return ( fb -- )
esp_camera_sensor_get ( -- sensor )
</pre>
<h5>SD_MMC</h5>
These words are inside the <code>SD_MMC</code> vocabulary.
<pre>
SD_MMC.begin ( mount mode1bit ) default mode1bit=false
SD_MMC.end ( -- )
SD_MMC.cardType ( -- n )
SD_MMC.totalBytes ( -- n )
SD_MMC.usedBytes ( -- n )
</pre>
<h4 id="webui">ESP32 WebUI</h4>
<p>
A terminal over the web can be activated.
Contact at port printed or via mDNS <a href="http://ueforth/">http://ueforth/</a>.
</p>
<pre>
webui ( network-z password-z -- )
</pre>
<p>Usage:</p>
<pre>
z" NETWORK-NAME" z" PASSWORD" webui
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino_server.fs">arduino_server.fs</a>.
</p>
<h4 id="autoexec">Autoexec.fs</h4>
<p>
The system will automatically attempt to mount SPIFFS filesystem at <code>/spiffs</code>.
It will then at start attempt to load <code>/spiffs/autoexec.fs</code>
</p>
<p>
One way this feature can be used to configure the Web UI to start by default.
When doing this, be sure to test your Web UI settings work well first.
</p>
<pre>
r| z" NETWORK-NAME" z" PASSWORD" webui | s" /spiffs/autoexec.fs" dump-file
</pre>
<p>
To remove a previously configured <code>autoexec.fs</code> you will need
to be able to reboot in a mode with Forth. One way to do this is to search
for the line in the .ino file that refers to <code>autoexec.fs</code>
and replace it with a different name. Then run the following:
</p>
<pre>
s" /spiffs/autoexec.fs" delete-file
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/autoboot.fs">autoboot.fs</a>.
</p>
<h4 id="adding_words">Adding Words</h4>
<p>
Adding words based on C functions can be done by editing the source code.
For ESP32 Arduino <code>arduino.template.ino</code> is the appropriate place.
</p>
<p>
Because of the use of <a href="https://en.wikipedia.org/wiki/X_Macro">X-Macros</a> words can be
added in as little as one line. Locate the macro called <code>PLATFORM_OPCODE_LIST</code>
and add your words there.
</p>
<p>NOTE: Be careful to end each line with a \ so the macros will chain correctly.</p>
<p>
To add a word containing only letters, numbers, and underscore you can use <code>Y</code>.
</p>
<pre>
Y(MY_WORD123, c_function_to_call()) \
</pre>
<p>
If your word name contains other characters, instead use <code>X</code>.
You will need to make up an alternate name for the middle parameter.
It must contain only letters, numbers, and underscore.
The name is not used anywhere else, but must be unique.
</p>
<pre>
X("myword!", MY_WORD_BANG, c_function_to_call()) \
</pre>
<p>
Values from the data stack can be accessed via
the variables <code>tos</code> (Top of Stack) and
<code>sp</code> (Pointer to the rest of the stack).
The stack has the data type <code>cell_t</code>.
</p>
<p>
You can push a value of any type to the stack with the macro <code>PUSH</code>:
</p>
<pre>
Y(MY_WORD, PUSH calculate_magic_value()) \
</pre>
<p>
To simplify calling C functions, you can also refer to elements on the stack
with the types positional names:
</p>
<pre>
n10 n9 n8 n7 n6 n5 n4 n3 n2 n1 n0 - Access stack as cell_t integer values
c4 c3 c2 c1 c0 - Access stack as char* values
b4 b3 b2 b1 b0 - Access stack as uint8_t* byte values
a4 a3 a2 a1 a0 - Access stack as void* values
Examples:
void send_message(const char *message, int code);
...
X("send-message", SEND_MESSAGE, send_message(c1, n0)) \
</pre>
<p>
You can always replace the top item on the stack with <code>SET</code>:
</p>
<pre>
Y(DECODE, SET decode_func(n0)) \
</pre>
<p>
You can drop elements from the stack with <code>DROP</code>
or <code>DROPn(number)</code>.
You can nip elements from below top of the stack with <code>NIP</code>
or <code>NIPn(number)</code>.
Be aware that like <code>PUSH</code> this will cause stack indices to change.
</p>
<pre>
int my_cool_function(char *foo, int bar, uint8_t *baz);
...
Y(MY_FUNC, n0 = my_cool_function(c2, n1, b0); NIPn(2)) \
</pre>
<p>
Multiple C statements can be included in the code area of a word,
but care must be taken to generally avoid {}s.
If you find you need nesting, a separate function is recommended.
</p>
<p>
New variables can be declared in each word and are scoped to that word.
</p>
<pre>
Y(MY_WORD, cell_t foo = n0; DROP; char *x = c0; DROP; \
PUSH my_func(foo, x)) \
</pre>
<h3>Windows</h3>
<h4>Windows Opcodes</h4>
<p>
The wealth of Windows .DLL and system functionality can be
accessed via the dynamic loading interface.
A handle to a library is obtained with <code>LOADLIBRARYA</code>,
and then individual symbols are accessed with <code>GETPROCADDRESS</code>.
</p>
<pre>
LOADLIBRARYA ( dllname-z -- module )
GETPROCADDRESS ( module name-z -- fn )
</pre>
<p>
And assembly version of <code>*/MOD</code> is provided to allow the EXE to build without
including MSVCRT.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows_main.c">windows_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Windows Imports</h4>
<p>
Various Win32 calls are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows.fs">windows.fs</a>.
In addition, a terminal that responds to ANSI escape codes is created and connected to
<code>TYPE</code> and <code>KEY</code>.
</p>
<h3>Linux</h3>
<h4>Linux Opcodes</h4>
<p>
Linux libraries and the operating system can be accessed via the use
of the <code>DLSYM</code> word. Functions can be requested by name from
particular modules. As the dynamic linking module is already loaded initially,
a 0 for the module allows the library loading function (<code>dlopen</code>)
to be loaded from Forth.
</p>
<pre>
DLSYM ( module name-z -- fn )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix_main.c">posix_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Linux Imports</h4>
<p>
Various Linux calls including Xlib are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix.fs">posix.fs</a> and
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/xlib.fs">xlib.fs</a>.
In addition, <code>TYPE</code> and <code>KEY</code> are connected to
<code>stdin</code> and <code>stdout</code>.
</p>
<h3>Windows &amp; Linux Calling</h3>
<p>
As unfortunately both Windows and Linux have system and library calls with
as many as 10 parameters (for example <code>XCreateImage</code>),
a collection of calling thunks is required.
A single varidic thunk would be ideal, but is hard to do without per platform
assembly language.
</p>
<pre>
CALL0 ( fn -- n )
CALL1 ( n fn -- n )
CALL2 ( n n fn -- n )
CALL3 ( n n n fn -- n )
CALL4 ( n n n n fn -- n )
CALL5 ( n n n n n fn -- n )
CALL6 ( n n n n n n fn -- n )
CALL7 ( n n n n n n n fn -- n )
CALL7 ( n n n n n n n n fn -- n )
CALL9 ( n n n n n n n n n fn -- n )
CALL10 ( n n n n n n n n n n fn -- n )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/calling.h">calling.h</a>.
</p>
<h3>Web</h3>
<font style="font-size: 18pt; color: #C00;">Work in Progress - Coming Soon</font>
<h3>µEforth Internals</h3>
<p>
µEforth (micro-Eforth) simplifies EForth even futher, by building just enough
of the core of the system in C to allow the rest to be be built in proper Forth.
</p>
<p>
A handful of "tricky" words that involve internal loops or many steps are built in their own
functions:
</p>
<pre>
FIND ( a n -- xt | 0 )
PARSE ( ch -- a n )
S&gt;NUMBER? ( a n -- n f | 0 )
CREATE ( "name" -- )
EVALUATE1 ( -- )
</pre>
<p>
This includes <code>EVALUATE1</code> which parses a single word and
interprets or compiles it (reusing <code>PARSE</code>,
<code>FIND</code>, and <code>S&gt;NUMBER?</code>).
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/core.h">core.h</a>.
</p>
<p>
A few global variables connect parsing and compilation state between
C and Forth (by way of a memory region accessed via <code>'SYS</code>):
</p>
<pre>
'TIB --- Pointer to the Translation Input Buffer
#TIB --- Length of the Translation Input Buffer
&gt;IN --- Number of characters consumed from TIB
BASE --- Numeric base for printing and parsing
STATE --- State of compiling, -1 for compiling, 0 for interpreting
CURRENT --- Pointer to pointer to last word of current vocabulary
CONTEXT --- Pointer to pointer to last word of context vocabulary
'NOTFOUND --- Execution token of a handler to call on word not found
</pre>
<p>
Error handling is routed via a deferred callback in <code>'NOTFOUND</code>
used when a word is absent from the dictionary.
This is eventually directed to an error routing that prints
a proper error, once I/O and exceptions are available.
</p>
<p>
<a href="https://en.wikipedia.org/wiki/X_Macro">X-Macros</a>
are then used to build up a small set of core opcodes defined in 1-3 lines each:
</p>
<pre>
0= 0&lt; + U/MOD */MOD AND OR XOR
DUP SWAP OVER DROP @ L@ C@ ! L! C!
SP@ SP! RP@ RP! &gt;R R&gt; R@ : ; EXIT
EXECUTE BRANCH 0BRANCH DONEXT DOLIT
ALITERAL CELL DOES&gt; IMMEDIATE 'SYS
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/opcodes.h">opcodes.h</a>.
</p>
<p>
I/O and access to systems outside Forth are connected via a few per platform words.
Typically this set of words should be minimal, while still allowing relevant parts
of the host system to be available to Forth.
</p>
<h2>Classic esp32Forth</h2>
<p>
esp32Forth - Version 6.3 for NodeMCU ESP32S - Tweaked for the Web
</p>
<ul>
<li><a href="static/espforth.ino">espforth.ino</a>
</ul>
<h3>Classic EForth Quirks</h3>
<p>
EForth uses <code>FOR..NEXT</code> in favor of <code>DO..LOOP</code>.
<a href="https://github.com/TG9541/stm8ef/wiki/eForth-FOR-..-NEXT">Details</a>
</p>
<p>
This construct has the odd property that it iterates one "extra" time for zero.
</p>
<pre>
: FOO 10 FOR R@ . NEXT ; FOO
10 9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
To permit a more ordinary loop the <code>AFT</code> word is used in the sequence
<code>FOR..AFT..THEN..NEXT</code>.
</p>
<pre>
: FOO 10 FOR ( 1st time only ) AFT R@ . THEN NEXT ; FOO
9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
The even more enigmatic <code>FOR..WHILE..NEXT..ELSE..THEN</code>
is used in place of <code>DO..LEAVE..LOOP</code>.
It allows a while condition to early out of a counted loop.
Choose you platform above.
</p>

View File

@ -0,0 +1,94 @@
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>ESP32forth</title>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<h1>µEforth Internals</h1>
<div class="menu">
<span><a href="ESP32forth.html">ESP32forth</a></span>
<span><a href="linux.html">Linux</a></span>
<span><a href="windows.html">Windows</a></span>
<span class="picked"><a href="internals.html">Internals</a></span>
<span><a href="classic.html">Classic</a></span>
</div>
<p>
µEforth (micro-Eforth) simplifies EForth even futher, by building just enough
of the core of the system in C to allow the rest to be be built in proper Forth.
</p>
<p>
A handful of "tricky" words that involve internal loops or many steps are built in their own
functions:
</p>
<pre>
FIND ( a n -- xt | 0 )
PARSE ( ch -- a n )
S&gt;NUMBER? ( a n -- n f | 0 )
CREATE ( "name" -- )
EVALUATE1 ( -- )
</pre>
<p>
This includes <code>EVALUATE1</code> which parses a single word and
interprets or compiles it (reusing <code>PARSE</code>,
<code>FIND</code>, and <code>S&gt;NUMBER?</code>).
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/core.h">core.h</a>.
</p>
<p>
A few global variables connect parsing and compilation state between
C and Forth (by way of a memory region accessed via <code>'SYS</code>):
</p>
<pre>
'TIB --- Pointer to the Translation Input Buffer
#TIB --- Length of the Translation Input Buffer
&gt;IN --- Number of characters consumed from TIB
BASE --- Numeric base for printing and parsing
STATE --- State of compiling, -1 for compiling, 0 for interpreting
CURRENT --- Pointer to pointer to last word of current vocabulary
CONTEXT --- Pointer to pointer to last word of context vocabulary
'NOTFOUND --- Execution token of a handler to call on word not found
</pre>
<p>
Error handling is routed via a deferred callback in <code>'NOTFOUND</code>
used when a word is absent from the dictionary.
This is eventually directed to an error routing that prints
a proper error, once I/O and exceptions are available.
</p>
<p>
<a href="https://en.wikipedia.org/wiki/X_Macro">X-Macros</a>
are then used to build up a small set of core opcodes defined in 1-3 lines each:
</p>
<pre>
0= 0&lt; + U/MOD */MOD AND OR XOR
DUP SWAP OVER DROP @ L@ C@ ! L! C!
SP@ SP! RP@ RP! &gt;R R&gt; R@ : ; EXIT
EXECUTE BRANCH 0BRANCH DONEXT DOLIT
ALITERAL CELL DOES&gt; IMMEDIATE 'SYS
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/opcodes.h">opcodes.h</a>.
</p>
<p>
I/O and access to systems outside Forth are connected via a few per platform words.
Typically this set of words should be minimal, while still allowing relevant parts
of the host system to be available to Forth.
</p>

187
ueforth/site/linux.html Normal file
View File

@ -0,0 +1,187 @@
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Linux</title>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<h1>µEforth Linux</h1>
<div class="menu">
<span><a href="ESP32forth.html">ESP32forth</a></span>
<span class="picked"><a href="linux.html">Linux</a></span>
<span><a href="windows.html">Windows</a></span>
<span><a href="internals.html">Internals</a></span>
<span><a href="classic.html">Classic</a></span>
</div>
<h2>Download</h2>
<p>
<a href="static/ueforth-{{VERSION}}.linux">ueforth-{{VERSION}}.linux</a>
- Linux 64-bit Executable µEforth
</p>
<p>
<a href="https://github.com/flagxor/eforth" target="_blank">http://github.com/flagxor/eforth</a>
- Complete Source Code (under ueforth)
</p>
<h2>µEforth</h2>
<h3>µEforth Specific Words</h3>
<h5>Null Terminated Strings</h5>
<p>
As null terminated strings are used by virtually all platforms,
their use is supported in Forth by way of several non-standard
words with the convention of using Z/z to refer to such strings
in names and stack comments.
</p>
<pre>
Z" ( "string" -- z ) Creates a null terminated string on the heap
Z&gt;S ( z -- a n ) Convert a null terminated string to a counted string
S&gt;Z ( a n -- z ) Conver a counted string string to null terminated (copies string to heap)
</pre>
<h5>Raw Strings</h5>
<p>
Raw strings are provided better support using a string
for the duration of the current command, without consuming heap memory.
</p>
<pre>
R" ( "string" -- a n ) Creates a temporary counted string
R| ( string| -- a n ) Creates a temporary counted string ending with |
</pre>
<h5>Utilities</h5>
<pre>
DUMP ( a n -- ) Dump a memory region
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h5>Vocabularies</h5>
<p>
µEforth uses a hybrid of Forth-79 and Forth-83 style vocabularies.
By default vocabularies chain to the vocabulary in which they were defined,
as in Forth-79. However, like Forth-83, <code>ALSO</code>
can be used to add vocabularies to a vocabulary stack of which
<code>CONTEXT @</code> is the first item.
The word <code>ONLY</code> clears the vocabulary stack, but as there is
no separate ONLY vocabulary, it also sets <code>CONTEXT</code>
to the <code>FORTH</code> vocabulary.
The word <code>SEALED</code> modifies the most recently defined vocabulary
such that it does not chain. Note, this must be done before words are added to it.
</p>
<pre>
VOCABULARY ( "name" ) Create a vocabulary with the current vocabulary as parent
FORTH ( -- ) Make the FORTH vocabulary the context vocabulary
DEFINITIONS ( -- ) Make the context vocabulary the current vocabulary
VLIST ( -- ) List the words in the context vocabulary (not chains)
WORDS ( -- ) List the words in the context vocabulary (including chains)
TRANSFER ( "name" ) Move a word from its current dictionary to the current vocabulary
Useful for "hiding" built-in words
ALSO ( -- ) Duplicate the vocabulary at the top of the vocabulary stack
ONLY ( -- ) Reset context stack to one item, the FORTH dictionary
Non-standard, as there's no distinct ONLY vocabulary
ORDER ( -- ) Print the vocabulary search order
SEALED ( -- ) Alter the last vocabulary defined so it doesn't chain
</pre>
<h5>Blocks</h5>
<pre>
USE ( "name" -- ) Use "name" as the blockfile, e.g. USE /spiffs/foo
OPEN-BLOCKS ( a n -- ) Open a file as the block file
LOAD ( n -- ) Evaluate a block
THRU ( a b -- ) Load blocks a thru b
LIST ( n -- ) List a block
BLOCK ( n -- a ) Get a 1024 byte block
BUFFER ( n -- a ) Get a 1024 byte block without regard to old contents
UPDATE ( -- ) Mark the last block modified
FLUSH ( -- ) Save and empty all buffers
EMPTY-BUFFERS ( -- ) Empty all buffers
SAVE-BUFFERS ( -- ) Save all buffers
SCR ( -- a ) Pointer to last listed block
</pre>
<h5>Block Editor</h5>
These words are available inside the <code>EDITOR</code> vocabulary.
<pre>
WIPE ( -- ) Blank out the current block
L ( -- ) List the current block
D ( n -- ) Delete a line in the current block
E ( n -- ) Clear a line in the current block
R ( n "text" -- ) Replace a line in the current block
A ( n "text" -- ) Add (insert) a line in the current block
P ( -- ) Move to the previous block
N ( -- ) Move to the next block
</pre>
<h5>Utilities</h5>
<pre>
SEE ( "name" -- ) Attempt to decompile a word
ECHO ( -- a ) -- Address of flag that determines if commands are echoed
</pre>
<h3>Linux</h3>
<h4>Linux Opcodes</h4>
<p>
Linux libraries and the operating system can be accessed via the use
of the <code>DLSYM</code> word. Functions can be requested by name from
particular modules. As the dynamic linking module is already loaded initially,
a 0 for the module allows the library loading function (<code>dlopen</code>)
to be loaded from Forth.
</p>
<pre>
DLSYM ( module name-z -- fn )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix_main.c">posix_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Linux Imports</h4>
<p>
Various Linux calls including Xlib are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix.fs">posix.fs</a> and
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/xlib.fs">xlib.fs</a>.
In addition, <code>TYPE</code> and <code>KEY</code> are connected to
<code>stdin</code> and <code>stdout</code>.
</p>
<h3>Windows &amp; Linux Calling</h3>
<p>
As unfortunately both Windows and Linux have system and library calls with
as many as 10 parameters (for example <code>XCreateImage</code>),
a collection of calling thunks is required.
A single varidic thunk would be ideal, but is hard to do without per platform
assembly language.
</p>
<pre>
CALL0 ( fn -- n )
CALL1 ( n fn -- n )
CALL2 ( n n fn -- n )
CALL3 ( n n n fn -- n )
CALL4 ( n n n n fn -- n )
CALL5 ( n n n n n fn -- n )
CALL6 ( n n n n n n fn -- n )
CALL7 ( n n n n n n n fn -- n )
CALL7 ( n n n n n n n n fn -- n )
CALL9 ( n n n n n n n n n fn -- n )
CALL10 ( n n n n n n n n n n fn -- n )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/calling.h">calling.h</a>.
</p>

View File

@ -0,0 +1,67 @@
body {
max-width: 800px;
margin-top: 0px;
}
h1 {
border-top: 3px solid #777;
background-color: #111;
color: #eee;
padding: 10px;
margin: 0px;
}
h2 {
border-top: 2px solid #777;
background-color: #ccc;
padding: 10px;
}
h3 {
border-top: 1px solid #777;
background-color: #eee;
padding: 10px;
}
h5 {
margin: 2px;
}
a:link {
color: #00c;
}
a:visited {
color: #00c;
}
a:active {
color: #0f0;
}
a:hover {
color: #0f0;
}
.menu {
background-color: #333;
border-top: 3px solid #777;
padding: 10px;
}
.menu span {
margin: 0px;
padding: 10px;
}
.menu a:link {
color: #fff;
}
.menu a:visited {
color: #fff;
}
.menu a:active {
color: #0f0;
}
.menu a:hover {
color: #0f0;
}
.menu .picked {
background-color: #070;
}
.menu .picked a:active {
color: #fff;
}
.menu .picked a:hover {
color: #fff;
}

197
ueforth/site/windows.html Normal file
View File

@ -0,0 +1,197 @@
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>EForth</title>
<link rel="stylesheet" href="static/eforth.css">
</head>
<body>
<h1>µEforth Windows</h1>
<div class="menu">
<span><a href="ESP32forth.html">ESP32forth</a></span>
<span><a href="linux.html">Linux</a></span>
<span class="picked"><a href="windows.html">Windows</a></span>
<span><a href="internals.html">Internals</a></span>
<span><a href="classic.html">Classic</a></span>
</div>
<h2>Download</h2>
<p>
<a href="static/uEf32-{{VERSION}}.exe">uEf32-{{VERSION}}.exe</a>
- Window 32-bit EXE µEforth
</p>
<p>
<a href="static/uEf64-{{VERSION}}.exe">uEf64-{{VERSION}}.exe</a>
- Window 64-bit EXE µEforth
</p>
<p>
<a href="https://github.com/flagxor/eforth" target="_blank">http://github.com/flagxor/eforth</a>
- Complete Source Code (under ueforth)
</p>
<h2>µEforth</h2>
<h3>µEforth Specific Words</h3>
<h5>Null Terminated Strings</h5>
<p>
As null terminated strings are used by virtually all platforms,
their use is supported in Forth by way of several non-standard
words with the convention of using Z/z to refer to such strings
in names and stack comments.
</p>
<pre>
Z" ( "string" -- z ) Creates a null terminated string on the heap
Z&gt;S ( z -- a n ) Convert a null terminated string to a counted string
S&gt;Z ( a n -- z ) Conver a counted string string to null terminated (copies string to heap)
</pre>
<h5>Raw Strings</h5>
<p>
Raw strings are provided better support using a string
for the duration of the current command, without consuming heap memory.
</p>
<pre>
R" ( "string" -- a n ) Creates a temporary counted string
R| ( string| -- a n ) Creates a temporary counted string ending with |
</pre>
<h5>Utilities</h5>
<pre>
DUMP ( a n -- ) Dump a memory region
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h5>Vocabularies</h5>
<p>
µEforth uses a hybrid of Forth-79 and Forth-83 style vocabularies.
By default vocabularies chain to the vocabulary in which they were defined,
as in Forth-79. However, like Forth-83, <code>ALSO</code>
can be used to add vocabularies to a vocabulary stack of which
<code>CONTEXT @</code> is the first item.
The word <code>ONLY</code> clears the vocabulary stack, but as there is
no separate ONLY vocabulary, it also sets <code>CONTEXT</code>
to the <code>FORTH</code> vocabulary.
The word <code>SEALED</code> modifies the most recently defined vocabulary
such that it does not chain. Note, this must be done before words are added to it.
</p>
<pre>
VOCABULARY ( "name" ) Create a vocabulary with the current vocabulary as parent
FORTH ( -- ) Make the FORTH vocabulary the context vocabulary
DEFINITIONS ( -- ) Make the context vocabulary the current vocabulary
VLIST ( -- ) List the words in the context vocabulary (not chains)
WORDS ( -- ) List the words in the context vocabulary (including chains)
TRANSFER ( "name" ) Move a word from its current dictionary to the current vocabulary
Useful for "hiding" built-in words
ALSO ( -- ) Duplicate the vocabulary at the top of the vocabulary stack
ONLY ( -- ) Reset context stack to one item, the FORTH dictionary
Non-standard, as there's no distinct ONLY vocabulary
ORDER ( -- ) Print the vocabulary search order
SEALED ( -- ) Alter the last vocabulary defined so it doesn't chain
</pre>
<h5>Blocks</h5>
<pre>
USE ( "name" -- ) Use "name" as the blockfile, e.g. USE /spiffs/foo
OPEN-BLOCKS ( a n -- ) Open a file as the block file
LOAD ( n -- ) Evaluate a block
THRU ( a b -- ) Load blocks a thru b
LIST ( n -- ) List a block
BLOCK ( n -- a ) Get a 1024 byte block
BUFFER ( n -- a ) Get a 1024 byte block without regard to old contents
UPDATE ( -- ) Mark the last block modified
FLUSH ( -- ) Save and empty all buffers
EMPTY-BUFFERS ( -- ) Empty all buffers
SAVE-BUFFERS ( -- ) Save all buffers
SCR ( -- a ) Pointer to last listed block
</pre>
<h5>Block Editor</h5>
These words are available inside the <code>EDITOR</code> vocabulary.
<pre>
WIPE ( -- ) Blank out the current block
L ( -- ) List the current block
D ( n -- ) Delete a line in the current block
E ( n -- ) Clear a line in the current block
R ( n "text" -- ) Replace a line in the current block
A ( n "text" -- ) Add (insert) a line in the current block
P ( -- ) Move to the previous block
N ( -- ) Move to the next block
</pre>
<h5>Utilities</h5>
<pre>
SEE ( "name" -- ) Attempt to decompile a word
ECHO ( -- a ) -- Address of flag that determines if commands are echoed
</pre>
<h3>Windows</h3>
<h4>Windows Opcodes</h4>
<p>
The wealth of Windows .DLL and system functionality can be
accessed via the dynamic loading interface.
A handle to a library is obtained with <code>LOADLIBRARYA</code>,
and then individual symbols are accessed with <code>GETPROCADDRESS</code>.
</p>
<pre>
LOADLIBRARYA ( dllname-z -- module )
GETPROCADDRESS ( module name-z -- fn )
</pre>
<p>
And assembly version of <code>*/MOD</code> is provided to allow the EXE to build without
including MSVCRT.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows_main.c">windows_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Windows Imports</h4>
<p>
Various Win32 calls are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows.fs">windows.fs</a>.
In addition, a terminal that responds to ANSI escape codes is created and connected to
<code>TYPE</code> and <code>KEY</code>.
</p>
<h3>Windows &amp; Linux Calling</h3>
<p>
As unfortunately both Windows and Linux have system and library calls with
as many as 10 parameters (for example <code>XCreateImage</code>),
a collection of calling thunks is required.
A single varidic thunk would be ideal, but is hard to do without per platform
assembly language.
</p>
<pre>
CALL0 ( fn -- n )
CALL1 ( n fn -- n )
CALL2 ( n n fn -- n )
CALL3 ( n n n fn -- n )
CALL4 ( n n n n fn -- n )
CALL5 ( n n n n n fn -- n )
CALL6 ( n n n n n n fn -- n )
CALL7 ( n n n n n n n fn -- n )
CALL7 ( n n n n n n n n fn -- n )
CALL9 ( n n n n n n n n n fn -- n )
CALL10 ( n n n n n n n n n n fn -- n )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/calling.h">calling.h</a>.
</p>