Skip to content

Instantly share code, notes, and snippets.

@crcx
Created December 20, 2009 01:17
Show Gist options
  • Save crcx/260308 to your computer and use it in GitHub Desktop.
Save crcx/260308 to your computer and use it in GitHub Desktop.
A Guide to the Retro Language
The Retro Language
==================
:Author: Charles Childers
:Version: 10.3 (20091212)
===========================
Section 1: Welcome to Retro
===========================
Introduction
------------
Retro is a small, minimalistic dialect of Forth.
The Retro language has a rich history going back to 1998
when it was first released as a 16-bit standalone Forth
for x86 PC's. Since then it's evolved through use into its
present form, which is a 32-bit implementation running on a
portable virtual machine called Ngaro. Today Retro runs on
all major operating systems, and thanks to a JavaScript
implementation of the virtual machine, on any modern web
browser.
The code and documentation for Retro are provided under
an open source license.
This documentation covers the core Retro language. The
virtual machine and library are covered separately.
==========================
Section 2: Getting Started
==========================
Obtaining
---------
Retro can be downloaded from http://retroforth.org
The Retro language is stored in a single file, containing a
binary snapshot called a retroImage ("image" for short).
Most users can use the image file distributed on retroforth.org,
but if you want to customize the basic system you can build a
new image from the source files.
To build a new image file, your will need a copy of the Ngaro VM
for your operating system and processor. You will also need to get
a copy of the current Retro image file (retroImage). The VM should
be kept in your path, and the retroImage should be in the current
working directory.
Developers who want to keep up with the latest changes are encouraged
to use Git. We have a repository at http://github.com/crcx/retro10 which
is kept up to date.
Building from Source (Unix-like host)
-------------------------------------
If you do choose to build the image from scratch, you will need a
Unix-like operating system (BSD, Linux, OS X) and the following
tools:
- Make
- Ngaro VM
Given these, edit the Makefile and modify the first line to
point to your Ngaro VM, then run make.
::
make
You should end up with a new **retroImage**.
Interacting with Retro
----------------------
Unlike most Forths, Retro does not buffer on a line by line basis. Input
is parsed as it is typed, and words are executed when the spacebar is
hit.
This is a significant source of confusion to users coming from other
Forth systems. Just remember: only space is recognized by a default
Retro system as a valid separator between words.
By default, cr, lf, and tab are remapped to be identical to space.
This can be disabled by typing:
::
whitespace off
To turn it back on:
::
whitespace on
Leaving Retro
-------------
Just type **bye** and hit space.
Images
------
The Retro language is stored in an image file. When you start Retro,
the VM looks for a **retroImage** file. If if can't find one, it uses
a minimal image that is built in instead.
You can **save** your current Retro session to a retroImage by using
the **save** word, and reload it later. All words/variables you have
created will be kept and you can continue working without having to
reload or retype everything.
You can also use the vector functionality in Retro to replace/alter
most of the existing words to meet your needs.
=========================
Section 3: Implementation
=========================
Overview
--------
Retro is not a standard-compliant Forth. It's significantly
different in many areas. This section will help explain these
differences and show how Retro works internally.
Threading Model
---------------
Retro uses subroutine threading with inline machine code for
select words. This model has been used by Retro since 2001
as it is simple, clean, and allows for optimization to be
done by the compiler if desired.
Taking a look at the subroutine threaded code generated by
Retro:
::
: foo 1 2 + . ;
Will compile to:
::
lit 1
lit 2
+
call .
;
Simple operations that map to single instructions can
(optionally) be inlined by the Retro compiler, saving
some call/return overhead. Other optimizations are also
possible.
Interpreting and Compiling
--------------------------
Retro has a very simple intepreter loop.
::
: listen ( - )
repeat ok 32 # accept search word? number? again ;
This displays a prompt (**ok**), accepts input until a space
is encountered (ASCII 32). The dictionary is searched, and if
the word is found, **word?** calls the class handler for the
word. If not found, **number?** tries to convert it to a
number. If this fails as well, an error is displayed. In any
case, exection repeats until a fatal error arises, or until
the user executes **bye**.
There is no separate compilation process. In Retro, the
**compiler** is nothing more than a state variable that the
*word classes* use to decide what to do with a word.
Word Classes
------------
As mentioned above, the interpreter loop (**listen**) passes
the words (and also data elements like numbers) to something
called a *word class*.
This is another area in which Retro's implementation differs
from standard Forths. The word class approach was created by
Helmar Wodtke and allows for the interpreter and compiler to
be extremely clean by allowing special words (*class handlers*)
to handle different types of words.
This means that the interpreter loop does not need to be
aware of the type a word has, or of any aspect of the system
state.
The standard Retro language has four classes defined.
+-----------+------------+-----------------------------------------+
| Name | Data Stack | Address Stack |
+===========+============+=========================================+
| .forth | a - | ``-`` |
+-----------+------------+-----------------------------------------+
| If interpreting, call the word. If compiling, compile a call |
| to the word. |
+-----------+------------+-----------------------------------------+
| .macro | a - | ``-`` |
+-----------+------------+-----------------------------------------+
| Always call the word. This is normally used for words that lay |
| down custom code at compile time, or which need to have |
| different behaviors during compilation. |
+-----------+------------+-----------------------------------------+
| .compiler | a - | ``-`` |
+-----------+------------+-----------------------------------------+
| Call the word when the compiler is on. If compiler is off, do |
| nothing. |
+-----------+------------+-----------------------------------------+
| .data | a - | ``-`` |
+-----------+------------+-----------------------------------------+
| If interpreting, leave the address on the stack. If compiling, |
| compile the address into the target definition as a literal. |
+-----------+------------+-----------------------------------------+
In addition to the three core classes, it is possible to create your
own classes. As an example, we'll create a class for naming and
displaying strings. Our class has the following behavior:
- If interpreting, display the string
- If compiling, lay down the code needed to display the
string
Retro has a convention of using a . as the first character of a
class name. In continuing this tradition, we'll call our new
class **.string**
Tip:
On entry to a class, the address of the word or data
structure is on the stack. The compiler state (which most
classes will need to check) is in a variable named compiler.
A first step is to lay down a simple skeleton. Since we need to
lay down custom code at compile time, the class handler will
have two parts.
::
: .string ( a—)
compiler @ 0 =if ( interpret time ) ;; then ( compile time )
;
We'll start with the interpret time action. We can replace this
with type, since the whole point of this class is to display a
string object.
::
: .string ( a — )
compiler @ 0 =if type ;; then ( compile time ) ;
The compile time action is more complex. We need to lay down
the machine code to leave the address of the string on the
stack when the word is run, and then compile a call to type. If
you look at the instruction set listing, you'll see that opcode
1 is the instruction for putting values on the stack. This
opcode takes a value from the following memory location and
puts it on the stack. So the first part of the compile time
action is:
::
: .string ( a — )
compiler @ 0 =if type ;; then 1 , , ;
Tip:
Use **,** to place values directly into memory. This is the
cornerstone of the entire compiler.
One more thing remains. We still have to compile a call to
type. We can do this by passing the address of type to
compile.
::
: .string ( a — )
compiler @ 0 =if type ;; then 1 , , ['] type compile ;
And now we have a new class handler. The second part is to use
the new class.
Tip:
New dictionary entries are made using create. The class can
be set after creation by accessing the proper fields in the
dictionary header. Words starting with **d->** are used to access
fields in the dictionary headers.
::
: displayString: ( "name" — )
create ['] .string reclass keepString last @ d->xt ! ;
This uses **create** to make a new word, then sets the class to
**.string** and the xt of the word to the string. It also makes the
string permanent using keepString. last is a variable pointing
to the most recently created dictionary entry. The words **d->class**,
**d->xt**, and **d->name** are dictionary field accessors and are used
to provide portable access to fields in the dictionary.
We can now test the new class:
::
" hello, world!" displayString: hello
hello
: foo hello cr ;
foo
Vectors
-------
Vectors are another important concept in Retro.
Most Forth systems provide a way to define a word which can
have its meaning altered later. Retro goes a step further by
allowing all words defined using **:** to be redefined. Words
which can be redefined are called *vectors*.
Vectors can be replaced by using **is**, or returned to their
original definition with **devector**. For instance:
::
: foo 23 . ;
foo
: bar 99 . ;
' bar is foo
foo
devector foo
foo
There are also variations of **is** and **devector** which take the
addresses of the words rather than parsing for the word name.
These are **:is** and **:devector**.
I/O Devices
-----------
Retro runs on a portable virtual machine. This machine provides a
few I/O devices that can be accessed.
- keyboard
- text display
- graphical canvas
- mouse
Please note that the only target currently supporting the canvas and
mouse is *javascript*.
When talking to an I/O device, set the stack as instructed, then
write a value to the port using **out**. You then **wait**, and,
depending on the device, may *read* a value back.
+-----------+------------+-----------------------------------------+
| Port | Send | Stack Effect |
+===========+============+=========================================+
| 0 | 0 | ``-`` |
+-----------+------------+-----------------------------------------+
| Tell the computer that an I/O request has been made. This is done|
| by **wait**. |
+-----------+------------+-----------------------------------------+
| 1 | 1 | ``-`` |
+-----------+------------+-----------------------------------------+
| Wait for a keypress. Read this port after a **wait** to get the |
| key. |
+-----------+------------+-----------------------------------------+
| 2 | 1 | ``c-`` |
+-----------+------------+-----------------------------------------+
| Display a character. Put the character on the stack, then |
| **wait**. |
+-----------+------------+-----------------------------------------+
| 3 | 0 | ``-`` |
+-----------+------------+-----------------------------------------+
| Send 0 to force a video update. This does not require **wait** |
+-----------+------------+-----------------------------------------+
| 4 | 1 | ``-`` |
+-----------+------------+-----------------------------------------+
| Save the image. |
+-----------+------------+-----------------------------------------+
| 5 | See Notes | ``-`` |
+-----------+------------+-----------------------------------------+
| This is the capabilities query port. An image can use this to |
| check the hardware supported by the VM. |
| |
| Send one of the following, **wait**, then read back to get the |
| result. |
| |
| - -1 : Amount of memory provided |
| - -2 : Is Canvas present? 0 if not, -1 if yes |
| - -3 : Canvas Width |
| - -4 : Canvas Height |
| - -5 : Stack Depth |
| - -6 : Address Stack Depth |
| - -7 : Is Mouse supported? 0 if not, -1 if yes |
+-----------+------------+-----------------------------------------+
| 6 | See Notes | See Notes |
+-----------+------------+-----------------------------------------+
| This is the canvas display driver. It has multiple operations. |
| |
| - 1 : n- : Change color |
| - 2 : xy- : Set pixel |
| - 3 : xyhw- : Draw a rectangle |
| - 4 : xyhw- : Draw a solid rectangle |
| - 5 : xyh- : Draw a vertical line |
| - 6 : xyw- : Draw a horizontal line |
| - 7 : xyw- : Draw a circle |
| - 8 : xyw- : Draw a solid circle |
+-----------+------------+-----------------------------------------+
| 7 | See Notes | See Notes |
+-----------+------------+-----------------------------------------+
| This is the mouse device. |
| |
| - 1 : -xy : Get mouse x, y coords |
| - 2 : -f : Get a flag indicating the up/down state of the button |
+-----------+------------+-----------------------------------------+
====================
Section 4: The Words
====================
Reading Stack Comments
----------------------
Stack comments in Retro are a compact form, using short codes
in place of actual words. These codes are listed in the next
section.
A typical comment for a word that takes two arguments and
leaves one will look like:
::
( xy-z )
In a few cases, words may consume or leave a variable number
of arguments. In this case, we denote it like:
::
( n-n || n- )
There are two other modifiers in use. Some words have different
compile-time and run-time stack use. We prefix the comment with
C: for compile-time, and R: for run-time actions.
If not specified, the stack comments are for runtime effects.
Words with no C: are assumed to have no stack impact during
compilation.
Codes used in the stack comments:
+------------+------------------------------------+
| x, y, z, n | Generic numbers |
+------------+------------------------------------+
| q, r | Quotient, Remainder (for division) |
+------------+------------------------------------+
| ``"`` * | Word parses for a string |
+------------+------------------------------------+
| a | Address |
+------------+------------------------------------+
| c | ASCII character |
+------------+------------------------------------+
| ``$`` | Zero-terminated string |
+------------+------------------------------------+
| f | Flag |
+------------+------------------------------------+
| ... | Variable number of values on stack |
+------------+------------------------------------+
List of Words by Class
----------------------
+--------------+--------------+------------+---------------+
| Name | Class | Data Stack | Address Stack |
+==============+==============+============+===============+
| 1+ | .word | x-y | |
+--------------+--------------+------------+---------------+
| Increment x by 1 |
+--------------+--------------+------------+---------------+
| 1- | .word | x-y | |
+--------------+--------------+------------+---------------+
| Decrement x by 1 |
+--------------+--------------+------------+---------------+
| swap | .word | xy-yx | |
+--------------+--------------+------------+---------------+
| Exchange the positions of the top two stack items |
+--------------+--------------+------------+---------------+
| drop | .word | xy-x | |
+--------------+--------------+------------+---------------+
| Remove the top item from the stack |
+--------------+--------------+------------+---------------+
| and | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Bitwise AND |
+--------------+--------------+------------+---------------+
| or | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Bitwise OR |
+--------------+--------------+------------+---------------+
| xor | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Bitwise XOR |
+--------------+--------------+------------+---------------+
| @ | .word | a-n | |
+--------------+--------------+------------+---------------+
| Fetch a value from an address |
+--------------+--------------+------------+---------------+
| ! | .word | na- | |
+--------------+--------------+------------+---------------+
| Store value n into address a |
+--------------+--------------+------------+---------------+
| ``+`` | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Add x to y |
+--------------+--------------+------------+---------------+
| ``-`` | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Subtract y from x |
+--------------+--------------+------------+---------------+
| ``*`` | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Multiply x and y |
+--------------+--------------+------------+---------------+
| /mod | .word | xy-qr | |
+--------------+--------------+------------+---------------+
| Divide x and y, getting the quotient and remainder |
+--------------+--------------+------------+---------------+
| << | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Shift x left by y bits |
+--------------+--------------+------------+---------------+
| >> | .word | xy-z | |
+--------------+--------------+------------+---------------+
| Shift x right by y bits |
+--------------+--------------+------------+---------------+
| nip | .word | xy-y | |
+--------------+--------------+------------+---------------+
| Drop the second item on the stack |
+--------------+--------------+------------+---------------+
| dup | .word | x-xx | |
+--------------+--------------+------------+---------------+
| Duplicate the top stack item |
+--------------+--------------+------------+---------------+
| in | .word | x-y | |
+--------------+--------------+------------+---------------+
| Read a value from an I/O port |
+--------------+--------------+------------+---------------+
| out | .word | xy- | |
+--------------+--------------+------------+---------------+
| Send a value to an I/O port |
+--------------+--------------+------------+---------------+
| here | .word | -a | |
+--------------+--------------+------------+---------------+
| Returns the next available address on the **heap** |
+--------------+--------------+------------+---------------+
| , | .word | n- | |
+--------------+--------------+------------+---------------+
| Store a byte to the next available address on the heap |
+--------------+--------------+------------+---------------+
| ] | .word | | |
+--------------+--------------+------------+---------------+
| Turn **compiler** on |
+--------------+--------------+------------+---------------+
| create | .word | "- | |
+--------------+--------------+------------+---------------+
| Create a new dictionary header with a class of **.data** |
| and have the address field point to **here** |
+--------------+--------------+------------+---------------+
| : | .word | "- | |
+--------------+--------------+------------+---------------+
| Create a new word with a class of **.word** and turn the |
| compiler on |
+--------------+--------------+------------+---------------+
| immediate | .word | | |
+--------------+--------------+------------+---------------+
| Set last defined word to .macro class |
+--------------+--------------+------------+---------------+
| compile-only | .word | | |
+--------------+--------------+------------+---------------+
| Set last defined word to .compiler class |
+--------------+--------------+------------+---------------+
| accept | .word | c- | |
+--------------+--------------+------------+---------------+
| Accept input until character *c* is found. Results are |
| stored in **tib** |
+--------------+--------------+------------+---------------+
| cr | .word | | |
+--------------+--------------+------------+---------------+
| Emit a newline character |
+--------------+--------------+------------+---------------+
| emit | .word | c- | |
+--------------+--------------+------------+---------------+
| Display an ASCII character on the screen |
+--------------+--------------+------------+---------------+
| type | .word | $- | |
+--------------+--------------+------------+---------------+
| Display a string on the screen |
+--------------+--------------+------------+---------------+
| clear | .word | | |
+--------------+--------------+------------+---------------+
| Clear the display |
+--------------+--------------+------------+---------------+
| words | .word | | |
+--------------+--------------+------------+---------------+
| Display a list of all words in the dictionary |
+--------------+--------------+------------+---------------+
| key | .word | -c | |
+--------------+--------------+------------+---------------+
| Read a single keypress |
+--------------+--------------+------------+---------------+
| over | .word | xy-xyx | |
+--------------+--------------+------------+---------------+
| Get a copy of the second item on the stack |
+--------------+--------------+------------+---------------+
| 2drop | .word | xy- | |
+--------------+--------------+------------+---------------+
| Drop the top two items from the stack |
+--------------+--------------+------------+---------------+
| not | .word | x-y | |
+--------------+--------------+------------+---------------+
| Logical NOT |
+--------------+--------------+------------+---------------+
| rot | .word | xyz-yzx | |
+--------------+--------------+------------+---------------+
| Shift the top three values around |
+--------------+--------------+------------+---------------+
| -rot | .word | xyz-xzy | |
+--------------+--------------+------------+---------------+
| **rot** twice |
+--------------+--------------+------------+---------------+
| tuck | .word | xy-yxy | |
+--------------+--------------+------------+---------------+
| Put a copy of TOS under the second item on the stack |
+--------------+--------------+------------+---------------+
| 2dup | .word | xy-xyxy | |
+--------------+--------------+------------+---------------+
| Duplicate the top two items on the stack |
+--------------+--------------+------------+---------------+
| on | .word | a- | |
+--------------+--------------+------------+---------------+
| Set a variable to -1 |
+--------------+--------------+------------+---------------+
| off | .word | a- | |
+--------------+--------------+------------+---------------+
| Set a variable to 0 |
+--------------+--------------+------------+---------------+
| / | .word | xy-q | |
+--------------+--------------+------------+---------------+
| Divide two numbers and get the quotient |
+--------------+--------------+------------+---------------+
| mod | .word | xy-r | |
+--------------+--------------+------------+---------------+
| Divide two numbers and get the remainder |
+--------------+--------------+------------+---------------+
| neg | .word | x-y | |
+--------------+--------------+------------+---------------+
| Invert the sign of x |
+--------------+--------------+------------+---------------+
| execute | .word | a- | |
+--------------+--------------+------------+---------------+
| Call a word by address |
+--------------+--------------+------------+---------------+
| " | .word | "-$ | |
+--------------+--------------+------------+---------------+
| Parse until " is encountered, returning a string |
+--------------+--------------+------------+---------------+
| compare | .word | $$-f | |
+--------------+--------------+------------+---------------+
| Compare two strings for equality |
+--------------+--------------+------------+---------------+
| wait | .word | | |
+--------------+--------------+------------+---------------+
| Wait for an I/O event. Normally used after **out** |
+--------------+--------------+------------+---------------+
| ' | .word | "-a | |
+--------------+--------------+------------+---------------+
| Parse for a word name and get the address of the word. |
| Inside a definition use **[']** instead. |
+--------------+--------------+------------+---------------+
| @+ | .word | a-an | |
+--------------+--------------+------------+---------------+
| Fetch a value from an address and return the next addrees|
| and the value fetched |
+--------------+--------------+------------+---------------+
| !+ | .word | na-a | |
+--------------+--------------+------------+---------------+
| Store a value to an address and return the next address |
+--------------+--------------+------------+---------------+
| +! | .word | na- | |
+--------------+--------------+------------+---------------+
| Add the value n to the contents of address a |
+--------------+--------------+------------+---------------+
| -! | .word | na- | |
+--------------+--------------+------------+---------------+
| Subtract the value n from the contents of address a |
+--------------+--------------+------------+---------------+
| :is | .word | aa- | |
+--------------+--------------+------------+---------------+
| Change the defintion of a word to call another word. Do |
| not use with **.data** elements |
+--------------+--------------+------------+---------------+
| :devector | .word | a- | |
+--------------+--------------+------------+---------------+
| Restore the original definition of a word. Not for use |
| with **.data** elements |
+--------------+--------------+------------+---------------+
| is | .word | a"- | |
+--------------+--------------+------------+---------------+
| Parse for a name and change its defintion to call the |
| specified address. Not for use with **.data** elements |
+--------------+--------------+------------+---------------+
| devector | .word | "- | |
+--------------+--------------+------------+---------------+
| Parse for a word name and restore it to the original |
| definition. Not for use with **.data** elements |
+--------------+--------------+------------+---------------+
| compile | .word | a- | |
+--------------+--------------+------------+---------------+
| Lay down the code to compile a call to a word |
+--------------+--------------+------------+---------------+
| literal, | .word | n- | |
+--------------+--------------+------------+---------------+
| Lay down the code to push a number to the stack |
+--------------+--------------+------------+---------------+
| tempString | .word | $-$ | |
+--------------+--------------+------------+---------------+
| Move a string to a temporary holding area away from the |
| **tib** |
+--------------+--------------+------------+---------------+
| redraw | .word | | |
+--------------+--------------+------------+---------------+
| If **update** is on, force a screen update. This is used |
| internally to improve performance of I/O operations. |
+--------------+--------------+------------+---------------+
| keepString | .word | $-$ | |
+--------------+--------------+------------+---------------+
| Move a string to a permanent storage area and return the |
| address |
+--------------+--------------+------------+---------------+
| getLength | .word | $-n | |
+--------------+--------------+------------+---------------+
| Return the length of a string |
+--------------+--------------+------------+---------------+
| bye | .word | | |
+--------------+--------------+------------+---------------+
| Exit Retro |
+--------------+--------------+------------+---------------+
| (remap-keys) | .word | c-c | |
+--------------+--------------+------------+---------------+
| Allows for handling and remapping odd key layouts to |
| something more sane. Called by **key** |
+--------------+--------------+------------+---------------+
| with-class | .word | aa- | |
+--------------+--------------+------------+---------------+
| Call an address using the specified class handler. This |
| can be revectored to allow tracking statistics or for |
| debugging purposes |
+--------------+--------------+------------+---------------+
| .word | .word | a- | |
+--------------+--------------+------------+---------------+
| Class handler for normal words |
+--------------+--------------+------------+---------------+
| .macro | .word | a- | |
+--------------+--------------+------------+---------------+
| Class handler for macros |
+--------------+--------------+------------+---------------+
| .compiler | .word | a- | |
+--------------+--------------+------------+---------------+
| Class handler for words that can only be called by the |
| compiler |
+--------------+--------------+------------+---------------+
| .data | .word | n- | |
+--------------+--------------+------------+---------------+
| Class handler for data elements |
+--------------+--------------+------------+---------------+
| d->class | .word | a-a | |
+--------------+--------------+------------+---------------+
| Given a dictionary header, return the class field |
+--------------+--------------+------------+---------------+
| d->xt | .word | a-a | |
+--------------+--------------+------------+---------------+
| Given a dictionary header, return the address field |
+--------------+--------------+------------+---------------+
| d->name | .word | a-a | |
+--------------+--------------+------------+---------------+
| Given a dictionary header, return the name field |
+--------------+--------------+------------+---------------+
| boot | .word | | |
+--------------+--------------+------------+---------------+
| A hook allowing for custom startup code in an image |
+--------------+--------------+------------+---------------+
| depth | .word | -n | |
+--------------+--------------+------------+---------------+
| Return the number of items on the stack |
+--------------+--------------+------------+---------------+
| reset | .word | ...- | |
+--------------+--------------+------------+---------------+
| Drop all items on the stack |
+--------------+--------------+------------+---------------+
| notfound | .word | | |
+--------------+--------------+------------+---------------+
| Called when a word is not found and conversion to a |
| number fails |
+--------------+--------------+------------+---------------+
| save | .word | | |
+--------------+--------------+------------+---------------+
| Save the image if the VM supports it, otherwise does |
| nothing |
+--------------+--------------+------------+---------------+
| >number | .word | $-n | |
+--------------+--------------+------------+---------------+
| Try to convert a string to a number |
+--------------+--------------+------------+---------------+
| ok | .word | | |
+--------------+--------------+------------+---------------+
| The "ok" prompt |
+--------------+--------------+------------+---------------+
| listen | .word | | |
+--------------+--------------+------------+---------------+
| The main interpreter loop |
+--------------+--------------+------------+---------------+
| s" | .macro | C: "- | |
| | | R: -$ | |
+--------------+--------------+------------+---------------+
| Parse until " is encounterd. Call **keepString** to move |
| the string to the permanent string table, and compile the|
| address of the string into the current definition |
+--------------+--------------+------------+---------------+
| [ | .macro | | |
+--------------+--------------+------------+---------------+
| Turn **compiler** off, but don't end the current |
| definition |
+--------------+--------------+------------+---------------+
| ; | .macro | | |
+--------------+--------------+------------+---------------+
| End the current definition and turn **compiler** off |
+--------------+--------------+------------+---------------+
| ;; | .macro | | |
+--------------+--------------+------------+---------------+
| Compile an exit to the word, but do not end the current |
| definiton |
+--------------+--------------+------------+---------------+
| =if | .macro | C: -a | |
| | | R: nn- | |
+--------------+--------------+------------+---------------+
| Compare two numbers for equality |
+--------------+--------------+------------+---------------+
| >if | .macro | C: -a | |
| | | R: nn- | |
+--------------+--------------+------------+---------------+
| Compare two numbers for greater than |
+--------------+--------------+------------+---------------+
| <if | .macro | C: -a | |
| | | R: nn- | |
+--------------+--------------+------------+---------------+
| Compare two numbers for less than |
+--------------+--------------+------------+---------------+
| !if | .macro | C: -a | |
| | | R: nn- | |
+--------------+--------------+------------+---------------+
| Compare two numbers for inequality |
+--------------+--------------+------------+---------------+
| then | .macro | C: a- | |
+--------------+--------------+------------+---------------+
| End a conditional |
+--------------+--------------+------------+---------------+
| repeat | .macro | C: -a | |
+--------------+--------------+------------+---------------+
| Begin an unconditional loop |
+--------------+--------------+------------+---------------+
| again | .macro | C: a- | |
+--------------+--------------+------------+---------------+
| End an unconditional loop. Branches back to the last |
| **repeat** |
+--------------+--------------+------------+---------------+
| 0; | .macro | R: n- | |
| | | R: n-n | |
+--------------+--------------+------------+---------------+
| If TOS is zero, exit the word and drop TOS. Otherwise it |
| leaves TOS alone and continues executing the word. This |
| is a lightweight control structure borrowed from |
| HerkForth |
+--------------+--------------+------------+---------------+
| push | .macro | R: n- | R: -n |
+--------------+--------------+------------+---------------+
| Move a value from the data stack to the address stack |
+--------------+--------------+------------+---------------+
| pop | .macro | R: -n | R: n- |
+--------------+--------------+------------+---------------+
| Move a value from the address stack to the data stack |
+--------------+--------------+------------+---------------+
| ['] | .macro | C: "- | |
| | | R: -n | |
+--------------+--------------+------------+---------------+
| Parse for a word name and compile the address of the word|
| into the current definition. |
+--------------+--------------+------------+---------------+
| for | .macro | C: -a | |
| | | R: n- | |
+--------------+--------------+------------+---------------+
| Begin a simple counted loop. Takes a count off the stack |
+--------------+--------------+------------+---------------+
| next | .macro | C: a- | |
+--------------+--------------+------------+---------------+
| End a simple counted loop. Decrements the counter by 1. |
| If 0, execute the rest of the word. Otherwise, jumps back|
| to the previous **for** |
+--------------+--------------+------------+---------------+
| ( | .macro | "- | |
+--------------+--------------+------------+---------------+
| Parse until ) is encounterd, ignoring everything. This is|
| used for comments. |
+--------------+--------------+------------+---------------+
| Holds Y coordinate for text output (framebuffer only) |
+--------------+--------------+------------+---------------+
| last | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds the address of the most recent dictionary header |
+--------------+--------------+------------+---------------+
| compiler | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds compiler state. 0 if off, -1 if on |
+--------------+--------------+------------+---------------+
| tib | .data | -a | |
+--------------+--------------+------------+---------------+
| The text input buffer |
+--------------+--------------+------------+---------------+
| update | .data | -a | |
+--------------+--------------+------------+---------------+
| Used by redraw, this allows for caching output to improve|
| performance. Set to 0 if no updates are waiting, or -1 |
| if something is ready to be drawn on the screen. |
+--------------+--------------+------------+---------------+
| fb | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds a flag indicating the presence of a canvas device |
+--------------+--------------+------------+---------------+
| fw | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds width of canvas |
+--------------+--------------+------------+---------------+
| fh | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds height of canvas |
+--------------+--------------+------------+---------------+
| #mem | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds the amount of memory provided by the VM. This may |
| or may not include the framebuffer memory, which can be |
| outside the normal range provided to a Retro image. |
+--------------+--------------+------------+---------------+
| heap | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds the address of the top of the heap. This can be |
| fetched using **here** |
+--------------+--------------+------------+---------------+
| which | .data | -a | |
+--------------+--------------+------------+---------------+
| Holds the address of the most recently looked up |
| dictionary header. |
+--------------+--------------+------------+---------------+
| whitespace | .data | -a | |
+--------------+--------------+------------+---------------+
| Flag indicting whether cr, lf, and tab should be remapped|
| to space. |
+--------------+--------------+------------+---------------+
| { | .word | | |
+--------------+--------------+------------+---------------+
| Start a local namespace |
+--------------+--------------+------------+---------------+
| } | .word | | |
+--------------+--------------+------------+---------------+
| Close a local namespace |
+--------------+--------------+------------+---------------+
| {{ | .word | | |
+--------------+--------------+------------+---------------+
| Start a mixed namespace |
+--------------+--------------+------------+---------------+
| ---reveal--- | .word | | |
+--------------+--------------+------------+---------------+
| Switch to global namespace |
+--------------+--------------+------------+---------------+
| }} | .word | | |
+--------------+--------------+------------+---------------+
| Close a mixed namespace |
+--------------+--------------+------------+---------------+
| allot | .word | n- | |
+--------------+--------------+------------+---------------+
| Allocate n cells of data |
+--------------+--------------+------------+---------------+
| variable: | .word | n"- | |
+--------------+--------------+------------+---------------+
| Create a variable with an initial value of n |
+--------------+--------------+------------+---------------+
| variable | .word | "- | |
+--------------+--------------+------------+---------------+
| Create a variable with an initial value of 0 |
+--------------+--------------+------------+---------------+
| constant | .word | n"- | |
+--------------+--------------+------------+---------------+
| Create a constant with a value of n |
+--------------+--------------+------------+---------------+
| ++ | .word | a- | |
+--------------+--------------+------------+---------------+
| Increment the value of a variable |
+--------------+--------------+------------+---------------+
| -- | .word | a- | |
+--------------+--------------+------------+---------------+
| Decrement a variable |
+--------------+--------------+------------+---------------+
| copy | .word | aan- | |
+--------------+--------------+------------+---------------+
| Copy n cells from source to dest |
+--------------+--------------+------------+---------------+
| fill | .word | ann- | |
+--------------+--------------+------------+---------------+
| Takes an address, a value, and a count and fills count |
| cells of memory starting at address with a value |
+--------------+--------------+------------+---------------+
| `\`` | .macro | "- | |
+--------------+--------------+------------+---------------+
| Replaces these forms: |
| :: |
| |
| ` wordname = ['] wordname compile |
| ` wordname = ['] wordname execute |
| ` number = number literal, |
+--------------+--------------+------------+---------------+
| ." | .macro | "- | |
+--------------+--------------+------------+---------------+
| Parse until " and display the string. If compiling, lay |
| down the code to display the string. |
+--------------+--------------+------------+---------------+
| TRUE | .word | -f | |
+--------------+--------------+------------+---------------+
| Return -1 |
+--------------+--------------+------------+---------------+
| FALSE | .word | -f | |
+--------------+--------------+------------+---------------+
| Return 0 |
+--------------+--------------+------------+---------------+
| if | .macro | C: -a | |
| | | R: f- | |
+--------------+--------------+------------+---------------+
| Start a conditional. Execute if flag is TRUE |
+--------------+--------------+------------+---------------+
| ;then | .macro | C: a- | |
+--------------+--------------+------------+---------------+
| Same as **;; then** |
+--------------+--------------+------------+---------------+
| = | .word | nn-f | |
+--------------+--------------+------------+---------------+
| Check for equality |
+--------------+--------------+------------+---------------+
| > | .word | nn-f | |
+--------------+--------------+------------+---------------+
| Check for greater than |
+--------------+--------------+------------+---------------+
| < | .word | nn-f | |
+--------------+--------------+------------+---------------+
| Check for less than |
+--------------+--------------+------------+---------------+
| <> | .word | nn-f | |
+--------------+--------------+------------+---------------+
| Check for inequality |
+--------------+--------------+------------+---------------+
| pow | .word | bp-n | |
+--------------+--------------+------------+---------------+
| Raise b to power of p |
+--------------+--------------+------------+---------------+
| r | .macro | -n | |
+--------------+--------------+------------+---------------+
| Get a copy of the TORS |
+--------------+--------------+------------+---------------+
| forget | .word | "- | |
+--------------+--------------+------------+---------------+
| Parse a word name, and remove that word and all words |
| defined after it from memory |
+--------------+--------------+------------+---------------+
| see | .word | "- | |
+--------------+--------------+------------+---------------+
| Decompile a word back to source. Parses for a word name, |
| then attempts to detect the end of the word. May display |
| the dictionary header for the following word as well. |
+--------------+--------------+------------+---------------+
| s | .word | n- | |
+--------------+--------------+------------+---------------+
| Select a new block |
+--------------+--------------+------------+---------------+
| p | .word | | |
+--------------+--------------+------------+---------------+
| Go back one block |
+--------------+--------------+------------+---------------+
| n | .word | | |
+--------------+--------------+------------+---------------+
| Advance to the next block |
+--------------+--------------+------------+---------------+
| ia | .word | cl"- | |
+--------------+--------------+------------+---------------+
| Insert text into block at line l, starting at column c |
+--------------+--------------+------------+---------------+
| i | .word | n"- | |
+--------------+--------------+------------+---------------+
| Insert text into block at line n, starting at column 0 |
+--------------+--------------+------------+---------------+
| x | .word | | |
+--------------+--------------+------------+---------------+
| Delete the current block |
+--------------+--------------+------------+---------------+
| d | .word | n- | |
+--------------+--------------+------------+---------------+
| Delete line n from current block |
+--------------+--------------+------------+---------------+
| v | .word | | |
+--------------+--------------+------------+---------------+
| View the current block |
+--------------+--------------+------------+---------------+
| e | .word | | |
+--------------+--------------+------------+---------------+
| Evaluate current block |
+--------------+--------------+------------+---------------+
| new | .word | | |
+--------------+--------------+------------+---------------+
| Delete all blocks |
+--------------+--------------+------------+---------------+
| set-blocks | .word | n- | |
+--------------+--------------+------------+---------------+
| Initialize the block array to n blocks, then calls "new" |
+--------------+--------------+------------+---------------+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment