retroforth/RETRO-Book.html
crc fef474b553 book: fix startup description for -c (now -i,c)
FossilOrigin-Name: 1eb3cb8402f8b572a94d10bad8132327990cdc90e4f34535b944f8a7f881cc58
2019-04-29 16:29:52 +00:00

3205 lines
119 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RETRO Handbook</title>
<link rel="stylesheet" href="https://stackedit.io/style.css" />
</head>
<body class="stackedit">
<div class="stackedit__left">
<div class="stackedit__toc">
<ul>
<li><a href="#retro-a-modern-pragmatic-forth">RETRO: a Modern, Pragmatic Forth</a></li>
<li><a href="#obtaining-retro">Obtaining RETRO</a>
<ul>
<li><a href="#stable-releases">Stable Releases</a></li>
<li><a href="#snapshots">Snapshots</a></li>
<li><a href="#repository">Repository</a></li>
</ul>
</li>
<li><a href="#building-retro-on-bsd">Building RETRO on BSD</a>
<ul>
<li><a href="#requirements">Requirements</a></li>
<li><a href="#process">Process</a></li>
<li><a href="#executables">Executables</a></li>
</ul>
</li>
<li><a href="#building-retro-on-linux">Building RETRO on Linux</a>
<ul>
<li><a href="#requirements-1">Requirements</a></li>
<li><a href="#process-1">Process</a></li>
<li><a href="#executables-1">Executables</a></li>
</ul>
</li>
<li><a href="#building-retro-on-macos">Building RETRO on macOS</a>
<ul>
<li><a href="#requirements-2">Requirements</a></li>
<li><a href="#process-2">Process</a></li>
<li><a href="#executables-2">Executables</a></li>
</ul>
</li>
<li><a href="#building-retro-on-windows">Building RETRO on Windows</a>
<ul>
<li><a href="#setup-build-environment">Setup Build Environment</a></li>
<li><a href="#prepare-source">Prepare Source</a></li>
<li><a href="#build">Build</a></li>
</ul>
</li>
<li><a href="#starting-retro">Starting RETRO</a>
<ul>
<li><a href="#interactive">Interactive</a></li>
<li><a href="#using-in-a-pipe">Using In a Pipe</a></li>
<li><a href="#running-a-program-in-a-file">Running A Program In A File</a></li>
<li><a href="#scripting">Scripting</a></li>
<li><a href="#command-line-arguments">Command Line Arguments</a></li>
</ul>
</li>
<li><a href="#basic-interactions">Basic Interactions</a></li>
<li><a href="#syntax">Syntax</a>
<ul>
<li><a href="#tokens">Tokens</a></li>
<li><a href="#prefixes">Prefixes</a></li>
<li><a href="#word-classes">Word Classes</a></li>
</ul>
</li>
<li><a href="#a-quick-tutorial">A Quick Tutorial</a></li>
<li><a href="#using-the-glossary">Using The Glossary</a>
<ul>
<li><a href="#example-entry">Example Entry</a></li>
<li><a href="#reading-the-entry">Reading The Entry</a></li>
<li><a href="#access-online">Access Online</a></li>
</ul>
</li>
<li><a href="#programming-techniques">Programming Techniques</a></li>
<li><a href="#unu-simple-literate-source-files">Unu: Simple, Literate Source Files</a></li>
<li><a href="#naming-conventions">Naming Conventions</a>
<ul>
<li><a href="#general-guidelines">General Guidelines</a></li>
<li><a href="#typical-format">Typical Format</a></li>
<li><a href="#case">Case</a></li>
<li><a href="#namespaces">Namespaces</a></li>
<li><a href="#tips">Tips</a></li>
</ul>
</li>
<li><a href="#stack-diagrams">Stack Diagrams</a></li>
<li><a href="#word-classes-1">Word Classes</a>
<ul>
<li><a href="#how-it-works">How It Works</a></li>
<li><a href="#using-classes">Using Classes</a></li>
</ul>
</li>
<li><a href="#using-combinators">Using Combinators</a>
<ul>
<li><a href="#types-of-combinators">Types of Combinators</a></li>
<li><a href="#compositional">Compositional</a></li>
<li><a href="#execution-flow">Execution Flow</a></li>
<li><a href="#data-flow">Data Flow</a></li>
</ul>
</li>
<li><a href="#the-stacks">The Stacks</a>
<ul>
<li><a href="#data-stack">Data Stack</a></li>
<li><a href="#address-stack">Address Stack</a></li>
<li><a href="#floating-point-stack">Floating Point Stack</a></li>
<li><a href="#tips-2">Tips</a></li>
<li><a href="#notes">Notes</a></li>
</ul>
</li>
<li><a href="#working-with-arrays">Working With Arrays</a>
<ul>
<li><a href="#namespace">Namespace</a></li>
<li><a href="#creating-arrays">Creating Arrays</a></li>
<li><a href="#accessing-elements">Accessing Elements</a></li>
<li><a href="#find-the-length">Find The Length</a></li>
<li><a href="#duplicate">Duplicate</a></li>
<li><a href="#filtering">Filtering</a></li>
<li><a href="#mapping">Mapping</a></li>
<li><a href="#reduce">Reduce</a></li>
<li><a href="#search">Search</a></li>
</ul>
</li>
<li><a href="#working-with-a-buffer">Working With a Buffer</a>
<ul>
<li><a href="#namespace-1">Namespace</a></li>
<li><a href="#implementation">Implementation</a></li>
<li><a href="#limitations">Limitations</a></li>
<li><a href="#set-the-active-buffer">Set The Active Buffer</a></li>
<li><a href="#add-value">Add Value</a></li>
<li><a href="#fetch-last-value">Fetch Last Value</a></li>
<li><a href="#get-data-about-the-buffer">Get Data About The Buffer</a></li>
<li><a href="#reset">Reset</a></li>
<li><a href="#example">Example</a></li>
</ul>
</li>
<li><a href="#working-with-characters">Working With Characters</a>
<ul>
<li><a href="#prefix">Prefix</a></li>
<li><a href="#namespace-2">Namespace</a></li>
<li><a href="#classification">Classification</a></li>
<li><a href="#conversions">Conversions</a></li>
<li><a href="#io">I/O</a></li>
</ul>
</li>
<li><a href="#working-with-the-dictionary">Working With The Dictionary</a>
<ul>
<li><a href="#namespace-3">Namespace</a></li>
<li><a href="#variables">Variables</a></li>
<li><a href="#header-structure">Header Structure</a></li>
<li><a href="#accessing-fields">Accessing Fields</a></li>
<li><a href="#shortcuts-for-the-latest-header">Shortcuts For The Latest Header</a></li>
<li><a href="#adding-headers">Adding Headers</a></li>
<li><a href="#searching">Searching</a></li>
<li><a href="#iteration">Iteration</a></li>
<li><a href="#listing-words">Listing Words</a></li>
</ul>
</li>
<li><a href="#working-with-floating-point">Working With Floating Point</a>
<ul>
<li><a href="#prefix-1">Prefix</a></li>
<li><a href="#namespace-4">Namespace</a></li>
<li><a href="#operation">Operation</a></li>
<li><a href="#constants">Constants</a></li>
<li><a href="#comparisons">Comparisons</a></li>
<li><a href="#basic-math">Basic Math</a></li>
<li><a href="#geometry">Geometry</a></li>
<li><a href="#storage-and-retrieval">Storage and Retrieval</a></li>
<li><a href="#io-1">I/O</a></li>
<li><a href="#encoded-values">Encoded Values</a></li>
</ul>
</li>
<li><a href="#working-with-numbers">Working With Numbers</a>
<ul>
<li><a href="#token-prefix">Token Prefix</a></li>
<li><a href="#namespace-5">Namespace</a></li>
</ul>
</li>
<li><a href="#working-with-pointers">Working With Pointers</a>
<ul>
<li><a href="#prefix-2">Prefix</a></li>
<li><a href="#examples">Examples</a></li>
<li><a href="#notes-1">Notes</a></li>
</ul>
</li>
<li><a href="#working-with-strings">Working With Strings</a>
<ul>
<li><a href="#prefix-3">Prefix</a></li>
<li><a href="#namespace-6">Namespace</a></li>
<li><a href="#lifetime">Lifetime</a></li>
<li><a href="#mutability">Mutability</a></li>
<li><a href="#searching-1">Searching</a></li>
<li><a href="#comparisons-1">Comparisons</a></li>
<li><a href="#extraction">Extraction</a></li>
<li><a href="#joining">Joining</a></li>
<li><a href="#tokenization">Tokenization</a></li>
<li><a href="#conversions-1">Conversions</a></li>
<li><a href="#cleanup">Cleanup</a></li>
<li><a href="#combinators">Combinators</a></li>
<li><a href="#other">Other</a></li>
<li><a href="#controlling-the-temporary-buffers">Controlling The Temporary Buffers</a></li>
</ul>
</li>
<li><a href="#working-with-assembly-language">Working With Assembly Language</a>
<ul>
<li><a href="#assembling-a-standalone-file">Assembling A Standalone File</a></li>
<li><a href="#runtime-assembler">Runtime Assembler</a></li>
</ul>
</li>
<li><a href="#lexical-scope">Lexical Scope</a>
<ul>
<li><a href="#example-1">Example</a></li>
<li><a href="#notes-2">Notes</a></li>
</ul>
</li>
<li><a href="#internals">Internals</a></li>
<li><a href="#internals-nga-virtual-machine">Internals: Nga Virtual Machine</a>
<ul>
<li><a href="#overview">Overview</a></li>
<li><a href="#instrution-table">Instrution Table</a></li>
<li><a href="#encoding">Encoding</a></li>
<li><a href="#shifts">Shifts</a></li>
<li><a href="#queries-memory-stacks">Queries: Memory, Stacks</a></li>
<li><a href="#io-devices">I/O Devices</a></li>
<li><a href="#trivia">Trivia</a></li>
</ul>
</li>
<li><a href="#internals-interface-layers">Internals: Interface Layers</a></li>
<li><a href="#internals-the-retro-image">Internals: The Retro Image</a>
<ul>
<li><a href="#format">Format</a></li>
<li><a href="#header">Header</a></li>
<li><a href="#layout">Layout</a></li>
</ul>
</li>
<li><a href="#additional-tools">Additional Tools</a>
<ul>
<li><a href="#retro">retro</a></li>
<li><a href="#retro-describe">retro-describe</a></li>
<li><a href="#retro-embedimage">retro-embedimage</a></li>
<li><a href="#retro-extend">retro-extend</a></li>
<li><a href="#retro-muri">retro-muri</a></li>
<li><a href="#retro-unu">retro-unu</a></li>
</ul>
</li>
<li><a href="#advanced-builds">Advanced Builds</a>
<ul>
<li><a href="#reduced-memory">Reduced Memory</a></li>
<li><a href="#custom-image">Custom Image</a></li>
</ul>
</li>
<li><a href="#the-optional-retro-compiler">The Optional Retro Compiler</a>
<ul>
<li><a href="#requirements-3">Requirements</a></li>
<li><a href="#building">Building</a></li>
<li><a href="#installing">Installing</a></li>
<li><a href="#using">Using</a></li>
<li><a href="#known-limitations">Known Limitations</a></li>
</ul>
</li>
<li><a href="#errors">Errors</a>
<ul>
<li><a href="#non-fatal">Non-Fatal</a></li>
<li><a href="#fatal">Fatal</a></li>
<li><a href="#rationale">Rationale</a></li>
</ul>
</li>
<li><a href="#security-concerns">Security Concerns</a>
<ul>
<li><a href="#runtime-checks">Runtime Checks</a></li>
<li><a href="#isolation">Isolation</a></li>
<li><a href="#future-direction">Future Direction</a></li>
<li><a href="#rationale-1">Rationale</a></li>
</ul>
</li>
<li><a href="#technical-notes-and-reflections">Technical Notes and Reflections</a>
<ul>
<li><a href="#metacompilation-and-assembly">Metacompilation and Assembly</a></li>
<li><a href="#the-path-to-self-hosting">The Path to Self Hosting</a></li>
<li><a href="#prefixes-as-a-language-element">Prefixes as a Language Element</a></li>
<li><a href="#on-the-kernel-wordset">On The Kernel Wordset</a></li>
<li><a href="#on-the-evolution-of-ngaro-into-nga">On The Evolution Of Ngaro Into Nga</a></li>
<li><a href="#retro-11-2011---2019-a-look-back">RETRO 11 (2011 - 2019): A Look Back</a></li>
</ul>
</li>
<li><a href="#historical-papers-and-notes">Historical Papers and Notes</a>
<ul>
<li><a href="#on-the-naming-of-retro">On the Naming of RETRO</a></li>
<li><a href="#the-design-philosophy-of-retro-native-forth">The Design Philosophy of RETRO Native Forth</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div class="stackedit__right">
<div class="stackedit__html">
<h1 id="retro-a-modern-pragmatic-forth">RETRO: a Modern, Pragmatic Forth</h1>
<p>Welcome to RETRO, my personal take on the Forth language. This<br>
is a modern system primarily targetting desktop, mobile, and<br>
servers, though it can also be used on some larger (ARM, MIPS32)<br>
embedded systems.</p>
<p>The language is Forth. It is untyped, uses a stack to pass data<br>
between functions called words, and a dictionary which tracks<br>
the word names and data structures.</p>
<p>But its not a traditional Forth. RETRO draws influences from<br>
many sources and takes a unique approach to the language.</p>
<p>RETRO has a large vocabulary of words. Keeping a copy of the<br>
Glossary on hand is highly recommended as you learn to use RETRO.</p>
<p>This book will hopefully help you develop a better understanding<br>
of RETRO and how it works.</p>
<h1 id="obtaining-retro">Obtaining RETRO</h1>
<p>The RETRO source code can be obtained from <a href="http://forthworks.com/retro">http://forthworks.com/retro</a><br>
or gopher://forthworks.com/1/retro</p>
<h2 id="stable-releases">Stable Releases</h2>
<p>I periodically make stable releases. This will typically happen<br>
two to four times per year. These are good for those needing a<br>
solid base that doesnt change frequently.</p>
<h2 id="snapshots">Snapshots</h2>
<p>A lot of development happens between releases. I make snapshots<br>
of my working source tree nightly (and often more often).</p>
<p>This is what I personally recommend for most users. It reflects<br>
my latest system and is normally reliable as its used daily in<br>
production.</p>
<p>The latest snapshot can be downloaded from the following stable<br>
URLs:</p>
<ul>
<li><a href="http://forthworks.com/retro/r/latest.tar.gz">http://forthworks.com/retro/r/latest.tar.gz</a></li>
<li>gopher://forthworks.com/9/retro/r/latest.tar.gz</li>
</ul>
<h2 id="repository">Repository</h2>
<p>I use a Fossil repository to manage development. To obtain a<br>
copy of the repository install Fossil and:</p>
<pre><code>fossil clone http://forthworks.com:8000 retro.fossil
mkdir retro
cd retro
fossil open /path/to/retro.fossil
</code></pre>
<p>See the Fossil documentation for details on using Fossil to<br>
keep your local copy of the repository current.</p>
<p>This will let you stay current with my latest changes faster<br>
than the snapshots, but you may occasionally encounter bigger<br>
problems as some commits may be in a partially broken state.</p>
<p>If you have problems, check the version of Fossil you are<br>
using. I am currently using Fossil 2.7, you may experience<br>
issues checking out or cloning if using older versions.</p>
<h1 id="building-retro-on-bsd">Building RETRO on BSD</h1>
<p>RETRO is well supported on BSD (FreeBSD, NetBSD, OpenBSD)<br>
systems. It should build on a base install of any of these<br>
without issue.</p>
<h2 id="requirements">Requirements</h2>
<ul>
<li>c compiler</li>
<li>make</li>
</ul>
<h2 id="process">Process</h2>
<p>Run <code>make</code></p>
<p>This will build the toolchain and then the main <code>retro</code><br>
executable.</p>
<h2 id="executables">Executables</h2>
<p>In the <code>bin/</code> directory:</p>
<pre><code>retro
retro-unu
retro-muri
retro-extend
retro-embedimage
retro-describe
</code></pre>
<h1 id="building-retro-on-linux">Building RETRO on Linux</h1>
<p>Building on Linux is pretty easy. Youll need to make sure<br>
you have a C compiler, headers, and make.</p>
<h2 id="requirements-1">Requirements</h2>
<ul>
<li>c compiler (tested: clang, tcc, gcc)</li>
<li>development headers</li>
<li>make</li>
</ul>
<h2 id="process-1">Process</h2>
<p>Run:</p>
<pre><code>make -f Makefile.linux
</code></pre>
<p>This will build the toolchain and then the main <code>retro</code><br>
executable.</p>
<h2 id="executables-1">Executables</h2>
<p>In the <code>bin/</code> directory:</p>
<pre><code>retro
retro-unu
retro-muri
retro-extend
retro-embedimage
retro-describe
</code></pre>
<h1 id="building-retro-on-macos">Building RETRO on macOS</h1>
<p>To build on macOS, you will need the command line tools from<br>
Xcode. Install these and you should be able to build and use<br>
RETRO.</p>
<h2 id="requirements-2">Requirements</h2>
<ul>
<li>command line tools from Xcode</li>
</ul>
<h2 id="process-2">Process</h2>
<p>Run <code>make</code></p>
<p>This will build the toolchain and then the main <code>retro</code><br>
executable.</p>
<h2 id="executables-2">Executables</h2>
<p>In the <code>bin/</code> directory:</p>
<pre><code>retro
retro-unu
retro-muri
retro-extend
retro-embedimage
</code></pre>
<h1 id="building-retro-on-windows">Building RETRO on Windows</h1>
<p>It is possible to build RETRO on Windows, though a few of the<br>
extensions are not supported:</p>
<ul>
<li>no <code>unix:</code> words</li>
<li>no <code>gopher:</code> words</li>
</ul>
<p>This is currently more difficult than on a Unix host. If you have<br>
Windows 10 and WSL, it may be better to build under that (using<br>
the Linux instructions).</p>
<h2 id="setup-build-environment">Setup Build Environment</h2>
<p>RETRO on Windows is built with TCC.</p>
<p>Go to <a href="http://download.savannah.gnu.org/releases/tinycc/">http://download.savannah.gnu.org/releases/tinycc/</a></p>
<p>Download the <em>winapi-full</em> and <em>tcc-xxxx-bin</em> packages for your<br>
system. Decompress them, copy the headers from the winapi<br>
package into the tcc directory.</p>
<h2 id="prepare-source">Prepare Source</h2>
<p>Youll need to comment out (or remove) some things before RETRO<br>
will build.</p>
<p>In <em>rre.c</em>:</p>
<ul>
<li>remove includes for unistd.h, sys/sockets.h, netinet/in.h,<br>
netdb.h, errno.h, sys/wait.h, signal.h</li>
<li>remove the #define USE_TERMIOS line</li>
<li>change the #define NUM_DEVICES to 6</li>
<li>remove io_unix_handler and io_gopher_handler from IO_deviceHandlers</li>
<li>remove io_unix_query and io_gopher_query from IO_queryHandlers</li>
</ul>
<p>In <em>image-functions.c</em>:</p>
<ul>
<li>remove includes for unistd.h</li>
</ul>
<p>In <em>image-functions.h</em>:</p>
<ul>
<li>remove includes for unistd.h</li>
</ul>
<p>In <em>io\filesystem.c</em>:</p>
<ul>
<li>remove includes for unistd.h</li>
</ul>
<p>In <em>io\floatingpoint.c</em>:</p>
<ul>
<li>remove includes for unistd.h</li>
</ul>
<h2 id="build">Build</h2>
<p>\path\to\tcc rre.c image-functions.c io\filesystem.c io\floatingpoint.c -o retro.exe</p>
<h1 id="starting-retro">Starting RETRO</h1>
<p>RETRO can be run for scripting or interactive use.</p>
<h2 id="interactive">Interactive</h2>
<p>To start it interactively, run: <code>retro</code> without any command line<br>
arguments, or with <code>-i</code>, <code>-s</code>, or <code>-i,c</code>.</p>
<p>Starting the interactive system:</p>
<pre><code>retro
</code></pre>
<p>Or:</p>
<pre><code>retro -i
</code></pre>
<p>This should be sufficient for most uses.</p>
<p>Starting the interactive system (without displaying the <code>Ok</code><br>
prompt or startup banner):</p>
<pre><code>retro -s
</code></pre>
<p>RETRO also has a <em>character breaking</em> mode, in which input is<br>
processed directly as entered, this is started with the <code>-c</code><br>
option:</p>
<pre><code>retro -i,c
</code></pre>
<h2 id="using-in-a-pipe">Using In a Pipe</h2>
<p>If using a Unix shell and piping input between processes, you<br>
will probably want to use <code>-s</code> to supress the startup messages<br>
and <code>Ok</code> prompt that normally appear.</p>
<p>E.g.,</p>
<pre><code>echo "'lol s:put nl" | retro -s
</code></pre>
<h2 id="running-a-program-in-a-file">Running A Program In A File</h2>
<p>You can run code in a file very easily. This is simply:</p>
<pre><code>retro filename
</code></pre>
<p>You can follow the filename with any arguments that it may need.<br>
These will be accessible to the program via the <code>sys:argc</code> and<br>
<code>sys:argv</code> words.</p>
<p>Source files must be written in Unu format.</p>
<h2 id="scripting">Scripting</h2>
<p>You can use RETRO to write scripts. Add a shebang:</p>
<pre><code>#!/usr/bin/env retro
</code></pre>
<p>And make the file executable.</p>
<p>Source files must be written in Unu format.</p>
<h2 id="command-line-arguments">Command Line Arguments</h2>
<p>For a summary of the full command line arguments available:</p>
<pre><code>Scripting Usage:
retro filename [script arguments...]
Interactive Usage:
retro [-h] [-i] [-c] [-s] [-f filename] [-t]
-h Display this help text
-i Interactive mode (line buffered)
-c Interactive mode (character buffered)
-s Suppress the 'ok' prompt and keyboard
echo in interactive mode
-f filename Run the contents of the specified file
-t Run tests (in ``` blocks) in any loaded files
</code></pre>
<h1 id="basic-interactions">Basic Interactions</h1>
<p>Start RETRO in interactive mode:</p>
<pre><code>retro -i
</code></pre>
<p>You should see something similar to this:</p>
<pre><code>RETRO 12 (rx-2019.6)
8388608 MAX, TIB @ 1025, Heap @ 9374
Ok
</code></pre>
<p>At this point you are at the <em>listener</em>, which reads and<br>
processes your input. You are now set to begin exploring<br>
RETRO.</p>
<p>To exit, run <code>bye</code>:</p>
<pre><code>bye
</code></pre>
<h1 id="syntax">Syntax</h1>
<p>RETRO has more syntax than a traditional Forth due to ideas<br>
borrowed from ColorForth and some design decisions. This has<br>
some useful traits, and helps to make the language more<br>
consistent.</p>
<h2 id="tokens">Tokens</h2>
<p>Input is divided into a series of whitespace delimited tokens.<br>
Each of these is then processed individually. There are no<br>
parsing words in RETRO.</p>
<p>Tokens may have a single character <em>prefix</em>, which RETRO will<br>
use to decide how to process the token.</p>
<h2 id="prefixes">Prefixes</h2>
<p>Prefixes are single characters added to the start of a token<br>
to guide the compiler. The use of these is a major way in<br>
which RETRO differs from traditional Forth.</p>
<p>When a token is passed to <code>interpret</code>, RETRO first takes the<br>
intitial character and looks to see if there is a word that<br>
matches this. If so, it will pass the rest of the token to<br>
that word to handle.</p>
<p>In a traditional Forth, the interpret process is something<br>
like:</p>
<pre><code>get token
is token in the dictionary?
yes:
is it immediate?
yes: call the word.
no: are we interpreting?
yes: call the word
no: compile a call to the word
no:
is it a number?
yes: are we interpreting?
yes: push the number to the stack
no: compile the number as a literal
no: report an error ("not found")
</code></pre>
<p>In RETRO, the interpret process is basically:</p>
<pre><code>get token
does the first character match a `prefix:` word?
yes: pass the token to the prefix handler
no: is token a word in the dictionary?
yes: push the XT to the stack and call the
class handler
no: report an error ("not found")
</code></pre>
<p>All of the actual logic for how to deal with tokens is moved<br>
to the individual prefix handlers, and the logic for handling<br>
words is moved to word class handlers.</p>
<p>This means that prefixes are used for a lot of things. Numbers?<br>
Handled by a <code>#</code> prefix. Strings? Use the <code>'</code> prefix. Comments?<br>
Use <code>(</code>. Making a new word? Use the <code>:</code> prefix.</p>
<p>The major prefixes are:</p>
<table>
<thead>
<tr>
<th>Prefix</th>
<th>Used For</th>
</tr>
</thead>
<tbody>
<tr>
<td>@</td>
<td>Fetch from variable</td>
</tr>
<tr>
<td>!</td>
<td>Store into variable</td>
</tr>
<tr>
<td>&amp;</td>
<td>Pointer to named item</td>
</tr>
<tr>
<td>#</td>
<td>Numbers</td>
</tr>
<tr>
<td>$</td>
<td>ASCII characters</td>
</tr>
<tr>
<td></td>
<td>Strings</td>
</tr>
<tr>
<td>(</td>
<td>Comments</td>
</tr>
<tr>
<td>:</td>
<td>Define a word</td>
</tr>
</tbody>
</table><p>The individual prefixes will be covered in more detail in the<br>
later chapters on working with different data types.</p>
<h2 id="word-classes">Word Classes</h2>
<p>Word classes are words which take a pointer and do something<br>
with it. These are covered in detail in their own chapter,<br>
but essentially they decide <em>how</em> to execute or compile specific<br>
types of words.</p>
<h1 id="a-quick-tutorial">A Quick Tutorial</h1>
<p>Programming in RETRO is all about creating words to solve<br>
the problem at hand. Words operate on data, which can be<br>
kept in memory or on the stack.</p>
<p>Lets look at this by solving a small problem: writing a<br>
word to determine if a string is a palindrome.</p>
<p>A palindrome is a phrase which reads the same backward<br>
and forward.</p>
<p>We first need a string to look at. Starting with something<br>
easy:</p>
<pre><code>'anna
</code></pre>
<p>Looking in the Glossary, there is a <code>s:reverse</code> word for<br>
reversing a string. We can find <code>dup</code> to copy a value, and<br>
<code>s:eq?</code> to compare two strings. So testing:</p>
<pre><code>'anna dup s:reverse s:eq?
</code></pre>
<p>This yields -1 (<code>TRUE</code>) as expected. So we can easily<br>
name it:</p>
<pre><code>:palindrome dup s:reverse s:eq? ;
</code></pre>
<p>Naming uses the <code>:</code> prefix to add a new word to the dictionary.<br>
The words that make up the definition are then placed, with a<br>
final word (<code>;</code>) ending the definition. We can then use this:</p>
<pre><code>'anna palindrome?
</code></pre>
<p>Once defined there is no difference between our new word and<br>
any of the words already provided by the RETRO system.</p>
<h1 id="using-the-glossary">Using The Glossary</h1>
<p>The Glossary is a valuable resource. It provides information<br>
on the RETRO words.</p>
<h2 id="example-entry">Example Entry</h2>
<pre><code>f:+
Data: -
Addr: -
Float: FF-F
Add two floating point numbers, returning the result.
Class: class:word | Namespace: f | Interface Layer: rre
Example #1:
.3.1 .22 f:+
</code></pre>
<h2 id="reading-the-entry">Reading The Entry</h2>
<p>An entry starts with the word name.</p>
<p>This is followed by the stack effect for each stack. All RETRO<br>
systems have Data and Address stacks, some also include a<br>
floating point stack).</p>
<p>The stack effect diagrams are followed by a short description<br>
of the word.</p>
<p>After the description is a line providing some useful data. This<br>
includes the class handler, namespace prefix, and the interface<br>
layer that provides the word.</p>
<p>Words in all systems will be listed as <code>all</code>. Some words (like<br>
the <code>pb:</code> words) are only on specific systems like iOS. These<br>
can be identified by looking at the interface layer field.</p>
<p>At the end of the entry may be an example or two.</p>
<h2 id="access-online">Access Online</h2>
<p>The latest Glossary can be browsed at <a href="http://forthworks.com:9999">http://forthworks.com:9999</a><br>
or gopher://forthworks.com:9999</p>
<h1 id="programming-techniques">Programming Techniques</h1>
<p>The upcoming chapters provide helpful information on using RETRO<br>
with different types of data and hints on how to solve problems<br>
in a way consistent with the RETRO system.</p>
<h1 id="unu-simple-literate-source-files">Unu: Simple, Literate Source Files</h1>
<p>RETRO is written in a literate style. Most of the sources<br>
are in a format called Unu. This allows easy mixing of<br>
commentary and code blocks, making it simple to document<br>
the code.</p>
<p>As an example,</p>
<pre><code># Determine The Average Word Name Length
To determine the average length of a word name two values
are needed. First, the total length of all names in the
Dictionary:
~~~
#0 [ d:name s:length + ] d:for-each
~~~
And then the number of words in the Dictionary:
~~~
#0 [ drop n:inc ] d:for-each
~~~
With these, a simple division is all that's left.
~~~
/
~~~
Finally, display the results:
~~~
'Average_name_length:_%n\n s:format s:put
~~~
</code></pre>
<p>This illustrates the format. Only code in the fenced blocks<br>
(between ~~~ pairs) get extracted and run.</p>
<p>(Note: this only applies to <em>source files</em>; fences are not used<br>
when entering code interactively).</p>
<h1 id="naming-conventions">Naming Conventions</h1>
<p>Word names in RETRO generally follow the following conventions.</p>
<h2 id="general-guidelines">General Guidelines</h2>
<ul>
<li>Readability is important</li>
<li>Be consistent</li>
<li>Dont use a prefix as the first character of a name</li>
<li>Use short names for indices</li>
</ul>
<h2 id="typical-format">Typical Format</h2>
<p>The word names will generally follow a form like:</p>
<pre><code>[namespace:]name
</code></pre>
<p>The <code>namespace:</code> is optional, but recommended for consistency<br>
with the rest of the system and to make it easier to identify<br>
related words.</p>
<h2 id="case">Case</h2>
<p>Word names are lowercase, with a dash (-) for compound names.</p>
<pre><code>hello
drop-pair
s:for-each
</code></pre>
<p>Variables use TitleCase, with no dash between compound names.</p>
<pre><code>Base
Heap
StringBuffers
</code></pre>
<p>Constants are UPPERCASE, with a dash (-) for compound names.</p>
<pre><code>TRUE
FALSE
f:PI
MAX-STRING-LENGTH
</code></pre>
<h2 id="namespaces">Namespaces</h2>
<p>Words are grouped into broad namespaces by attaching a short<br>
prefix string to the start of a name.</p>
<p>The common namespaces are:</p>
<table>
<thead>
<tr>
<th>Prefix</th>
<th>Contains</th>
</tr>
</thead>
<tbody>
<tr>
<td>a:</td>
<td>Words operating on simple arrays</td>
</tr>
<tr>
<td>ASCII:</td>
<td>ASCII character constants for control characters</td>
</tr>
<tr>
<td>buffer:</td>
<td>Words for operating on a simple linear LIFO buffer</td>
</tr>
<tr>
<td>c:</td>
<td>Words for operating on ASCII character data</td>
</tr>
<tr>
<td>class:</td>
<td>Contains class handlers for words</td>
</tr>
<tr>
<td>d:</td>
<td>Words operating on the Dictionary</td>
</tr>
<tr>
<td>err:</td>
<td>Words for handling errors</td>
</tr>
<tr>
<td>io:</td>
<td>General I/O words</td>
</tr>
<tr>
<td>n:</td>
<td>Words operating on numeric data</td>
</tr>
<tr>
<td>prefix:</td>
<td>Contains prefix handlers</td>
</tr>
<tr>
<td>s:</td>
<td>Words operating on string data</td>
</tr>
<tr>
<td>v:</td>
<td>Words operating on variables</td>
</tr>
<tr>
<td>file:</td>
<td>File I/O words</td>
</tr>
<tr>
<td>f:</td>
<td>Floating Point words</td>
</tr>
<tr>
<td>gopher:</td>
<td>Gopher protocol words</td>
</tr>
<tr>
<td>unix:</td>
<td>Unix system call words</td>
</tr>
</tbody>
</table><h2 id="tips">Tips</h2>
<p>Avoid using a prefix as the first character of a word name. RETRO<br>
will look for prefixes first, this will prevent direct use of<br>
the work in question.</p>
<p>To find a list of prefix characters, do:</p>
<pre><code>'prefix: d:words-with
</code></pre>
<h1 id="stack-diagrams">Stack Diagrams</h1>
<p>Most words in RETRO have a stack comment. These look like:</p>
<pre><code>(-)
(nn-n)
</code></pre>
<p>As with all comments, a stack comment begins with <code>(</code> and<br>
should end with a <code>)</code>. There are two parts to the comment.<br>
On the left side of the <code>-</code> is what the word <em>consumes</em>. On<br>
the right is what it <em>leaves</em>.</p>
<p>RETRO uses a short notation, with one character per value<br>
taken or left. In general, the following symbols represent<br>
certain types of values.</p>
<table>
<thead>
<tr>
<th>Notation</th>
<th>Represents</th>
</tr>
</thead>
<tbody>
<tr>
<td>b, n, m, o, x, y, z</td>
<td>generic numeric values</td>
</tr>
<tr>
<td>s</td>
<td>string</td>
</tr>
<tr>
<td>v</td>
<td>variable</td>
</tr>
<tr>
<td>p, a</td>
<td>pointers</td>
</tr>
<tr>
<td>q</td>
<td>quotation</td>
</tr>
<tr>
<td>d</td>
<td>dictionary header</td>
</tr>
<tr>
<td>f</td>
<td><code>TRUE</code> or <code>FALSE</code> flag.</td>
</tr>
</tbody>
</table><p>In the case of something like <code>(xyz-m)</code>, RETRO expects z to be<br>
on the top of the stack, with y below it and x below the y<br>
value. And after execution, a single value (m) will be left on<br>
the stack.</p>
<p>Words with no stack effect have a comment of (-)</p>
<h1 id="word-classes-1">Word Classes</h1>
<p>Word classes are one of the two elements at the heart of<br>
RETROs interpreter.</p>
<p>There are different types of words in a Forth system. At a<br>
minimum there are data words, regular words, and immediate<br>
words. There are numerous approaches to dealing with this.</p>
<p>In RETRO I define special words which receive a pointer and<br>
decide how to deal with it. These are grouped into a <code>class:</code><br>
namespace.</p>
<h2 id="how-it-works">How It Works</h2>
<p>When a word is found in the dictionary, RETRO will push a<br>
pointer to the definition (the <code>d:xt</code> field) to the stack<br>
and then call the word specified by the <code>d:class</code> field.</p>
<p>The word called is responsible for processing the pointer<br>
passed to it.</p>
<p>As a simple case, lets look at <code>immediate</code> words. These are<br>
words which will always be called when encountered. A common<br>
strategy is to have an immediacy bit which the interpreter<br>
will look at, but RETRO uses a class for this. The class is<br>
defined:</p>
<pre><code>:class:immediate (a-) call ;
</code></pre>
<p>Or a normal word. These should be called at interpret time<br>
or compiled into definitions. The handler for this can look<br>
like:</p>
<pre><code>:class:word (a-) compiling? [ compile:call ] [ call ] choose ;
</code></pre>
<h2 id="using-classes">Using Classes</h2>
<p>The ability to add new classes is useful. If I wanted to add<br>
a category of word that preserves an input value, I could do<br>
it with a class:</p>
<pre><code>:class:duplicating (a-)
compiling? [ &amp;dup compile:call ] [ &amp;dup dip ] choose
class:word ;
:duplicating &amp;class:duplicating reclass ;
:. n:put nl ; duplicating
#100 . . .
</code></pre>
<h1 id="using-combinators">Using Combinators</h1>
<p>A combinator is a function that consumes functions as input.<br>
They are used heavily by the RETRO system.</p>
<h2 id="types-of-combinators">Types of Combinators</h2>
<p>Combinators are divided into three primary types: compositional,<br>
execution flow, and data flow.</p>
<h2 id="compositional">Compositional</h2>
<p>A compositional combinator takes elements from the stack and<br>
returns a new quote.</p>
<p><code>curry</code> takes a value and a quote and returns a new quote<br>
applying the specified quote to the specified value. As an<br>
example,</p>
<pre><code>:acc (n-) here swap , [ dup v:inc fetch ] curry ;
</code></pre>
<p>This would create an accumulator function, which takes an<br>
initial value and returns a quote that will increase the<br>
accumulator by 1 each time it is invoked. It will also return<br>
the latest value. So:</p>
<pre><code>#10 acc
dup call n:put
dup call n:put
dup call n:put
</code></pre>
<h2 id="execution-flow">Execution Flow</h2>
<p>Combinators of this type execute other functions.</p>
<h3 id="fundamental">Fundamental</h3>
<p><code>call</code> takes a quote and executes it immediately.</p>
<pre><code>[ #1 n:put ] call
&amp;words call
</code></pre>
<h3 id="conditionals">Conditionals</h3>
<p>RETRO provides three primary combinators for use with<br>
conditional execution of quotes. These are <code>choose</code>, <code>if</code>,<br>
and <code>-if</code>.</p>
<p><code>choose</code> takes a flag and two quotes from the stack. If the<br>
flag is true, the first quote is executed. If false, the<br>
second quote is executed.</p>
<pre><code>#-1 [ 'true s:put ] [ 'false s:put ] choose
#0 [ 'true s:put ] [ 'false s:put ] choose
</code></pre>
<p><code>if</code> takes a flag and one quote from the stack. If the flag is<br>
true, the quote is executed. If false, the quote is discarded.</p>
<pre><code>#-1 [ 'true s:put ] if
#0 [ 'true s:put ] if
</code></pre>
<p><code>-if</code> takes a flag and one quote from the stack. If the flag is<br>
false, the quote is executed. If true, the quote is discarded.</p>
<pre><code>#-1 [ 'false s:put ] -if
#0 [ 'false s:put ] -if
</code></pre>
<p>RETRO also provides <code>case</code> and <code>s:case</code> for use when you have<br>
multiple values to check against. This is similar to a <code>switch</code><br>
in C.</p>
<p><code>case</code> takes two numbers and a quote. The initial value is<br>
compared to the second one. If they match, the quote is<br>
executed. If false, the quote is discarded and the initial<br>
value is left on the stack.</p>
<p>Additionally, if the first value was matched, <code>case</code> will exit<br>
the calling function, but if false, it returns to the calling<br>
function.</p>
<p><code>s:case</code> works the same way, but for strings instead of simple<br>
values.</p>
<pre><code>:test (n-)
#1 [ 'Yes s:put ] case
#2 [ 'No s:put ] case
drop 'No idea s:put ;
</code></pre>
<h3 id="looping">Looping</h3>
<p>Several combinators are available for handling various looping<br>
constructs.</p>
<p><code>while</code> takes a quote from the stack and executes it repeatedly<br>
as long as the quote returns a true flag on the stack. This flag<br>
must be well formed and equal -1 or 0.</p>
<pre><code>#10 [ dup n:put sp n:dec dup 0 -eq? ] while
</code></pre>
<p><code>times</code> takes a count and quote from the stack. The quote will<br>
be executed the number of times specified. No indexes are pushed<br>
to the stack.</p>
<pre><code>#1 #10 [ dup n:put sp n:inc ] times drop
</code></pre>
<p>There is also a <code>times&lt;with-index&gt;</code> variation that provides<br>
access to the loop index (via <code>I</code>) and parent loop indexes<br>
(via <code>J</code> and <code>K</code>).</p>
<pre><code>#10 [ I n:put sp ] times&lt;with-index&gt;
</code></pre>
<h2 id="data-flow">Data Flow</h2>
<p>These combinators exist to simplify stack usage in various<br>
circumstances.</p>
<h3 id="preserving">Preserving</h3>
<p>Preserving combinators execute code while preserving portions<br>
of the data stack.</p>
<p><code>dip</code> takes a value and a quote, moves the value off the main<br>
stack temporarily, executes the quote, and then restores the<br>
value.</p>
<pre><code>#10 #20 [ n:inc ] dip
</code></pre>
<p>Would yield the following on the stack:</p>
<pre><code>11 20
</code></pre>
<p><code>sip</code> is similar to <code>dip</code>, but leaves a copy of the original<br>
value on the stack during execution of the quote. So:</p>
<pre><code>#10 [ n:inc ] sip
</code></pre>
<p>Leaves us with:</p>
<pre><code>11 10
</code></pre>
<h3 id="cleave">Cleave</h3>
<p>Cleave combinators apply multiple quotations to a single value<br>
or set of values.</p>
<p><code>bi</code> takes a value and two quotes, it then applies each quote to<br>
a copy of the value.</p>
<pre><code>#100 [ n:inc ] [ n:dec ] bi
</code></pre>
<p><code>tri</code> takes a value and three quotes. It then applies each quote<br>
to a copy of the value.</p>
<pre><code>#100 [ n:inc ] [ n:dec ] [ dup * ] tri
</code></pre>
<h3 id="spread">Spread</h3>
<p>Spread combinators apply multiple quotations to multiple values.<br>
The asterisk suffixed to these function names signifies that<br>
they are spread combinators.</p>
<p><code>bi*</code> takes two values and two quotes. It applies the first<br>
quote to the first value and the second quote to the second<br>
value.</p>
<pre><code>#1 #2 [ n:inc ] [ #2 * ] bi*
</code></pre>
<p><code>tri*</code> takes three values and three quotes, applying the<br>
first quote to the first value, the second quote to the<br>
second value, and the third quote to the third value.</p>
<pre><code>#1 #2 #3 [ n:inc ] [ #2 * ] [ n:dec ] tri*
</code></pre>
<h3 id="apply">Apply</h3>
<p>Apply combinators apply a single quotation to multiple values.<br>
The @ sign suffixed to these function names signifies that they<br>
are apply combinators.</p>
<p><code>bi@</code> takes two values and a quote. It then applies the quote to<br>
each value.</p>
<pre><code>#1 #2 [ n:inc ] bi@
</code></pre>
<p><code>tri@</code> takes three values and a quote. It then applies the quote<br>
to each value.</p>
<pre><code>#1 #2 #3 [ n:inc ] tri@
</code></pre>
<p>RETRO also provides <code>for-each</code> combinators for various data<br>
structures. The exact usage of these varies; consult the<br>
Glossary and relevant chapters for more details on these.</p>
<h1 id="the-stacks">The Stacks</h1>
<p>The stacks are a defining feature of Forth. They are are used<br>
to pass data between words and to track return addresses for<br>
function calls.</p>
<p>RETRO always has two stacks, and optionally (if built with<br>
floating point support) a third.</p>
<h2 id="data-stack">Data Stack</h2>
<p>This is the primary stack. Values are placed here, passed to<br>
words which consume them and then return results. When I<br>
refer to “the stack”, this is the one I mean. Learning to use<br>
the stack is a crucial part to making effective use of RETRO.</p>
<h3 id="placing-values-on-the-stack">Placing Values On The Stack</h3>
<p>Values can be placed on the stack directly.</p>
<table>
<thead>
<tr>
<th>Example</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>#300123</code></td>
<td>Push the number <code>300123</code> to the stack</td>
</tr>
<tr>
<td><code>$h</code></td>
<td>Push the ASCII code for <code>h</code> to the stack</td>
</tr>
<tr>
<td><code>'hello_world</code></td>
<td>Push a pointer to a string to the stack</td>
</tr>
<tr>
<td><code>&amp;fetch</code></td>
<td>Push the address of <code>fetch</code> to the stack</td>
</tr>
</tbody>
</table><h3 id="reordering-the-stack">Reordering The Stack</h3>
<p>RETRO provides a number of <em>shufflers</em> for reordering items<br>
on the stack.</p>
<p>Some of the most common ones are:</p>
<table>
<thead>
<tr>
<th>Word</th>
<th>Before</th>
<th>After</th>
</tr>
</thead>
<tbody>
<tr>
<td>dup</td>
<td>#1</td>
<td>#1 #1</td>
</tr>
<tr>
<td>drop</td>
<td>#1 #2</td>
<td>#1</td>
</tr>
<tr>
<td>swap</td>
<td>#1 #2</td>
<td>#2 #1</td>
</tr>
<tr>
<td>over</td>
<td>#1 #2</td>
<td>#1 #2 #1</td>
</tr>
<tr>
<td>tuck</td>
<td>#1 #2</td>
<td>#2 #1 #2</td>
</tr>
<tr>
<td>nip</td>
<td>#1 #2</td>
<td>#2</td>
</tr>
<tr>
<td>rot</td>
<td>#1 #2 #3</td>
<td>#3 #1 #2</td>
</tr>
</tbody>
</table><p>You can use <code>push</code> and <code>pop</code> to move values to and from the<br>
address stack. Make sure you <code>pop</code> them back before the word<br>
ends or RETRO will crash. These two words can not be used<br>
at the interpreter.</p>
<p>There is also a special one, <code>reorder</code>, which allows for big<br>
stack restructuring. This is slow but can be very useful.</p>
<p>As an example, lets say we have four values:</p>
<pre><code>#1 #2 #3 #4
</code></pre>
<p>And we want them to become:</p>
<pre><code>#4 #3 #2 #1
</code></pre>
<p>Doing this with the basic shufflers is difficult. You could end<br>
up with something similar to:</p>
<pre><code>swap rot push rot pop swap
</code></pre>
<p>But with <code>reorder</code>, you can just express the before and after<br>
states:</p>
<pre><code>'abcd 'dcba reorder
</code></pre>
<h3 id="resetting-the-stack">Resetting The Stack</h3>
<p>If you need to quickly empty the stack, use <code>reset</code>.</p>
<h3 id="get-the-stack-depth">Get The Stack Depth</h3>
<p>To find out how many items are on the stack, use <code>depth</code>.</p>
<h3 id="displaying-the-stack">Displaying The Stack</h3>
<p>You can display the stack by running <code>dump-stack</code>.</p>
<h3 id="data-flow-combinators">Data Flow Combinators</h3>
<p>RETRO provides <em>combinators</em> for working with data order on<br>
the stack. These are covered in a later chapter and are worth<br>
learning to use as they can help provide a cleaner, more<br>
structured means of working.</p>
<h3 id="tips-1">Tips</h3>
<p>The stack is <em>not</em> an array in addressable memory. Dont try<br>
to treat it like one.</p>
<h2 id="address-stack">Address Stack</h2>
<p>This stack primarily holds return addresses for function calls.<br>
You normally wont need to directly interact with this stack,<br>
but you can use <code>push</code> and <code>pop</code> to move values between the<br>
data stack and this.</p>
<h2 id="floating-point-stack">Floating Point Stack</h2>
<p>If you are using a build with floating point support a third<br>
stack will be present. Floating point values are kept and<br>
passed between words using this.</p>
<p>See the Floating Point chapter for more details on this.</p>
<h2 id="tips-2">Tips</h2>
<p>I recommend keeping the data stack shallow. Dont try to juggle<br>
too much; its better to factor definitions into shorter ones<br>
that deal with simpler parts of the stack values than to have<br>
a big definition with a lot of complex shuffling.</p>
<h2 id="notes">Notes</h2>
<p>The standard system is configured with a very deep data stack<br>
(around 2,000 items) and an address stack that is 3x deeper.<br>
In actual use, your programs are unlikely to ever need this,<br>
but if you do, keep the limits in mind.</p>
<h1 id="working-with-arrays">Working With Arrays</h1>
<p>RETRO offers a number of words for operating on statically sized<br>
arrays.</p>
<h2 id="namespace">Namespace</h2>
<p>The words operating on arrays are kept in an <code>a:</code> namespace.</p>
<h2 id="creating-arrays">Creating Arrays</h2>
<p>The easiest way to create an array is to wrap the values in a<br>
<code>{</code> and <code>}</code> pair:</p>
<pre><code>{ #1 #2 #3 #4 }
{ 'this 'is 'an 'array 'of 'strings }
{ 'this 'is 'a 'mixed 'array #1 #2 #3 }
</code></pre>
<p>You can also make an array from a quotation which returns<br>
values and the number of values to store in the a:</p>
<pre><code>[ #1 #2 #3 #3 ] a:counted-results
[ #1 #2 #3 #3 ] a:make
</code></pre>
<h2 id="accessing-elements">Accessing Elements</h2>
<p>You can access a specific value with <code>a:nth</code> and <code>fetch</code> or<br>
<code>store</code>:</p>
<pre><code>{ #1 #2 #3 #4 } #3 a:nth fetch
</code></pre>
<h2 id="find-the-length">Find The Length</h2>
<p>Use <code>a:length</code> to find the size of the array.</p>
<pre><code>{ #1 #2 #3 #4 } a:length
</code></pre>
<h2 id="duplicate">Duplicate</h2>
<p>Use <code>a:dup</code> to make a copy of an a:</p>
<pre><code>{ #1 #2 #3 #4 } a:dup
</code></pre>
<h2 id="filtering">Filtering</h2>
<p>RETRO provides <code>a:filter</code> which extracts matching values<br>
from an array. This is used like:</p>
<pre><code>{ #1 #2 #3 #4 #5 #6 #7 #8 } [ n:even? ] a:filter
</code></pre>
<p>The quote will be passed each value in the array and should<br>
return TRUE or FALSE. Values that lead to TRUE will be collected<br>
into a new array.</p>
<h2 id="mapping">Mapping</h2>
<p><code>a:map</code> applies a quotation to each item in an array and<br>
constructs a new array from the returned values.</p>
<p>Example:</p>
<pre><code>{ #1 #2 #3 } [ #10 * ] a:map
</code></pre>
<h2 id="reduce">Reduce</h2>
<p><code>a:reduce</code> takes an array, a starting value, and a quote. It<br>
executes the quote once for each item in the array, passing the<br>
item and the value to the quote. The quote should consume both<br>
and return a new value.</p>
<pre><code>{ #1 #2 #3 } #0 [ + ] a:reduce
</code></pre>
<h2 id="search">Search</h2>
<p>RETRO provides <code>a:contains?</code> and <code>a:contains-string?</code><br>
to search an array for a value (either a number or string) and<br>
return either TRUE or FALSE.</p>
<pre><code>#100 { #1 #2 #3 } a:contains?
'test { 'abc 'def 'test 'ghi } a:contains-string?
</code></pre>
<h1 id="working-with-a-buffer">Working With a Buffer</h1>
<p>RETRO provides words for operating on a linear memory area.<br>
This can be useful in building strings or custom data<br>
structures.</p>
<h2 id="namespace-1">Namespace</h2>
<p>Words operating on the buffer are kept in the <code>buffer:</code><br>
namespace.</p>
<h2 id="implementation">Implementation</h2>
<p>A buffer is a linear sequence of memory. The buffer words<br>
provide a means of incrementally storing and retrieving<br>
values from it.</p>
<p>The buffer words keep track of the start and end of the<br>
buffer. They also ensure that an <code>ASCII:NULL</code> is written<br>
after the last value, which make using them for string<br>
data easy.</p>
<h2 id="limitations">Limitations</h2>
<p>Only one buffer can be active at a time. RETRO provides a<br>
<code>buffer:preserve</code> combinator to allow using a second one<br>
before returning to the prior one.</p>
<h2 id="set-the-active-buffer">Set The Active Buffer</h2>
<p>To set a buffer as the active one use <code>buffer:set</code>. This takes<br>
an address.</p>
<p>The buffer will be assumed to be empty. The inital value will<br>
be set to ASCII:NULL.</p>
<h2 id="add-value">Add Value</h2>
<p>Use <code>buffer:add</code> to append a value to the buffer. This takes<br>
a single value and will also add an ASCII:NULL after the end<br>
of the buffer.</p>
<h2 id="fetch-last-value">Fetch Last Value</h2>
<p>To return the last value in the buffer you can use <code>buffer:get</code>.<br>
This removes the value and sets an ASCII:NULL in the memory<br>
location the returned value occupied.</p>
<h2 id="get-data-about-the-buffer">Get Data About The Buffer</h2>
<p>RETRO provides <code>buffer:start</code> to get the initial address in<br>
the buffer, <code>buffer:end</code> to get the last address (ignoring the<br>
ASCII:NULL), and <code>buffer:size</code> to return the number of values<br>
in the buffer.</p>
<h2 id="reset">Reset</h2>
<p>You can reset a buffer to the empty state using <code>buffer:empty</code>.</p>
<h2 id="example">Example</h2>
<p>To begin, create a memory region to use as a buffer.</p>
<pre><code>'Test d:create #1025 allot
</code></pre>
<p>Then you can set this as the current buffer:</p>
<pre><code>&amp;Test buffer:set
</code></pre>
<p>When a buffer is set, the vocabulary sets an internal<br>
index to the first address in it. This will be<br>
incremented when you add data and decremented when you<br>
remove data.</p>
<p>Lets add some stuff using <code>buffer:add</code>:</p>
<pre><code>#100 buffer:add
#200 buffer:add
#300 buffer:add
</code></pre>
<p>And then retreive the values:</p>
<pre><code>buffer:get n:put nl
buffer:get n:put nl
buffer:get n:put nl
</code></pre>
<p>You can remove all values using <code>buffer:empty</code>:</p>
<pre><code>#100 buffer:add
#200 buffer:add
#300 buffer:add
buffer:empty
</code></pre>
<p>And ask the buffer how many items it contains:</p>
<pre><code>buffer:size n:put nl
#100 buffer:add
#200 buffer:add
#300 buffer:add
buffer:size n:put nl
buffer:empty
</code></pre>
<p>The other functions are <code>buffer:start</code>, which returns<br>
the address of the buffer, <code>buffer:end</code>, which returns<br>
the address of the last value, and <code>buffer:preserve</code>.<br>
The first is easy to demo:</p>
<pre><code>buffer:start Test eq? n:put nl
</code></pre>
<p>The last one is useful. Only one buffer is ever active<br>
at a given time. The <code>buffer:preserve</code> combinator lets<br>
you execute a word, saving and restoring the current<br>
buffer indexes. So the word could assign and use a new<br>
buffer and this will reset the previous one after<br>
control returns.</p>
<p>There are a few notes that need to be considered. The<br>
preserve combinator saves the start and current index<br>
but <em>not</em> the contents. If the word you call uses the<br>
same buffer, the contents will remain altered.</p>
<p>Finally, the buffer words have one interesting trait:<br>
they store an ASCII NULL after adding each item to the<br>
buffer. This lets one use them to build strings easily.</p>
<pre><code>Test buffer:set
$h buffer:add
$e buffer:add
$l buffer:add
$l buffer:add
$o buffer:add
$, buffer:add
#32 buffer:add
$w buffer:add
$o buffer:add
$r buffer:add
$l buffer:add
$d buffer:add
buffer:start s:put nl
</code></pre>
<h1 id="working-with-characters">Working With Characters</h1>
<p>RETRO provides words for working with ASCII characters.</p>
<h2 id="prefix">Prefix</h2>
<p>Character constants are returned using the <code>$</code> prefix.</p>
<h2 id="namespace-2">Namespace</h2>
<p>Words operating on characters are in the <code>c:</code> namespace.</p>
<h2 id="classification">Classification</h2>
<p>RETRO provides a number of words to determine if a character<br>
fits into predefined groups.</p>
<p>The primary words for this are:</p>
<ul>
<li><code>c:consonant?</code></li>
<li><code>c:digit?</code></li>
<li><code>c:letter?</code></li>
<li><code>c:lowercase?</code></li>
<li><code>c:uppercase?</code></li>
<li><code>c:visible?</code></li>
<li><code>c:vowel?</code></li>
<li><code>c:whitespace?</code></li>
</ul>
<p>There are also corresponding “not” forms:</p>
<ul>
<li><code>c:-consonant?</code></li>
<li><code>c:-digit?</code></li>
<li><code>c:-lowercase?</code></li>
<li><code>c:-uppercase?</code></li>
<li><code>c:-visible?</code></li>
<li><code>c:-vowel?</code></li>
<li><code>c:-whitespace?</code></li>
</ul>
<p>All of these take a character and return either a <code>TRUE</code> or<br>
<code>FALSE</code> flag.</p>
<h2 id="conversions">Conversions</h2>
<p>A few words are provided to convert case. Each takes a character<br>
and returns the modified character.</p>
<ul>
<li><code>c:to-lower</code></li>
<li><code>c:to-number</code></li>
<li><code>c:to-upper</code></li>
<li><code>c:toggle-case</code></li>
</ul>
<p>RETRO also has <code>c:to-string</code>, which takes a character and<br>
creates a new temporary string with the character.</p>
<h2 id="io">I/O</h2>
<p>Characters can be displayed using <code>c:put</code>.</p>
<pre><code>$a c:put
</code></pre>
<p>With the default system on BSD, Linux, and macOS (and other<br>
Unix style hosts), <code>c:get</code> is provided to read input. This<br>
may be buffered, depending on the host.</p>
<h1 id="working-with-the-dictionary">Working With The Dictionary</h1>
<p>The Dictionary is a linked list containing the dictionary<br>
headers.</p>
<h2 id="namespace-3">Namespace</h2>
<p>Words operating on the dictionary are in the <code>d:</code> namespace.</p>
<h2 id="variables">Variables</h2>
<p><code>Dictionary</code> is a variable holding a pointer to the most recent<br>
header.</p>
<h2 id="header-structure">Header Structure</h2>
<p>Each entry follows the following structure:</p>
<pre><code>Offset Contains
------ ---------------------------
0000 Link to Prior Header
0001 Link to XT
0002 Link to Class Handler
0003+ Word name (null terminated)
</code></pre>
<p>RETRO provides words for accessing the fields in a portable<br>
manner. Its recommended to use these to allow for future<br>
revision of the header structure.</p>
<h2 id="accessing-fields">Accessing Fields</h2>
<p>Given a pointer to a header, you can use <code>d:xt</code>, <code>d:class</code>,<br>
and <code>d:name</code> to access the address of each specific field.<br>
There is no <code>d:link</code>, as the link will always be the first<br>
field.</p>
<h2 id="shortcuts-for-the-latest-header">Shortcuts For The Latest Header</h2>
<p>RETRO provides several words for operating on the most recent<br>
header.</p>
<p><code>d:last</code> returns a pointer to the latest header. <code>d:last&lt;xt&gt;</code><br>
will give the contents of the <code>d:xt</code> field for the latest<br>
header. There are also <code>d:last&lt;class&gt;</code> and <code>d:last&lt;name&gt;</code>.</p>
<h2 id="adding-headers">Adding Headers</h2>
<p>Two words exist for making new headers. The easy one is<br>
<code>d:create</code>. This takes a string for the name and makes a<br>
new header with the class set to <code>class:data</code> and the XT<br>
field pointing to <code>here</code>.</p>
<p>Example:</p>
<pre><code>'Base d:create
</code></pre>
<p>The other is <code>d:add-header</code>. This takes a string, a pointer<br>
to the class handler, and a pointer for the XT field and<br>
builds a new header using these.</p>
<p>Example:</p>
<pre><code>'Base &amp;class:data #10000 d:add-header
</code></pre>
<h2 id="searching">Searching</h2>
<p>RETRO provides two words for searching the dictionary.</p>
<p><code>d:lookup</code> takes a string and tries to find it in the<br>
dictionary. It will return a pointer to the dictionary header<br>
or a value of zero if the word was not found.</p>
<p><code>d:lookup-xt</code> takes a pointer and will return the dictionary<br>
header that has this as the <code>d:xt</code> field, or zero if no match<br>
is found.</p>
<h2 id="iteration">Iteration</h2>
<p>You can use the <code>d:for-each</code> combinator to iterate over all<br>
entries in the dictionary. For instance, to display the names<br>
of all words:</p>
<pre><code>[ d:name s:put sp ] d:for-each
</code></pre>
<p>For each entry, this combinator will push a pointer to the<br>
entry to the stack and call the quotation.</p>
<h2 id="listing-words">Listing Words</h2>
<p>Most Forth systems provide WORDS for listing the names of all<br>
words in the dictionary. RETRO does as well, but this is named<br>
<code>d:words</code>.</p>
<p>This isnt super useful as looking through several hundred<br>
names is annoying. RETRO also provides <code>d:words-with</code> to help<br>
in filtering the results.</p>
<p>Example:</p>
<pre><code>'class: d:words-with
</code></pre>
<h1 id="working-with-floating-point">Working With Floating Point</h1>
<p>Some RETRO systems include support for floating point numbers.<br>
When present, this is built over the system <code>libm</code> using the<br>
C <code>double</code> type.</p>
<p>Floating point values are typically 64 bit IEEE 754 double<br>
precision (1 bit for the sign, 11 bits for the exponent, and<br>
the remaining 52 bits for the value), i.e. 15 decimal digits<br>
of precision.</p>
<h2 id="prefix-1">Prefix</h2>
<p>Floating point numbers start with a <code>.</code></p>
<p>Examples:</p>
<p>Token Value<br>
.1 1.0<br>
.0.5 0.5<br>
.-.4 -0.4<br>
.1.3 1.3</p>
<h2 id="namespace-4">Namespace</h2>
<p>Floating point words are in the <code>f:</code> namespace. There is also<br>
a related <code>e:</code> namespace for <em>encoded values</em>, which allows<br>
storing of floats in standard memory.</p>
<h2 id="operation">Operation</h2>
<p>Floating point values exist on a separate stack, and are bigger<br>
than the standard memory cells, so can not be directly stored<br>
and fetched from memory.</p>
<p>The floating point system also provides an alternate stack that<br>
can be used to temporarily store values.</p>
<p>The following words exist for arranging values on the floating<br>
point stack. These are direct analogs to the non-prefiexd words<br>
for dealing with the data stack.</p>
<ul>
<li><code>f:nip</code></li>
<li><code>f:over</code></li>
<li><code>f:depth</code></li>
<li><code>f:drop</code></li>
<li><code>f:drop-pair</code></li>
<li><code>f:dup</code></li>
<li><code>f:dup-pair</code></li>
<li><code>f:dump-stack</code></li>
<li><code>f:tuck</code></li>
<li><code>f:swap</code></li>
<li><code>f:rot</code></li>
</ul>
<p>For the secondary floating point stack, the following words are<br>
provided:</p>
<ul>
<li><code>f:push</code></li>
<li><code>f:pop</code></li>
<li><code>f:adepth</code></li>
<li><code>f:dump-astack</code></li>
</ul>
<h2 id="constants">Constants</h2>
<pre><code>| Name | Returns |
| -------- | ----------------- |
| `f:E` | Euler's number |
| `f:-INF` | Negative infinity |
| `f:INF` | Positive infinity |
| `f:NAN` | Not a Number |
| `f:PI` | PI |
</code></pre>
<h2 id="comparisons">Comparisons</h2>
<p>The basic set of comparators are the same as those for<br>
operating on integers. These are:</p>
<ul>
<li><code>f:-eq?</code></li>
<li><code>f:between?</code></li>
<li><code>f:eq?</code></li>
<li><code>f:gt?</code></li>
<li><code>f:lt?</code></li>
<li><code>f:negative?</code></li>
<li><code>f:positive?</code></li>
<li><code>f:case</code></li>
</ul>
<p>There are also a few additions for comparing to special values<br>
like infinity and NaN.</p>
<ul>
<li><code>f:-inf?</code></li>
<li><code>f:inf?</code></li>
<li><code>f:nan?</code></li>
</ul>
<h2 id="basic-math">Basic Math</h2>
<ul>
<li><code>f:*</code></li>
<li><code>f:+</code></li>
<li><code>f:-</code></li>
<li><code>f:/</code></li>
<li><code>f:abs</code></li>
<li><code>f:floor</code></li>
<li><code>f:inc</code></li>
<li><code>f:limit</code></li>
<li><code>f:max</code></li>
<li><code>f:min</code></li>
<li><code>f:negate</code></li>
<li><code>f:power</code></li>
<li><code>f:ceiling</code></li>
<li><code>f:dec</code></li>
<li><code>f:log</code></li>
<li><code>f:sqrt</code></li>
<li><code>f:square</code></li>
<li><code>f:round</code></li>
<li><code>f:sign</code></li>
<li><code>f:signed-sqrt</code></li>
<li><code>f:signed-square</code></li>
</ul>
<h2 id="geometry">Geometry</h2>
<p>RETRO provides a small number of words for doing geometric<br>
related calculations.</p>
<table>
<thead>
<tr>
<th>Word</th>
<th>Returns</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>f:acos</code></td>
<td>arc cosine</td>
</tr>
<tr>
<td><code>f:asin</code></td>
<td>arc sine</td>
</tr>
<tr>
<td><code>f:atan</code></td>
<td>arc tangent</td>
</tr>
<tr>
<td><code>f:cos</code></td>
<td>cosine</td>
</tr>
<tr>
<td><code>f:sin</code></td>
<td>sine</td>
</tr>
<tr>
<td><code>f:tan</code></td>
<td>tangent</td>
</tr>
</tbody>
</table><h2 id="storage-and-retrieval">Storage and Retrieval</h2>
<p>By leveraging the encoded value functions, RETRO is able to<br>
allow storage of floating point values in memory. This does<br>
have a tradeoff in accuracy as the memory cells are considerably<br>
smaller than a full floating point size.</p>
<p>You can use <code>f:fetch</code> to fetch a floating point value and<br>
<code>f:store</code> to store one.</p>
<p>If you need more precision, try Kiyoshi Yonedas FloatVar<br>
example (<code>example/FloatVar.forth</code>), which includes words to<br>
store and retrieve values using multiple cells.</p>
<ul>
<li><code>f:to-number</code></li>
<li><code>f:to-string</code></li>
</ul>
<h2 id="io-1">I/O</h2>
<p>The floating point vocabulary has a single I/O word, <code>f:put</code>,<br>
for the display of floating point numbers.</p>
<h2 id="encoded-values">Encoded Values</h2>
<p>RETRO provides a means of encoding and decoding floating point<br>
values into standard integer cells. This is based on the paper<br>
“Encoding floating point values to shorter integers” by Kiyoshi<br>
Yoneda and Charles Childers.</p>
<ul>
<li><code>f:E1</code></li>
<li><code>f:to-e</code></li>
<li><code>e:-INF</code></li>
<li><code>e:-inf?</code></li>
<li><code>e:INF</code></li>
<li><code>e:MAX</code></li>
<li><code>e:MIN</code></li>
<li><code>e:NAN</code></li>
<li><code>e:clip</code></li>
<li><code>e:inf?</code></li>
<li><code>e:max?</code></li>
<li><code>e:min?</code></li>
<li><code>e:n?</code></li>
<li><code>e:nan?</code></li>
<li><code>e:put</code></li>
<li><code>e:to-f</code></li>
<li><code>e:zero?</code></li>
</ul>
<h1 id="working-with-numbers">Working With Numbers</h1>
<p>Numbers in RETRO are signed, 32 bit integers with a range of<br>
-2,147,483,648 to 2,147,483,647.</p>
<h2 id="token-prefix">Token Prefix</h2>
<p>All numbers start with a <code>#</code> prefix.</p>
<h2 id="namespace-5">Namespace</h2>
<p>Most words operating on numbers are in the <code>n:</code> namespace.</p>
<h1 id="working-with-pointers">Working With Pointers</h1>
<h2 id="prefix-2">Prefix</h2>
<p>Pointers are returned by the <code>&amp;</code> prefix.</p>
<h2 id="examples">Examples</h2>
<pre><code>'Base var
&amp;Base fetch
#10 &amp;Base store
#10 &amp;n:inc call
</code></pre>
<h2 id="notes-1">Notes</h2>
<p>The use of <code>&amp;</code> to get a pointer to a data structure (with a<br>
word class of <code>class:data</code>) is not required. I like to use it<br>
anyway as it makes my intent a little clearer.</p>
<p>Pointers are useful with combinators. Consider:</p>
<pre><code>:abs dup n:negative? [ n:negate ] if ;
</code></pre>
<p>Since the target quote body is a single word, it is more<br>
efficient to use a pointer instead:</p>
<pre><code>:abs dup n:negative? &amp;n:negate if ;
</code></pre>
<p>The advantages are speed (saves a level of call/return by<br>
avoiding the quotation) and size (for the same reason).<br>
This may be less readable though, so consider the balance<br>
of performance to readability when using this approach.</p>
<h1 id="working-with-strings">Working With Strings</h1>
<p>Strings in RETRO are NULL terminated sequences of values<br>
representing characters. Being NULL terminated, they cant<br>
contain a NULL (ASCII 0).</p>
<p>The character words in RETRO are built around ASCII, but<br>
strings can contain UTF8 encoded data if the host platform<br>
allows. Words like <code>s:length</code> will return the number of bytes,<br>
not the number of logical characters in this case.</p>
<h2 id="prefix-3">Prefix</h2>
<p>Strings begin with a single <code>'</code>.</p>
<pre><code>'Hello
'This_is_a_string
'This_is_a_much_longer_string_12345_67890_!!!
</code></pre>
<p>RETRO will replace spaces with underscores. If you need both<br>
spaces and underscores in a string, escape the underscores and<br>
use <code>s:format</code>:</p>
<pre><code>'This_has_spaces_and_under\_scored_words. s:format
</code></pre>
<h2 id="namespace-6">Namespace</h2>
<p>Words operating on strings are in the <code>s:</code> namespace.</p>
<h2 id="lifetime">Lifetime</h2>
<p>At the interpreter, strings get allocated in a rotating buffer.<br>
This is used by the words operating on strings, so if you need<br>
to keep them around, use <code>s:keep</code> or <code>s:copy</code> to move them to<br>
more permanent storage.</p>
<p>In a definition, the string is compiled inline and so is in<br>
permanent memory.</p>
<p>You can manually manage the string lifetime by using <code>s:keep</code><br>
to place it into permanent memory or <code>s:temp</code> to copy it to<br>
the rotating buffer.</p>
<h2 id="mutability">Mutability</h2>
<p>Strings are mutable. If you need to ensure that a string is<br>
not altered, make a copy before operating on it or see the<br>
individual glossary entries for notes on words that may do<br>
this automatically.</p>
<h2 id="searching-1">Searching</h2>
<p>RETRO provides four words for searching within a string.</p>
<p><code>s:contains-char?</code><br>
<code>s:contains-string?</code><br>
<code>s:index-of</code><br>
<code>s:index-of-string</code></p>
<h2 id="comparisons-1">Comparisons</h2>
<p><code>s:eq?</code><br>
<code>s:case</code></p>
<h2 id="extraction">Extraction</h2>
<p>To obtain a new string containing the first <code>n</code> characters from<br>
a source string, use <code>s:left</code>:</p>
<pre><code>'Hello_World #5 s:left
</code></pre>
<p>To obtain a new string containing the last <code>n</code> characters from<br>
a source string, use <code>s:right</code>:</p>
<pre><code>'Hello_World #5 s:right
</code></pre>
<p>If you need to extract data from the middle of the string, use<br>
<code>s:substr</code>. This takes a string, the offset of the first<br>
character, and the number of characters to extract.</p>
<pre><code>'Hello_World #3 #5 s:substr
</code></pre>
<h2 id="joining">Joining</h2>
<p>You can use <code>s:append</code> or <code>s:prepend</code> to merge two strings.</p>
<pre><code>'First 'Second s:append
'Second 'First s:prepend
</code></pre>
<h2 id="tokenization">Tokenization</h2>
<p><code>s:tokenize</code><br>
<code>s:tokenize-on-string</code><br>
<code>s:split</code><br>
<code>s:split-on-string</code></p>
<h2 id="conversions-1">Conversions</h2>
<p>To convert the case of a string, RETRO provides <code>s:to-lower</code><br>
and <code>s:to-upper</code>.</p>
<p><code>s:to-number</code> is provided to convert a string to an integer<br>
value. This has a few limitations:</p>
<ul>
<li>only supports decimal</li>
<li>non-numeric characters will result in incorrect values</li>
</ul>
<h2 id="cleanup">Cleanup</h2>
<p>RETRO provides a handful of words for cleaning up strings.</p>
<p><code>s:chop</code> will remove the last character from a string. This<br>
is done by replacing it with an ASCII:NULL.</p>
<p><code>s:trim</code> removes leading and trailing whitespace from a string.<br>
For more control, there is also <code>s:trim-left</code> and <code>s:trim-right</code><br>
which let you trim just the leading or trailing end as desired.</p>
<h2 id="combinators">Combinators</h2>
<p><code>s:for-each</code><br>
<code>s:filter</code><br>
<code>s:map</code></p>
<h2 id="other">Other</h2>
<p><code>s:evaluate</code><br>
<code>s:copy</code><br>
<code>s:reverse</code><br>
<code>s:hash</code><br>
<code>s:length</code><br>
<code>s:replace</code><br>
<code>s:format</code><br>
<code>s:empty</code></p>
<h2 id="controlling-the-temporary-buffers">Controlling The Temporary Buffers</h2>
<p>As dicussed in the Lifetime subsection, temporary strings are<br>
allocated in a rotating buffer. The details of this can be<br>
altered by updating two variables.</p>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Holds</th>
</tr>
</thead>
<tbody>
<tr>
<td>TempStrings</td>
<td>The number of temporary strings</td>
</tr>
<tr>
<td>TempStringMax</td>
<td>The maximum length of a temporary string</td>
</tr>
</tbody>
</table><p>For example, to increase the number of temporary strings to<br>
48:</p>
<pre><code>#48 !TempStrings
</code></pre>
<p>The defaults are:</p>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Default</th>
</tr>
</thead>
<tbody>
<tr>
<td>TempStrings</td>
<td>32</td>
</tr>
<tr>
<td>TempStringMax</td>
<td>512</td>
</tr>
</tbody>
</table><p>Its also important to note that altering these will affect<br>
the memory map for all temporary buffers. Do not use anything<br>
already in the buffers after updating these or you will risk<br>
data corruption and possible crashes.</p>
<h1 id="working-with-assembly-language">Working With Assembly Language</h1>
<p>RETRO runs on a virtual machine called Nga. It provides a<br>
standard assembler for this called <em>Muri</em>.</p>
<p>Muri is a simple, multipass model thats not fancy, but<br>
suffices for RETROs needs.</p>
<h2 id="assembling-a-standalone-file">Assembling A Standalone File</h2>
<p>A small example (<em>test.muri</em>)</p>
<pre><code>~~~
i liju....
r main
: c:put
i liiire..
i 0
: main
i lilica..
d 97
i liju....
r main
~~~
</code></pre>
<p>Assembling it:</p>
<pre><code>retro-muri test.muri
</code></pre>
<p>So breaking down: Muri extracts the assembly code blocks to<br>
assemble, then proceeds to do the assembly. Each source line<br>
starts with a directive, followed by a space, and then ending<br>
with a value.</p>
<dl>
<dt>The directives are:</dt>
<dd>value is a label<br>
i value is an instruction bundle<br>
d value is a numeric value<br>
r value is a reference<br>
s value is a string to inline</dd>
</dl>
<p>Instructions for Nga are provided as bundles. Each memory<br>
location can store up to four instructions. And each instruction<br>
gets a two character identifier.</p>
<p>From the list of instructions:</p>
<pre><code>0 nop 5 push 10 ret 15 fetch 20 div 25 zret
1 lit 6 pop 11 eq 16 store 21 and 26 end
2 dup 7 jump 12 neq 17 add 22 or 27 ienum
3 drop 8 call 13 lt 18 sub 23 xor 28 iquery
4 swap 9 ccall 14 gt 19 mul 24 shift 29 iinvoke
</code></pre>
<p>This reduces to:</p>
<pre><code>0 .. 5 pu 10 re 15 fe 20 di 25 zr
1 li 6 po 11 eq 16 st 21 an 26 en
2 du 7 ju 12 ne 17 ad 22 or 27 ie
3 dr 8 ca 13 lt 18 su 23 xo 28 iq
4 sw 9 cc 14 gt 19 mu 24 sh 29 ii
</code></pre>
<p>Most are just the first two letters of the instruction name. I<br>
use <code>..</code> instead of <code>no</code> for <code>NOP</code>, and the first letter of<br>
each I/O instruction name. So a bundle may look like:</p>
<pre><code>dumure..
</code></pre>
<p>(This would correspond to <code>dup multiply return nop</code>).</p>
<h2 id="runtime-assembler">Runtime Assembler</h2>
<p>RETRO also has a runtime variation of Muri that can be used<br>
when you need to generate more optimal code. So one can write:</p>
<pre><code>:n:square dup * ;
</code></pre>
<p>Or:</p>
<pre><code>:n:square as{ 'dumure.. i }as ;
</code></pre>
<p>The second one will be faster, as the entire definition is one<br>
bundle, which reduces memory reads and decoding by 2/3.</p>
<p>Doing this is less readable, so I only recommend doing so after<br>
you have finalized working RETRO level code and determined the<br>
best places to optimize.</p>
<p>The runtime assembler has the following directives:</p>
<pre><code>i value is an instruction bundle
d value is a numeric value
r value is a reference
</code></pre>
<p>Additionally, in the runtime assembler, these are reversed:</p>
<pre><code>'dudumu.. i
</code></pre>
<p>Instead of:</p>
<pre><code>i dudumu..
</code></pre>
<h1 id="lexical-scope">Lexical Scope</h1>
<p>RETRO has a single dictionary, but does provide a means of using<br>
lexical scope to keep this dictionary clean.</p>
<h2 id="example-1">Example</h2>
<pre><code>{{
'A var
:++A &amp;A v:inc ;
---reveal---
:B ++A ++A @A n:put nl ;
}}
</code></pre>
<p>In this example, the lexical namespace is created with <code>{{</code>. A<br>
variable (<code>A</code>) and word (<code>++A</code>) are defined. Then a marker is<br>
set with <code>---reveal---</code>. Another word (<code>B</code>) is defined, and the<br>
lexical area is closed with <code>}}</code>.</p>
<p>The headers between <code>{{</code> and <code>---reveal---</code> are then hidden from<br>
the dictionary, leaving only the headers between <code>---reveal---</code><br>
and <code>}}</code> exposed.</p>
<h2 id="notes-2">Notes</h2>
<p>This only affects word visibility within the scoped area. As an<br>
example:</p>
<pre><code>:a #1 ;
{{
:a #2 ;
---reveal---
:b 'a s:evaluate n:put ;
}}
</code></pre>
<p>In this, after <code>}}</code> closes the area, the <code>:a #2 ;</code> is hidden and<br>
the <code>s:evaluate</code> will find the <code>:a #1 ;</code> when <code>b</code> is run.</p>
<h1 id="internals">Internals</h1>
<p>The next few chapters dive into RETROs architecture. If you<br>
seek to implement a port to a new platform or to extend the<br>
I/O functionality youll find helpful information here.</p>
<h1 id="internals-nga-virtual-machine">Internals: Nga Virtual Machine</h1>
<h2 id="overview">Overview</h2>
<p>At the heart of RETRO is a simple MISC (minimal instruction<br>
set computer) processor for a dual stack architecture.</p>
<p>This is a very simple and straightforward system. There are<br>
30 instructions. The memory is a linear array of signed 32<br>
bit values. And there are two stacks: one for data and one<br>
for return addresses.</p>
<h2 id="instrution-table">Instrution Table</h2>
<table>
<thead>
<tr>
<th>Opcode</th>
<th>Muri</th>
<th>Full Name</th>
<th>Data Stack</th>
<th>Address Stack</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td></td>
<td>nop</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>1</td>
<td>li</td>
<td>lit</td>
<td>-n</td>
<td>-</td>
</tr>
<tr>
<td>2</td>
<td>du</td>
<td>dup</td>
<td>n-nn</td>
<td>-</td>
</tr>
<tr>
<td>3</td>
<td>dr</td>
<td>drop</td>
<td>n-</td>
<td>-</td>
</tr>
<tr>
<td>4</td>
<td>sw</td>
<td>swap</td>
<td>xy-yx</td>
<td>-</td>
</tr>
<tr>
<td>5</td>
<td>pu</td>
<td>push</td>
<td>n-</td>
<td>-n</td>
</tr>
<tr>
<td>6</td>
<td>po</td>
<td>pop</td>
<td>-n</td>
<td>n-</td>
</tr>
<tr>
<td>7</td>
<td>ju</td>
<td>jump</td>
<td>a-</td>
<td>-</td>
</tr>
<tr>
<td>8</td>
<td>ca</td>
<td>call</td>
<td>a-</td>
<td>-A</td>
</tr>
<tr>
<td>9</td>
<td>cc</td>
<td>conditional call</td>
<td>af-</td>
<td>-A</td>
</tr>
<tr>
<td>10</td>
<td>re</td>
<td>return</td>
<td>-</td>
<td>A-</td>
</tr>
<tr>
<td>11</td>
<td>eq</td>
<td>equality</td>
<td>xy-f</td>
<td>-</td>
</tr>
<tr>
<td>12</td>
<td>ne</td>
<td>inequality</td>
<td>xy-f</td>
<td>-</td>
</tr>
<tr>
<td>13</td>
<td>lt</td>
<td>less than</td>
<td>xy-f</td>
<td>-</td>
</tr>
<tr>
<td>14</td>
<td>gt</td>
<td>greater than</td>
<td>xy-f</td>
<td>-</td>
</tr>
<tr>
<td>15</td>
<td>fe</td>
<td>fetch</td>
<td>a-n</td>
<td>-</td>
</tr>
<tr>
<td>16</td>
<td>st</td>
<td>store</td>
<td>na-</td>
<td>-</td>
</tr>
<tr>
<td>17</td>
<td>ad</td>
<td>addition</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>18</td>
<td>su</td>
<td>subtraction</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>19</td>
<td>mu</td>
<td>multiplication</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>20</td>
<td>di</td>
<td>divide &amp; remainder</td>
<td>xy-rq</td>
<td>-</td>
</tr>
<tr>
<td>21</td>
<td>an</td>
<td>bitwise and</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>22</td>
<td>or</td>
<td>bitwise or</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>23</td>
<td>xo</td>
<td>bitwise xor</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>24</td>
<td>sh</td>
<td>shift</td>
<td>xy-n</td>
<td>-</td>
</tr>
<tr>
<td>25</td>
<td>zr</td>
<td>zero return</td>
<td>n-?</td>
<td>-</td>
</tr>
<tr>
<td>26</td>
<td>en</td>
<td>end</td>
<td>-</td>
<td>-</td>
</tr>
<tr>
<td>27</td>
<td>ie</td>
<td>i/o enumerate</td>
<td>-n</td>
<td>-</td>
</tr>
<tr>
<td>28</td>
<td>iq</td>
<td>i/o query</td>
<td>n-xy</td>
<td>-</td>
</tr>
<tr>
<td>29</td>
<td>ii</td>
<td>i/o invoke</td>
<td>…n-</td>
<td>-</td>
</tr>
</tbody>
</table><h2 id="encoding">Encoding</h2>
<p>Up to four instructions can be packed into each memory cell.</p>
<p>As an example,</p>
<pre><code>Opcode 1 Opcode 2 Opcode 3 Opcode 4
00000000:00000000:00000000:00000000
</code></pre>
<p>If we have a bundle of <code>lidumu..</code>, it would look like:</p>
<pre><code> li du mu ..
00000001:00000010:00010011:00000000
</code></pre>
<p>Each <code>li</code> should have a value in the following cell(s). These<br>
values will be pushed to the stack. E.g., <code>lili....</code> and<br>
1, 2:</p>
<pre><code>00000001:00000001:00000000:00000000
00000000 00000000 00000000 00000001 (1)
00000000 00000000 00000000 00000010 (2)
</code></pre>
<h2 id="shifts">Shifts</h2>
<p><code>sh</code> performs a bitwise arithmetic shift operation.</p>
<p>This takes two values:</p>
<pre><code>xy
</code></pre>
<p>And returns a single one:</p>
<pre><code>z
</code></pre>
<p>If y is positive, this shifts <code>x</code> right by <code>y</code> bits. If negative,<br>
it shifts left.</p>
<h2 id="queries-memory-stacks">Queries: Memory, Stacks</h2>
<p>The <code>fe</code> instruction allows queries of some data related to<br>
the Nga VM state. These are returned by reading from negative<br>
addresses:</p>
<table>
<thead>
<tr>
<th>Address</th>
<th>Returns</th>
</tr>
</thead>
<tbody>
<tr>
<td>-1</td>
<td>Data stack depth</td>
</tr>
<tr>
<td>-2</td>
<td>Address stack depth</td>
</tr>
<tr>
<td>-3</td>
<td>Maximum Image Size</td>
</tr>
</tbody>
</table><h2 id="io-devices">I/O Devices</h2>
<p>Nga provides three instructions for interacting with I/O devices.<br>
These are:</p>
<pre><code>ie i/o enumerate returns the number of attached devices
iq i/o query returns information about a device
ii i/o interact invokes an interaction with a device
</code></pre>
<p>As an example, with an implementation providing an output source,<br>
a block storage system, and keyboard:</p>
<pre><code>ie will return `3` since there are three i/o devices
0 iq will return 0 0, since the first device is a screen (0)
with a version of 0
1 iq will return 1 3, since the second device is a block
storage (3), with a version of 1
2 iq will return 0 1, since the third device is a keyboard
(1), with a version of 0
</code></pre>
<dl>
<dt>In this case, some interactions can be defined:</dt>
<dd>
<p>c:put<br>
i liiire…<br>
d 0</p>
</dd>
<dd>
<p>c:get<br>
i liiire…<br>
d 2</p>
</dd>
</dl>
<p>Setup the stack, push the device ID to the stack, and then use<br>
<code>ii</code> to invoke the interaction.</p>
<p>A RETRO system requires one I/O device (a generic output for a<br>
single character). This must be the first device, and must have<br>
a device ID of 0.</p>
<p>All other devices are optional and can be specified in any order.</p>
<p>The currently supported and reserved device identifiers are:</p>
<table>
<thead>
<tr>
<th>ID</th>
<th>Device Type</th>
<th>Notes</th>
</tr>
</thead>
<tbody>
<tr>
<td>0000</td>
<td>Generic Output</td>
<td>Always present as device 0</td>
</tr>
<tr>
<td>0001</td>
<td>Keyboard</td>
<td></td>
</tr>
<tr>
<td>0002</td>
<td>Floating Point</td>
<td></td>
</tr>
<tr>
<td>0003</td>
<td>Block Storage</td>
<td>Raw, 1024 cell blocks</td>
</tr>
<tr>
<td>0004</td>
<td>Filesystem</td>
<td>Unix-style Files</td>
</tr>
<tr>
<td>0005</td>
<td>Network: Gopher</td>
<td>Make gopher requests</td>
</tr>
<tr>
<td>0006</td>
<td>Network: HTTP</td>
<td>Make HTTP requests</td>
</tr>
<tr>
<td>0007</td>
<td>Network: Sockets</td>
<td></td>
</tr>
<tr>
<td>0008</td>
<td>Syscalls: Unix</td>
<td></td>
</tr>
<tr>
<td>0009</td>
<td>Scripting Hooks</td>
<td></td>
</tr>
<tr>
<td>0010</td>
<td>Random Number</td>
<td></td>
</tr>
</tbody>
</table><p>This list may be revised in the future. The only guaranteed<br>
stable indentifier is 0000 for generic output.</p>
<h2 id="trivia">Trivia</h2>
<p>There are 810,000 possible combinations of instructions. Only<br>
73 are used in the implementation of RETRO.</p>
<h1 id="internals-interface-layers">Internals: Interface Layers</h1>
<p>Nga provides a virtual processor and an extensible way of adding<br>
I/O devices, but does not provide any I/O itself. Adding I/O is<br>
the responsability of the <em>interface layer</em>.</p>
<p>An interface layer will wrap Nga, providing at least one I/O<br>
device (a generic output target), and a means of interacting<br>
with the <em>retro image</em>.</p>
<p>Its expected that this layer will be host specific, adding any<br>
system interactions that are needed via the I/O instructions.<br>
The image will typically be extended with words to use these.</p>
<h1 id="internals-the-retro-image">Internals: The Retro Image</h1>
<p>The actual RETRO language is stored as a memory image for Nga.</p>
<h2 id="format">Format</h2>
<p>The image file is a flat, linear sequence of signed 32-bit<br>
values. Each value is stored in little endian format. The<br>
size is not fixed. An interface should check when loading to<br>
ensure that the physical image is not larger than the emulated<br>
memory.</p>
<h2 id="header">Header</h2>
<p>The image will start with two cells. The first is a liju…<br>
instruction, the second is the target address for the jump.<br>
This serves to skip over the rest of the data and reach the<br>
actual entry point.</p>
<p>This is followed by a pointer to the most recent dictionary<br>
header, a pointer to the next free address in memory, and<br>
then the RETRO version number.</p>
<pre><code>| Offset | Contains |
| ------ | --------------------------- |
| 0 | lit call nop nop |
| 1 | Pointer to main entry point |
| 2 | Dictionary |
| 3 | Heap |
| 4 | RETRO version |
</code></pre>
<p>The actual code starts after this header.</p>
<p>The version number is the year and month. As an example,<br>
the 12.2019.6 release will have a version number of<br>
<code>201906</code>.</p>
<h2 id="layout">Layout</h2>
<p>Assuming an Nga built with 524287 cells of memory:</p>
<pre><code>| RANGE | CONTAINS |
| --------------- | ---------------------------- |
| 0 - 1024 | rx kernel |
| 1025 - 1535 | token input buffer |
| 1536 + | start of heap space |
| ............... | free memory for your use |
| 506879 | buffer for string evaluate |
| 507904 | temporary strings (32 * 512) |
| 524287 | end of memory |
</code></pre>
<p>The buffers at the end of memory will resize when specific<br>
variables related to them are altered.</p>
<h1 id="additional-tools">Additional Tools</h1>
<p>In addition to the core <code>retro</code> binary, the <code>bin</code> directory<br>
will contain a few other tools.</p>
<h2 id="retro">retro</h2>
<p>This is the main RETRO binary.</p>
<h2 id="retro-describe">retro-describe</h2>
<p>This is a program that looks up entries in the Glossary.</p>
<p>At the command line, you can use it like:</p>
<pre><code>retro-describe s:for-each
</code></pre>
<h2 id="retro-embedimage">retro-embedimage</h2>
<p>This is a program which generates a C file with the ngaImage<br>
contents. Its used when building <code>retro</code>.</p>
<pre><code>retro-embedimage ngaImage
</code></pre>
<p>The output is written to stdout; redirect it as needed.</p>
<h2 id="retro-extend">retro-extend</h2>
<p>This is a program which compiles code into the ngaImage.<br>
Its used when building <code>retro</code> and when you want to make a<br>
standalone image with custom additions.</p>
<p>Example command line:</p>
<pre><code>retro-extend ngaImage example/rot13.forth
</code></pre>
<p>Pass the image name as the first argument, and then file names<br>
as susequent ones. Do <em>not</em> use this for things relying on I/O<br>
apart from the basic console output as it doesnt emulate other<br>
devices. If you need to load in things that rely on using the<br>
optional I/O devices, see the Advanced Builds chapter.</p>
<h2 id="retro-muri">retro-muri</h2>
<p>This is the assembler for Nga. Its used to build the initial<br>
RETRO kernel and can be used by other tools as well.</p>
<h2 id="retro-unu">retro-unu</h2>
<p>This is the literate source extraction tool for RETRO. It<br>
is used in building <code>retro</code>.</p>
<p>Example usage:</p>
<pre><code>retro-unu literate/RetroForth.md
</code></pre>
<p>Output is written to stdout; redirect as neeeded.</p>
<h1 id="advanced-builds">Advanced Builds</h1>
<h2 id="reduced-memory">Reduced Memory</h2>
<p>RETRO can be built for reduced memory targets. This is primarily<br>
intendeded for use with embedded targets, but can be useful on<br>
large machines as well.</p>
<p>To do this, <code>make</code> with <code>CFLAGS</code> set to <code>-DMEM1024K</code>, <code>-DMEM512K</code>,<br>
<code>-DMEM256K</code>, <code>-DMEM192K</code>, <code>-DMEM128K</code> or <code>-DMEM96K</code>. These will<br>
target memory sizes as specified per the following table.</p>
<table>
<thead>
<tr>
<th></th>
<th>1024kB</th>
<th>512kB</th>
<th>256kB</th>
<th>192kB</th>
<th>128kB</th>
<th>96kB</th>
</tr>
</thead>
<tbody>
<tr>
<td>Total Bytes</td>
<td>1,048,579</td>
<td>524,288</td>
<td>262,144</td>
<td>196,608</td>
<td>131,072</td>
<td>98,304</td>
</tr>
<tr>
<td>Image</td>
<td>968,000</td>
<td>450,000</td>
<td>192,000</td>
<td>126,000</td>
<td>96,000</td>
<td>72,000</td>
</tr>
<tr>
<td>Data Stack</td>
<td>512</td>
<td>512</td>
<td>512</td>
<td>512</td>
<td>512</td>
<td>512</td>
</tr>
<tr>
<td>Address Stack</td>
<td>1,024</td>
<td>1,024</td>
<td>1,024</td>
<td>1,024</td>
<td>1,024</td>
<td>1,024</td>
</tr>
<tr>
<td>Remaining</td>
<td>79,040</td>
<td>72,752</td>
<td>68,608</td>
<td>69,072</td>
<td>33,536</td>
<td>24,768</td>
</tr>
</tbody>
</table><p>The remaining memory is available for use by the VM.</p>
<h2 id="custom-image">Custom Image</h2>
<p>For users of BSD, Linux, macOS, you can customize the image at<br>
build time.</p>
<p>In the top level directory is a <code>package</code> directory containing<br>
a file named <code>list</code>. You can add files to compile into your<br>
system by adding them to the <code>list</code> and rebuilding.</p>
<p>Example:</p>
<p>If you have wanted to include the NumbersWithoutPrefixes.forth<br>
example, add:</p>
<pre><code>~~~
'example/NumbersWithoutPrefixes.forth include
~~~
</code></pre>
<p>To the start of the <code>list</code> file and then run <code>make</code> again. The<br>
newly built <code>bin/retro</code> will now include your additions.</p>
<h1 id="the-optional-retro-compiler">The Optional Retro Compiler</h1>
<p>In addition to the base system, users of RETRO on Unix hosts<br>
with ELF executables can build and use the <code>retro-compiler</code><br>
to generate turnkey executables.</p>
<h2 id="requirements-3">Requirements</h2>
<ul>
<li>Unix host</li>
<li>ELF executable support</li>
<li>objcpy in the $PATH</li>
</ul>
<h2 id="building">Building</h2>
<p>BSD users:</p>
<p>make bin/retro-compiler</p>
<p>Linux users:</p>
<p>make -f Makefile.linux bin/retro-compiler</p>
<h2 id="installing">Installing</h2>
<p>Copy <code>bin/retro-compiler</code> to somewhere in your $PATH.</p>
<h2 id="using">Using</h2>
<p><code>retro-compiler</code> takes two arguments: the source file to<br>
compile and the name of the word to use as the main entry<br>
point.</p>
<p>Example:</p>
<p>Given a <code>hello.forth</code>:</p>
<pre><code>:hello 'Hello_World! s:put nl ;
</code></pre>
<p>Use:</p>
<pre><code>retro-compiler hello.forth hello
</code></pre>
<p>The compiler will generate an <code>a.out</code> file which you can<br>
then rename.</p>
<h2 id="known-limitations">Known Limitations</h2>
<p>This does not provide the scripting support for command line<br>
arguments that the standard <code>retro</code> interface offers.</p>
<p>A copy of <code>objcopy</code> needs to be in the path for compilation<br>
to work.</p>
<p>The current working directory must be writable.</p>
<p>This only supports hosts using ELF executables.</p>
<p>The output file name is fixed to <code>a.out</code>.</p>
<h1 id="errors">Errors</h1>
<p>RETRO does only minimal error checking.</p>
<h2 id="non-fatal">Non-Fatal</h2>
<p>A non-fatal error will be reported on <em>word not found</em> during<br>
interactive or compile time. Note that this only applies to<br>
calls: if you try to get a pointer to an undefined word, the<br>
returned pointer will be zero.</p>
<h2 id="fatal">Fatal</h2>
<p>A number of conditions are known to cause fatal errors. The<br>
main ones are stack overflow, stack underflow, and division<br>
by zero.</p>
<p>On these, RETRO will generally exit. For stack depth issues,<br>
the VM will attempt to display an error prior to exiting.</p>
<p>In some cases, the VM may get stuck in an endless loop. If this<br>
occurs, try using CTRL+C to kill the process, or kill it using<br>
whatever means your host system provides.</p>
<h2 id="rationale">Rationale</h2>
<p>Error checks are useful, but slow - especially on a minimal<br>
system like RETRO. The overhead of doing depth or other checks<br>
adds up quickly.</p>
<p>As an example, adding a depth check to <code>drop</code> increases the<br>
time to use it 250,000 times in a loop from 0.16 seconds to<br>
1.69 seconds.</p>
<h1 id="security-concerns">Security Concerns</h1>
<p>The standard RETRO is not a good choice for applications<br>
needing to be highly secure.</p>
<h2 id="runtime-checks">Runtime Checks</h2>
<p>The RETRO system performs only minimal checks. It will not<br>
load an image larger than the max set at build time. And<br>
stack over/underflow are checked for as code executes.</p>
<p>The system does not attempt to validate anything else, its<br>
quite easy to crash.</p>
<h2 id="isolation">Isolation</h2>
<p>The VM itself and the core code is self contained. Nga does<br>
not make use of malloc/free, and uses only standard system<br>
libraries. Its possible for buffer overruns within the image<br>
(overwriting Nga code), but the RETRO image shouldnt leak<br>
into the C portions.</p>
<p>I/O presents a bigger issue. Anything involving I/O, especially<br>
with the <code>unix:</code> words, may be a vector for attacks.</p>
<h2 id="future-direction">Future Direction</h2>
<p>Im not planning to add anything to the <em>image</em> side as, for me,<br>
the performance hit due to added checks is bigger than the<br>
benefits.</p>
<p>The story is different on the VM side. Ive already begun taking<br>
steps to address some of the issues, using functions that check<br>
for overruns with strings and doing some minor testing for these<br>
conditions. I will be gradually addressing the various I/O<br>
related extensions, though its unlikely to ever be fully guarded<br>
against attacks.</p>
<h2 id="rationale-1">Rationale</h2>
<p>RETRO is, primarily, a personal system. Im running code I wrote<br>
to solve problems I face. On the occasions where I run code sent<br>
to me by others, I read it carefully first and then run inside a<br>
sandboxed environment if Im worried about anything in it.</p>
<h1 id="technical-notes-and-reflections">Technical Notes and Reflections</h1>
<p>This is a collection of short papers providing some additional<br>
background and reflections on design decisions.</p>
<h2 id="metacompilation-and-assembly">Metacompilation and Assembly</h2>
<p>RETRO 10 and 11 were written in themselves using a metacompiler.<br>
I had been fascinated by this idea for a long time and was able<br>
to explore it heavily. While I still find it to be a good idea,<br>
the way I ended up doing it was problematic.</p>
<p>The biggest issue I faced was that I wanted to do this in one<br>
step, where loading the RETRO source would create a new image<br>
in place of the old one, switch to the new one, and then load<br>
the higher level parts of the language over this. In retrospect,<br>
this was a really bad idea.</p>
<p>My earlier design for RETRO was very flexible. I allowed almost<br>
everything to be swapped out or extended at any time. This made<br>
it extremely easy to customize the language and environment, but<br>
made it crucial to keep track of what was in memory and what had<br>
been patched so that the metacompiler wouldnt refer to anything<br>
in the old image during the relocation and control change. It<br>
was far too easy to make a mistake, discover that elements of<br>
the new image were broken, and then have to go and revert many<br>
changes to try to figure out what went wrong.</p>
<p>This was also complicated by the fact that I built new images<br>
as I worked, and, while a new image could be built from the last<br>
built one, it wasnt always possible to build a new image from<br>
the prior release version. (Actually, it was often worse - I<br>
failed to check in every change as I went, so often even the<br>
prior commits couldnt rebuild the latest images).</p>
<p>For RETRO 12 I wanted to avoid this problem, so I decided to go<br>
back to writing the kernel (“Rx”) in assembly. I actually wrote<br>
a Machine Forth dialect to generate the initial assembly, before<br>
eventually hand tuning the final results to its current state.</p>
<p>I could (and likely will eventually) write the assembler in<br>
RETRO, but the current one is in C, and is built as part of the<br>
standard toolchain.</p>
<p>My VM actually has two assemblers. The older one is Naje. This<br>
was intended to be fairly friendly to work with, and handles<br>
many of the details of packing instructions for the user. Here<br>
is an example of a small program in it:</p>
<pre><code>:square
dup
mul
ret
:main
lit 35
lit &amp;square
call
lit &amp;square
call
end
</code></pre>
<p>The other assembler is Muri. This is a far more minimalistic<br>
assembler, but Ive actually grown to prefer it. The above<br>
example in Muri would become:</p>
<pre><code>i liju....
r main
: square
i dumure..
: main
i lilica..
d 35
r square
i en......
</code></pre>
<p>In Muri, each instruction is reduced to two characters, and the<br>
bundlings are listed as part of an instruction bundle (lines<br>
starting with <code>i</code>). This is less readable if you arent very<br>
familiar with Ngas assembly and packing rules, but allows a<br>
very quick, efficient way of writing assembly for those who are.</p>
<p>I eventually rewrote the kernel in the Muri style as its what<br>
I prefer, and since theres not much need to make changes in it.</p>
<h2 id="the-path-to-self-hosting">The Path to Self Hosting</h2>
<p>RETRO is an image based Forth system running on a lightweight<br>
virtual machine. This is the story of how that image is made.</p>
<p>The first RETRO to use an image based approach was RETRO 10.<br>
The earliest images were built using a compiler written in<br>
Toka, an earlier experimental stack language I had written.<br>
It didnt take long to want to drop the dependency on Toka,<br>
so I rewrote the image compiler in RETRO and then began<br>
development at a faster pace.</p>
<p>RETRO 11 was built using the last RETRO 10 image and an<br>
evolved version of the metacompiler. This worked well, but<br>
I eventually found it to be problematic.</p>
<p>One of the issues I faced was the inability to make a new<br>
image from the prior stable release. Since I develop and<br>
test changes incrementally, I reached a point where the<br>
current metacompiler and image required each other. This<br>
wasnt a fatal flaw, but it was annoying.</p>
<p>Perhaps more critical was the fragility of the system. In<br>
R11 small mistakes could result in a corrupt image. The test<br>
suite helped identify some of these, but there were a few<br>
times I was forced to dig back through the version control<br>
history to recover a working image.</p>
<p>The fragile nature was amplified by some design decisions.<br>
In R11, after the initial kernel was built, it would be<br>
moved to memory address 0, then control would jump into the<br>
new kernel to finish building the higher level parts.</p>
<p>Handling this was a tricky task. In R11 almost everything<br>
could be revectored, so the metacompiler had to ensure that<br>
it didnt rely on anything in the old image during the move.<br>
This caused a large number of issues over R11s life.</p>
<p>So on to RETRO 12. I decided that this would be different.<br>
First, the kernel would be assembly, with an external tool<br>
to generate the core image. The kernel is in <code>Rx.md</code> and the<br>
assembler is <code>Muri</code>. To load the standard library, I wrote a<br>
second tool, <code>retro-extend</code>. This separation has allowed me<br>
many fewer headaches as I can make changes more easily and<br>
rebuild from scratch when necessary.</p>
<p>But I miss self-hosting. So last fall I decided to resolve<br>
this. And today Im pleased to say that it is now done.</p>
<p>There are a few parts to this.</p>
<p><strong>Unu</strong>. I use a Markdown variation with fenced code blocks.<br>
The tool I wrote in C to extract these is called <code>unu</code>. For<br>
a self hosting RETRO, I rewrote this as a combinator that<br>
reads in a file and runs another word against each line in the<br>
file. So I could display the code block contents by doing:</p>
<pre><code>'filename [ s:put nl ] unu
</code></pre>
<p>This made it easier to implement the other tools.</p>
<p><strong>Muri</strong>. This is my assembler. Its minimalistic, fast, and<br>
works really well for my purposes. RETRO includes a runtime<br>
version of this (using <code>as{</code>, <code>}as</code>, <code>i</code>, <code>d</code>, and <code>r</code>), so<br>
all I needed for this was to write a few words to parse the<br>
lines and run the corresponding runtime words. As with the C<br>
version, this is a two pass assembler.</p>
<p>Muri generates a new <code>ngaImage</code> with the kernel. To create a<br>
full image I needed a way to load in the standard library and<br>
I/O extensions.</p>
<p>This is handled by <strong>retro-extend</strong>. This is where it gets<br>
more complex. I implemented the Nga virtual machine in RETRO<br>
to allow this to run the new image in isolation from the<br>
host image. The new ngaImage is loaded, the interpreter is<br>
located, and each token is passed to the interpreter. Once<br>
done, the new image is written to disk.</p>
<p>So at this point Im pleased to say that I can now develop<br>
RETRO using only an existing copy of RETRO (VM+image) and<br>
tools (unu, muri, retro-extend, and a line oriented text<br>
editor) written in RETRO.</p>
<p>This project has delivered some additional side benefits.<br>
During the testing I was able to use it to identify a few<br>
bugs in the I/O extensions, and the Nga-in-RETRO will replace<br>
the older attempt at this in the debugger, allowing a safer<br>
testing environment.</p>
<p>What issues remain?</p>
<p>The extend process is <em>slow</em>. On my main development server<br>
(Linode 1024, OpenBSD 6.4, 64-bit) it takes a bit over five<br>
minutes to complete loading the standard library, and a few<br>
additional depending on the I/O drivers selected.</p>
<p>Most of the performance issues come from running Nga-in-RETRO<br>
to isolate the new image from the host one. Itd be possible<br>
to do something a bit more clever (e.g., running a RETRO<br>
instance using the new image via a subprocess and piping in<br>
the source, or doing relocations of the data), but this is<br>
less error prone and will work on all systems that I plan to<br>
support (including, with a few minor adjustments, the native<br>
hardware versions [assuming the existance of mass storage]).</p>
<p>Sources:</p>
<p><strong>Unu</strong></p>
<ul>
<li><a href="http://forth.works/c8820f85e0c52d32c7f9f64c28f435c0">http://forth.works/c8820f85e0c52d32c7f9f64c28f435c0</a></li>
<li>gopher://forth.works/0/c8820f85e0c52d32c7f9f64c28f435c0</li>
</ul>
<p><strong>Muri</strong></p>
<ul>
<li><a href="http://forth.works/09d6c4f3f8ab484a31107dca780058e3">http://forth.works/09d6c4f3f8ab484a31107dca780058e3</a></li>
<li>gopher://forth.works/0/09d6c4f3f8ab484a31107dca780058e3</li>
</ul>
<p><strong>retro-extend</strong></p>
<ul>
<li><a href="http://forth.works/c812416f397af11db58e97388a3238f2">http://forth.works/c812416f397af11db58e97388a3238f2</a></li>
<li>gopher://forth.works/0/c812416f397af11db58e97388a3238f2</li>
</ul>
<h2 id="prefixes-as-a-language-element">Prefixes as a Language Element</h2>
<p>A big change in RETRO 12 was the elimination of the traditional<br>
parser from the language. This was a sacrifice due to the lack<br>
of an I/O model. RETRO has no way to know <em>how</em> input is given<br>
to the <code>interpret</code> word, or whether anything else will ever be<br>
passed into it.</p>
<p>And so <code>interpret</code> operates only on the current token. The core<br>
language does not track what came before or attempt to guess at<br>
what might come in the future.</p>
<p>This leads into the prefixes. RETRO 11 had a complicated system<br>
for prefixes, with different types of prefixes for words that<br>
parsed ahead (e.g., strings) and words that operated on the<br>
current token (e.g., <code>@</code>). RETRO 12 eliminates all of these in<br>
favor of just having a single prefix model.</p>
<p>The first thing <code>interpret</code> does is look to see if the first<br>
character in a token matches a <code>prefix:</code> word. If it does, it<br>
passes the rest of the token as a string pointer to the prefix<br>
specific handler to deal with. If there is no valid prefix<br>
found, it tries to find it in the dictionary. Assuming that it<br>
finds the words, it passes the <code>d:xt</code> field to the handler that<br>
<code>d:class</code> points to. Otherwise it calls <code>err:notfound</code>.</p>
<p>This has an important implication: <em>words can not reliably<br>
have names that start with a prefix character.</em></p>
<p>It also simplifies things. Anything that would normally parse<br>
becomes a prefix handler. So creating a new word? Use the <code>:</code><br>
prefix. Strings? Use <code>'</code>. Pointers? Try <code>&amp;</code>. And so on. E.g.,</p>
<pre><code>In ANS | In RETRO
: foo ... ; | :foo ... ;
' foo | &amp;foo
: bar ... ['] foo ; | :bar ... &amp;foo ;
s" hello world!" | 'hello_world!
</code></pre>
<p>If you are familiar with ColorForth, prefixes are a similar<br>
idea to colors, but can be defined by the user as normal words.</p>
<p>After doing this for quite a while I rather like it. I can see<br>
why Chuck Moore eventually went towards ColorForth as using<br>
color (or prefixes in my case) does simplify the implementation<br>
in many ways.</p>
<h2 id="on-the-kernel-wordset">On The Kernel Wordset</h2>
<p>In implementing the RETRO 12 kernel (called Rx) I had to decide<br>
on what functionality would be needed. It was important to me<br>
that this be kept clean and minimalistic, as I didnt want to<br>
spend a lot of time changing it as time progressed. Its far<br>
nicer to code at the higher level, where the RETRO language is<br>
functional, as opposed to writing more assembly code.</p>
<p>So what made it in?</p>
<p>Primitives</p>
<p>These are words that map directly to Nga instructions.</p>
<pre><code>dup drop swap call eq? -eq? lt? gt?
fetch store + - * /mod and or
xor shift push pop 0;
</code></pre>
<p>Memory</p>
<pre><code>fetch-next store-next , s,
</code></pre>
<p>Strings</p>
<pre><code>s:to-number s:eq? s:length
</code></pre>
<p>Flow Control</p>
<pre><code>choose if -if repeat again
</code></pre>
<p>Compiler &amp; Interpreter</p>
<pre><code>Compiler Heap ; [ ] Dictionary
d:link d:class d:xt d:name d:add-header
class:word class:primitive class:data class:macro
prefix:: prefix:# prefix:&amp; prefix:$
interpret d:lookup err:notfound
</code></pre>
<p>I <em>could</em> slightly reduce this. The $ prefix could be defined in<br>
higher level code, and I dont strictly <em>need</em> to expose the<br>
<code>fetch-next</code> and <code>store-next</code> here. But since the are already<br>
implemented as dependencies of the words in the kernel, it would<br>
be a bit wasteful to redefine them later in higher level code.</p>
<p>With these words the rest of the language can be built up. Note<br>
that the Rx kernel does not provide any I/O words. Its assumed<br>
that the RETRO interfaces will add these as best suited for the<br>
systems they run on.</p>
<p>There is another small bit. All images start with a few key<br>
pointers in fixed offsets of memory. These are:</p>
<pre><code>| Offset | Contains |
| ------ | --------------------------- |
| 0 | lit call nop nop |
| 1 | Pointer to main entry point |
| 2 | Dictionary |
| 3 | Heap |
| 4 | RETRO version identifier |
</code></pre>
<p>An interface can use the dictionary pointer and knowledge of the<br>
dictionary format for a specific RETRO version to identify the<br>
location of essential words like <code>interpret</code> and <code>err:notfound</code><br>
when implementing the user facing interface.</p>
<h2 id="on-the-evolution-of-ngaro-into-nga">On The Evolution Of Ngaro Into Nga</h2>
<p>When I decided to begin work on what became RETRO 12, I knew<br>
the process would involve updating Ngaro, the virtual machine<br>
that RETRO 10 and 11 ran on.</p>
<p>Ngaro rose out of an earlier experimental virtual machine I had<br>
written back in 2005-2006. This earlier VM, called Maunga, was<br>
very close to what Ngaro ended up being, though it had a very<br>
different approach to I/O. (All I/O in Maunga was intended to be<br>
memory mapped; Ngaro adopted a port based I/O system).</p>
<p>Ngaro itself evolved along with RETRO, gaining features like<br>
automated skipping of NOPs and a LOOP opcode to help improve<br>
performance. But the I/O model proved to be a problem. When I<br>
created Ngaro, I had the idea that I would always be able to<br>
assume a console/terminal style environment. The assumption was<br>
that all code would be entered via the keyboard (or maybe a<br>
block editor), and that proved to be the fundamental flaw as<br>
time went on.</p>
<p>As RETRO grew it was evident that the model had some serious<br>
problems. Need to load code from a file? The VM and language had<br>
functionality to pretend it was being typed in. Want to run on<br>
something like a browser, Android, or iOS? The VM would need to<br>
be implemented in a way that simulates input being typed into<br>
the VM via a simulated keyboard. And RETRO was built around this.<br>
I couldnt change it because of a promise to maintain, as much<br>
as possible, source compatibility for a period of at least five<br>
years.</p>
<p>When the time came to fix this, I decided at the start to keep<br>
the I/O model separate from the core VM. I also decided that the<br>
core RETRO language would provide some means of interpreting<br>
code without requiring an assumption that a traditional terminal<br>
was being used.</p>
<p>So Nga began. I took the opportunity to simplify the instruction<br>
set to just 26 essential instructions, add support for packing<br>
multiple instructions per memory location (allowing a long due<br>
reduction in memory footprint), and to generally just make a far<br>
simpler design.</p>
<p>Ive been pleased with Nga. On its own it really isnt useful<br>
though. So with RETRO I embed it into a larger framework that<br>
adds some basic I/O functionality. The <em>interfaces</em> handle the<br>
details of passing tokens into the language and capturing any<br>
output. They are free to do this in whatever model makes most<br>
sense on a given platform.</p>
<p>So far Ive implemented:</p>
<pre><code>- a scripting interface, reading input from a file and
offering file i/o, gopher, and reading from stdin, and
sending output to stdout.
- an interactive interface, built around ncurses, reading
input from stdin, and displaying output to a scrolling
buffer.
- an iOS interface, built around a text editor, directing
output to a separate interface pane.
- an interactive block editor, using a gopher-based block
data store. Output is displayed to stdout, and input is
done via the blocks being evaluated or by reading from
stdin.
</code></pre>
<p>In all cases, the only common I/O word that has to map to an<br>
exposed instruction is <code>putc</code>, to display a single character to<br>
some output device. There is no requirement for a traditional<br>
keyboard input model.</p>
<p>By doing this I was able to solve the biggest portability issue<br>
with the RETRO 10/11 model, and make a much simpler, cleaner<br>
language in the end.</p>
<h2 id="retro-11-2011---2019-a-look-back">RETRO 11 (2011 - 2019): A Look Back</h2>
<p>So its now been about five years since the last release of RETRO<br>
11. While I still see some people obtaining and using it, Ive<br>
moved on to the twelth generation of RETRO. Its time for me to<br>
finally retire RETRO 11.</p>
<p>As I prepare to do so, I thought Id take a brief look back.</p>
<p>RETRO 11 began life in 2011. It grew out of RETRO 10, which was<br>
the first version of RETRO to not be written in x86 assembly<br>
language. For R10 and R11, I wrote a portable virtual machine<br>
(with numerous implementations) and the Forth dialect was kept<br>
in an image file which ran on the VM.</p>
<p>RETRO 10 worked, but was always a bit too sloppy and changed<br>
drastically between releases. The major goal of RETRO 11 was to<br>
provide a stable base for a five year period. In retrospect,<br>
this was mostly achieved. Code from earlier releases normally<br>
needed only minor adjustments to run on later releases, though<br>
newer releases added significantly to the language.</p>
<p>There were seven releases.</p>
<ul>
<li>Release 11.0: 2011, July</li>
<li>Release 11.1: 2011, November</li>
<li>Release 11.2: 2012, January</li>
<li>Release 11.3: 2012, March</li>
<li>Release 11.4: 2012, July</li>
<li>Release 11.5: 2013, March</li>
<li>Release 11.6: 2014, August</li>
</ul>
<p>Development was fast until 11.4. This was the point at which I<br>
had to slow down due to RSI problems. It was also the point<br>
which I started experiencing some problems with the metacompiler<br>
(as discussed previously).</p>
<p>RETRO 11 was flexible. All colon definitions were setup as hooks,<br>
allowing new functionality to be layered in easily. This allowed<br>
the later releases to add things like vocabularies, search order,<br>
tab completion, and keyboard remapping. This all came at a cost<br>
though: later things could use the hooks to alter behavior of<br>
existing words, so it was necessary to use a lot of caution to<br>
ensure that the layers didnt break the earlier code.</p>
<p>The biggest issue was the I/O model. RETRO 11 and the Ngaro VM<br>
assumed the existence of a console environment. All input was<br>
required to be input at the keyboard, and all output was to be<br>
shown on screen. This caused some problems. Including code from<br>
a file required some tricks, temporarily rewriting the keyboard<br>
input function to read from the file. It also became a major<br>
issue when I wrote the iOS version. The need to simulate the<br>
keyboard and console complicated everything and I had to spend<br>
a considerable amount of effort to deal with battery performance<br>
resulting from the I/O polling and wait states.</p>
<p>But on the whole it worked well. I used RETRO 11.6 until I started<br>
work on RETRO 12 in late 2016, and continued running some tools<br>
written in R11 until the first quarter of last year.</p>
<p>The final image file was 23,137 cells (92,548 bytes). This was<br>
bloated by keeping some documentation (stack comments and short<br>
descriptions) in the image, which started in 11.4. This contained<br>
269 words.</p>
<p>I used RETRO 11 for a wide variety of tasks. A small selection of<br>
things that were written includes:</p>
<ul>
<li>a pastebin</li>
<li>front end to ii (irc client)</li>
<li>small explorations of interactive fiction</li>
<li>irc log viewer</li>
<li>tool to create html from templates</li>
<li>tool to automate creation of an SVCD from a set of photos</li>
<li>tools to generate reports from data sets for my employer</li>
</ul>
<p>In the end, Im happy with how RETRO 11 turned out. I made some<br>
mistakes in embracing too much complexity, but despite this it<br>
was a successful system for many years.</p>
<h1 id="historical-papers-and-notes">Historical Papers and Notes</h1>
<h2 id="on-the-naming-of-retro">On the Naming of RETRO</h2>
<p>Taken from <a href="http://lists.tunes.org/archives/tunes-lll/1999-July/000121.html">http://lists.tunes.org/archives/tunes-lll/1999-July/000121.html</a></p>
<p>On Fri, Jul 30, 1999 at 07:43:54PM -0400, Paul Dufresne wrote:</p>
<blockquote>
<p>My brother did found it funny that Retro is called like that.<br>
For him retro means going back (generally in time) so this<br>
does not looks like a name of a OS to come. So hed like to<br>
know from where the name came.</p>
</blockquote>
<p>Heheh, heres the story: When I started playing with OS stuff<br>
last year (not seriously), I was reading about some old things<br>
like FORTH and ITS, dating back to the 1960s and 70s. The<br>
past few years in America, theres been a revival of disco<br>
music (along with bell bottoms, platform shoes, and all that<br>
crap) and they call it “retro”. Now, my OS was named by<br>
musicians… I was telling a fellow musician about my ideas,<br>
how it would be cool to have a small OS that isnt bloated and<br>
unmanageable like Windows… go back to the 70s and resurrect<br>
a line of software that died out. He goes “hmm… sounds kinda<br>
retro…”</p>
<p>I think it sounds kinda rebellious, which is a Good Thing now<br>
that everybody hates the M$ empire. :) It seems like other<br>
people are as sick of the future as I am. Look at TUNES, the<br>
idea there isnt to make some great new invention, just take<br>
some decades-old ideas and combine them in one OS. The first<br>
time I saw Knuths “Art of Computer Programming” in the library<br>
I thought “god that looks old… 1973!!! nevermind…” Now its<br>
my programming bible. Find me something better published in<br>
the 90s… if such a thing exists, itll be like a needle in a<br>
haystack. “Newer” doesnt necessarily mean “better”.</p>
<pre><code>New cars = flimsier
New farming methods = more devastating
New version of Netscape = more bloat, more bullshit
</code></pre>
<p>One thing is better now: computer hardware. Give me 70s<br>
software on 90s and 00s hardware :)</p>
<ul>
<li>Tom Novelli <a href="mailto:tcn@tunes.org">tcn@tunes.org</a></li>
</ul>
<h2 id="the-design-philosophy-of-retro-native-forth">The Design Philosophy of RETRO Native Forth</h2>
<p>Computer software is a technology in its infancy, a mere fifty years<br>
old. The last 25 years in particular have seen an explosion in the<br>
software business. However, software has seen little innovation while<br>
hardware technology has improved phenomenally (notwithstanding the advent<br>
of lousy slave-made parts). Proven software techniques of forty years ago<br>
have yet to reach widespread use, in deference to the “latest and<br>
greatest” proprietary solutions of dubious value. Thanks to agressive<br>
marketing, we make huge investments in these dead-end technologies<br>
(through our businesses and governments, if not personally) and we end up<br>
with a reliance on a heap of complicated, error-prone, poorly understood<br>
junk software.</p>
<p>Complexity will dominate the software industry for the foreseeable<br>
future. The Retro philosophy is a simple alternative for those willing to<br>
make a clean break with legacy software. A Retro system can communicate<br>
with other systems, but it wont run much legacy software, especially<br>
proprietary software without source code. An emulation layer could be<br>
added, but doing so would defeat the purpose of a simple operating system.<br>
I think TCP/IP support is all the compatibility thats needed.</p>
<p>At first Retro will appeal to computer hobbyists and electronic<br>
engineers. Once the rough edges are smoothed out, it could catch on with<br>
ordinary folks who dont like waiting five minutes just to check their<br>
email (not to mention the long hours of setup and maintenance). Game<br>
programmers who take their craft seriously may also be interested.<br>
Businesses might even see a use for it, if the managers decide its more<br>
cost-effective to carefully design software for specific needs, rather<br>
than buying off-the-shelf crap and spending countless manhours working<br>
around the bugs. Since its not practical for businesses to make a clean<br>
break, my advice is to run Retro (and its ilk) on separate machines<br>
connected by a network. Retro is efficient enough to run on older<br>
machines that would otherwise sit idle, being too slow for the latest<br>
Microsoft bloatware (or Linux, for that matter).</p>
<p>I strive to avoid the extraneous. That applies even to proven<br>
technologies, if I dont need them. If my computer isnt set up for<br>
people to log in over the network, I dont want security features; they<br>
just get in the way. If Im only running programs I wrote, I should be<br>
able to run them with full access to the hardware; I dont need protection<br>
from viruses. If I download something I dont trust, then I can run it in<br>
an isolated process, which is customary with Unix and kin. But thats not<br>
core functionality. All thats needed is the flexibility to add things<br>
like security, graphical interfaces, and distributed processing - if the<br>
need ever arises.</p>
<p>In programming languagues, I was misled. Its the Tower of Babel all<br>
over again. The thousands of languages in existence all fall into a<br>
handful of archetypes: Assembler, LISP, FORTRAN and FORTH represent the<br>
earliest descendants of nearly all languages. I hesitate to name a<br>
definitive “object-oriented” language, and heres why: Object-Oriented<br>
programming is just a technique, and any language will suffice, even<br>
Assembler. The complexites of fancy languages like Ada and C++ are a<br>
departure from reality the reality of the actual physical machine.<br>
When it all boils down, even LISP, FORTRAN and FORTH are only extensions<br>
of the machine.</p>
<p>I chose FORTH as the “native tongue” of Retro. LISP, FORTRAN, and<br>
other languages can be efficiently implemented as extensions of FORTH, but<br>
the reverse isnt so efficient. Theoretically all languages are<br>
equivalent, but when design time, compilation time, and complexity are<br>
accounted for, FORTH is most efficient. FORTH also translates most<br>
directly to the hardware. (In fact, FORTH has been implemented in<br>
hardware; these “stack machines” are extremely efficient.) FORTH is also<br>
the easiest language to implement from scratch - a major concern when<br>
youre trying to make a clean break. So with simplicity in mind, FORTH<br>
was the obvious choice.</p>
<p>Im perfectly happy working with text only, and I go to great lengths<br>
to avoid using the standard graphical environments, which have major<br>
problems: windows, pulldown menus, and mice. Windows cant share the<br>
screen nicely; that idea is hopeless. Pulldowns are tedious. Mice get in<br>
the way of typing without reducing the need for it; all they give me is<br>
tendonitis. Their main use is for drawing.</p>
<p>Some of my favorite interfaces: Telix, Telegard BBS, Pine, Pico, Lynx,<br>
and ScreamTracker. All “hotkey” interfaces where you press a key or two<br>
to perform an action. Usually the important commands are listed at the<br>
bottom of the screen, or at least on a help screen. The same principles<br>
apply to graphical interfaces: use the full screen, except for a status<br>
and menu area on one edge. Resist the temptation to clutter up the<br>
screen.</p>
<p>As for switching between programs, the Windows methods suck; the only<br>
thing worse is Unix job control (jobs, fg, and such). The Linux method is<br>
tolerable: Alt-Arrows, Alt-F1, Alt-F2, etc. Still, things could be<br>
better: F11 and F12 cycle back and forth through all open programs; Alt-F1<br>
assigns the currently selected program to F1, and likewise for the other<br>
function keys. Programs just wont use function keys - Control and Alt<br>
combinations are less awkward and easier to remember, besides. Ill also<br>
want a “last channel” key and a “task list” key; maybe Ill borrow those<br>
stupid Win95 keys. The Pause key will do like it says - pause the current<br>
program - and Ctrl-Pause (Break) will kill it.</p>
<p>One more thing: consistency. I like programs to look different so I<br>
can tell them apart, but the keys should be the same as much as possible.<br>
Keys should be configured in one place, for all programs. Finally,<br>
remember the most consistent interface, one of the few constants<br>
throughout the history of computing - the text screen and keyboard, and<br>
the teletypewriter before that. Dont overlook it.</p>
<p>More to come, maybe… :)</p>
<p>“If its on line, its a work in progress.”</p>
<p>Tom Novelli, 3/4/2000</p>
</div>
</div>
</body>
</html>