ref: ca961874a00531d88c9b22c8abc09f9c7f90333e
parent: e5f0c0798b44ffaa03772477138ff0ae4df4763b
author: jsadler <jsadler@ficl.sf.net>
date: Tue Jun 6 23:25:57 CDT 2000
<>
--- a/Makefile
+++ b/Makefile
@@ -2,7 +2,7 @@
HEADERS= ficl.h math64.h sysdep.h
#
# Flags for shared library
-#SHFLAGS = -fPIC
+SHFLAGS = -fPIC
CFLAGS= -O -c $(SHFLAGS)
CC=gcc
LIB = ar cr
@@ -15,16 +15,18 @@
# static library build
libficl.a: $(OBJECTS)
- $(LIB) libficl.a $(OBJECTS)
- $(RANLIB) libficl.a
+ $(LIB) libficl.a $(OBJECTS)
+ $(RANLIB) libficl.a
# shared library build
libficl.so.$(MAJOR).$(MINOR): $(OBJECTS)
- $(CC) -shared -Wl,-soname,libficl.so.$(MAJOR) \
- -o libficl.so.$(MAJOR).$(MINOR) $(OBJECTS)
+ $(CC) -shared -Wl,-soname,libficl.so.$(MAJOR).$(MINOR) \
+ -o libficl.so.$(MAJOR).$(MINOR) $(OBJECTS)
+ ln -s libficl.so.$(MAJOR).$(MINOR) libficl.so
testmain: testmain.o ficl.h sysdep.h libficl.so.$(MAJOR).$(MINOR)
- $(CC) testmain.o -o testmain -L. -lficl -lm
+ $(CC) testmain.o -o testmain -L. -lficl -lm
+ ln -s libficl.so.$(MAJOR).$(MINOR) libficl.so.$(MAJOR)
#
# generic object code
@@ -32,10 +34,15 @@
.SUFFIXES: .cxx .cc .c .o
.c.o:
- $(CC) $(CFLAGS) -c $*.c
+ $(CC) $(CFLAGS) -c $*.c
.cxx.o:
- $(CPP) $(CPFLAGS) -c $*.cxx
+ $(CPP) $(CPFLAGS) -c $*.cxx
.cc.o:
- $(CPP) $(CPFLAGS) -c $*.cc
+ $(CPP) $(CPFLAGS) -c $*.cc
+#
+# generic cleanup code
+#
+clean:
+ rm -f *.o *.a testmain libficl.so*
--- a/ReadMe.txt
+++ b/ReadMe.txt
@@ -1,9 +1,47 @@
-Edit paste works more sensibly if there's already text on the
-line being appended to...
+Coming up:
+Rewrite exception words using inner loop function
+Web server scripting extension (GoAhead port)
-rel 2.03 (April 1999)
+ficlwin Debugger pane - step, stack trace, breakpoint
+Design:
+0. Debug pane or window - step-into step-over go
+1. DEBUG <word> --- lookup word, decompile it into debug pane
+2. At each STEP, stack pane displays stack state
+3. GO runs until breakpoint or leaves debug mode if no breaks
+4. BREAK stops debug vm at next step
+Requires a debug VM that checks for breaks, step mode, etc.
+rel 2.04 -- May 2000
ficlwin:
+- Catches exceptions thrown by VM in ficlThread (0 @ for example) rather than
+ passing them off to the OS.
+
+ficl bugs vanquished
+- Fixed leading delimiter bugs in s" ." .( and ( (reported by Reuben Thomas)
+- Makefile tabs restored (thanks to Michael Somos)
+- ABORT" now throws -2 per the DPANS (thanks to Daniel Sobral for sharp eyes again)
+- ficlExec does not print the prompt string unless (source-id == 0)
+- Various fixes from the FreeBSD team
+
+ficl enhancements
+- Words.c: modified ficlCatch to use vmExecute and vmInnerLoop (request of Daniel Sobral)
+- Added vmPop and vmPush functions (by request of Lars Krueger ) in vm.c
+ These are shortcuts to the param stack. (Use LVALUEtoCELL to get things into CELL form)
+- Added function vmGetStringEx with a flag to specify whether or not to
+ skip lead delimiters
+- Added non-std word: number?
+- Added CORE EXT word AGAIN (by request of Reuben Thomas)
+- Added double cell local (2local) support
+- Augmented Johns Hopkins local syntax so that locals whose names begin
+ with char 2 are treated as 2locals (OK - it's goofy, but handy for OOP)
+- C-string class revised and enhanced - now dynamically sized
+- C-hashstring class derived from c-string computes hashcode too.
+
+rel 2.03 -- April 1999
+
+ficlwin:
+- Edit paste works more sensibly if there's already text on the
+ line being appended to...
- File Menu: recent file list and Open now load files.
- Text ouput function is now faster through use of string
caching. Cache flushes at the end of each line and each
@@ -161,89 +199,4 @@
-
-========================================================================
- MICROSOFT FOUNDATION CLASS LIBRARY : ficlwin
-========================================================================
-
-
-AppWizard has created this ficlwin application for you. This application
-not only demonstrates the basics of using the Microsoft Foundation classes
-but is also a starting point for writing your application.
-
-This file contains a summary of what you will find in each of the files that
-make up your ficlwin application.
-
-ficlwin.h
- This is the main header file for the application. It includes other
- project specific headers (including Resource.h) and declares the
- CFiclwinApp application class.
-
-ficlwin.cpp
- This is the main application source file that contains the application
- class CFiclwinApp.
-
-ficlwin.rc
- This is a listing of all of the Microsoft Windows resources that the
- program uses. It includes the icons, bitmaps, and cursors that are stored
- in the RES subdirectory. This file can be directly edited in Microsoft
- Developer Studio.
-
-res\ficlwin.ico
- This is an icon file, which is used as the application's icon. This
- icon is included by the main resource file ficlwin.rc.
-
-res\ficlwin.rc2
- This file contains resources that are not edited by Microsoft
- Developer Studio. You should place all resources not
- editable by the resource editor in this file.
-
-ficlwin.clw
- This file contains information used by ClassWizard to edit existing
- classes or add new classes. ClassWizard also uses this file to store
- information needed to create and edit message maps and dialog data
- maps and to create prototype member functions.
-
-/////////////////////////////////////////////////////////////////////////////
-
-For the main frame window:
-
-MainFrm.h, MainFrm.cpp
- These files contain the frame class CMainFrame, which is derived from
- CFrameWnd and controls all SDI frame features.
-
-res\Toolbar.bmp
- This bitmap file is used to create tiled images for the toolbar.
- The initial toolbar and status bar are constructed in the
- CMainFrame class. Edit this toolbar bitmap along with the
- array in MainFrm.cpp to add more toolbar buttons.
-
-/////////////////////////////////////////////////////////////////////////////
-
-AppWizard creates one document type and one view:
-
-ficlwinDoc.h, ficlwinDoc.cpp - the document
- These files contain your CFiclwinDoc class. Edit these files to
- add your special document data and to implement file saving and loading
- (via CFiclwinDoc::Serialize).
-
-ficlwinView.h, ficlwinView.cpp - the view of the document
- These files contain your CFiclwinView class.
- CFiclwinView objects are used to view CFiclwinDoc objects.
-
-
-
-/////////////////////////////////////////////////////////////////////////////
-Other standard files:
-
-StdAfx.h, StdAfx.cpp
- These files are used to build a precompiled header (PCH) file
- named ficlwin.pch and a precompiled types file named StdAfx.obj.
-
-Resource.h
- This is the standard header file, which defines new resource IDs.
- Microsoft Developer Studio reads and updates this file.
-
-
-/////////////////////////////////////////////////////////////////////////////
--- a/dict.c
+++ b/dict.c
@@ -346,6 +346,7 @@
pDict = ficlMalloc(nAlloc);
assert(pDict);
+ memset(pDict, 0, sizeof (FICL_DICT));
pDict->size = nCells;
dictEmpty(pDict, nHash);
return pDict;
@@ -367,8 +368,7 @@
/**************************************************************************
d i c t E m p t y
** Empty the dictionary, reset its hash table, and reset its search order.
-** Clears and (re-)creates the main hash table (pForthWords) with the
-** size specified by nHash.
+** Clears and (re-)creates the hash table with the size specified by nHash.
**************************************************************************/
void dictEmpty(FICL_DICT *pDict, unsigned nHash)
{
--- a/doc/ficl.html
+++ b/doc/ficl.html
@@ -1,2904 +1,2667 @@
-<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
+
<head>
- <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
- <meta name="Author" content="john sadler">
- <meta name="GENERATOR" content="Mozilla/4.5 [en] (Win95; U) [Netscape]">
- <meta name="Description" content="all about the coolest scripting language ever">
- <title>ficl 2.03 release notes</title>
+<meta http-equiv="Content-Type"
+content="text/html; charset=iso-8859-1">
+<meta name="Author" content="john sadler">
+<meta name="Description"
+content="the coolest embedded scripting language ever">
+<meta name="GENERATOR" content="Microsoft FrontPage Express 2.0">
+<title>ficl release notes</title>
</head>
+
<body>
-<center>
-<h1>
-<b>ficl 2.03 release notes</b></h1></center>
+<h1 align="center"><b>ficl 2.04 release notes</b></h1>
-<table BORDER=0 CELLSPACING=3 WIDTH="600" >
-<tr>
-<td><b>Forth Inspired Command Language </b></td>
-
-<td ROWSPAN="4"><img SRC="ficl_logo.jpg" height=64 width=64></td>
-</tr>
-
-<tr>
-<td><b>Author: John Sadler (<a href="mailto:john_sadler@alum.mit.edu">john_sadler@alum.mit.edu</a>)</b></td>
-</tr>
-
-<tr>
-<td><b>Created: 19 July 1997 </b></td>
-</tr>
-
-<tr>
-<td><b>Revision 2.03: 20 May 1999 </b></td>
-</tr>
+<table border="0" cellspacing="3" width="600">
+ <tr>
+ <td><b>Forth Inspired Command Language </b></td>
+ <td rowspan="4"><img src="ficl_logo.jpg" width="64"
+ height="64"></td>
+ </tr>
+ <tr>
+ <td><b>Author: John Sadler (</b><a
+ href="mailto:john_sadler@alum.mit.edu"><b>john_sadler@alum.mit.edu</b></a><b>)</b></td>
+ </tr>
+ <tr>
+ <td><b>Created: 19 July 1997 </b></td>
+ </tr>
+ <tr>
+ <td><b>Revision 2.04: 20 May 2000</b></td>
+ </tr>
</table>
-<h2>
-Contents</h2>
+<h2>Contents</h2>
<ul>
-<li>
-<a href="#whatis">What is ficl?</a></li>
-
-<li>
-<a href="#features">Ficl features</a></li>
-
-<li>
-<a href="#porting">Porting</a></li>
-
-<li>
-<a href="#api">Application Programming Interface</a></li>
-
-<li>
-<a href="#manifest">Distribution source files</a></li>
-
-<li>
-<a href="#whatsnew">What's new in this release</a></li>
-
-<li>
-<a href="#objects">Objects in ficl</a></li>
-
-<ul>
-<li>
-<a href="ficl.html#oopgloss">OOP glossary</a></li>
-
-<li>
-<a href="#glossinstance">Instance variable glossary</a></li>
-
-<li>
-<a href="#glossclass">Class methods glossary</a></li>
-
-<li>
-<a href="#objectgloss">Object base class methods glossary</a></li>
-
-<li>
-<a href="#stockclasses">Supplied Classes</a></li>
+ <li><a href="#whatsnew">Release notes</a></li>
+ <li><a href="#whatis">What is ficl?</a></li>
+ <li><a href="#features">Ficl features</a></li>
+ <li><a href="#porting">Porting</a></li>
+ <li><a href="#api">Application Programming Interface</a></li>
+ <li><a href="#manifest">Distribution source files</a></li>
+ <li><a href="#locals">Local variables</a></li>
+ <li><a href="#objects">Object Oriented Programming in ficl</a></li>
+ <li><a href="#ootutorial">Ficl OO Tutorial</a></li>
+ <li><a href="#cstring">Ficl String Classes</a></li>
+ <li><a href="ficl.html#oopgloss">OOP glossary</a><ul>
+ <li><a href="#glossinstance">Instance variable
+ glossary</a></li>
+ <li><a href="#glossclass">Class methods glossary</a></li>
+ <li><a href="#objectgloss">Object base class methods
+ glossary</a></li>
+ <li><a href="#stockclasses">Supplied Classes</a></li>
+ </ul>
+ </li>
+ <li><a href="#extras">Ficl extras</a></li>
+ <li><a href="#ansinfo">ANS required information</a></li>
+ <li><a href="#links">Forth and Ficl references, <font
+ color="#000000"><b>download</b></font></a></li>
+ <li><a href="#includesficl"><font color="#000000">Some
+ software that includes ficl</font></a></li>
+ <li><a href="#lawyerbait">Disclaimer & License</a></li>
</ul>
-<li>
-<a href="#extras">Ficl extras</a></li>
+<p> </p>
-<li>
-<a href="#ansinfo">ANS required information</a></li>
-
-<li>
-<a href="#links">Forth and Ficl references, <b><font color="#000000">download</font></b></a></li>
-
-<li>
-<font color="#000000"><a href="#includesficl">Some software that includes
-ficl</a></font></li>
-
-<li>
-<a href="#lawyerbait">Disclaimer & License</a></li>
-</ul>
-
-<hr WIDTH="100%">
-<table CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="whatis"></a>What is ficl?</h2>
-Ficl (Forth inspired command language) is an ANS Forth interpreter written
-in C. Unlike traditional Forths, this interpreter is designed to be embedded
-into other systems as a command/macro/development prototype language. Ficl
-provides object extensions that can be used to wrap methods and structures
-of the host system without altering them. See below for examples of <a href="#includesficl">software
-that includes ficl</a>.</td>
-</tr>
-
-<tr>
-<td>Where Forths usually view themselves as the center of the system and
-expect the rest of the system to be coded in Forth, Ficl acts as a component
-of the system. It is easy to export code written in C or ASM to Ficl in
-the style of TCL, or to invoke Ficl code from a compiled module. This allows
-you to do incremental development in a way that combines the best features
-of threaded languages (rapid development, quick code/test/debug cycle,
-reasonably fast) with the best features of C (everyone knows it, easier
-to support large blocks of code, efficient, type checking). In addition,
-Ficl provides a simple object model that can act as an object oriented
-adapter for code written in C (or asm, Forth, C++...). </td>
-</tr>
-
-<tr>
-<td><b>Ficl Design goals</b>
-<ul>
-<li>
-Target 32 bit processors (<i>version 2.03 targets 64 bit processors too</i>)</li>
-
-<li>
-Scripting, prototyping, and extension language for systems written also
-in C</li>
-
-<li>
-Supportable - code is as transparent as I can make it</li>
-
-<li>
-Interface to functions written in C</li>
-
-<li>
-Conform to the Forth DPANS 94</li>
-
-<li>
-Minimize porting effort - require an ANSI C runtime environment and minimal
-glue code</li>
-
-<li>
-Provide object oriented extensions</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<br>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="features"></a>Ficl features</h2>
-
-<ul>
-<li>
-Code is written in ANSI C for portability. </li>
-
-<li>
-Standard: Implements the ANS Forth CORE word set, part of the CORE EXT
-word set, SEARCH and SEARCH EXT, TOOLS and part of TOOLS EXT, LOCAL and
-LOCAL EXT, EXCEPTION, MEMORY, and various extras.</li>
-
-<li>
-Extensible: you can export code written in Forth, C, or asm in a straightforward
-way. Ficl provides open facilities for extending the language in an application
-specific way. You can even add new control structures (not surprising if
-you're familiar with Forth)</li>
-
-<li>
-Ficl and C can interact in two ways: Ficl can wrap C code, and C functions
-can invoke ficl code.</li>
-
-<li>
-Ficl code is thread safe and re-entrant: All Ficl VMs share one system
-dictionary; each Ficl virtual machine has an otherwise complete state,
-and each can be bound to a separate I/O channel (or none at all). An optional
-function called ficlLockDictionary() can control exclusive dictionary access.
-This function is stubbed out by default (See FICL_MULTITHREAD in sysdep.h).
-As long as there is only one "session" that can compile words into the
-dictionary, you do not need exclusive dictionary access for multithreading.
-<font color="#000099"><b>Note</b>:
-while the code is re-entrant, there are still restrictions on how you can
-use it safely in a multithreaded system. Specifically, the VM itself maintains
-state, so you generally need a VM per thread in a multithreaded system.
-If interrupt service routines make calls into Ficl code that alters VM
-state, then these generally need their own VM as well. Alternatively, you
-could provide a mutual exclusion mechanism to serialize access to a VM
-from multiple threads.</font></li>
-
-<li>
-Simple incorporation into existing systems: the sample implementation requires
-three Ficl function calls (see the example program in testmain.c).</li>
-
-<li>
-ROM able: Ficl is designed to work in RAM based and ROM code / RAM data
-environments. It does require somewhat more memory than a pure ROM implementation
-because it builds its system dictionary in RAM at startup time.</li>
-
-<li>
-Written an ANSI C to be as simple as I can make it to understand, support,
-debug, and port. Compiles without complaint at /Az /W4 (require ANSI C,
-max. warnings) under Microsoft VC++</li>
-
-<li>
-Does full 32 bit math (but you need to implement two mixed precision math
-primitives (see sysdep.c))</li>
-
-<li>
-Type 1 indirect threaded interpreter</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<p>
-<hr WIDTH="100%">
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="porting"></a>Porting ficl</h2>
-To install ficl on your target system, you need an ANSI C compiler and
-its runtime library. Inspect the system dependent macros and functions
-in <tt>sysdep.h</tt> and <tt>sysdep.c</tt> and edit them to suit your system.
-For example, <tt>INT16</tt> is a <tt>short</tt> on some compilers and an
-<tt>int</tt>
-on others. Check the default <tt>CELL</tt> alignment controlled by <tt>FICL_ALIGN</tt>.
-If necessary, add new definitions of <tt>ficlMalloc, ficlFree, ficlLockDictionary</tt>,
-and <tt>ficlTextOut</tt> to work with your operating system. Finally, use
-<tt>testmain.c</tt>
-as a guide to installing the ficl system and one or more virtual machines
-into your code. You do not need to include <tt>testmain.c</tt> in your
-build.
-<p>Feel free to stub out the double precision math functions (which are
-presently implemented as inline assembly because it's so easy on many 32
-bit processors) with kludge code that only goes to 32 bit precision. In
-most applications, you won't notice the difference. If you're doing a lot
-of number crunching, consider implementing them correctly.
-<h3>
-Build controls</h3>
-The file sysdep.h contains default values for build controls. Most of these
-are written such that if you define them on the compiler command line,
-the defaults are overridden. I suggest you take the defaults on everything
-below the "build controls" section until you're confident of your port.
-Beware of declaring too small a dictionary, for example. You need about
-3200 cells for a full system, about 2000 if you strip out most of the "soft"
-words.
-<h3>
-To-Do List (target system dependent words)</h3>
-
-<ul>
-<li>
-Unimplemented system dependent <tt>CORE</tt> word: <tt>KEY</tt> </li>
-
-<li>
-Kludged <tt>CORE</tt> word: <tt>ACCEPT</tt></li>
-</ul>
-</td>
-</tr>
-</table>
-
-<br>
-<table COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="api"></a>Application Programming Interface</h2>
-<i>See the comments in ficl.c and ficl.h for additional information, and
-the example in file testmain.c.</i>
-<br>
-<dl>
-<dt>
-<b>void ficlInitSystem(int nDictCells)</b></dt>
-
-<dd>
-Initializes Ficl's shared system data structures, and creates the dictionary
-allocating the specified number of CELLs from the heap (by a call to ficlMalloc)</dd>
-
-<dt>
-<b>void ficlTermSystem(void)</b></dt>
-
-<dd>
-Reclaims memory allocated for the ficl system including all dictionaries
-and all virtual machines created by vmCreate. Any uses of the memory allocation
-words (allocate and resize) are your problem.</dd>
-
-<dt>
-<b>int ficlBuild(char *name, FICL_CODE code, char flags)</b></dt>
-
-<dd>
-Create a primitive word in ficl's main dictionary with the given name,
-code pointer, and properties (immediate, compile only, etc) as described
-by the flags (see ficl.h for flag descriptions of the form FW_XXXX)</dd>
-
-<dt>
-<b>int ficlExec(FICL_VM *pVM, char *text)</b></dt>
-
-<dd>
-Feed the specified C string ('\0' terminated) to the given virtual machine
-for evaluation. Returns various exception codes (VM_XXXX in ficl.h) to
-indicate the reason for returning. Normal exit condition is VM_OUTOFTEXT,
-indicating that the VM consumed the string successfully and is back for
-more. ficlExec calls can be nested, and the function itself is re-entrant,
-but note that a VM is static, so you have to take reasonable precautions
-(for example, use one VM per thread in a multithreaded system if you want
-multiple threads to be able to execute commands).</dd>
-
-<dt>
-<b>int ficlExecC(FICL_VM *pVM, char *text, int nChars)</b></dt>
-
-<dd>
-Same as ficlExec, but takes a count indicating the length of the supplied
-string. Setting nChars to -1 is equivalent to ficlExec (expects '\0' termination).</dd>
-
-<dt>
-<b>int ficlExecXT(FICL_VM *pVM, FICL_WORD *pFW)</b></dt>
-
-<dd>
-Same as ficlExec, but takes a pointer to a FICL_WORD instead of a string.
-Executes the word and returns after it has finished. If executing the word
-results in an exception, this function will re-throw the same code if it
-is nested under another ficlExec family function, or return the exception
-code directly if not. This function is useful if you need to execute the
-same word repeatedly - you save the dictionary search and outer interpreter
-overhead.</dd>
-
-<dt>
-<b>FICL_VM *ficlNewVM(void)</b></dt>
-
-<dd>
-Create, initialize, and return a VM from the heap using ficlMalloc. Links
-the VM into the system VM list for later reclamation by ficlTermSystem.</dd>
-
-<dt>
-<b>FICL_WORD *ficlLookup(char *name)</b></dt>
-
-<dd>
-Returns the address (also known as an XT in this case) of the specified
-word in the main dictionary. If not found, returns NULL. The address can
-be used in a call to ficlExecXT.</dd>
-
-<dt>
-<b>FICL_DICT *ficlGetDict(void)</b></dt>
-
-<dd>
-Returns a pointer to the main system dictionary, or NULL if the system
-is uninitialized.</dd>
-
-<dt>
-<b>FICL_DICT *ficlGetEnv(void)</b></dt>
-
-<dd>
-Returns a pointer to the environment dictionary. This dictionary stores
-information that describes this implementation as required by the Standard.</dd>
-
-<dt>
-<b>void ficlSetEnv(char *name, UNS32 value)</b></dt>
-
-<dd>
-Enters a new constant into the environment dictionary, with the specified
-name and value.</dd>
-
-<dt>
-<b>void ficlSetEnvD(char *name, UNS32 hi, UNS32 lo)</b></dt>
-
-<dd>
-Enters a new double-cell constant into the environment dictionary with
-the specified name and value.</dd>
-
-<dt>
-<b>FICL_DICT *ficlGetLoc(void)</b></dt>
-
-<dd>
-Returns a pointer to the locals dictionary. This function is defined only
-if FICL_WANT_LOCALS is #defined as non-zero (see sysdep.h). The locals
-dictionary is the symbol table for <a href="#locals">local variables</a>.</dd>
-
-<dt>
-<b>void ficlCompileCore(FICL_DICT *dp)</b></dt>
-
-<dd>
-Defined in words.c, this function builds ficl's primitives. </dd>
-
-<dt>
-<b>void ficlCompileSoftCore(FICL_VM *pVM)</b></dt>
-
-<dd>
-Defined in softcore.c, this function builds ANS required words and ficl
-extras by evaluating a text string (think of it as a memory mapped file
-;-) ). The string itself is built from files in the softwords directory
-by PERL script softcore.pl. </dd>
-</dl>
-</td>
-</tr>
-</table>
-
-<hr WIDTH="100%">
-<table BORDER=0 CELLSPACING=5 WIDTH="600" >
-<tr>
-<td COLSPAN="2">
-<h2>
- <a NAME="manifest"></a>Ficl Source Files</h2>
-</td>
-</tr>
-
-<tr>
-<td><b>ficl.h</b></td>
-
-<td>Declares most public functions and all data structures. Includes sysdep.h
-and math.h</td>
-</tr>
-
-<tr>
-<td><b>sysdep.h</b></td>
-
-<td>Declares system dependent functions and contains build control macros.
-Edit this file to port to another system.</td>
-</tr>
-
-<tr>
-<td><b>math.h</b></td>
-
-<td>Declares functions for 64 bit math</td>
-</tr>
-
-<tr>
-<td><b>words.c</b></td>
-
-<td>Exports ficlCompileCore(), the run-time dictionary builder, and contains
-all primitive words as static functions.</td>
-</tr>
-
-<tr>
-<td><b>vm.c</b></td>
-
-<td>Virtual Machine methods</td>
-</tr>
-
-<tr>
-<td><b>stack.c</b></td>
-
-<td>Stack methods</td>
-</tr>
-
-<tr>
-<td><b>ficl.c</b></td>
-
-<td>System initialization, termination, and ficlExec</td>
-</tr>
-
-<tr>
-<td><b>dict.c</b></td>
-
-<td>Dictionary</td>
-</tr>
-
-<tr>
-<td><b>math64.c</b></td>
-
-<td>Implementation of 64 bit math words (except the two unsigned primitives
-declared in sysdep.h and implemented in sysdep.c)</td>
-</tr>
-
-<tr>
-<td><b>softcore.c</b></td>
-
-<td>Contains all of the "soft" words - those written in Forth and compiled
-by Ficl at startup time. Sources for these words are in the softwords directory.
-The files softwords/softcore.bat and softwords/softcore.pl generate softcore.c
-from the .fr sources.</td>
-</tr>
-
-<tr>
-<td><b>sysdep.c</b></td>
-
-<td>Implementation of system dependent functions declared in sysdep.h</td>
-</tr>
-
-<tr>
-<td><b>softwords/</b></td>
-
-<td>Directory contains sources and translation scripts for the words defined
-in softcore.c. Softcore.c depends on most of the files in this directory.
-See softcore.bat for the actual list of files that contribute to softcore.c.
-This is where you'll find source code for the object oriented extensions.</td>
-</tr>
-</table>
-
-<hr WIDTH="100%">
-<table BORDER=0 CELLPADDING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="whatsnew"></a>What's new in version 2.03</h2>
-This is the first version of Ficl that includes contributed code. Thanks
-especially to Daniel Sobral, Michael Gauland for contributions and bug
-finding.
-<p>New words
-<ul>
-<li>
-<tt><a href="#clock">clock</a>
-(FICL)</tt></li>
-
-<li>
-<tt><a href="#clockspersec">clocks/sec</a>
-(FICL)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans8.htm#8.6.1.1230">dnegate</a>
-(DOUBLE)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans10.htm#10.6.2.1905">ms</a>
-(FACILITY EXT - replaces MSEC)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans9.htm#9.6.1.2275">throw</a>
-(EXCEPTION)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans9.htm#9.6.1.0875">catch</a>
-(EXCEPTION)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.0707">allocate</a>
-(MEMORY)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.1605">free</a>
-(MEMORY)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.2145">resize</a>
-(MEMORY)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans6.htm#6.2.2440">within</a>
-(CORE EXT)</tt></li>
-
-<li>
-<tt><a href="#alloc">alloc</a>
-(class method)</tt></li>
-
-<li>
-<tt><a href="#allocarray">alloc-array</a>
-(class method)</tt></li>
-
-<li>
-<tt><a href="#oofree">free</a>
-(class method)</tt></li>
-</ul>
-Bugs Fixed
-<ul>
-<li>
-Bug fix in isNumber(): used to treat chars between 'Z' and 'a' as valid
-in base 10... (harmless, but weird)</li>
-
-<li>
-ficlExec pushes the <i>ip</i> and <tt>interpret</tt>s at the right times
-so that nested calls to ficlExec behave the way you'd expect them to.</li>
-
-<li>
-<tt>evaluate</tt> respects count parameter, and also passes exceptional
-return conditions back out to the calling instance of ficlExec.</li>
-
-<li>
-VM_QUIT now clears the locals dictionary in ficlExec.</li>
-</ul>
-Ficlwin Enhancements
-<ul>
-<li>
-File Menu: recent file list and Open now load files.</li>
-
-<li>
-Text ouput function is now faster through use of string caching. Cache
-flushes at the end of each line and each time ficlExec returns.</li>
-
-<li>
-Edit/paste now behaves more reasonably for text. File/open loads the specified
-file.</li>
-
-<li>
-Registry entries specify dictionary and stack sizes, default window placement,
-and whether or not to create a splitter for multiple VMs. See HKEY_CURRENT_USER/Software/CodeLab/ficlwin/Settings</li>
-</ul>
-Ficl Enhancements
-<ul>
-<li>
-This version includes changes to make it <b>64 bit friendly</b>. This unfortunately
-meant that I had to tweak some core data types and structures. I've tried
-to make this transparent to 32 bit code, but a couple of things got renamed.
-INT64 is now DPINT. UNS64 is now DPUNS. FICL_INT and FICL_UNS are synonyms
-for INT32 and UNS32 in 32 bit versions, but a are obsolescent. Please use
-the new data types instead. Typed stack operations on INT32 and UNS32 have
-been renamed because they operate on CELL scalar types, which are 64 bits
-wide on 64 bit systems. Added BITS_PER_CELL, which has legal values of
-32 or 64. Default is 32.</li>
-
-<li>
-ficl.c: Added ficlExecXT() - executes an xt completely before returning,
-passing back any exception codes generated in the process. Normal exit
-code is VM_INNEREXIT.</li>
-
-<li>
-ficl.c: Added ficlExecC() to operate on counted strings as opposed to zero
-terminated ones.</li>
-
-<li>
-ficlExec pushes ip and executes interpret at the right times so that nested
-calls to ficlExec behave the way you'd expect them to.</li>
-
-<li>
-ficlSetStackSize() allows specification of stack size at run-time (affects
-subsequent invocations of ficlNewVM()).</li>
-
-<li>
-vm.c: vmThrow() checks for (pVM->pState != NULL) before longjmping it.
-vmCreate nulls this pointer initially. </li>
-
-<li>
-EXCEPTION wordset contributed by Daniel Sobral of FreeBSD</li>
-
-<li>
-MEMORY-ALLOC wordset contributed by Daniel Sobral, too. Added class methods
-<tt>alloc</tt>
-and <tt>alloc-array</tt> in softwords/oo.fr to allocate objects from the
-heap.</li>
-
-<li>
-Control structure match check upgraded (thanks to Daniel Sobral for this
-suggestion). Control structure mismatches are now errors, not warnings,
-since the check accepts all syntactally legal constructs.</li>
-
-<li>
-Added vmInnerLoop() to vm.h. This function/macro factors the inner
-interpreter out of ficlExec so it can be used in other places. Function/macro
-behavior is conditioned on INLINE_INNER_LOOP in sysdep.h. Default: 1 unless
-_DEBUG is set. In part, this is because VC++ 5 goes apoplectic when trying
-to compile it as a function. See </li>
-
-<br>comments in vm.c
-<li>
-EVALUATE respects the count parameter, and also passes exceptional return
-conditions back out to the calling instance of ficlExec.</li>
-
-<li>
-VM_QUIT clears locals dictionary in ficlExec()</li>
-
-<li>
-Added Michael Gauland's ficlLongMul and ficlLongDiv and support routines
-to math64.c and .h. These routines are coded in C, and are compiled only
-if PORTABLE_LONGMULDIV == 1 (default is 0).</li>
-
-<li>
-Added definition of ficlRealloc to sysdep.c (needed for memory allocation
-wordset). If your target OS supports realloc(), you'll probably want to
-redefine ficlRealloc in those terms. The default version does ficlFree
-followed by ficlMalloc.</li>
-
-<li>
-testmain.c: Changed gets() in testmain to fgets() to appease the security
-gods.</li>
-
-<li>
-testmain: <tt>msec</tt> renamed to <tt><a href="#ficlms">ms</a></tt> in
-line with the ANS</li>
-
-<li>
-softcore.pl now removes comments & spaces at the start and end of lines.
-As a result: sizeof (softWords) == 7663 bytes (used to be 20000)
-and consumes 11384 bytes of dictionary when compiled</li>
-
-<li>
-Deleted license paste-o in readme.txt (oops).</li>
-</ul>
-</td>
-</tr>
-</table>
-
-<hr WIDTH="100%">
-<table BORDER=0 CELLPADDING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-What's new in version 2.02</h2>
-New words
-<ul>
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans6.htm#6.2.1850">marker</a>
-(CORE EXT)</tt></li>
-
-<li>
-<tt><a href="http://www.taygeta.com/forth/dpans15.htm#15.6.2.1580">forget</a>
-(TOOLS EXT)</tt></li>
-
-<li>
-<tt><a href="#ficlforgetwid">forget-wid</a>
-(FICL)</tt></li>
-
-<li>
-<tt><a href="#ficlwordlist">ficl-wordlist</a> (FICL)</tt></li>
-
-<li>
-<tt><a href="#ficlvocabulary">ficl-vocabulary</a> (FICL)</tt></li>
-
-<li>
-<tt><a href="#ficlhide">hide</a>
-(FICL)</tt></li>
-
-<li>
-<tt><a href="#ficlhidden">hidden</a>
-(FICL)</tt></li>
-
-<li>
-<a href="#jhlocal">Johns Hopkins local variable syntax</a> (as best I can
-determine)</li>
-</ul>
-Bugs Fixed
-<ul>
-<li>
-<tt>forget</tt> now adjusts the dictionary pointer to remove the name of
-the word being forgotten (name chars come before the word header in ficl's
-dictionary)</li>
-
-<li>
-<tt>:noname</tt> used to push the colon control marker and its execution
-token in the wrong order</li>
-
-<li>
-<tt>source-id</tt> now behaves correctly when loading a file.</li>
-
-<li>
-<tt>refill</tt> returns zero at EOF (Win32 load). Win32 <tt><a href="#ficlload">load</a></tt>
-command continues to be misnamed. Really ought to be called <tt>included</tt>,
-but does not exactly conform to that spec either (because <tt>included</tt>
-expects a string signature on the stack, while Ficl's <tt><a href="#ficlload">load</a></tt>
-expects a filename upon invocation). The "real" <tt>LOAD</tt> is a <tt>BLOCK</tt>
-word.</li>
-</ul>
-Enhancements (IMHO)
-<ul>
-<li>
-dictUnsmudge no longer links anonymous definitions into the dictionary</li>
-
-<li>
-<tt>oop</tt> is no longer the default compile wordlist at startup, nor
-is it in the search order. Execute <b><tt>also oop definitions</tt></b>
-to use Ficl OOP.</li>
+<table border="0" cellpadding="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="whatsnew"></a>What's new in version 2.04</h2>
+ <h3>ficlwin</h3>
+ <ul>
+ <li>Catches exceptions thrown by VM in ficlThread (0
+ @ for example) rather than passing them off to
+ the OS. </li>
+ </ul>
+ <h3>ficl bugs vanquished</h3>
+ <ul>
+ <li>Fixed leading delimiter bugs in s" ."
+ .( and ( (reported by Reuben Thomas)</li>
+ <li>Makefile tabs restored (thanks to Michael Somos)</li>
+ <li>ABORT" now throws -2 per the DPANS (thanks
+ to Daniel Sobral for sharp eyes again) </li>
+ <li>ficlExec does not print the prompt string unless
+ (source-id == 0)</li>
+ <li>Various fixes contributed by the FreeBSD team.</li>
+ </ul>
+ <h3>ficl enhancements</h3>
+ <ul>
+ <li>Words.c: modified ficlCatch to use vmExecute and
+ vmInnerLoop (request of Daniel Sobral) Added
+ vmPop and vmPush functions (by request of Lars
+ Krueger ) in vm.c These are shortcuts to the
+ param stack. (Use LVALUEtoCELL to get things into
+ CELL form) </li>
+ <li>Added function vmGetStringEx with a flag to
+ specify whether or not to skip lead delimiters</li>
+ <li>Added non-std word: number?</li>
+ <li>Added CORE EXT word AGAIN (by request of Reuben
+ Thomas) </li>
+ <li>Added double cell local (2local) support</li>
+ <li>Augmented Johns Hopkins local syntax so that
+ locals whose names begin with char 2 are treated
+ as 2locals (OK - it's goofy, but handy for OOP)</li>
+ <li>C-string class revised and enhanced - now
+ dynamically sized</li>
+ <li>C-hashstring class derived from c-string computes
+ hashcode too.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td><h2>What's new in version 2.03</h2>
+ <p>This is the first version of Ficl that includes
+ contributed code. Thanks especially to Daniel Sobral,
+ Michael Gauland for contributions and bug finding. </p>
+ <p>New words </p>
+ <ul>
+ <li><a href="#clock"><tt>clock</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#clockspersec"><tt>clocks/sec</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans8.htm#8.6.1.1230"><tt>dnegate</tt></a><tt>
+ (DOUBLE)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans10.htm#10.6.2.1905"><tt>ms</tt></a><tt>
+ (FACILITY EXT - replaces MSEC </tt><i><tt>ficlWin
+ only</tt></i><tt>)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans9.htm#9.6.1.2275"><tt>throw</tt></a><tt>
+ (EXCEPTION)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans9.htm#9.6.1.0875"><tt>catch</tt></a><tt>
+ (EXCEPTION)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.0707"><tt>allocate</tt></a><tt>
+ (MEMORY)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.1605"><tt>free</tt></a><tt>
+ (MEMORY)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans14.htm#14.6.1.2145"><tt>resize</tt></a><tt>
+ (MEMORY)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans6.htm#6.2.2440"><tt>within</tt></a><tt>
+ (CORE EXT)</tt></li>
+ <li><a href="#alloc"><tt>alloc</tt></a><tt>
+ (class method)</tt></li>
+ <li><a href="#allocarray"><tt>alloc-array</tt></a><tt>
+ (class method)</tt></li>
+ <li><a href="#oofree"><tt>free</tt></a><tt>
+ (class method)</tt></li>
+ </ul>
+ <p>Bugs Fixed </p>
+ <ul>
+ <li>Bug fix in isNumber(): used to treat chars
+ between 'Z' and 'a' as valid in base 10...
+ (harmless, but weird)</li>
+ <li>ficlExec pushes the <i>ip</i> and <tt>interpret</tt>s
+ at the right times so that nested calls to
+ ficlExec behave the way you'd expect them to.</li>
+ <li><tt>evaluate</tt> respects count parameter, and
+ also passes exceptional return conditions back
+ out to the calling instance of ficlExec.</li>
+ <li>VM_QUIT now clears the locals dictionary in
+ ficlExec.</li>
+ </ul>
+ <p>Ficlwin Enhancements </p>
+ <ul>
+ <li>File Menu: recent file list and Open now load
+ files.</li>
+ <li>Text ouput function is now faster through use of
+ string caching. Cache flushes at the end of each
+ line and each time ficlExec returns.</li>
+ <li>Edit/paste now behaves more reasonably for text.
+ File/open loads the specified file.</li>
+ <li>Registry entries specify dictionary and stack
+ sizes, default window placement, and whether or
+ not to create a splitter for multiple VMs. See
+ HKEY_CURRENT_USER/Software/CodeLab/ficlwin/Settings</li>
+ </ul>
+ <p>Ficl Enhancements </p>
+ <ul>
+ <li>This version includes changes to make it <b>64
+ bit friendly</b>. This unfortunately meant that I
+ had to tweak some core data types and structures.
+ I've tried to make this transparent to 32 bit
+ code, but a couple of things got renamed. INT64
+ is now DPINT. UNS64 is now DPUNS. FICL_INT and
+ FICL_UNS are synonyms for INT32 and UNS32 in 32
+ bit versions, but a are obsolescent. Please use
+ the new data types instead. Typed stack
+ operations on INT32 and UNS32 have been renamed
+ because they operate on CELL scalar types, which
+ are 64 bits wide on 64 bit systems. Added
+ BITS_PER_CELL, which has legal values of 32 or
+ 64. Default is 32.</li>
+ <li>ficl.c: Added ficlExecXT() - executes an xt
+ completely before returning, passing back any
+ exception codes generated in the process. Normal
+ exit code is VM_INNEREXIT.</li>
+ <li>ficl.c: Added ficlExecC() to operate on counted
+ strings as opposed to zero terminated ones.</li>
+ <li>ficlExec pushes ip and executes interpret at the
+ right times so that nested calls to ficlExec
+ behave the way you'd expect them to.</li>
+ <li>ficlSetStackSize() allows specification of stack
+ size at run-time (affects subsequent invocations
+ of ficlNewVM()).</li>
+ <li>vm.c: vmThrow() checks for (pVM->pState !=
+ NULL) before longjmping it. vmCreate nulls this
+ pointer initially. </li>
+ <li>EXCEPTION wordset contributed by Daniel Sobral of
+ FreeBSD</li>
+ <li>MEMORY-ALLOC wordset contributed by Daniel
+ Sobral, too. Added class methods <tt>alloc</tt>
+ and <tt>alloc-array</tt> in softwords/oo.fr to
+ allocate objects from the heap.</li>
+ <li>Control structure match check upgraded (thanks to
+ Daniel Sobral for this suggestion). Control
+ structure mismatches are now errors, not
+ warnings, since the check accepts all syntactally
+ legal constructs.</li>
+ <li>Added vmInnerLoop() to vm.h. This function/macro
+ factors the inner interpreter out of
+ ficlExec so it can be used in other places.
+ Function/macro behavior is conditioned on
+ INLINE_INNER_LOOP in sysdep.h. Default: 1 unless
+ _DEBUG is set. In part, this is because VC++ 5
+ goes apoplectic when trying to compile it as a
+ function. See </li>
+ <li><br>
+ comments in vm.c </li>
+ <li>EVALUATE respects the count parameter, and also
+ passes exceptional return conditions back out to
+ the calling instance of ficlExec.</li>
+ <li>VM_QUIT clears locals dictionary in ficlExec()</li>
+ <li>Added Michael Gauland's ficlLongMul and
+ ficlLongDiv and support routines to math64.c and
+ .h. These routines are coded in C, and are
+ compiled only if PORTABLE_LONGMULDIV == 1
+ (default is 0).</li>
+ <li>Added definition of ficlRealloc to sysdep.c
+ (needed for memory allocation wordset). If your
+ target OS supports realloc(), you'll probably
+ want to redefine ficlRealloc in those terms. The
+ default version does ficlFree followed by
+ ficlMalloc.</li>
+ <li>testmain.c: Changed gets() in testmain to fgets()
+ to appease the security gods.</li>
+ <li>testmain: <tt>msec</tt> renamed to <a
+ href="#ficlms"><tt>ms</tt></a> in line with the
+ ANS</li>
+ <li>softcore.pl now removes comments & spaces at
+ the start and end of lines. As a result: sizeof
+ (softWords) == 7663 bytes (used to be
+ 20000) and consumes 11384 bytes of
+ dictionary when compiled</li>
+ <li>Deleted license paste-o in readme.txt (oops).</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td><h2>What's new in version 2.02</h2>
+ <p>New words </p>
+ <ul>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans6.htm#6.2.1850"><tt>marker</tt></a><tt>
+ (CORE EXT)</tt></li>
+ <li><a
+ href="http://www.taygeta.com/forth/dpans15.htm#15.6.2.1580"><tt>forget</tt></a><tt>
+ (TOOLS EXT)</tt></li>
+ <li><a href="#ficlforgetwid"><tt>forget-wid</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#ficlwordlist"><tt>ficl-wordlist</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#ficlvocabulary"><tt>ficl-vocabulary</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#ficlhide"><tt>hide</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#ficlhidden"><tt>hidden</tt></a><tt>
+ (FICL)</tt></li>
+ <li><a href="#jhlocal">Johns Hopkins local variable
+ syntax</a> (as best I can determine)</li>
+ </ul>
+ <p>Bugs Fixed </p>
+ <ul>
+ <li><tt>forget</tt> now adjusts the dictionary
+ pointer to remove the name of the word being
+ forgotten (name chars come before the word header
+ in ficl's dictionary)</li>
+ <li><tt>:noname</tt> used to push the colon control
+ marker and its execution token in the wrong order</li>
+ <li><tt>source-id</tt> now behaves correctly when
+ loading a file.</li>
+ <li><tt>refill</tt> returns zero at EOF (Win32 load).
+ Win32 <a href="#ficlload"><tt>load</tt></a>
+ command continues to be misnamed. Really ought to
+ be called <tt>included</tt>, but does not exactly
+ conform to that spec either (because <tt>included</tt>
+ expects a string signature on the stack, while
+ Ficl's <a href="#ficlload"><tt>load</tt></a>
+ expects a filename upon invocation). The
+ "real" <tt>LOAD</tt> is a <tt>BLOCK</tt>
+ word.</li>
+ </ul>
+ <p>Enhancements (IMHO) </p>
+ <ul>
+ <li>dictUnsmudge no longer links anonymous
+ definitions into the dictionary</li>
+ <li><tt>oop</tt> is no longer the default compile
+ wordlist at startup, nor is it in the search
+ order. Execute <b><tt>also oop definitions</tt></b>
+ to use Ficl OOP.</li>
+ <li>Revised oo.fr extensively to make more use of
+ early binding</li>
+ <li>Added <tt>meta</tt> - a constant that pushes the
+ address of metaclass. See oo.fr for examples of
+ use.</li>
+ <li>Added classes: <tt>c-ptr c-bytePtr
+ c-2bytePtr c-cellPtr </tt>These classes
+ model pointers to non-object data, but each knows
+ the size of its referent.</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td><h2>What's new in version 2.01</h2>
+ <ul>
+ <li>Bug fix: <tt>(local)</tt> used to leave a value
+ on the stack between the first and last locals
+ declared. This value is now stored in a static.</li>
+ <li>Added new local syntax with parameter
+ re-ordering. <a href="#newlocal">See description
+ below</a>. (No longer compiled in version 2.02,
+ in favor of the Johns Hopkins syntax)</li>
+ </ul>
+ </td>
+ </tr>
+ <tr>
+ <td><h2>What's new in version 2.0</h2>
+ <ul>
+ <li>New ANS Forth words: <tt>TOOLS</tt> and part of <tt>TOOLS
+ EXT, SEARCH</tt> and <tt>SEARCH EXT, LOCALS</tt>
+ and <tt>LOCALS EXT</tt> word sets, additional
+ words from <tt>CORE EXT, DOUBLE</tt>, and <tt>STRING</tt>.
+ (See the function ficlCompileCore in words.c for
+ an alphabetical list by word set).</li>
+ <li>Simple <tt>USER</tt> variable support - a user
+ variable is a virtual machine instance variable.
+ User variables behave as <tt>VARIABLE</tt>s in
+ all other respects.</li>
+ <li>Object oriented syntax extensions (see below)</li>
+ <li>Optional stack underflow and overflow checking in
+ many CORE words (enabled when FICL_ROBUST >=
+ 2)</li>
+ <li>Various bug fixes</li>
+ </ul>
+ </td>
+ </tr>
+</table>
-<li>
-Revised oo.fr extensively to make more use of early binding</li>
+<hr>
-<li>
-Added <tt>meta</tt> - a constant that pushes the address of metaclass.
-See oo.fr for examples of use.</li>
-
-<li>
-Added classes: <tt>c-ptr c-bytePtr c-2bytePtr c-cellPtr
-</tt>These
-classes model pointers to non-object data, but each knows the size of its
-referent.</li>
-</ul>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h1><a name="whatis"></a>What is ficl?</h1>
+ <p><font size="4">Ficl (Forth inspired command language)
+ is an ANS Forth interpreter written in C. Unlike
+ traditional Forths, this interpreter is designed to be
+ embedded into other systems as a
+ command/macro/development prototype language. Ficl
+ provides object extensions that can be used to wrap
+ methods and structures of the host system without
+ altering them. See below for examples of </font><a
+ href="#includesficl"><font size="4">software that
+ includes ficl</font></a><font size="4">.</font></p>
+ </td>
+ </tr>
+ <tr>
+ <td>Where Forths usually view themselves as the center of
+ the system and expect the rest of the system to be coded
+ in Forth, Ficl acts as a component of the system. It is
+ easy to export code written in C or ASM to Ficl in the
+ style of TCL, or to invoke Ficl code from a compiled
+ module. This allows you to do incremental development in
+ a way that combines the best features of threaded
+ languages (rapid development, quick code/test/debug
+ cycle, reasonably fast) with the best features of C
+ (everyone knows it, easier to support large blocks of
+ code, efficient, type checking). In addition, Ficl
+ provides a simple object model that can act as an object
+ oriented adapter for code written in C (or asm, Forth,
+ C++...). </td>
+ </tr>
+ <tr>
+ <td><b>Ficl Design goals</b> <ul>
+ <li>Target 32 bit processors (<i>version 2.03 targets
+ 64 bit processors too</i>)</li>
+ <li>Scripting, prototyping, and extension language
+ for systems written also in C</li>
+ <li>Supportable - code is as transparent as I can
+ make it</li>
+ <li>Interface to functions written in C</li>
+ <li>Conform to the Forth DPANS 94</li>
+ <li>Minimize porting effort - require an ANSI C
+ runtime environment and minimal glue code</li>
+ <li>Provide object oriented extensions</li>
+ </ul>
+ </td>
+ </tr>
</table>
-<hr WIDTH="100%">
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-What's new in version 2.01</h2>
+<p> </p>
-<ul>
-<li>
-Bug fix: <tt>(local)</tt> used to leave a value on the stack between the
-first and last locals declared. This value is now stored in a static.</li>
-
-<li>
-Added new local syntax with parameter re-ordering. <a href="#newlocal">See
-description below</a>. (No longer compiled in version 2.02, in favor of
-the Johns Hopkins syntax)</li>
-</ul>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="features"></a>Ficl features</h2>
+ <ul>
+ <li>Code is written in ANSI C for portability. </li>
+ <li>Standard: Implements the ANS Forth CORE word set,
+ part of the CORE EXT word set, SEARCH and SEARCH
+ EXT, TOOLS and part of TOOLS EXT, LOCAL and LOCAL
+ EXT, EXCEPTION, MEMORY, and various extras.</li>
+ <li>Extensible: you can export code written in Forth,
+ C, or asm in a straightforward way. Ficl provides
+ open facilities for extending the language in an
+ application specific way. You can even add new
+ control structures (not surprising if you're
+ familiar with Forth)</li>
+ <li>Ficl and C can interact in two ways: Ficl can
+ wrap C code, and C functions can invoke ficl
+ code.</li>
+ <li>Ficl code is thread safe and re-entrant:
+ All Ficl VMs share one system dictionary; each
+ Ficl virtual machine has an otherwise complete
+ state, and each can be bound to a separate I/O
+ channel (or none at all). An optional function
+ called ficlLockDictionary() can control exclusive
+ dictionary access. This function is stubbed out
+ by default (See FICL_MULTITHREAD in sysdep.h). As
+ long as there is only one "session"
+ that can compile words into the dictionary, you
+ do not need exclusive dictionary access for
+ multithreading. <font color="#000099"><b>Note</b>:
+ while the code is re-entrant, there are still
+ restrictions on how you can use it safely in a
+ multithreaded system. Specifically, the VM itself
+ maintains state, so you generally need a VM per
+ thread in a multithreaded system. If interrupt
+ service routines make calls into Ficl code that
+ alters VM state, then these generally need their
+ own VM as well. Alternatively, you could provide
+ a mutual exclusion mechanism to serialize access
+ to a VM from multiple threads.</font></li>
+ <li>Simple incorporation into existing systems: the
+ sample implementation requires three Ficl
+ function calls (see the example program in
+ testmain.c).</li>
+ <li>ROM able: Ficl is designed to work in RAM based
+ and ROM code / RAM data environments. It does
+ require somewhat more memory than a pure ROM
+ implementation because it builds its system
+ dictionary in RAM at startup time.</li>
+ <li>Written an ANSI C to be as simple as I can make
+ it to understand, support, debug, and port.
+ Compiles without complaint at /Az /W4 (require
+ ANSI C, max. warnings) under Microsoft VC++</li>
+ <li>Does full 32 bit math (but you need to implement
+ two mixed precision math primitives (see
+ sysdep.c))</li>
+ <li>Type 1 indirect threaded interpreter</li>
+ </ul>
+ </td>
+ </tr>
</table>
-<hr WIDTH="100%">
-<table BORDER=0 CELLPADDING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-What's new in version 2.0</h2>
+<hr>
-<ul>
-<li>
-New ANS Forth words: <tt>TOOLS</tt> and part of <tt>TOOLS EXT, SEARCH</tt>
-and <tt>SEARCH EXT, LOCALS</tt> and <tt>LOCALS EXT</tt> word sets, additional
-words from <tt>CORE EXT, DOUBLE</tt>, and <tt>STRING</tt>. (See the function
-ficlCompileCore in words.c for an alphabetical list by word set).</li>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="porting"></a>Porting ficl</h2>
+ <p>To install ficl on your target system, you need an
+ ANSI C compiler and its runtime library. Inspect the
+ system dependent macros and functions in <tt>sysdep.h</tt>
+ and <tt>sysdep.c</tt> and edit them to suit your system.
+ For example, <tt>INT16</tt> is a <tt>short</tt> on some
+ compilers and an <tt>int</tt> on others. Check the
+ default <tt>CELL</tt> alignment controlled by <tt>FICL_ALIGN</tt>.
+ If necessary, add new definitions of <tt>ficlMalloc,
+ ficlFree, ficlLockDictionary</tt>, and <tt>ficlTextOut</tt>
+ to work with your operating system. Finally, use <tt>testmain.c</tt>
+ as a guide to installing the ficl system and one or more
+ virtual machines into your code. You do not need to
+ include <tt>testmain.c</tt> in your build. </p>
+ <p>Feel free to stub out the double precision math
+ functions (which are presently implemented as inline
+ assembly because it's so easy on many 32 bit processors)
+ with kludge code that only goes to 32 bit precision. In
+ most applications, you won't notice the difference. If
+ you're doing a lot of number crunching, consider
+ implementing them correctly. </p>
+ <h3>Build controls</h3>
+ <p>The file sysdep.h contains default values for build
+ controls. Most of these are written such that if you
+ define them on the compiler command line, the defaults
+ are overridden. I suggest you take the defaults on
+ everything below the "build controls" section
+ until you're confident of your port. Beware of declaring
+ too small a dictionary, for example. You need about 3200
+ cells for a full system, about 2000 if you strip out most
+ of the "soft" words. </p>
+ <h3>To-Do List (target system dependent words)</h3>
+ <ul>
+ <li>Unimplemented system dependent <tt>CORE</tt>
+ word: <tt>KEY</tt> </li>
+ <li>Kludged <tt>CORE</tt> word: <tt>ACCEPT</tt></li>
+ </ul>
+ </td>
+ </tr>
+</table>
-<li>
-Simple <tt>USER</tt> variable support - a user variable is a virtual machine
-instance variable. User variables behave as <tt>VARIABLE</tt>s in all other
-respects.</li>
+<p> </p>
-<li>
-Object oriented syntax extensions (see below)</li>
+<table border="0" width="600" cols="1">
+ <tr>
+ <td><h2><a name="api"></a>Application Programming
+ Interface</h2>
+ <p><i>See the comments in ficl.c and ficl.h for
+ additional information, and the example in file
+ testmain.c.</i> </p>
+ <dl>
+ <dt><b>void ficlInitSystem(int nDictCells)</b></dt>
+ <dd>Initializes Ficl's shared system data structures,
+ and creates the dictionary allocating the
+ specified number of CELLs from the heap (by a
+ call to ficlMalloc)</dd>
+ <dt><b>void ficlTermSystem(void)</b></dt>
+ <dd>Reclaims memory allocated for the ficl system
+ including all dictionaries and all virtual
+ machines created by vmCreate. Any uses of the
+ memory allocation words (allocate and resize) are
+ your problem.</dd>
+ <dt><b>int ficlBuild(char *name, FICL_CODE code, char
+ flags)</b></dt>
+ <dd>Create a primitive word in ficl's main dictionary
+ with the given name, code pointer, and properties
+ (immediate, compile only, etc) as described by
+ the flags (see ficl.h for flag descriptions of
+ the form FW_XXXX)</dd>
+ <dt><b>int ficlExec(FICL_VM *pVM, char *text)</b></dt>
+ <dd>Feed the specified C string ('\0' terminated) to
+ the given virtual machine for evaluation. Returns
+ various exception codes (VM_XXXX in ficl.h) to
+ indicate the reason for returning. Normal exit
+ condition is VM_OUTOFTEXT, indicating that the VM
+ consumed the string successfully and is back for
+ more. ficlExec calls can be nested, and the
+ function itself is re-entrant, but note that a VM
+ is static, so you have to take reasonable
+ precautions (for example, use one VM per thread
+ in a multithreaded system if you want multiple
+ threads to be able to execute commands).</dd>
+ <dt><b>int ficlExecC(FICL_VM *pVM, char *text, int
+ nChars)</b></dt>
+ <dd>Same as ficlExec, but takes a count indicating
+ the length of the supplied string. Setting nChars
+ to -1 is equivalent to ficlExec (expects '\0'
+ termination).</dd>
+ <dt><b>int ficlExecXT(FICL_VM *pVM, FICL_WORD *pFW)</b></dt>
+ <dd>Same as ficlExec, but takes a pointer to a
+ FICL_WORD instead of a string. Executes the word
+ and returns after it has finished. If executing
+ the word results in an exception, this function
+ will re-throw the same code if it is nested under
+ another ficlExec family function, or return the
+ exception code directly if not. This function is
+ useful if you need to execute the same word
+ repeatedly - you save the dictionary search and
+ outer interpreter overhead.</dd>
+ <dt><b>FICL_VM *ficlNewVM(void)</b></dt>
+ <dd>Create, initialize, and return a VM from the heap
+ using ficlMalloc. Links the VM into the system VM
+ list for later reclamation by ficlTermSystem.</dd>
+ <dt><b>FICL_WORD *ficlLookup(char *name)</b></dt>
+ <dd>Returns the address (also known as an XT in this
+ case) of the specified word in the main
+ dictionary. If not found, returns NULL. The
+ address can be used in a call to ficlExecXT.</dd>
+ <dt><b>FICL_DICT *ficlGetDict(void)</b></dt>
+ <dd>Returns a pointer to the main system dictionary,
+ or NULL if the system is uninitialized.</dd>
+ <dt><b>FICL_DICT *ficlGetEnv(void)</b></dt>
+ <dd>Returns a pointer to the environment dictionary.
+ This dictionary stores information that describes
+ this implementation as required by the Standard.</dd>
+ <dt><b>void ficlSetEnv(char *name, UNS32 value)</b></dt>
+ <dd>Enters a new constant into the environment
+ dictionary, with the specified name and value.</dd>
+ <dt><b>void ficlSetEnvD(char *name, UNS32 hi, UNS32
+ lo)</b></dt>
+ <dd>Enters a new double-cell constant into the
+ environment dictionary with the specified name
+ and value.</dd>
+ <dt><b>FICL_DICT *ficlGetLoc(void)</b></dt>
+ <dd>Returns a pointer to the locals dictionary. This
+ function is defined only if FICL_WANT_LOCALS is
+ #defined as non-zero (see sysdep.h). The locals
+ dictionary is the symbol table for <a
+ href="#locals">local variables</a>.</dd>
+ <dt><b>void ficlCompileCore(FICL_DICT *dp)</b></dt>
+ <dd>Defined in words.c, this function builds ficl's
+ primitives. </dd>
+ <dt><b>void ficlCompileSoftCore(FICL_VM *pVM)</b></dt>
+ <dd>Defined in softcore.c, this function builds ANS
+ required words and ficl extras by evaluating a
+ text string (think of it as a memory mapped file
+ ;-) ). The string itself is built from files in
+ the softwords directory by PERL script
+ softcore.pl. </dd>
+ </dl>
+ </td>
+ </tr>
+</table>
-<li>
-Optional stack underflow and overflow checking in many CORE words (enabled
-when FICL_ROBUST >= 2)</li>
+<hr>
-<li>
-Various bug fixes</li>
-</ul>
-</td>
-</tr>
+<table border="0" cellspacing="5" width="600">
+ <tr>
+ <td colspan="2"><h2> <a name="manifest"></a>Ficl
+ Source Files</h2>
+ </td>
+ </tr>
+ <tr>
+ <td><b>ficl.h</b></td>
+ <td>Declares most public functions and all data
+ structures. Includes sysdep.h and math.h</td>
+ </tr>
+ <tr>
+ <td><b>sysdep.h</b></td>
+ <td>Declares system dependent functions and contains
+ build control macros. Edit this file to port to another
+ system.</td>
+ </tr>
+ <tr>
+ <td><b>math.h</b></td>
+ <td>Declares functions for 64 bit math</td>
+ </tr>
+ <tr>
+ <td><b>words.c</b></td>
+ <td>Exports ficlCompileCore(), the run-time dictionary
+ builder, and contains all primitive words as static
+ functions.</td>
+ </tr>
+ <tr>
+ <td><b>vm.c</b></td>
+ <td>Virtual Machine methods</td>
+ </tr>
+ <tr>
+ <td><b>stack.c</b></td>
+ <td>Stack methods</td>
+ </tr>
+ <tr>
+ <td><b>ficl.c</b></td>
+ <td>System initialization, termination, and ficlExec</td>
+ </tr>
+ <tr>
+ <td><b>dict.c</b></td>
+ <td>Dictionary</td>
+ </tr>
+ <tr>
+ <td><b>math64.c</b></td>
+ <td>Implementation of 64 bit math words (except the two
+ unsigned primitives declared in sysdep.h and implemented
+ in sysdep.c)</td>
+ </tr>
+ <tr>
+ <td><b>softcore.c</b></td>
+ <td>Contains all of the "soft" words - those
+ written in Forth and compiled by Ficl at startup time.
+ Sources for these words are in the softwords directory.
+ The files softwords/softcore.bat and
+ softwords/softcore.pl generate softcore.c from the .fr
+ sources.</td>
+ </tr>
+ <tr>
+ <td><b>sysdep.c</b></td>
+ <td>Implementation of system dependent functions declared
+ in sysdep.h</td>
+ </tr>
+ <tr>
+ <td><b>softwords/</b></td>
+ <td>Directory contains sources and translation scripts
+ for the words defined in softcore.c. Softcore.c depends
+ on most of the files in this directory. See softcore.bat
+ for the actual list of files that contribute to
+ softcore.c. This is where you'll find source code for the
+ object oriented extensions.</td>
+ </tr>
</table>
-<hr WIDTH="100%">
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="locals"></a>Local Variables</h3>
-Ficl includes support for <tt>LOCALS</tt> and <tt>LOCALS EXT</tt> words
-(all three of them!). I've implemented both of the local variable syntaxes
-suggested in DPANS Appendix A.13. Examples: (By the way, Ficl implements
-<tt>-ROT</tt>
-as <tt>: -rot 2 -roll ;</tt> )
-<ul><b><tt>\ Using LOCALS| from LOCALS EXT</tt></b>
-<br><b><tt>: -rot ( a b c -- c a b )</tt></b>
-<br><b><tt> locals| c b a |</tt></b>
-<br><b><tt> c a b </tt></b>
-<br><b><tt>;</tt></b>
-<br><b><tt>\ Using LOCAL END-LOCAL</tt></b>
-<br><b><tt>: -rot ( a b c -- c a b )</tt></b>
-<br><b><tt> local c</tt></b>
-<br><b><tt> local b</tt></b>
-<br><b><tt> local a</tt></b>
-<br><b><tt> end-locals</tt></b>
-<br><b><tt> c a b</tt></b>
-<br><b><tt>;</tt></b></ul>
-Local variable support is optional because it adds a small amount of overhead
-to the outer interpreter. You can disable it by setting FICL_WANT_LOCALS
-to 0 in sysdep.h. Beware: much of the OOP code described below uses local
-variables, so if you disable locals, you're going to lose other capabilities
-too. Local variables can make Forth code quite a bit easier to read, so
-I'd encourage you to experiment with them.
-<br>The default maximum number of local variables is 16. It's controlled
-by FICL_MAX_LOCALS in sysdep.h.
-<br><a NAME="jhlocal"></a>Ficl 2.02 includes by default an implementation
-of the Johns Hopkins local syntax (as best I can determine it from examples
-on the web). This syntax lets you declare local variables that look very
-much like a stack comment. Variables in the declaration appear in the "correct"
-order for a stack comment. Everything after the -- is treated as a comment.
-In addition, you can insert a | before the -- to declare one or more zero-initialized
-locals. Example:
-<blockquote><b><tt>:tuck0 { a b c | d -- 0 a b c }</tt></b>
-<br><b><tt> d a b c ;</tt></b></blockquote>
-The | and -- delimiters can appear at most once, and must appear in the
-order shown in the example to work correctly. The local declaration ends
-at the first occurrence of }. The declaration must all be on one line as
-presently implemented.
-<br><a NAME="newlocal"></a>Ficl 2.01 added yet another local syntax that
-models a stack comment. This one is not compiled in the release, but you
-can add it by editing softwords/softcore.bat to include the file ficllocal.fr.
-In this case, parameters are re-ordered so that the rightmost initialized
-param comes from the top of the stack. The syntax is:
-<ul><b><tt>{{ <initialized params> -- <cleared params> }}</tt></b></ul>
-You can omit either the initialized or the cleared parameters. Parameters
-after the double dash are set to zero initially. Those to the left are
-initialized from the stack at execution time. Examples (lame ones, admittedly):
-<ul><b><tt>: -rot ( a b c -- c a b )</tt></b>
-<br><b><tt> {{ a b c }}</tt></b>
-<br><b><tt> c a b </tt></b>
-<br><b><tt>;</tt></b>
-<br><b><tt>: tuck0 ( a b c -- 0 a b c )</tt></b>
-<br><b><tt> {{ a b c -- d }}</tt></b>
-<br><b><tt> d a b c </tt></b>
-<br><b><tt>; </tt></b></ul>
+<hr>
-<h3>
-Search Order</h3>
-Ficl implements many of the search order words in terms of two primitives
-called <tt><a href="#tosearch">>SEARCH</a></tt> and <tt><a href="#searchfrom">SEARCH></a></tt>.
-As their names suggest (assuming you're familiar with Forth), they push
-and pop the search order stack. See the list of <a href="#extras">Ficl
-extras</a> for details.
-<br>The standard does not appear to specify any conditions under which
-the search order is reset to a sane state. Ficl resets the search order
-to its default state whenever <tt>ABORT</tt> happens. This includes stack
-underflows and overflows. <tt>QUIT</tt> does not affect the search order.
-The minimum search order (set by <tt>ONLY</tt>) is equivalent to
-<br><b><tt>FORTH-WORDLIST 1 SET-ORDER</tt></b>
-<br>There is a default maximum of 16 wordlists in the search order. This
-can be changed by redefining FICL_DEFAULT_VOCS (declared in sysdep.h).
-<h3>
-Soft Words</h3>
-Many words from all the supported wordsets are written in Forth, and stored
-as a big string that Ficl compiles when it starts. The sources for all
-of these words are in directory ficl/softwords. There is a .bat file (softcore.bat)
-and a PERL 5 script (softcore.pl) that convert Forth files into the file
-softcore.c, so softcore.c is really dependent on the Forth sources. This
-is not reflected in the Visual C++ project database. For the time being,
-it's a manual step. You can edit softcore.bat to change the list of files
-that contribute to softcore.c. </td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="locals"></a>Local Variables</h2>
+ <p>Locally scoped variables came late to Forth. Purists
+ seem to feel that experienced Forth programmers can write
+ supportable code using only anonymous stack variables and
+ good factoring, but they complain that novices use global
+ variables too much. Local variables cost little in terms
+ of code size and execution speed, and are very convenient
+ for OO programming, where stack effects are more complex.</p>
+ <p>Ficl includes support for <tt>LOCALS</tt> and <tt>LOCALS
+ EXT</tt> words (all three of them!). I've implemented
+ both of the local variable syntaxes suggested in DPANS
+ Appendix A.13. Examples: (By the way, Ficl implements <tt>-ROT</tt>
+ as <tt>: -rot 2 -roll ;</tt> ) </p>
+ <ul>
+ <li><b><tt>\ Using LOCALS| from LOCALS EXT</tt></b> <br>
+ <b><tt>: -rot ( a b c -- c a b )</tt></b>
+ <br>
+ <b><tt> locals| c b a |</tt></b>
+ <br>
+ <b><tt> c a b </tt></b> <br>
+ <b><tt>;</tt></b> <br>
+ <b><tt>\ Using LOCAL END-LOCAL</tt></b> <br>
+ <b><tt>: -rot ( a b c -- c a b )</tt></b>
+ <br>
+ <b><tt> local c</tt></b> <br>
+ <b><tt> local b</tt></b> <br>
+ <b><tt> local a</tt></b> <br>
+ <b><tt> end-locals</tt></b> <br>
+ <b><tt> c a b</tt></b> <br>
+ <b><tt>;</tt></b></li>
+ </ul>
+ <p>Local variable support is optional because it adds a
+ small amount of overhead to the outer interpreter. You
+ can disable it by setting FICL_WANT_LOCALS to 0 in
+ sysdep.h. Beware: much of the OOP code described below
+ uses local variables, so if you disable locals, you're
+ going to lose other capabilities too. Local variables can
+ make Forth code quite a bit easier to read, so I'd
+ encourage you to experiment with them. <br>
+ The default maximum number of local variables is 16. It's
+ controlled by FICL_MAX_LOCALS in sysdep.h. </p>
+ <p><a name="jhlocal"></a>Ficl 2.02 includes by default an
+ implementation of the Johns Hopkins local syntax (as best
+ I can determine it from examples on the web). This syntax
+ lets you declare local variables that look very much like
+ a stack comment. Variables in the declaration appear in
+ the "correct" order for a stack comment.
+ Everything after the -- is treated as a comment. In
+ addition, you can insert a | before the -- to declare one
+ or more zero-initialized locals. Example: </p>
+ <blockquote>
+ <p><b><tt>:tuck0 { a b c | d -- 0 a b c }</tt></b>
+ <br>
+ <b><tt> d a b c ;</tt></b></p>
+ </blockquote>
+ <p>The | and -- delimiters can appear at most once, and
+ must appear in the order shown in the example to work
+ correctly. The local declaration ends at the first
+ occurrence of }. The declaration must all be on one line
+ as presently implemented. </p>
+ <p>In ficl 2.04 and later, this facilty can also declare
+ double cell locals (this is handy for <a
+ href="#ootutorial">OOP</a>, where objects take two cells
+ to represent on the stack). Double cell locals (AKA
+ 2locals) have names that start with 2. See
+ ficl/softwords/string.fr for examples.</p>
+ <p><a name="newlocal"></a>Ficl 2.01 added yet another
+ local syntax that models a stack comment. This one is not
+ compiled in the release, but you can add it by editing
+ softwords/softcore.bat to include the file ficllocal.fr.
+ In this case, parameters are re-ordered so that the
+ rightmost initialized param comes from the top of the
+ stack. The syntax is: </p>
+ <blockquote>
+ <p><b><tt>{{ <initialized params> --
+ <cleared params> }}</tt></b></p>
+ </blockquote>
+ <p>You can omit either the initialized or the cleared
+ parameters. Parameters after the double dash are set to
+ zero initially. Those to the left are initialized from
+ the stack at execution time. Examples (lame ones,
+ admittedly): </p>
+ <p><!--webbot bot="HTMLMarkup" startspan --><pre><!--webbot
+ bot="HTMLMarkup" endspan --><b><tt>: -rot ( a
+ b c -- c a b )</tt></b><br>
+ <b><tt> {{ a b c }}</tt></b> <br>
+ <b><tt> c a b </tt></b> <br>
+ <b><tt>;</tt></b> <br>
+ <b><tt>: tuck0 ( a b c -- 0 a b c )</tt></b> <br>
+ <b><tt> {{ a b c -- d }}</tt></b> <br>
+ <b><tt> d a b c </tt></b> <br>
+ <b><tt>; <!--webbot bot="HTMLMarkup" startspan --></pre><!--webbot
+ bot="HTMLMarkup" endspan --></tt></b></p>
+ <h3>Search Order</h3>
+ <p>Ficl implements many of the search order words in
+ terms of two primitives called <a href="#tosearch"><tt>>SEARCH</tt></a>
+ and <a href="#searchfrom"><tt>SEARCH></tt></a>. As
+ their names suggest (assuming you're familiar with
+ Forth), they push and pop the search order stack. See the
+ list of <a href="#extras">Ficl extras</a> for
+ details. <br>
+ The standard does not appear to specify any conditions
+ under which the search order is reset to a sane state.
+ Ficl resets the search order to its default state
+ whenever <tt>ABORT</tt> happens. This includes stack
+ underflows and overflows. <tt>QUIT</tt> does not affect
+ the search order. The minimum search order (set by <tt>ONLY</tt>)
+ is equivalent to <br>
+ <b><tt>FORTH-WORDLIST 1 SET-ORDER</tt></b> <br>
+ There is a default maximum of 16 wordlists in the search
+ order. This can be changed by redefining
+ FICL_DEFAULT_VOCS (declared in sysdep.h). </p>
+ <h3>Soft Words</h3>
+ <p>Many words from all the supported wordsets are written
+ in Forth, and stored as a big string that Ficl compiles
+ when it starts. The sources for all of these words are in
+ directory ficl/softwords. There is a .bat file
+ (softcore.bat) and a PERL 5 script (softcore.pl) that
+ convert Forth files into the file softcore.c, so
+ softcore.c is really dependent on the Forth sources. This
+ is not reflected in the Visual C++ project database. For
+ the time being, it's a manual step. You can edit
+ softcore.bat to change the list of files that contribute
+ to softcore.c. </p>
+ </td>
+ </tr>
</table>
-<h2>
+<hr>
-<hr WIDTH="100%"></h2>
-
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="objects"></a>Objects in ficl</h2>
-Ficl is not the first Forth to include Object Oriented extensions. Ficl's
-OO syntax owes a debt to the work of John Hayes and Dick Pountain, among
-others. OO Ficl is different from other OO Forths in a few ways, though
-(some things never change). First, unlike several implementations, the
-syntax is documented (<a href="#ootutorial">below</a>) beyond the source
-code. In Ficl's spirit of working with C code, the OO syntax provides means
-to adapt existing data structures. I've tried to make Ficl's OO model simple
-and safe by unifying classes and objects, providing late binding by default,
-and separating namespaces so that methods and regular Forth words are not
-easily confused.
-<h3>
-Design goals of Ficl OO syntax</h3>
-Ficl's object extensions provide the traditional OO benefits of associating
-data with the code that manipulates it, and reuse through single inheritance.
-Ficl also has some unusual capabilities that support interoperation with
-systems written in C.
-<ul>
-<li>
-Ficl objects are normally late bound for safety (late binding guarantees
-that the appropriate method will always be invoked for a particular object).
-Early binding is also available, provided you know the object's class at
-compile-time.</li>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="objects"></a>Object Oriented Programming
+ in ficl</h2>
+ <p>Ficl is not the first Forth to include Object Oriented
+ extensions. Ficl's OO syntax owes a debt to the work of
+ John Hayes and Dick Pountain, among others. OO Ficl is
+ different from other OO Forths in a few ways, though
+ (some things never change). First, unlike several
+ implementations, the syntax is documented (<a
+ href="#ootutorial">below</a>) beyond the source code. In
+ Ficl's spirit of working with C code, the OO syntax
+ provides means to adapt existing data structures. I've
+ tried to make Ficl's OO model simple and safe by unifying
+ classes and objects, providing late binding by default,
+ and separating namespaces so that methods and regular
+ Forth words are not easily confused. </p>
+ <h3>Design goals of Ficl OO syntax</h3>
+ <p>Ficl's object extensions provide the traditional OO
+ benefits of associating data with the code that
+ manipulates it, and reuse through single inheritance.
+ Ficl also has some unusual capabilities that support
+ interoperation with systems written in C. </p>
+ <ul>
+ <li>Ficl objects are normally late bound for safety
+ (late binding guarantees that the appropriate
+ method will always be invoked for a particular
+ object). Early binding is also available,
+ provided you know the object's class at
+ compile-time.</li>
+ <li>Ficl OOP supports single inheritance,
+ aggregation, and arrays of objects.</li>
+ <li>Classes have independent name spaces for their
+ methods: methods are only visible in the context
+ of a class or object. Methods can be overridden
+ or added in subclasses; there is no fixed limit
+ on the number of methods of a class or subclass.</li>
+ <li>Ficl OOP syntax is regular and unified over
+ classes and objects. In ficl, all classes are
+ objects. Class methods include the ability to
+ subclass and instantiate.</li>
+ <li>Ficl can adapt legacy data structures with object
+ wrappers. You can model a structure in a Ficl
+ class, and create an instance that refers to an
+ address in memory that holds an instance of the
+ structure. The <i>ref object</i> can then
+ manipulate the structure directly. This lets you
+ wrap data structures written and instantiated in
+ C.</li>
+ </ul>
+ </td>
+ </tr>
+</table>
-<li>
-Ficl OOP supports single inheritance, aggregation, and arrays of objects.</li>
-
-<li>
-Classes have independent name spaces for their methods: methods are only
-visible in the context of a class or object. Methods can be overridden
-or added in subclasses; there is no fixed limit on the number of methods
-of a class or subclass.</li>
-
-<li>
-Ficl OOP syntax is regular and unified over classes and objects. In ficl,
-a classes are objects. Class methods include the ability to subclass and
-instantiate.</li>
-
-<li>
-Ficl can adapt legacy data structures with object wrappers. You can model
-a structure in a Ficl class, and create an instance that refers to an address
-in memory that holds an instance of the structure. The <i>ref object</i>
-can then manipulate the structure directly. This lets you wrap data structures
-written and instantiated in C.</li>
-</ul>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3>Ficl Object Model</h3>
+ <p>All classes in Ficl are derived from the common base
+ class <a href="#objectgloss"><tt>OBJECT</tt></a>. All
+ classes are instances of <a href="#glossclass"><tt>METACLASS</tt></a>.
+ This means that classes are objects, too. <tt>METACLASS</tt>
+ implements the methods for messages sent to classes.
+ Class methods create instances and subclasses, and give
+ information about the class. Classes have exactly three
+ elements: </p>
+ <ul>
+ <li>The address ( <tt>.CLASS</tt> ) of a parent
+ class, or zero if it's a base class (only <tt>OBJECT</tt>
+ and <tt>METACLASS</tt> have this property)</li>
+ <li>The size ( <tt>.SIZE</tt> ) in address units of
+ an instance of the class</li>
+ <li>A wordlist ID ( <tt>.WID</tt> ) for the methods
+ of the class</li>
+ </ul>
+ <p>In the figure below, <tt>METACLASS</tt> and <tt>OBJECT</tt>
+ are system-supplied classes. The others are contrived to
+ illustrate the relationships among derived classes,
+ instances, and the two system base classes. The dashed
+ line with an arrow at the end indicates that the
+ object/class at the arrow end is an instance of the class
+ at the other end. The vertical line with a triangle
+ denotes inheritance. </p>
+ <p>Note for the curious: <tt>METACLASS</tt> behaves like
+ a class - it responds to class messages and has the same
+ properties as any other class. If you want to twist your
+ brain in knots, you can think of <tt>METACLASS</tt> as an
+ instance of itself. <br>
+ </p>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-Ficl Object Model</h3>
-All classes in Ficl are derived from the common base class <tt><a href="#objectgloss">OBJECT</a></tt>.
-All classes are instances of <tt><a href="#glossclass">METACLASS</a></tt>.
-This means that classes are objects, too. <tt>METACLASS</tt> implements
-the methods for messages sent to classes. Class methods create instances
-and subclasses, and give information about the class. Classes have exactly
-three elements:
-<ul>
-<li>
-The address ( <tt>.CLASS</tt> ) of a parent class, or zero if it's a base
-class (only <tt>OBJECT</tt> and <tt>METACLASS</tt> have this property)</li>
+<p><img src="ficl_oop.jpg" vspace="10" width="652" height="442"> </p>
-<li>
-The size ( <tt>.SIZE</tt> ) in address units of an instance of the class</li>
-
-<li>
-A wordlist ID ( <tt>.WID</tt> ) for the methods of the class</li>
-</ul>
-In the figure below, <tt>METACLASS</tt> and <tt>OBJECT</tt> are system-supplied
-classes. The others are contrived to illustrate the relationships among
-derived classes, instances, and the two system base classes. The dashed
-line with an arrow at the end indicates that the object/class at the arrow
-end is an instance of the class at the other end. The vertical line with
-a triangle denotes inheritance.
-<p>Note for the curious: <tt>METACLASS</tt> behaves like a class - it responds
-to class messages and has the same properties as any other class. If you
-want to twist your brain in knots, you can think of <tt>METACLASS</tt>
-as an instance of itself.
-<br> </td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="ootutorial"></a>Ficl OO Syntax Tutorial</h2>
+ <h3>Introduction</h3>
+ <p>Ficl objects associate a class with an instance
+ (really the storage for one set of instance variables).
+ This is done explicitly, in that any Ficl object is
+ represented by the cell pair: </p>
+ <blockquote>
+ <p><b><tt>( instance-addr class-addr )</tt></b></p>
+ </blockquote>
+ <p>on the stack. Whenever a named Ficl object executes,
+ it leaves this "signature". All methods expect
+ a class and instance on the stack when they execute, too.
+ In many other OO languages, including C++, instances
+ contain information about their classes (a vtable
+ pointer, for example). By making this pairing explicit
+ rather than implicit, Ficl can be OO about chunks of data
+ that don't realize that they are objects, without
+ sacrificing any robustness for native objects.
+ Whenever you create an object in Ficl, you specify
+ its class. After that, the object always pushes its class
+ and the address of its payload (instance variable space)
+ when invoked by name. </p>
+ <p>Classes are special kinds of objects that store the
+ methods of their instances, the size of an instance's
+ payload, and a parent class pointer. Classes themselves
+ are instances of a special base class called <tt>METACLASS</tt>,
+ and all classes inherit from class <tt>OBJECT</tt>. This
+ is confusing at first, but it means that Ficl has a very
+ simple syntax for constructing and using objects. Class
+ methods include subclassing (<tt>SUB</tt>), creating
+ initialized and uninitialized instances (<tt>NEW</tt> and
+ <tt>INSTANCE</tt>), and creating reference instances (<tt>REF</tt>).
+ Classes also have methods for disassembling their methods
+ (<tt>SEE</tt>), identifying themselves (<tt>ID</tt>), and
+ listing their pedigree (<tt>PEDIGREE</tt>). All objects
+ inherit methods for initializing instances and arrays of
+ instances, for performing array operations, and for
+ getting information about themselves. </p>
+ <h3>Methods and messages</h3>
+ <p>Methods are the chunks of code that objects execute in
+ response to messages. A message is a request to an object
+ for a behavior that the object supports. When it receives
+ a message, the target object looks up a method that
+ performs the behavior for its class, and executes it. Any
+ specific message will be bound to different methods in
+ different objects, according to class. This separation of
+ messages and methods allows objects to behave
+ polymorphically. (In Ficl, methods are words defined in
+ the context of a class, and messages are the names of
+ those words.) Ficl classes associate messages with
+ methods for their instances (a fancy way of saying that
+ each class owns a wordlist). Ficl provides a late-binding
+ operator <b><tt>--></tt></b> that sends messages to
+ objects at run-time, and an early-binding operator <b><tt>=></tt></b>
+ that compiles a specific class's method. These operators
+ are the only supported way to invoke methods. Regular
+ Forth words are not visible to the method-binding
+ operators, so there's no chance of confusing a
+ message with a regular word of the same name. </p>
+ </td>
+ </tr>
</table>
-<img SRC="ficl_oop.jpg" VSPACE=10 height=442 width=652>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="ootutorial"></a>Ficl OO Syntax Tutorial</h2>
-<h3>
-Introduction</h3>
-Ficl objects associate a class with an instance (really the storage for
-one set of instance variables). This is done explicitly, in that any Ficl
-object is represented by the cell pair:
-<ul><b><tt>( instance-addr class-addr )</tt></b></ul>
-on the stack. Whenever a named Ficl object executes, it leaves this "signature".
-All methods expect a class and instance on the stack when they execute,
-too. In many other OO languages, including C++, instances contain information
-about their classes (a vtable pointer, for example). By making this pairing
-explicit rather than implicit, Ficl can be OO about chunks of data that
-don't realize that they are objects, without sacrificing any robustness
-for native objects. Whenever you create an object in Ficl, you specify
-its class. After that, the object always pushes its class and the address
-of its payload (instance variable space) when invoked by name.
-<p>Classes are special kinds of objects that store the methods of their
-instances, the size of an instance's payload, and a parent class pointer.
-Classes themselves are instances of a special base class called <tt>METACLASS</tt>,
-and all classes inherit from class <tt>OBJECT</tt>. This is confusing at
-first, but it means that Ficl has a very simple syntax for constructing
-and using objects. Class methods include subclassing (<tt>SUB</tt>), creating
-initialized and uninitialized instances (<tt>NEW</tt> and <tt>INSTANCE</tt>),
-and creating reference instances (<tt>REF</tt>). Classes also have methods
-for disassembling their methods (<tt>SEE</tt>), identifying themselves
-(<tt>ID</tt>), and listing their pedigree (<tt>PEDIGREE</tt>). All objects
-inherit methods for initializing instances and arrays of instances, for
-performing array operations, and for getting information about themselves.
-<h3>
-Methods and messages</h3>
-Methods are the chunks of code that objects execute in response to messages.
-A message is a request to an object for a behavior that the object supports.
-When it receives a message, the target object looks up a method that performs
-the behavior for its class, and executes it. Any specific message will
-be bound to different methods in different objects, according to class.
-This separation of messages and methods allows objects to behave polymorphically.
-(In Ficl, methods are words defined in the context of a class, and messages
-are the names of those words.) Ficl classes associate messages with methods
-for their instances (a fancy way of saying that each class owns a wordlist).
-Ficl provides a late-binding operator <b><tt>--></tt></b> that sends messages
-to objects at run-time, and an early-binding operator
-<b><tt>=></tt></b>
-that compiles a specific class's method. These operators are the only supported
-way to invoke methods. Regular Forth words are not visible to the method-binding
-operators, so there's no chance of confusing a message with a regular
-word of the same name. </td>
-</tr>
-</table>
-
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-Tutorial (finally!)</h3>
-Since this is a tutorial, I'm assuming you're following along by pasting
-the examples into ficlWin, the Win32 version of Ficl (or some other build
-that includes the OO part of softcore.c). I also assume that you're familiar
-with Forth. If not, please see one of the <a href="#links">references</a>,
-below. Ficl's OOP words are in vocabulary OOP. To put OOP in the search
-order and make it the compilation wordlist from the default search order
-(as set by <tt>ONLY</tt>), type:
-<ul><b><tt>ONLY ( reset to default search order )</tt></b>
-<br><b><tt>ALSO OOP DEFINITIONS</tt></b></ul>
-To start, we'll work with the two base classes <tt>OBJECT</tt> and <tt>METACLASS</tt>.
-Try this:
-<ul><b><tt>metaclass --> methods</tt></b></ul>
-The line above contains three words. The first is the name of a class,
-so it pushes its signature on the stack. Since all classes are instances
-of <tt>METACLASS</tt>, <tt>METACLASS</tt> behaves as if it is an instance
-of itself (this is the only class with this property). It pushes the same
-address twice: once for the class and once for the payload, since they
-are the same. The next word finds a method in the context of a class and
-executes it. In this case, the name of the method is <tt>methods</tt>.
-Its job is to list all the methods that a class knows. What you get when
-you execute this line is a list of all the class methods Ficl provides.
-<ul><b><tt>object --> sub c-foo</tt></b></ul>
-Causes base-class <tt>OBJECT</tt> to derive from itself a new class called
-c-foo. Now we'll add some instance variables and methods to the new class...
-<ul><b><tt>cell: m_cell1</tt></b>
-<br><b><tt>4 chars: m_chars</tt></b>
-<br><b><tt>: init ( inst class -- )</tt></b>
-<br><b><tt> locals| class inst |</tt></b>
-<br><b><tt> 0 inst class --> m_cell1 !</tt></b>
-<br><b><tt> inst class --> m_chars 4 0 fill</tt></b>
-<br><b><tt> ." initializing an instance of c_foo at "
-inst x. cr</tt></b>
-<br><b><tt>;</tt></b>
-<br><b><tt>end-class</tt></b></ul>
-The first two lines add named instance variables to the class, and create
-a method for each. <i>Untyped</i> instance variable methods (like those
-created by <tt>cell: cells: char:</tt> and <tt>chars:</tt>) just push the
-address of the corresponding instance variable when invoked on an instance
-of the class. It's up to you to remember the size of the instance variable
-and manipulate it with the usual Forth words for fetching and storing (we'll
-see below how to aggregate objects, which do know their size). We've also
-defined a method called <tt>init</tt> that clears the instance variables.
-Notice that the method expects the addresses of the class and instance
-when it's called. It stashes those in local variables to avoid stack tricks,
-and puts them onto the stack whenever it calls a method. In this case,
-we're storing zero to the two member variables.
-<p>The <tt>init</tt> method is special for Ficl objects: whenever you create
-an initialized instance using <b><tt>new</tt></b> or <b><tt>new-array</tt></b>,
-Ficl calls the class's <tt>init</tt> method for you on that instance. The
-default <tt>init</tt> method supplied by class <tt>object</tt> clears the
-instance, so we didn't really need to override it in this case (see the
-source code in ficl/softwords/oo.fr).
-<br>Now make an instance of the new class:
-<ul><b><tt>c-foo --> new foo-instance</tt></b></ul>
-And try a few things...
-<ul><b><tt>foo-instance --> methods</tt></b>
-<br><b><tt>foo-instance --> pedigree</tt></b></ul>
-Or you could type this with the same effect:
-<ul><b><tt>foo-instance 2dup --> methods --> pedigree</tt></b></ul>
-Notice that we've overridden the init method supplied by object, and added
-two more methods for the member variables. If you type WORDS, you'll see
-that these methods are not visible outside the context of the class that
-contains them. The method finder --> uses the class to look up methods.
-You can use this word in a definition, as we did in <tt>init</tt>, and
-it performs late binding, meaning that the mapping from message (method
-name) to method (the code) is deferred until run-time. To see this, you
-can decompile the init method like this:
-<ul><b><tt>c-foo --> see init</tt></b>
-<br>or
-<br><b><tt>foo-instance --> class --> see init</tt></b></ul>
-Ficl also provides early binding, but you have to ask for it. Ficl's early
-binding operator pops a class off the stack and compiles the method you've
-named, so that that method executes regardless of the class of object it's
-used on. This can be dangerous, since it defeats the data-to-code matching
-mechanism object oriented languages were created to provide, but it does
-increase run-time speed by binding the method at compile time. In many
-cases, such as the init method, you can be reasonably certain of the class
-of thing you're working on. This is also true when invoking class methods,
-since all classes are instances of <tt>metaclass</tt>. Here's an example
-from the definition of <tt>metaclass</tt> in oo.fr (don't paste this into
-ficlWin - it's already there):
-<ul><b><tt>: new \ ( class metaclass "name" -- )</tt></b>
-<br><b><tt> metaclass => instance --> init ;</tt></b></ul>
-Try this...
-<ul><b><tt>metaclass --> see new</tt></b></ul>
-Decompiling the method with <tt>SEE</tt> shows the difference between the
-two strategies. The early bound method is compiled inline, while the late-binding
-operator compiles the method name and code to find and execute it in the
-context of whatever class is supplied on the stack at run-time.
-<br>Notice that the early-binding operator requires a class at compile
-time. For this reason, classes are <tt>IMMEDIATE</tt>, meaning that they
-push their signature at compile time or run time. I'd recommend that you
-avoid early binding until you're very comfortable with Forth, object-oriented
-programming, and Ficl's OOP syntax.
-<p>As advertised earlier, Ficl provides ways to objectify existing data
-structures without changing them. Instead, you can create a Ficl class
-that models the structure, and instantiate a <b>ref </b>from this class,
-supplying the address of the structure. After that, the <i>ref instance</i>
-behaves as a Ficl object, but its instance variables take on the values
-in the existing structure. Example (from ficlclass.fr):
-<br>
-<ul><b><tt>object subclass c-wordlist \ OO model of FICL_HASH</tt></b>
-<br><b><tt> cell: .parent</tt></b>
-<br><b><tt> cell: .size</tt></b>
-<br><b><tt> cell: .hash</tt></b>
-<p><b><tt> : push drop >search ;</tt></b>
-<br><b><tt> : pop 2drop previous ;</tt></b>
-<br><b><tt> : set-current drop set-current ;</tt></b>
-<br><b><tt> : words --> push words previous ;</tt></b>
-<br><b><tt>end-class</tt></b>
-<p><b><tt>: named-wid ( "name" -- ) </tt></b>
-<br><b><tt> wordlist postpone c-wordlist
-metaclass => ref ;</tt></b></ul>
-In this case, <tt>c-wordlist</tt> describes Ficl's wordlist structure;
-named-wid creates a wordlist and binds it to a ref instance of <tt>c-wordlist</tt>.
-The fancy footwork with <tt>POSTPONE</tt> and early binding is required
-because classes are immediate. An equivalent way to define named-wid with
-late binding is:
-<ul><b><tt>: named-wid ( "name" -- )</tt></b>
-<br><b><tt> wordlist postpone c-wordlist
---> ref ;</tt></b></ul>
-To do the same thing at run-time (and call it my-wordlist):
-<ul><b><tt>wordlist c-wordlist --> ref my-wordlist</tt></b></ul>
-Now you can deal with the wordlist through the ref instance:
-<ul><b><tt>my-wordlist --> push</tt></b>
-<br><b><tt>my-wordlist --> set-current</tt></b>
-<br><b><tt>order</tt></b></ul>
-Ficl can also model linked lists and other structures that contain pointers
-to structures of the same or different types. The class constructor word
-<b><tt><a href="#exampleref:">ref:</a></tt></b>
-makes an aggregate reference to a particular class. See the <a href="#glossinstance">instance
-variable glossary</a> for an <a href="#exampleref:">example</a>.
-<p>Ficl can make arrays of instances, and aggregate arrays into class descripions.
-The <a href="#glossclass">class methods</a> <b><tt>array</tt></b> and <b><tt>new-array</tt></b>
-create uninitialized and initialized arrays, respectively, of a class.
-In order to initialize an array, the class must define (or inherit) a reasonable
-<b><tt>init</tt></b>
-method. <b><tt>New-array</tt></b> invokes it on each member of the array
-in sequence from lowest to highest. Array instances and array members use
-the object methods <b><tt>index</tt></b>, <b><tt>next</tt></b>, and <b><tt>prev</tt></b>
-to navigate. Aggregate a member array of objects using <b><tt><a href="#arraycolon">array:</a></tt></b>.
-The objects are not automatically initialized in this case - your class
-initializer has to call <b><tt>array-init</tt></b> explicitly if you want
-this behavior.
-<p>For further examples of OOP in Ficl, please see the source file ficl/softwords/ficlclass.fr.
-This file wraps several Ficl internal data structures in objects and gives
-use examples. </td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3>Tutorial (finally!)</h3>
+ <p>Since this is a tutorial, I'm assuming you're
+ following along by pasting the examples into ficlWin, the
+ Win32 version of Ficl (or some other build that includes
+ the OO part of softcore.c). I also assume that you're
+ familiar with Forth. If not, please see one of the <a
+ href="#links">references</a>, below. Ficl's OOP words are
+ in vocabulary OOP. To put OOP in the search order and
+ make it the compilation wordlist from the default search
+ order (as set by <tt>ONLY</tt>), type: </p>
+ <blockquote>
+ <p><b><tt>ONLY ( reset to default search
+ order )</tt></b> <br>
+ <b><tt>ALSO OOP DEFINITIONS</tt></b></p>
+ </blockquote>
+ <p>To start, we'll work with the two base classes <tt>OBJECT</tt>
+ and <tt>METACLASS</tt>. Try this: </p>
+ <blockquote>
+ <p><b><tt>metaclass --> methods</tt></b></p>
+ </blockquote>
+ <p>The line above contains three words. The first is the
+ name of a class, so it pushes its signature on the stack.
+ Since all classes are instances of <tt>METACLASS</tt>, <tt>METACLASS</tt>
+ behaves as if it is an instance of itself (this is the
+ only class with this property). It pushes the same
+ address twice: once for the class and once for the
+ payload, since they are the same. The next word finds a
+ method in the context of a class and executes it. In this
+ case, the name of the method is <tt>methods</tt>. Its job
+ is to list all the methods that a class knows. What you
+ get when you execute this line is a list of all the class
+ methods Ficl provides. </p>
+ <blockquote>
+ <p><b><tt>object --> sub c-foo</tt></b></p>
+ </blockquote>
+ <p>Causes base-class <tt>OBJECT</tt> to derive from
+ itself a new class called c-foo. Now we'll add some
+ instance variables and methods to the new class... </p>
+ <blockquote>
+ <p><b><tt>cell: m_cell1</tt></b> <br>
+ <b><tt>4 chars: m_chars</tt></b> <br>
+ <b><tt>: init ( inst class -- )</tt></b> <br>
+ <b><tt> locals| class inst |</tt></b>
+ <br>
+ <b><tt> 0 inst class --> m_cell1
+ !</tt></b> <br>
+ <b><tt> inst class --> m_chars 4
+ 0 fill</tt></b> <br>
+ <b><tt> ." initializing an
+ instance of c_foo at " inst x. cr</tt></b> <br>
+ <b><tt>;</tt></b> <br>
+ <b><tt>end-class</tt></b></p>
+ </blockquote>
+ <p>The first two lines add named instance variables to
+ the class, and create a method for each. <i>Untyped</i>
+ instance variable methods (like those created by <tt>cell:
+ cells: char:</tt> and <tt>chars:</tt>) just push the
+ address of the corresponding instance variable when
+ invoked on an instance of the class. It's up to you to
+ remember the size of the instance variable and manipulate
+ it with the usual Forth words for fetching and storing
+ (we'll see below how to aggregate objects, which do know
+ their size). We've also defined a method called <tt>init</tt>
+ that clears the instance variables. Notice that the
+ method expects the addresses of the class and instance
+ when it's called. It stashes those in local variables to
+ avoid stack tricks, and puts them onto the stack whenever
+ it calls a method. In this case, we're storing zero to
+ the two member variables. </p>
+ <p>The <tt>init</tt> method is special for Ficl objects:
+ whenever you create an initialized instance using <b><tt>new</tt></b>
+ or <b><tt>new-array</tt></b>, Ficl calls the class's <tt>init</tt>
+ method for you on that instance. The default <tt>init</tt>
+ method supplied by class <tt>object</tt> clears the
+ instance, so we didn't really need to override it in this
+ case (see the source code in ficl/softwords/oo.fr).
+ <br>
+ Now make an instance of the new class: </p>
+ <blockquote>
+ <p><b><tt>c-foo --> new foo-instance</tt></b></p>
+ </blockquote>
+ <p>And try a few things... </p>
+ <blockquote>
+ <p><b><tt>foo-instance --> methods</tt></b> <br>
+ <b><tt>foo-instance --> pedigree</tt></b></p>
+ </blockquote>
+ <p>Or you could type this with the same effect: </p>
+ <blockquote>
+ <p><b><tt>foo-instance 2dup --> methods -->
+ pedigree</tt></b></p>
+ </blockquote>
+ <p>Notice that we've overridden the init method supplied
+ by object, and added two more methods for the member
+ variables. If you type WORDS, you'll see that these
+ methods are not visible outside the context of the class
+ that contains them. The method finder --> uses the
+ class to look up methods. You can use this word in a
+ definition, as we did in <tt>init</tt>, and it performs
+ late binding, meaning that the mapping from message
+ (method name) to method (the code) is deferred until
+ run-time. To see this, you can decompile the init method
+ like this: </p>
+ <blockquote>
+ <p><b><tt>c-foo --> see init</tt></b> <br>
+ or <br>
+ <b><tt>foo-instance --> class --> see init</tt></b></p>
+ </blockquote>
+ <p>Ficl also provides early binding, but you have to ask
+ for it. Ficl's early binding operator pops a class off
+ the stack and compiles the method you've named, so that
+ that method executes regardless of the class of object
+ it's used on. This can be dangerous, since it defeats the
+ data-to-code matching mechanism object oriented languages
+ were created to provide, but it does increase run-time
+ speed by binding the method at compile time. In many
+ cases, such as the init method, you can be reasonably
+ certain of the class of thing you're working on. This is
+ also true when invoking class methods, since all classes
+ are instances of <tt>metaclass</tt>. Here's an example
+ from the definition of <tt>metaclass</tt> in oo.fr (don't
+ paste this into ficlWin - it's already there): </p>
+ <blockquote>
+ <p><b><tt>: new \ ( class metaclass
+ "name" -- )</tt></b> <br>
+ <b><tt> metaclass => instance
+ --> init ;</tt></b></p>
+ </blockquote>
+ <p>Try this... </p>
+ <blockquote>
+ <p><b><tt>metaclass --> see new</tt></b></p>
+ </blockquote>
+ <p>Decompiling the method with <tt>SEE</tt> shows the
+ difference between the two strategies. The early bound
+ method is compiled inline, while the late-binding
+ operator compiles the method name and code to find and
+ execute it in the context of whatever class is supplied
+ on the stack at run-time. <br>
+ Notice that the early-binding operator requires a class
+ at compile time. For this reason, classes are <tt>IMMEDIATE</tt>,
+ meaning that they push their signature at compile time or
+ run time. I'd recommend that you avoid early binding
+ until you're very comfortable with Forth, object-oriented
+ programming, and Ficl's OOP syntax. </p>
+ <p>As advertised earlier, Ficl provides ways to objectify
+ existing data structures without changing them. Instead,
+ you can create a Ficl class that models the structure,
+ and instantiate a <b>ref </b>from this class, supplying
+ the address of the structure. After that, the <i>ref
+ instance</i> behaves as a Ficl object, but its instance
+ variables take on the values in the existing structure.
+ Example (from ficlclass.fr): <br>
+ </p>
+ <blockquote>
+ <p><b><tt>object subclass c-wordlist \ OO model of
+ FICL_HASH</tt></b> <br>
+ <b><tt> cell: .parent</tt></b> <br>
+ <b><tt> cell: .size</tt></b> <br>
+ <b><tt> cell: .hash</tt></b> </p>
+ </blockquote>
+ <blockquote>
+ <p><b><tt> : push drop >search ;</tt></b>
+ <br>
+ <b><tt> : pop 2drop previous ;</tt></b>
+ <br>
+ <b><tt> : set-current drop
+ set-current ;</tt></b> <br>
+ <b><tt> : words --> push
+ words previous ;</tt></b> <br>
+ <b><tt>end-class</tt></b> </p>
+ </blockquote>
+ <blockquote>
+ <p><b><tt>: named-wid ( "name"
+ -- ) </tt></b> <br>
+ <b><tt> wordlist postpone
+ c-wordlist metaclass => ref ;</tt></b></p>
+ </blockquote>
+ <p>In this case, <tt>c-wordlist</tt> describes Ficl's
+ wordlist structure; named-wid creates a wordlist and
+ binds it to a ref instance of <tt>c-wordlist</tt>. The
+ fancy footwork with <tt>POSTPONE</tt> and early binding
+ is required because classes are immediate. An equivalent
+ way to define named-wid with late binding is: </p>
+ <blockquote>
+ <p><b><tt>: named-wid ( "name"
+ -- )</tt></b> <br>
+ <b><tt> wordlist postpone
+ c-wordlist --> ref ;</tt></b></p>
+ </blockquote>
+ <p>To do the same thing at run-time (and call it
+ my-wordlist): </p>
+ <blockquote>
+ <p><b><tt>wordlist c-wordlist --> ref
+ my-wordlist</tt></b></p>
+ </blockquote>
+ <p>Now you can deal with the wordlist through the ref
+ instance: </p>
+ <blockquote>
+ <p><b><tt>my-wordlist --> push</tt></b> <br>
+ <b><tt>my-wordlist --> set-current</tt></b> <br>
+ <b><tt>order</tt></b></p>
+ </blockquote>
+ <p>Ficl can also model linked lists and other structures
+ that contain pointers to structures of the same or
+ different types. The class constructor word <a
+ href="#exampleref:"><b><tt>ref:</tt></b></a> makes an
+ aggregate reference to a particular class. See the <a
+ href="#glossinstance">instance variable glossary</a> for
+ an <a href="#exampleref:">example</a>. </p>
+ <p>Ficl can make arrays of instances, and aggregate
+ arrays into class descripions. The <a href="#glossclass">class
+ methods</a> <b><tt>array</tt></b> and <b><tt>new-array</tt></b>
+ create uninitialized and initialized arrays,
+ respectively, of a class. In order to initialize an
+ array, the class must define (or inherit) a reasonable <b><tt>init</tt></b>
+ method. <b><tt>New-array</tt></b> invokes it on each
+ member of the array in sequence from lowest to highest.
+ Array instances and array members use the object methods <b><tt>index</tt></b>,
+ <b><tt>next</tt></b>, and <b><tt>prev</tt></b> to
+ navigate. Aggregate a member array of objects using <a
+ href="#arraycolon"><b><tt>array:</tt></b></a>. The
+ objects are not automatically initialized in this case -
+ your class initializer has to call <b><tt>array-init</tt></b>
+ explicitly if you want this behavior. </p>
+ <p>For further examples of OOP in Ficl, please see the
+ source file ficl/softwords/ficlclass.fr. This file wraps
+ several Ficl internal data structures in objects and
+ gives use examples. </p>
+ </td>
+ </tr>
+ <tr>
+ <td><h2><a name="cstring"></a>Ficl String classes</h2>
+ <p>c-string (ficl 2.04 and later) is a reasonably useful
+ dynamic string class. Source code for the class is
+ located in ficl/softwords/string.fr. Features: dynamic
+ creation and resizing; deletion, char cout,
+ concatenation, output, comparison; creation from quoted
+ string constant (s").</p>
+ <p>Examples of use:</p>
+ <blockquote>
+ <pre><strong>c-string --> new homer
+s" In this house, " homer --> set
+s" we obey the laws of thermodynamics!" homer --> cat
+homer --> type</strong></pre>
+ </blockquote>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="oopgloss"></a>OOP Glossary</h3>
-Note: with the exception of the binding operators (the first two definitions
-here), all of the words in this section are internal factors that you don't
-need to worry about. These words provide method binding for all classes
-and instances. Also described are supporting words and execution factors.
-All are defined in softwords/oo.fr.
-<dl>
-<dt>
-<b><tt>--> ( instance class "method-name" -- xn )</tt></b></dt>
-
-<dd>
-Late binding: looks up and executes the given method in the context of
-the class on top of the stack. </dd>
-
-<dt>
-<b><tt>=> comp: ( class meta "method-name" -- ) exec:
-( inst class -- xn )</tt></b></dt>
-
-<dd>
-Early binding: compiles code to execute the method of the class specified
-at compile time.</dd>
-
-<dt>
-<b><tt>do-do-instance</tt></b></dt>
-
-<dd>
-When executed, causes the instance to push its ( instance class ) stack
-signature. Implementation factor of <b><tt>metaclass --> sub</tt></b>.
-Compiles <b><tt>.do-instance</tt></b> in the context of a class; <tt>.do-instance</tt>
-implements the <tt>does></tt> part of a named instance. </dd>
-
-<dt>
-<b><tt>exec-method ( instance class c-addr u -- xn )</tt></b></dt>
-
-<dd>
-Given the address and length of a message (method name) on the stack, finds
-the method in the context of the specified class and invokes it. Upon entry
-to the method, the instance and class are on top of the stack, as usual.
-If unable to find the method, prints an error message and aborts.</dd>
-
-<dt>
-<b><tt>find-method-xt ( class "method-name" -- class xt )</tt></b></dt>
-
-<dd>
-Attempts to map the message to a method in the specified class. If successful,
-leaves the class and the execution token of the method on the stack. Otherwise
-prints an error message and aborts.</dd>
-
-<dt>
-<b><tt>lookup-method ( class c-addr u -- class xt )</tt></b></dt>
-
-<dd>
-Given the address and length of a message (method name) on the stack, finds
-the method in the context of the specified class. If unable to find the
-method, prints an error message and aborts.</dd>
-
-<dt>
-<b><tt>parse-method comp: ( "method-name" -- ) exec:
-( -- c-addr u )</tt></b></dt>
-
-<dd>
-Parse "name" from the input stream and compile code to push its length
-and address when the enclosing definition runs.</dd>
-</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="oopgloss"></a>OOP Glossary</h2>
+ <p>Note: with the exception of the binding operators (the
+ first two definitions here), all of the words in this
+ section are internal factors that you don't need to worry
+ about. These words provide method binding for all classes
+ and instances. Also described are supporting words and
+ execution factors. All are defined in softwords/oo.fr. </p>
+ <dl>
+ <dt><b><tt>--> ( instance class
+ "method-name" -- xn )</tt></b></dt>
+ <dd>Late binding: looks up and executes the given
+ method in the context of the class on top of the
+ stack. </dd>
+ <dt><b><tt>=> comp: ( class meta
+ "method-name" -- ) exec: ( inst
+ class -- xn )</tt></b></dt>
+ <dd>Early binding: compiles code to execute the
+ method of the class specified at compile time.</dd>
+ <dt><b><tt>do-do-instance</tt></b></dt>
+ <dd>When executed, causes the instance to push its (
+ instance class ) stack signature. Implementation
+ factor of <b><tt>metaclass --> sub</tt></b>.
+ Compiles <b><tt>.do-instance</tt></b> in the
+ context of a class; <tt>.do-instance</tt>
+ implements the <tt>does></tt> part of a named
+ instance. </dd>
+ <dt><b><tt>exec-method ( instance class
+ c-addr u -- xn )</tt></b></dt>
+ <dd>Given the address and length of a message (method
+ name) on the stack, finds the method in the
+ context of the specified class and invokes it.
+ Upon entry to the method, the instance and class
+ are on top of the stack, as usual. If unable to
+ find the method, prints an error message and
+ aborts.</dd>
+ <dt><b><tt>find-method-xt ( class
+ "method-name" -- class xt )</tt></b></dt>
+ <dd>Attempts to map the message to a method in the
+ specified class. If successful, leaves the class
+ and the execution token of the method on the
+ stack. Otherwise prints an error message and
+ aborts.</dd>
+ <dt><b><tt>lookup-method ( class c-addr u
+ -- class xt )</tt></b></dt>
+ <dd>Given the address and length of a message (method
+ name) on the stack, finds the method in the
+ context of the specified class. If unable to find
+ the method, prints an error message and aborts.</dd>
+ <dt><b><tt>parse-method comp: (
+ "method-name" -- ) exec: ( --
+ c-addr u )</tt></b></dt>
+ <dd>Parse "name" from the input stream and
+ compile code to push its length and address when
+ the enclosing definition runs.</dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="glossinstance"></a>Instance Variable Glossary</h3>
-<b>Note</b>: these words are only visible when creating a subclass! To
-create a subclass, use the <tt>sub</tt> method on <tt>object</tt> or any
-class derived from it (<i>not</i> <tt>metaclass</tt>). Source code for
-Ficl OOP is in ficl/softwords/oo.fr.
-<dt>
-Instance variable words do two things: they create methods that do an action
-appropriate for the type of instance variable they represent, and they
-reserve space in the class template for the instance variable. We'll use
-the term <i>instance variable</i> to refer both to the method that gives
-access to a particular field of an object, and to the field itself. Rather
-than give esentially the same example over and over, here's one example
-that shows several of the instance variable construction words in use:</dt>
-
-<ul>
-<dt>
-<tt>object subclass c-example</tt></dt>
-
-<dt>
-<tt> cell:
-.cell0</tt></dt>
-
-<br><tt> c-4byte obj: .nCells</tt>
-<br><tt> 4 c-4byte array: .quad</tt>
-<br><tt> char:
-.length</tt>
-<br><tt> 79 chars:
-.name</tt>
-<br><tt>end-class</tt></ul>
-This class only defines instance variables, and it inherits some methods
-from <tt>object</tt>. Each untyped instance variable (.cell0, .length,
-.name) pushes its address when executed. Each object instance variable
-pushes the address and class of the aggregate object. Similar to C, an
-array instance variable leaves its base address (and its class) when executed.
-The word <tt>subclass</tt> is shorthand for "<tt>--> sub</tt>"
-<br>
-<dt>
-<b><tt>cell: ( offset "name"
--- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- cell-addr )</tt></b></dt>
-
-<dl>
-<dd>
-Create an untyped instance variable one cell wide. The instance variable
-leaves its payload's address when executed. </dd>
-
-<dt>
-<b><tt>cells: ( offset nCells "name"
--- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- cell-addr )</tt></b></dt>
-
-<dd>
-Create an untyped instance variable n cells wide.</dd>
-
-<dt>
-<b><tt>char: ( offset "name"
--- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- char-addr )</tt></b></dt>
-
-<dd>
-Create an untyped member variable one char wide</dd>
-
-<dt>
-<b><tt>chars: ( offset nChars "name"
--- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- char-addr )</tt></b></dt>
-
-<dd>
-Create an untyped member variable n chars wide.</dd>
-
-<dt>
-<b><tt>obj: ( offset class
-meta "name" -- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- instance class )</tt></b></dt>
-
-<dd>
-Aggregate an uninitialized instance of <b>class</b> as a member variable
-of the class under construction.</dd>
-
-<dt>
-<a NAME="arraycolon"></a><b><tt>array:
-( offset n class meta "name" -- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- instance class )</tt></b></dt>
-
-<dd>
-Aggregate an uninitialized array of instances of the class specified as
-a member variable of the class under construction.</dd>
-
-<dt>
-<a NAME="exampleref:"></a><b><tt>ref:
-( offset class meta "name" -- offset' )</tt></b></dt>
-
-<dt>
-<b><tt>
-Execution: ( -- ref-instance ref-class )</tt></b></dt>
-
-<dd>
-Aggregate a reference to a class instance. There is no way to set the value
-of an aggregated ref - it's meant as a way to manipulate existing data
-structures with a Ficl OO model. For example, if your system contains a
-linked list of 4 byte quantities, you can make a class that represents
-a list element like this: </dd>
-
-<dl>
-<dd>
-<tt>object subclass c-4list</tt></dd>
-
-<dd>
-<tt>c-4list ref: .link</tt></dd>
-
-<dd>
-<tt>c-4byte obj: .payload</tt></dd>
-
-<dd>
-<tt>end-class;</tt></dd>
-
-<dd>
-<tt>address-of-existing-list c-4list --> ref mylist</tt></dd>
-</dl>
-
-<dd>
-The last line binds the existing structure to an instance of the class
-we just created. The link method pushes the link value and the class c_4list,
-so that the link looks like an object to Ficl and like a struct to C (it
-doesn't carry any extra baggage for the object model - the Ficl methods
-alone take care of storing the class information). </dd>
-
-<dd>
-Note: Since a ref: aggregate can only support one class, it's good for
-modeling static structures, but not appropriate for polymorphism. If you
-want polymorphism, aggregate a c_ref (see classes.fr for source) into your
-class - it has methods to set and get an object.</dd>
-
-<dd>
-By the way, it is also possible to construct a pair of classes that contain
-aggregate pointers to each other. Here's a rough example:</dd>
-
-<dl>
-<dd>
-<tt>object subclass c-fee</tt></dd>
-
-<dd>
-<tt>object subclass c-fie</tt></dd>
-
-<dd>
-<tt> c-fee ref: .fee</tt></dd>
-
-<dd>
-<tt>end-class \ done with
-c-fie</tt></dd>
-
-<dd>
-<tt> c-fie ref: .fie</tt></dd>
-
-<br><tt>end-class
-\ done with c-fee</tt></dl>
-</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3><a name="glossinstance"></a>Instance Variable
+ Glossary</h3>
+ <p><b>Note</b>: these words are only visible when
+ creating a subclass! To create a subclass, use the <tt>sub</tt>
+ method on <tt>object</tt> or any class derived from it (<i>not</i>
+ <tt>metaclass</tt>). Source code for Ficl OOP is in
+ ficl/softwords/oo.fr. </p>
+ <ul>
+ <li>Instance variable words do two things: they
+ create methods that do an action appropriate for
+ the type of instance variable they represent, and
+ they reserve space in the class template for the
+ instance variable. We'll use the term <i>instance
+ variable</i> to refer both to the method that
+ gives access to a particular field of an object,
+ and to the field itself. Rather than give
+ esentially the same example over and over, here's
+ one example that shows several of the instance
+ variable construction words in use:</li>
+ <li><ul>
+ </ul>
+ </li>
+ <li><tt>object subclass c-example</tt></li>
+ <li><tt>
+ cell:
+ .cell0</tt></li>
+ <li><br>
+ <tt> c-4byte obj:
+ .nCells</tt> <br>
+ <tt> 4 c-4byte array: .quad</tt> <br>
+ <tt>
+ char:
+ .length</tt> <br>
+ <tt> 79
+ chars:
+ .name</tt> <br>
+ <tt>end-class</tt> This class only defines
+ instance variables, and it inherits some methods
+ from <tt>object</tt>. Each untyped instance
+ variable (.cell0, .length, .name) pushes its
+ address when executed. Each object instance
+ variable pushes the address and class of the
+ aggregate object. Similar to C, an array instance
+ variable leaves its base address (and its class)
+ when executed. The word <tt>subclass</tt> is
+ shorthand for "<tt>--> sub</tt>"
+ <br>
+ </li>
+ </ul>
+ <dl>
+ <dt><font size="2" face="Courier New"><strong>cell:
+ ( offset "name" -- offset' )</strong></font></dt>
+ <dt><font size="2" face="Courier New"><strong>Execution:
+ ( -- cell-addr )</strong></font></dt>
+ <dd>Create an untyped instance variable one cell
+ wide. The instance variable leaves its payload's
+ address when executed. </dd>
+ <dt><b><tt>cells:
+ ( offset nCells "name" -- offset' )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- cell-addr )</tt></b></dt>
+ <dd>Create an untyped instance variable n cells wide.</dd>
+ <dt><b><tt>char:
+ ( offset "name" -- offset' )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- char-addr )</tt></b></dt>
+ <dd>Create an untyped member variable one char wide</dd>
+ <dt><b><tt>chars:
+ ( offset nChars "name" -- offset' )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- char-addr )</tt></b></dt>
+ <dd>Create an untyped member variable n chars wide.</dd>
+ <dt><b><tt>obj:
+ ( offset class meta "name" -- offset' )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- instance class )</tt></b></dt>
+ <dd>Aggregate an uninitialized instance of <b>class</b>
+ as a member variable of the class under
+ construction.</dd>
+ <dt><a name="arraycolon"></a><b><tt>array:
+ ( offset n class meta "name" -- offset'
+ )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- instance class )</tt></b></dt>
+ <dd>Aggregate an uninitialized array of instances of
+ the class specified as a member variable of the
+ class under construction.</dd>
+ <dt><a name="exampleref:"></a><b><tt>ref:
+ ( offset class meta "name" -- offset' )</tt></b></dt>
+ <dt><b><tt>
+ Execution: ( -- ref-instance ref-class )</tt></b></dt>
+ <dd>Aggregate a reference to a class instance. There
+ is no way to set the value of an aggregated ref -
+ it's meant as a way to manipulate existing data
+ structures with a Ficl OO model. For example, if
+ your system contains a linked list of 4 byte
+ quantities, you can make a class that represents
+ a list element like this: </dd>
+ <dd><dl>
+ <dd><tt>object subclass c-4list</tt></dd>
+ <dd><tt>c-4list ref: .link</tt></dd>
+ <dd><tt>c-4byte obj: .payload</tt></dd>
+ <dd><tt>end-class;</tt></dd>
+ <dd><tt>address-of-existing-list c-4list
+ --> ref mylist</tt></dd>
+ </dl>
+ </dd>
+ <dd>The last line binds the existing structure to an
+ instance of the class we just created. The link
+ method pushes the link value and the class
+ c_4list, so that the link looks like an object to
+ Ficl and like a struct to C (it doesn't carry any
+ extra baggage for the object model - the Ficl
+ methods alone take care of storing the class
+ information). </dd>
+ <dd>Note: Since a ref: aggregate can only support one
+ class, it's good for modeling static structures,
+ but not appropriate for polymorphism. If you want
+ polymorphism, aggregate a c_ref (see classes.fr
+ for source) into your class - it has methods to
+ set and get an object.</dd>
+ <dd>By the way, it is also possible to construct a
+ pair of classes that contain aggregate pointers
+ to each other. Here's a rough example:</dd>
+ <dd><dl>
+ <dd><tt>object subclass c-fee</tt></dd>
+ <dd><tt>object subclass c-fie</tt></dd>
+ <dd><tt> c-fee ref: .fee</tt></dd>
+ <dd><tt>end-class
+ \ done with c-fie</tt></dd>
+ <dd><tt> c-fie ref: .fie</tt></dd>
+ <dd><br>
+ <tt>end-class
+ \ done with c-fee</tt></dd>
+ </dl>
+ </dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="glossclass"></a>Class Methods Glossary</h3>
-These words are methods of <tt>metaclass</tt>. They define the manipulations
-that can be performed on classes. Methods include various kinds of instantiation,
-programming tools, and access to member variables of classes. Source is
-in softwords/oo.fr.
-<dl>
-<dt>
-<b><tt>instance ( class metaclass "name" -- instance
-class )</tt></b> </dt>
-
-<dd>
-Create an uninitialized instance of the class, giving it the name specified.
-The method leaves the instance 's signature on the stack (handy if you
-want to initialize). Example:</dd>
-
-<dd>
-<tt>c_ref --> instance uninit-ref 2drop</tt></dd>
-
-<dt>
-<b><tt>new ( class
-metaclass "name" -- )</tt></b> </dt>
-
-<dd>
-Create an initialized instance of class, giving it the name specified.
-This method calls init to perform initialization. </dd>
-
-<dt>
-<b><tt>array ( nObj class metaclass
-"name" -- nObjs instance class )</tt></b> </dt>
-
-<dd>
-Create an array of nObj instances of the specified class. Instances are
-not initialized. Example:</dd>
-
-<dd>
-<tt>10 c_4byte --> array 40-raw-bytes 2drop drop</tt></dd>
-
-<dt>
-<b><tt>new-array ( nObj class metaclass "name" -- )</tt></b> </dt>
-
-<dd>
-Creates an initialized array of nObj instances of the class. Same syntax
-as <tt>array</tt></dd>
-
-<dt>
-<a NAME="alloc"></a><b><tt>alloc ( class metaclass -- instance
-class )</tt></b></dt>
-
-<dd>
-Creates an anonymous instance of <b>class</b> from the heap (using a call
-to ficlMalloc() to get the memory). Leaves the payload and class addresses
-on the stack. Usage example:</dd>
-
-<dd>
-<tt>c-ref --> alloc 2constant instance-of-ref</tt></dd>
-
-<dd>
-Creates a double-cell constant that pushes the payload and class address
-of a heap instance of c-ref.</dd>
-
-<dt>
-<a NAME="allocarray"></a><b><tt>alloc-array ( nObj class metaclass
--- instance class )</tt></b></dt>
-
-<dd>
-Same as new-array, but creates anonymous instances from the heap using
-a call to ficlMalloc(). Each instance is initialized using the class's
-<tt>init</tt>
-method</dd>
-
-<dt>
-<b><tt>ref ( instance-addr
-class metaclass "name" -- )</tt></b> </dt>
-
-<dd>
-Make a ref instance of the class that points to the supplied instance address.
-No new instance space is allotted. Instead, the instance refers to the
-address supplied on the stack forever afterward. For wrapping existing
-structures.</dd>
-</dl>
-
-<dl>
-<dt>
-<b><tt>sub ( class
-metaclass -- old-wid addr[size] size )</tt></b></dt>
-
-<dd>
-Derive a subclass. You can add or override methods, and add instance variables.
-Alias: <tt>subclass</tt>. Examples:</dd>
-
-<dl>
-<dd>
-<tt>c_4byte --> sub c_special4byte</tt></dd>
-
-<dd>
-<tt>( your new methods and instance variables here )</tt></dd>
-
-<dd>
-<tt>end-class</tt></dd>
-
-<dd>
-or</dd>
-
-<dd>
-<tt>c_4byte subclass c_special4byte</tt></dd>
-
-<dd>
-<tt>( your new methods and instance variables here )</tt></dd>
-
-<dd>
-<tt>end-class</tt></dd>
-</dl>
-
-<dt>
-<b><tt>.size ( class metaclass
--- instance-size )</tt></b> </dt>
-
-<dd>
-Returns address of the class's instance size field, in address units. This
-is a metaclass member variable.</dd>
-
-<dt>
-<b><tt>.super ( class metaclass --
-superclass )</tt></b> </dt>
-
-<dd>
-Returns address of the class's superclass field. This is a metaclass member
-variable.</dd>
-
-<dt>
-<b><tt>.wid ( class metaclass
--- wid )</tt></b> </dt>
-
-<dd>
-Returns the address of the class's wordlist ID field. This is a metaclass
-member variable.</dd>
-
-<dt>
-<b><tt>get-size</tt></b></dt>
-
-<dd>
-Returns the size of an instance of the class in address units. Imeplemented
-as</dd>
-
-<dd>
-<tt>: get-size metaclass => .size @ ;</tt></dd>
-
-<dt>
-<b><tt>get-wid</tt></b></dt>
-
-<dd>
-Returns the wordlist ID of the class. Implemented as </dd>
-
-<dd>
-<tt>: get-wid metaclass => .wid @ ;</tt></dd>
-
-<dt>
-<b><tt>get-super</tt></b></dt>
-
-<dd>
-Returns the class's superclass. Implemented as</dd>
-
-<dd>
-<tt>: get-super metaclass => .super @ ;</tt></dd>
-
-<dt>
-<b><tt>id (
-class metaclass -- c-addr u )</tt></b> </dt>
-
-<dd>
-Returns the address and length of a string that names the class.</dd>
-
-<dt>
-<b><tt>methods ( class metaclass -- )</tt></b> </dt>
-
-<dd>
-Lists methods of the class and all its superclasses</dd>
-
-<dt>
-<b><tt>offset-of ( class metaclass "name" -- offset )</tt></b></dt>
-
-<dd>
-Pushes the offset from the instance base address of the named member variable.
-If the name is not that of an instance variable method, you get garbage.
-There is presently no way to detect this error. Example:</dd>
-
-<dl>
-<dd>
-<tt>metaclass --> offset-of .wid</tt></dd>
-</dl>
-
-<dt>
-<b><tt>pedigree ( class metaclass -- )</tt></b> </dt>
-
-<dd>
-Lists the pedigree of the class (inheritance trail)</dd>
-
-<dt>
-<b><tt>see ( class
-metaclass "name" -- )</tt></b> </dt>
-
-<dd>
-Decompiles the specified method - obect version of <tt>SEE</tt>, from the
-<tt>TOOLS</tt>
-wordset.</dd>
-</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3><a name="glossclass"></a>Class Methods Glossary</h3>
+ <p>These words are methods of <tt>metaclass</tt>. They
+ define the manipulations that can be performed on
+ classes. Methods include various kinds of instantiation,
+ programming tools, and access to member variables of
+ classes. Source is in softwords/oo.fr. </p>
+ <dl>
+ <dt><b><tt>instance ( class
+ metaclass "name" -- instance class )</tt></b> </dt>
+ <dd>Create an uninitialized instance of the class,
+ giving it the name specified. The method leaves
+ the instance 's signature on the stack (handy if
+ you want to initialize). Example:</dd>
+ <dd><tt>c_ref --> instance uninit-ref 2drop</tt></dd>
+ <dt><b><tt>new
+ ( class metaclass "name" -- )</tt></b> </dt>
+ <dd>Create an initialized instance of class, giving
+ it the name specified. This method calls init to
+ perform initialization. </dd>
+ <dt><b><tt>array
+ ( nObj class metaclass "name" -- nObjs
+ instance class )</tt></b> </dt>
+ <dd>Create an array of nObj instances of the
+ specified class. Instances are not initialized.
+ Example:</dd>
+ <dd><tt>10 c_4byte --> array
+ 40-raw-bytes 2drop drop</tt></dd>
+ <dt><b><tt>new-array ( nObj class
+ metaclass "name" -- )</tt></b> </dt>
+ <dd>Creates an initialized array of nObj instances of
+ the class. Same syntax as <tt>array</tt></dd>
+ <dt><a name="alloc"></a><b><tt>alloc (
+ class metaclass -- instance class )</tt></b></dt>
+ <dd>Creates an anonymous instance of <b>class</b>
+ from the heap (using a call to ficlMalloc() to
+ get the memory). Leaves the payload and class
+ addresses on the stack. Usage example:</dd>
+ <dd><tt>c-ref --> alloc 2constant instance-of-ref</tt></dd>
+ <dd>Creates a double-cell constant that pushes the
+ payload and class address of a heap instance of
+ c-ref.</dd>
+ <dt><a name="allocarray"></a><b><tt>alloc-array
+ ( nObj class metaclass -- instance class )</tt></b></dt>
+ <dd>Same as new-array, but creates anonymous
+ instances from the heap using a call to
+ ficlMalloc(). Each instance is initialized using
+ the class's <tt>init</tt> method</dd>
+ <dt><b><tt>ref
+ ( instance-addr class metaclass "name"
+ -- )</tt></b> </dt>
+ <dd>Make a ref instance of the class that points to
+ the supplied instance address. No new instance
+ space is allotted. Instead, the instance refers
+ to the address supplied on the stack forever
+ afterward. For wrapping existing structures.</dd>
+ </dl>
+ <dl>
+ <dt><b><tt>sub
+ ( class metaclass -- old-wid addr[size] size )</tt></b></dt>
+ <dd>Derive a subclass. You can add or override
+ methods, and add instance variables. Alias: <tt>subclass</tt>.
+ Examples:</dd>
+ <dd><dl>
+ <dd><tt>c_4byte --> sub c_special4byte</tt></dd>
+ <dd><tt>( your new methods and instance
+ variables here )</tt></dd>
+ <dd><tt>end-class</tt></dd>
+ <dd>or</dd>
+ <dd><tt>c_4byte subclass c_special4byte</tt></dd>
+ <dd><tt>( your new methods and instance
+ variables here )</tt></dd>
+ <dd><tt>end-class</tt></dd>
+ </dl>
+ </dd>
+ <dt><b><tt>.size
+ ( class metaclass -- instance-size )</tt></b> </dt>
+ <dd>Returns address of the class's instance size
+ field, in address units. This is a metaclass
+ member variable.</dd>
+ <dt><b><tt>.super
+ ( class metaclass -- superclass )</tt></b> </dt>
+ <dd>Returns address of the class's superclass field.
+ This is a metaclass member variable.</dd>
+ <dt><b><tt>.wid
+ ( class metaclass -- wid )</tt></b> </dt>
+ <dd>Returns the address of the class's wordlist ID
+ field. This is a metaclass member variable.</dd>
+ <dt><b><tt>get-size</tt></b></dt>
+ <dd>Returns the size of an instance of the class in
+ address units. Imeplemented as</dd>
+ <dd><tt>: get-size metaclass => .size
+ @ ;</tt></dd>
+ <dt><b><tt>get-wid</tt></b></dt>
+ <dd>Returns the wordlist ID of the class. Implemented
+ as </dd>
+ <dd><tt>: get-wid metaclass => .wid @
+ ;</tt></dd>
+ <dt><b><tt>get-super</tt></b></dt>
+ <dd>Returns the class's superclass. Implemented as</dd>
+ <dd><tt>: get-super metaclass =>
+ .super @ ;</tt></dd>
+ <dt><b><tt>id
+ ( class metaclass -- c-addr u )</tt></b> </dt>
+ <dd>Returns the address and length of a string that
+ names the class.</dd>
+ <dt><b><tt>methods (
+ class metaclass -- )</tt></b> </dt>
+ <dd>Lists methods of the class and all its
+ superclasses</dd>
+ <dt><b><tt>offset-of ( class
+ metaclass "name" -- offset )</tt></b></dt>
+ <dd>Pushes the offset from the instance base address
+ of the named member variable. If the name is not
+ that of an instance variable method, you get
+ garbage. There is presently no way to detect this
+ error. Example:</dd>
+ <dd><dl>
+ <dd><tt>metaclass --> offset-of .wid</tt></dd>
+ </dl>
+ </dd>
+ <dt><b><tt>pedigree ( class
+ metaclass -- )</tt></b> </dt>
+ <dd>Lists the pedigree of the class (inheritance
+ trail)</dd>
+ <dt><b><tt>see
+ ( class metaclass "name" -- )</tt></b> </dt>
+ <dd>Decompiles the specified method - obect version
+ of <tt>SEE</tt>, from the <tt>TOOLS</tt> wordset.</dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="objectgloss"></a><tt>object</tt> base-class Methods Glossary</h3>
-These are methods that are defined for all instances by the base class
-<tt>object</tt>.
-The methods include default initialization, array manipulations, aliases
-of class methods, upcasting, and programming tools.
-<dl>
-<dt>
-<b><tt>init ( instance
-class -- )</tt> </b></dt>
-
-<dd>
-Default initializer called automatically for all instances created with
-<tt>new</tt>
-or <tt>new-array</tt>. Zero-fills the instance. You do not normally need
-to invoke <tt>init</tt> explicitly.</dd>
-
-<dt>
-<b><tt>array-init ( nObj instance class -- )</tt></b> </dt>
-
-<dd>
-Applies <tt>init</tt> to an array of objects created by <tt>new-array</tt>.
-Note that <tt>array:</tt> does not cause aggregate arrays to be initialized
-automatically. You do not normally need to invoke <tt>array-init</tt> explicitly.</dd>
-
-<dt>
-<a NAME="oofree"></a><b><tt>free ( instance class -- )</tt></b></dt>
-
-<dd>
-Releases memory used by an instance previously created with <tt>alloc</tt>
-or <tt>alloc-array</tt>. Note - this method is not presently protected
-against accidentally deleting something from the dictionary. If you do
-this, Bad Things are likely to happen. Be careful for the moment to apply
-free only to instances created with <tt>alloc</tt> or <tt>alloc-array</tt>.</dd>
-
-<dt>
-<b><tt>class ( instance class
--- class metaclass )</tt></b> </dt>
-
-<dd>
-Convert an object signature into that of its class. Useful for calling
-class methods that have no object aliases.</dd>
-
-<dt>
-<b><tt>super ( instance class
--- instance parent-class )</tt></b> </dt>
-
-<dd>
-Upcast an object to its parent class. The parent class of <tt>object</tt>
-is zero. Useful for invoking an overridden parent class method.</dd>
-
-<dt>
-<b><tt>pedigree ( instance class -- )</tt></b> </dt>
-
-<dd>
-Display an object's pedigree - its chain of inheritance. This is an alias
-for the corresponding class method.</dd>
-
-<dt>
-<b><tt>size ( instance
-class -- sizeof(instance) )</tt></b> </dt>
-
-<dd>
-Returns the size, in address units, of one instance. Does not know about
-arrays! This is an alias for the class method <tt>get-size</tt></dd>
-
-<dt>
-<b><tt>methods ( instance class -- )</tt></b> </dt>
-
-<dd>
-Class method alias. Displays the list of methods of the class and all superclasses
-of the instance.</dd>
-
-<dt>
-<b><tt>index ( n instance class
--- instance[n] class )</tt></b> </dt>
-
-<dd>
-Convert array-of-objects base signature into signature for array element
-n. No check for bounds overflow. Index is zero-based, like C, so </dd>
-
-<dl>
-<dd>
-<tt>0 my-obj --> index</tt> </dd>
-</dl>
-
-<dd>
-is equivalent to </dd>
-
-<dl>
-<dd>
-<tt>my-obj</tt></dd>
-</dl>
-
-<dd>
-Check out the <a href="#minusrot">description of <tt>-ROT</tt></a> for
-help in dealing with indices on the stack.</dd>
-
-<dt>
-<b><tt>next ( instance[n]
-class -- instance[n+1] class )</tt></b> </dt>
-
-<dd>
-Convert an array-object signature into the signature of the next
-object in the array. No check for bounds overflow.</dd>
-
-<dt>
-<b><tt>prev ( instance[n]
-class -- instance[n-1] class )</tt></b> </dt>
-
-<br>Convert an object signature into the signature of the previous object
-in the array. No check for bounds underflow.</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3><a name="objectgloss"></a><tt>object</tt>
+ base-class Methods Glossary</h3>
+ <p>These are methods that are defined for all instances
+ by the base class <tt>object</tt>. The methods include
+ default initialization, array manipulations, aliases of
+ class methods, upcasting, and programming tools. </p>
+ <dl>
+ <dt><b><tt>init
+ ( instance class -- )</tt></b><b> </b></dt>
+ <dd>Default initializer called automatically for all
+ instances created with <tt>new</tt> or <tt>new-array</tt>.
+ Zero-fills the instance. You do not normally need
+ to invoke <tt>init</tt> explicitly.</dd>
+ <dt><b><tt>array-init ( nObj instance
+ class -- )</tt></b> </dt>
+ <dd>Applies <tt>init</tt> to an array of objects
+ created by <tt>new-array</tt>. Note that <tt>array:</tt>
+ does not cause aggregate arrays to be initialized
+ automatically. You do not normally need to invoke
+ <tt>array-init</tt> explicitly.</dd>
+ <dt><a name="oofree"></a><b><tt>free (
+ instance class -- )</tt></b></dt>
+ <dd>Releases memory used by an instance previously
+ created with <tt>alloc</tt> or <tt>alloc-array</tt>.
+ Note - this method is not presently protected
+ against accidentally deleting something from the
+ dictionary. If you do this, Bad Things are likely
+ to happen. Be careful for the moment to apply
+ free only to instances created with <tt>alloc</tt>
+ or <tt>alloc-array</tt>.</dd>
+ <dt><b><tt>class
+ ( instance class -- class metaclass )</tt></b> </dt>
+ <dd>Convert an object signature into that of its
+ class. Useful for calling class methods that have
+ no object aliases.</dd>
+ <dt><b><tt>super
+ ( instance class -- instance parent-class )</tt></b> </dt>
+ <dd>Upcast an object to its parent class. The parent
+ class of <tt>object</tt> is zero. Useful for
+ invoking an overridden parent class method.</dd>
+ <dt><b><tt>pedigree (
+ instance class -- )</tt></b> </dt>
+ <dd>Display an object's pedigree - its chain of
+ inheritance. This is an alias for the
+ corresponding class method.</dd>
+ <dt><b><tt>size
+ ( instance class -- sizeof(instance) )</tt></b> </dt>
+ <dd>Returns the size, in address units, of one
+ instance. Does not know about arrays! This is an
+ alias for the class method <tt>get-size</tt></dd>
+ <dt><b><tt>methods (
+ instance class -- )</tt></b> </dt>
+ <dd>Class method alias. Displays the list of methods
+ of the class and all superclasses of the
+ instance.</dd>
+ <dt><b><tt>index
+ ( n instance class -- instance[n] class )</tt></b> </dt>
+ <dd>Convert array-of-objects base signature into
+ signature for array element n. No check for
+ bounds overflow. Index is zero-based, like C,
+ so </dd>
+ <dd><dl>
+ <dd><tt>0 my-obj --> index</tt> </dd>
+ </dl>
+ </dd>
+ <dd>is equivalent to </dd>
+ <dd><dl>
+ <dd><tt>my-obj</tt></dd>
+ </dl>
+ </dd>
+ <dd>Check out the <a href="#minusrot">description of <tt>-ROT</tt></a>
+ for help in dealing with indices on the stack.</dd>
+ <dt><b><tt>next
+ ( instance[n] class -- instance[n+1] class )</tt></b> </dt>
+ <dd>Convert an array-object signature into the
+ signature of the next object in the array. No
+ check for bounds overflow.</dd>
+ <dt><b><tt>prev
+ ( instance[n] class -- instance[n-1] class )</tt></b> </dt>
+ <dd><br>
+ Convert an object signature into the signature of
+ the previous object in the array. No check for
+ bounds underflow.</dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h3>
-<a NAME="stockclasses"></a>Supplied Classes (See classes.fr)</h3>
-
-<dl>
-<dt>
-<b><tt>metaclass </tt></b></dt>
-
-<dd>
-Describes all classes of Ficl. Contains class methods. Should never be
-directly instantiated or subclassed. Defined in oo.fr. Methods described
-above.</dd>
-
-<dt>
-<b><tt>object</tt> </b></dt>
-
-<dd>
-Mother of all Ficl objects. Defines default initialization and array indexing
-methods. Defined in oo.fr. Methods described above.</dd>
-
-<dt>
-<b><tt>c-ref</tt> </b></dt>
-
-<dd>
-Holds the signature of another object. Aggregate one of these into a data
-structure or container class to get polymorphic behavior. Methods &
-members: </dd>
-
-<dd>
-<tt>get ( inst class -- ref-inst ref-class )</tt></dd>
-
-<dd>
-<tt>set ( ref-inst ref-class inst class -- )</tt></dd>
-
-<dd>
-<tt>.instance ( inst class -- a-addr ) </tt>cell member that
-holds the instance</dd>
-
-<dd>
-<tt>.class ( inst class -- a-addr ) </tt>cell member that holds
-the class</dd>
-
-<dt>
-<b><tt>c-byte </tt></b></dt>
-
-<dd>
-Primitive class derived from <tt>object</tt>, with a 1-byte payload. Set
-and get methods perform correct width fetch and store. Methods & members:</dd>
-
-<dd>
-<tt>get ( inst class -- c )</tt></dd>
-
-<dd>
-<tt>set ( c inst class -- )</tt></dd>
-
-<dd>
-<tt>.payload ( inst class -- addr ) </tt>member holds instance's
-value</dd>
-
-<dt>
-<b><tt>c-2byte</tt></b> </dt>
-
-<dd>
-Primitive class derived from <tt>object</tt>, with a 2-byte payload. Set
-and get methods perform correct width fetch and store. Methods & members:</dd>
-
-<dd>
-<tt>get ( inst class -- 2byte )</tt></dd>
-
-<dd>
-<tt>set ( 2byte inst class -- )</tt></dd>
-
-<dd>
-<tt>.payload ( inst class -- addr ) </tt>member holds instance's
-value</dd>
-
-<dt>
-<b><tt>c-4byte</tt></b> </dt>
-
-<dd>
-Primitive class derived from <tt>object</tt>, with a 4-byte (cell) payload.
-Set and get methods perform correct width fetch and store. Methods &
-members:</dd>
-
-<dd>
-<tt>get ( inst class -- x )</tt></dd>
-
-<dd>
-<tt>set ( x inst class -- )</tt></dd>
-
-<dd>
-<tt>.payload ( inst class -- addr ) </tt>member holds instance's
-value</dd>
-
-<dt>
-<b><tt>c-ptr</tt></b></dt>
-
-<dd>
-Base class derived from <tt>object</tt> for pointers to non-object types.
-This class is not complete by itself: several methods depend on a derived
-class definition of <tt>@size</tt>. Methods & members:</dd>
-
-<dd>
-<tt>.addr ( inst class -- a-addr )</tt> member variable - holds
-the pointer address</dd>
-
-<dd>
-<tt>get-ptr ( inst class -- ptr )</tt></dd>
-
-<dd>
-<tt>set-ptr ( ptr inst class -- )</tt></dd>
-
-<dd>
-<tt>inc-ptr ( inst class -- )</tt> Adds @size to pointer address</dd>
-
-<dd>
-<tt>dec-ptr ( inst class -- )</tt> Subtracts @size from pointer
-address</dd>
-
-<dd>
-<tt>index-ptr ( i inst class -- )</tt> Adds i*@size to pointer
-address</dd>
-
-<dt>
-<b><tt>c-bytePtr</tt></b></dt>
-
-<dd>
-Pointer to byte derived from c-ptr. Methods & members:</dd>
-
-<dd>
-<tt>@size ( inst class -- size )</tt> Push size of the pointed-to
-thing</dd>
-
-<dd>
-<tt>get ( inst class -- c ) </tt>Fetch the pointer's
-referent byte</dd>
-
-<dd>
-<tt>set ( c inst class -- ) </tt>Store c at the pointer address</dd>
-
-<dt>
-<b><tt>c-2bytePtr</tt></b></dt>
-
-<dd>
-Pointer to double byte derived from c-ptr. Methods & members:</dd>
-
-<dd>
-<tt>@size ( inst class -- size )</tt> Push size of the pointed-to
-thing</dd>
-
-<dd>
-<tt>get ( inst class -- x ) </tt>Fetch the pointer's
-referent 2byte</dd>
-
-<dd>
-<tt>set ( x inst class -- )</tt> Store 2byte x at the pointer
-address</dd>
-
-<dt>
-<b><tt>c-cellPtr</tt></b></dt>
-
-<dd>
-Pointer to cell derived from c-ptr. Methods & members:</dd>
-
-<dd>
-<tt>@size ( inst class -- size )</tt> Push size of the pointed-to
-thing</dd>
-
-<dd>
-<tt>get ( inst class -- x ) </tt>Fetch the pointer's
-referent cell</dd>
-
-<dd>
-<tt>set ( x inst class -- )</tt> Storex at the pointer address</dd>
-
-<dt>
-<b><tt>c-string</tt></b> </dt>
-
-<dd>
-Counted string (thin)</dd>
-</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h3><a name="stockclasses"></a>Supplied Classes (See
+ classes.fr)</h3>
+ <dl>
+ <dt><b><tt>metaclass </tt></b></dt>
+ <dd>Describes all classes of Ficl. Contains class
+ methods. Should never be directly instantiated or
+ subclassed. Defined in oo.fr. Methods described
+ above.</dd>
+ <dt><b><tt>object</tt></b><b> </b></dt>
+ <dd>Mother of all Ficl objects. Defines default
+ initialization and array indexing methods.
+ Defined in oo.fr. Methods described above.</dd>
+ <dt><b><tt>c-ref</tt></b><b> </b></dt>
+ <dd>Holds the signature of another object. Aggregate
+ one of these into a data structure or container
+ class to get polymorphic behavior. Methods &
+ members: </dd>
+ <dd><tt>get ( inst class -- ref-inst
+ ref-class )</tt></dd>
+ <dd><tt>set ( ref-inst ref-class inst
+ class -- )</tt></dd>
+ <dd><tt>.instance ( inst class -- a-addr
+ ) </tt>cell member that holds the instance</dd>
+ <dd><tt>.class ( inst class -- a-addr ) </tt>cell
+ member that holds the class</dd>
+ <dt><b><tt>c-byte </tt></b></dt>
+ <dd>Primitive class derived from <tt>object</tt>,
+ with a 1-byte payload. Set and get methods
+ perform correct width fetch and store. Methods
+ & members:</dd>
+ <dd><tt>get ( inst class -- c )</tt></dd>
+ <dd><tt>set ( c inst class -- )</tt></dd>
+ <dd><tt>.payload ( inst class -- addr ) </tt>member
+ holds instance's value</dd>
+ <dt><b><tt>c-2byte</tt></b> </dt>
+ <dd>Primitive class derived from <tt>object</tt>,
+ with a 2-byte payload. Set and get methods
+ perform correct width fetch and store. Methods
+ & members:</dd>
+ <dd><tt>get ( inst class -- 2byte )</tt></dd>
+ <dd><tt>set ( 2byte inst class -- )</tt></dd>
+ <dd><tt>.payload ( inst class -- addr ) </tt>member
+ holds instance's value</dd>
+ <dt><b><tt>c-4byte</tt></b> </dt>
+ <dd>Primitive class derived from <tt>object</tt>,
+ with a 4-byte (cell) payload. Set and get methods
+ perform correct width fetch and store. Methods
+ & members:</dd>
+ <dd><tt>get ( inst class -- x )</tt></dd>
+ <dd><tt>set ( x inst class -- )</tt></dd>
+ <dd><tt>.payload ( inst class -- addr ) </tt>member
+ holds instance's value</dd>
+ <dt><b><tt>c-ptr</tt></b></dt>
+ <dd>Base class derived from <tt>object</tt> for
+ pointers to non-object types. This class is not
+ complete by itself: several methods depend on a
+ derived class definition of <tt>@size</tt>.
+ Methods & members:</dd>
+ <dd><tt>.addr ( inst class -- a-addr )</tt>
+ member variable - holds the pointer address</dd>
+ <dd><tt>get-ptr ( inst class -- ptr )</tt></dd>
+ <dd><tt>set-ptr ( ptr inst class -- )</tt></dd>
+ <dd><tt>inc-ptr ( inst class -- )</tt>
+ Adds @size to pointer address</dd>
+ <dd><tt>dec-ptr ( inst class -- )</tt>
+ Subtracts @size from pointer address</dd>
+ <dd><tt>index-ptr ( i inst class -- )</tt>
+ Adds i*@size to pointer address</dd>
+ <dt><b><tt>c-bytePtr</tt></b></dt>
+ <dd>Pointer to byte derived from c-ptr. Methods &
+ members:</dd>
+ <dd><tt>@size ( inst class -- size )</tt>
+ Push size of the pointed-to thing</dd>
+ <dd><tt>get ( inst class -- c ) </tt>Fetch
+ the pointer's referent byte</dd>
+ <dd><tt>set ( c inst class -- ) </tt>Store
+ c at the pointer address</dd>
+ <dt><b><tt>c-2bytePtr</tt></b></dt>
+ <dd>Pointer to double byte derived from c-ptr.
+ Methods & members:</dd>
+ <dd><tt>@size ( inst class -- size )</tt>
+ Push size of the pointed-to thing</dd>
+ <dd><tt>get ( inst class -- x ) </tt>Fetch
+ the pointer's referent 2byte</dd>
+ <dd><tt>set ( x inst class -- )</tt>
+ Store 2byte x at the pointer address</dd>
+ <dt><b><tt>c-cellPtr</tt></b></dt>
+ <dd>Pointer to cell derived from c-ptr. Methods &
+ members:</dd>
+ <dd><tt>@size ( inst class -- size )</tt>
+ Push size of the pointed-to thing</dd>
+ <dd><tt>get ( inst class -- x ) </tt>Fetch
+ the pointer's referent cell</dd>
+ <dd><tt>set ( x inst class -- )</tt>
+ Storex at the pointer address</dd>
+ <dt><b><tt>c-string</tt></b> </dt>
+ <dd>Dynamically allocated string similar to MFC
+ CString (Partial list of methods follows)</dd>
+ <dd><font size="2" face="Courier New">set ( c-addr u
+ 2this -- ) </font><font size="3">Initialize
+ buffer to the specified string</font></dd>
+ <dd><font size="2" face="Courier New">get ( 2this --
+ c-addr u ) Return buffer contents as counted
+ string</font></dd>
+ <dd><font size="2" face="Courier New">cat ( c-addr u
+ 2this -- ) Append given string to end of buffer</font></dd>
+ <dd><font size="2" face="Courier New">compare (
+ 2string 2this -- n ) Return result of lexical
+ compare</font></dd>
+ <dd><font size="2" face="Courier New">type ( 2this --
+ ) Print buffer to the output stream</font></dd>
+ <dd><font size="2" face="Courier New">hashcode (
+ 2this -- x ) Return hashcode of string (as in
+ dictionary)</font></dd>
+ <dd><font size="2" face="Courier New">free ( 2this --
+ ) Release internal buffer</font></dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<h2>
+<hr>
-<hr WIDTH="100%"></h2>
-
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<dl>
-<h2>
-<a NAME="extras"></a>Ficl extras</h2>
-
-<h3>
-Number syntax</h3>
-You can precede a number with "0x", as in C, and it will be interpreted
-as a hex value regardless of the value of <tt>BASE</tt>. Example:
-<dl><tt>ok> decimal 123 . cr</tt>
-<br><tt>123 </tt>
-<br><tt>ok> 0x123 . cr</tt>
-<br><tt>291 </tt></dl>
-
-<h3>
-Search order words</h3>
-Note: Ficl resets the search order whenever it does <tt>ABORT</tt>. If
-you don't like this behavior, just comment out the dictResetSearchOrder()
-lines in ficlExec().
-<br>
-<dt>
-<a NAME="tosearch"></a><tt>>search ( wid -- )</tt></dt>
-
-<dd>
-Push <tt>wid</tt> onto the search order. Many of the other search order
-words are written in terms of the <tt>SEARCH></tt> and <tt>>SEARCH</tt>
-primitives.</dd>
-
-<dt>
-<a NAME="searchfrom"></a><tt>search> ( -- wid )</tt></dt>
-
-<dd>
-Pop <tt>wid</tt> off the search order</dd>
-
-<dt>
-<a NAME="ficlsetcurrent"></a><tt>ficl-set-current ( wid --
-old-wid )</tt></dt>
-
-<dd>
-Set wid as compile wordlist, leaving the previous compile wordlist on the
-stack</dd>
-
-<dt>
-<a NAME="ficlvocabulary"></a><tt>ficl-vocabulary ( nBins "name"
--- )</tt></dt>
-
-<dd>
-Creates a <tt>ficl-wordlist</tt> with the specified number of hash table
-bins, binds it to the name, and associates the semantics of <tt>vocabulary</tt>
-with it (replaces the top wid in the search order list with its own wid
-when executed)</dd>
-
-<dt>
-<a NAME="ficlwordlist"></a><tt>ficl-wordlist ( nBins -- wid
-)</tt></dt>
-
-<dd>
-Creates a <font face="">wordlist</font> with the specified number of hash
-table bins, and leaves the address of the wordlist on the stack. A <tt>ficl-wordlist</tt>
-behaves exactly as a regular wordlist, but it may search faster depending
-on the number of bins chosen and the number of words it contains at search
-time. As implemented in ficl, a <tt>wordlist</tt> is single threaded by
-default. </dd>
-
-<dt>
-<a NAME="ficlforgetwid"></a><tt>forget-wid ( wid -- )</tt></dt>
-
-<dd>
-Iterates through the specified wordlist and unlinks all definitions whose
-xt addresses are greater than or equal to the value of <tt>HERE</tt>, the
-dictionary fill pointer. </dd>
-
-<dt>
-<a NAME="ficlhide"></a><tt>hide ( -- current-wid-was )</tt></dt>
-
-<dd>
-Push the <tt>hidden</tt> wordlist onto the search order, and set it as
-the current compile wordlist (unsing <tt>ficl-set-current</tt>). Leaves
-the previous compile wordlist ID. I use this word to hide implementation
-factor words that have low reuse potential so that they don't clutter the
-default wordlist. To undo the effect of hide, execute <b><tt>previous
-set-current</tt></b></dd>
-
-<dt>
-<a NAME="ficlhidden"></a><tt>hidden ( -- wid )</tt></dt>
-
-<dd>
-Wordlist for storing implementation factors of ficl provided words. To
-see what's in there, try: <b><tt>hide words previous set-current</tt></b></dd>
-
-<dt>
-<tt>wid-set-super ( wid -- )</tt></dt>
-
-<dd>
-Ficl wordlists have a parent wordlist pointer that is not specified in
-standard Forth. Ficl initializes this pointer to NULL whenever it creates
-a wordlist, so it ordinarily has no effect. This word sets the parent pointer
-to the wordlist specified on the top of the stack. Ficl's implementation
-of <tt>SEARCH-WORDLIST</tt> will chain backward through the parent link
-of the wordlist when searching. This simplifies Ficl's object model in
-that the search order does not need to reflect an object's class hierarchy
-when searching for a method. It is possible to implement Ficl object syntax
-in strict ANS Forth, but method finders need to manipulate the search order
-explicitly.</dd>
-</dl>
-
-<h3>
-User variables</h3>
-
-<dl>
-<dt>
-<tt>user ( -- ) name</tt></dt>
-
-<dd>
-Create a user variable with the given name. User variables are virtual
-machine local. Each VM allocates a fixed amount of storage for them. You
-can change the maximum number of user variables allowed by defining FICL_USER_CELLS
-on your compiiler's command line. Default is 16 user cells.</dd>
-</dl>
-
-<h3>
-Miscellaneous</h3>
-
-<dl>
-<dt>
-<tt>-roll ( xu xu-1 ... x0 u -- x0 xu-1 ... x1 ) </tt></dt>
-
-<dd>
-Rotate u+1 items on top of the stack after removing u. Rotation is in the
-opposite sense to <tt>ROLL</tt></dd>
-</dl>
-
-<dl>
-<dt>
-<a NAME="minusrot"></a><tt>-rot ( a b c -- c a b )</tt></dt>
-
-<dd>
-Rotate the top three stack entries, moving the top of stack to third place.
-I like to think of this as <tt>1<sup>1</sup>/<sub>2</sub>swap</tt> because
-it's good for tucking a single cell value behind a cell-pair (like an object). </dd>
-</dl>
-
-<dl>
-<dt>
-<tt>.env ( -- )</tt></dt>
-
-<dd>
-List all environment variables of the system</dd>
-
-<dt>
-<tt>.hash ( -- )</tt></dt>
-
-<dd>
-List hash table performance statistics of the wordlist that's first in
-the search order</dd>
-
-<dt>
-<tt>.ver ( -- )</tt></dt>
-
-<dd>
-Display ficl version ID</dd>
-
-<dt>
-<tt>>name ( xt -- c-addr u )</tt></dt>
-
-<dd>
-Convert a word's execution token into the address and length of its name</dd>
-
-<dt>
-<tt>body> ( a-addr -- xt )</tt></dt>
-
-<dd>
-Reverses the effect of <tt>CORE</tt> word <tt>>body </tt>(converts a parameter
-field address to an execution token)</dd>
-
-<dt>
-<tt>compile-only</tt></dt>
-
-<dd>
-Mark the most recently defined word as being executable only while in compile
-state. Many <tt>immediate</tt> words have this property.</dd>
-
-<dt>
-<tt>empty ( -- )</tt> </dt>
-
-<dd>
-Empty the parameter stack</dd>
-
-<dt>
-<tt>endif</tt></dt>
-
-<dd>
-Synonym for <tt>THEN</tt></dd>
-
-<dt>
-<tt>parse-word ( <spaces>name -- c-addr u )</tt></dt>
-
-<dd>
-Skip leading spaces and parse name delimited by a space. c-addr is the
-address within the input buffer and u is the length of the selected string.
-If the parse area is empty, the resulting string has a zero length. (From
-the Standard)</dd>
-
-<dt>
-<tt>w@ ( addr -- x )</tt></dt>
-
-<dd>
-Fetch a 16 bit quantity from the specified address</dd>
-
-<dt>
-<tt>w! ( x addr -- )</tt></dt>
-
-<dd>
-Store a 16 bit quantity to the specified address (the low 16 bits of the
-given value)</dd>
-
-<dt>
-<tt>x. ( x -- )</tt></dt>
-
-<dd>
-Pop and display the value in hex format, regardless of the current value
-of <tt>BASE</tt></dd>
-</dl>
-
-<h3>
-FiclWin Extras (defined in testmain.c)</h3>
-
-<dl>
-<dt>
-<tt>break ( -- )</tt></dt>
-
-<dd>
-Does nothing - just a handy place to set a debugger breakpoint</dd>
-
-<dt>
-<tt>cd ( "directory-name<newline>" --
-)</tt></dt>
-
-<dd>
-Executes the Win32 chdir() function, changing the program's logged directory.</dd>
-
-<dt>
-<a NAME="clock"></a><tt>clock ( -- now )</tt></dt>
-
-<dd>
-Wrapper for the ANSI C clock() function. Returns the number of clock ticks
-elapsed since process start.</dd>
-
-<dt>
-<a NAME="clockspersec"></a><tt>clocks/sec ( -- clocks_per_sec
-)</tt></dt>
-
-<dd>
-Pushes the number of ticks in a second as returned by <tt>clock</tt></dd>
-
-<dt>
-<a NAME="ficlload"></a><tt>load ( "filename<newline>"
--- )</tt></dt>
-
-<dd>
-Opens the Forth source file specified and loads it one line at a time,
-like <tt>INCLUDED (FILE)</tt></dd>
-
-<dt>
-<tt>pwd ( -- )</tt></dt>
-
-<dd>
-Prints the current working directory as set by <tt>cd</tt></dd>
-
-<dt>
-<tt>system ( "command<newline>" -- )</tt></dt>
-
-<dd>
-Issues a command to a shell; implemented with the Win32 system() call.</dd>
-
-<dt>
-<tt>spewhash ( "filename<newline>" -- )</tt></dt>
-
-<dd>
-Dumps all threads of the current compilation wordlist to the specified
-text file. This was useful when I thought there might be some point in
-attempting to optimize the hash function. I no longer harbor those illusions.</dd>
-
-<h3>
-FiclWin Exclusives (no source provided)</h3>
-
-<dt>
-<tt>!oreg ( c -- )</tt></dt>
-
-<dd>
-Set the value of the simulated LED register as specified (0..255)</dd>
-
-<dt>
-<tt>@ireg ( -- c )</tt></dt>
-
-<dd>
-Gets the value of the simulated switch block (0..255)</dd>
-
-<dt>
-<tt>!dac ( c -- )</tt></dt>
-
-<dd>
-Sets the value of the bargraph control as specified. Valid values range
-from 0..255</dd>
-
-<dt>
-<tt>@adc ( -- c )</tt></dt>
-
-<dd>
-Fetches the current position of the slider control. Range is 0..255</dd>
-
-<dt>
-<tt>status" ( "ccc<quote>" -- )</tt></dt>
-
-<dd>
-Set the mainframe window's status line to the text specified, up to the
-first trailing quote character.</dd>
-
-<dt>
-<a NAME="ficlms"></a><tt><a href="http://www.taygeta.com/forth/dpans10.htm#10.6.2.1905">ms</a>
-( u -- )</tt></dt>
-
-<dd>
-Causes the running virtual machine to sleep() for the number of milliseconds
-specified by the top-of-stack value.</dd>
-</dl>
-</td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><dl>
+ <dd><h2><a name="extras"></a>Ficl extras</h2>
+ <h3>Number syntax</h3>
+ <p>You can precede a number with "0x",
+ as in C, and it will be interpreted as a hex
+ value regardless of the value of <tt>BASE</tt>.
+ Example: </p>
+ <dl>
+ <dt><tt>ok> decimal 123 . cr</tt> <br>
+ <tt>123 </tt> <br>
+ <tt>ok> 0x123 . cr</tt> <br>
+ <tt>291 </tt></dt>
+ </dl>
+ <h3>Search order words</h3>
+ <p>Note: Ficl resets the search order whenever it
+ does <tt>ABORT</tt>. If you don't like this
+ behavior, just comment out the
+ dictResetSearchOrder() lines in ficlExec().
+ <br>
+ </p>
+ </dd>
+ <dt><a name="tosearch"></a><tt>>search
+ ( wid -- )</tt></dt>
+ <dd>Push <tt>wid</tt> onto the search order. Many of
+ the other search order words are written in terms
+ of the <tt>SEARCH></tt> and <tt>>SEARCH</tt>
+ primitives.</dd>
+ <dt><a name="searchfrom"></a><tt>search>
+ ( -- wid )</tt></dt>
+ <dd>Pop <tt>wid</tt> off the search order</dd>
+ <dt><a name="ficlsetcurrent"></a><tt>ficl-set-current
+ ( wid -- old-wid )</tt></dt>
+ <dd>Set wid as compile wordlist, leaving the previous
+ compile wordlist on the stack</dd>
+ <dt><a name="ficlvocabulary"></a><tt>ficl-vocabulary
+ ( nBins "name" -- )</tt></dt>
+ <dd>Creates a <tt>ficl-wordlist</tt> with the
+ specified number of hash table bins, binds it to
+ the name, and associates the semantics of <tt>vocabulary</tt>
+ with it (replaces the top wid in the search order
+ list with its own wid when executed)</dd>
+ <dt><a name="ficlwordlist"></a><tt>ficl-wordlist
+ ( nBins -- wid )</tt></dt>
+ <dd>Creates a wordlist with the specified number of
+ hash table bins, and leaves the address of the
+ wordlist on the stack. A <tt>ficl-wordlist</tt>
+ behaves exactly as a regular wordlist, but it may
+ search faster depending on the number of bins
+ chosen and the number of words it contains at
+ search time. As implemented in ficl, a <tt>wordlist</tt>
+ is single threaded by default. </dd>
+ <dt><a name="ficlforgetwid"></a><tt>forget-wid
+ ( wid -- )</tt></dt>
+ <dd>Iterates through the specified wordlist and
+ unlinks all definitions whose xt addresses are
+ greater than or equal to the value of <tt>HERE</tt>,
+ the dictionary fill pointer. </dd>
+ <dt><a name="ficlhide"></a><tt>hide ( --
+ current-wid-was )</tt></dt>
+ <dd>Push the <tt>hidden</tt> wordlist onto the search
+ order, and set it as the current compile wordlist
+ (unsing <tt>ficl-set-current</tt>). Leaves the
+ previous compile wordlist ID. I use this word to
+ hide implementation factor words that have low
+ reuse potential so that they don't clutter the
+ default wordlist. To undo the effect of hide,
+ execute <b><tt>previous set-current</tt></b></dd>
+ <dt><a name="ficlhidden"></a><tt>hidden (
+ -- wid )</tt></dt>
+ <dd>Wordlist for storing implementation factors of
+ ficl provided words. To see what's in there,
+ try: <b><tt>hide words previous set-current</tt></b></dd>
+ <dt><tt>wid-set-super ( wid -- )</tt></dt>
+ <dd>Ficl wordlists have a parent wordlist pointer
+ that is not specified in standard Forth. Ficl
+ initializes this pointer to NULL whenever it
+ creates a wordlist, so it ordinarily has no
+ effect. This word sets the parent pointer to the
+ wordlist specified on the top of the stack.
+ Ficl's implementation of <tt>SEARCH-WORDLIST</tt>
+ will chain backward through the parent link of
+ the wordlist when searching. This simplifies
+ Ficl's object model in that the search order does
+ not need to reflect an object's class hierarchy
+ when searching for a method. It is possible to
+ implement Ficl object syntax in strict ANS Forth,
+ but method finders need to manipulate the search
+ order explicitly.</dd>
+ </dl>
+ <h3>User variables</h3>
+ <dl>
+ <dt><tt>user ( -- ) name</tt></dt>
+ <dd>Create a user variable with the given name. User
+ variables are virtual machine local. Each VM
+ allocates a fixed amount of storage for them. You
+ can change the maximum number of user variables
+ allowed by defining FICL_USER_CELLS on your
+ compiiler's command line. Default is 16 user
+ cells.</dd>
+ </dl>
+ <h3>Miscellaneous</h3>
+ <dl>
+ <dt><tt>-roll ( xu xu-1 ... x0 u -- x0
+ xu-1 ... x1 ) </tt></dt>
+ <dd>Rotate u+1 items on top of the stack after
+ removing u. Rotation is in the opposite sense to <tt>ROLL</tt></dd>
+ </dl>
+ <dl>
+ <dt><a name="minusrot"></a><tt>-rot ( a b
+ c -- c a b )</tt></dt>
+ <dd>Rotate the top three stack entries, moving the
+ top of stack to third place. I like to think of
+ this as <tt>1</tt><sup><tt>1</tt></sup><tt>/</tt><sub><tt>2</tt></sub><tt>swap</tt>
+ because it's good for tucking a single cell value
+ behind a cell-pair (like an object). </dd>
+ </dl>
+ <dl>
+ <dt><tt>.env ( -- )</tt></dt>
+ <dd>List all environment variables of the system</dd>
+ <dt><tt>.hash ( -- )</tt></dt>
+ <dd>List hash table performance statistics of the
+ wordlist that's first in the search order</dd>
+ <dt><tt>.ver ( -- )</tt></dt>
+ <dd>Display ficl version ID</dd>
+ <dt><tt>>name ( xt -- c-addr u )</tt></dt>
+ <dd>Convert a word's execution token into the address
+ and length of its name</dd>
+ <dt><tt>body> ( a-addr -- xt )</tt></dt>
+ <dd>Reverses the effect of <tt>CORE</tt> word <tt>>body
+ </tt>(converts a parameter field address to an
+ execution token)</dd>
+ <dt><tt>compile-only</tt></dt>
+ <dd>Mark the most recently defined word as being
+ executable only while in compile state. Many <tt>immediate</tt>
+ words have this property.</dd>
+ <dt><tt>empty ( -- )</tt> </dt>
+ <dd>Empty the parameter stack</dd>
+ <dt><tt>endif</tt></dt>
+ <dd>Synonym for <tt>THEN</tt></dd>
+ <dt><tt>parse-word ( <spaces>name
+ -- c-addr u )</tt></dt>
+ <dd>Skip leading spaces and parse name delimited by a
+ space. c-addr is the address within the input
+ buffer and u is the length of the selected
+ string. If the parse area is empty, the resulting
+ string has a zero length. (From the Standard)</dd>
+ <dt><tt>w@ ( addr -- x )</tt></dt>
+ <dd>Fetch a 16 bit quantity from the specified
+ address</dd>
+ <dt><tt>w! ( x addr -- )</tt></dt>
+ <dd>Store a 16 bit quantity to the specified address
+ (the low 16 bits of the given value)</dd>
+ <dt><tt>x. ( x -- )</tt></dt>
+ <dd>Pop and display the value in hex format,
+ regardless of the current value of <tt>BASE</tt></dd>
+ </dl>
+ <h3>FiclWin Extras (defined in testmain.c)</h3>
+ <dl>
+ <dt><tt>break ( -- )</tt></dt>
+ <dd>Does nothing - just a handy place to set a
+ debugger breakpoint</dd>
+ <dt><tt>cd (
+ "directory-name<newline>" -- )</tt></dt>
+ <dd>Executes the Win32 chdir() function, changing the
+ program's logged directory.</dd>
+ <dt><a name="clock"></a><tt>clock ( --
+ now )</tt></dt>
+ <dd>Wrapper for the ANSI C clock() function. Returns
+ the number of clock ticks elapsed since process
+ start.</dd>
+ <dt><a name="clockspersec"></a><tt>clocks/sec
+ ( -- clocks_per_sec )</tt></dt>
+ <dd>Pushes the number of ticks in a second as
+ returned by <tt>clock</tt></dd>
+ <dt><a name="ficlload"></a><tt>load
+ ( "filename<newline>" -- )</tt></dt>
+ <dd>Opens the Forth source file specified and loads
+ it one line at a time, like <tt>INCLUDED (FILE)</tt></dd>
+ <dt><tt>pwd ( -- )</tt></dt>
+ <dd>Prints the current working directory as set by <tt>cd</tt></dd>
+ <dt><tt>system (
+ "command<newline>" -- )</tt></dt>
+ <dd>Issues a command to a shell; implemented with the
+ Win32 system() call.</dd>
+ <dt><tt>spewhash (
+ "filename<newline>" -- )</tt></dt>
+ <dd>Dumps all threads of the current compilation
+ wordlist to the specified text file. This was
+ useful when I thought there might be some point
+ in attempting to optimize the hash function. I no
+ longer harbor those illusions.</dd>
+ <dd><h3>FiclWin Exclusives (no source provided)</h3>
+ </dd>
+ <dt><tt>!oreg ( c -- )</tt></dt>
+ <dd>Set the value of the simulated LED register as
+ specified (0..255)</dd>
+ <dt><tt>@ireg ( -- c )</tt></dt>
+ <dd>Gets the value of the simulated switch block
+ (0..255)</dd>
+ <dt><tt>!dac ( c -- )</tt></dt>
+ <dd>Sets the value of the bargraph control as
+ specified. Valid values range from 0..255</dd>
+ <dt><tt>@adc ( -- c )</tt></dt>
+ <dd>Fetches the current position of the slider
+ control. Range is 0..255</dd>
+ <dt><tt>status" (
+ "ccc<quote>" -- )</tt></dt>
+ <dd>Set the mainframe window's status line to the
+ text specified, up to the first trailing quote
+ character.</dd>
+ <dt><a name="ficlms"></a><a
+ href="http://www.taygeta.com/forth/dpans10.htm#10.6.2.1905"><tt>ms</tt></a><tt>
+ ( u -- )</tt></dt>
+ <dd>Causes the running virtual machine to sleep() for
+ the number of milliseconds specified by the
+ top-of-stack value.</dd>
+ </dl>
+ </td>
+ </tr>
</table>
-<h2>
+<hr>
-<hr WIDTH="100%"><a NAME="ansinfo"></a>ANS Required Information</h2>
+<p><a name="ansinfo"></a></p>
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td><b>ANS Forth System</b>
-<br><b>Providing names from the Core Extensions word set </b>
-<br><b>Providing the Exception word set</b>
-<br><b>Providing names from the Exception Extensions word set</b>
-<br><b>Providing the Locals word set </b>
-<br><b>Providing the Locals Extensions word set </b>
-<br><b>Providing the Memory Allocation word set</b>
-<br><b>Providing the Programming-Tools word set</b>
-<br><b>Providing names from the Programming-Tools Extensions word set</b>
-<br><b>Providing the Search-Order word set</b>
-<br><b>Providing the Search-Order Extensions word set</b>
-<h3>
-Implementation-defined Options</h3>
-The implementation-defined items in the following list represent characteristics
-and choices left to the discretion of the implementor, provided that the
-requirements of the Standard are met. A system shall document the values
-for, or behaviors of, each item.
-<ul>
-<li>
-<b>aligned address requirements (3.1.3.3 Addresses);</b> </li>
+<p>ANS Required Information </p>
-<br><font color="#000000">System dependent. You can change the default
-address alignment by defining FICL_ALIGN on your compiler's command line.
-The default value is set to 2 in sysdep.h. This causes dictionary entries
-and <tt>ALIGN</tt> and <tt>ALIGNED</tt> to align on 4 byte boundaries.
-To align on <b>2<sup><font face="">n</font></sup></b> byte boundaries,
-set FICL_ALIGN to <b>n</b>. </font>
-<li>
-<b>behavior of 6.1.1320 EMIT for non-graphic characters</b>; </li>
-
-<br><font color="#000000">Depends on target system, C runtime library,
-and your implementation of ficlTextOut().</font>
-<li>
-<b>character editing of 6.1.0695 ACCEPT and 6.2.1390 EXPECT</b>; </li>
-
-<br><font color="#000000">None implemented in the versions supplied in
-words.c. Because ficlExec() is supplied a text buffer externally, it's
-up to your system to define how that buffer will be obtained.</font>
-<li>
-<b>character set (3.1.2 Character types, 6.1.1320 EMIT, 6.1.1750 KEY)</b>; </li>
-
-<br><font color="#000000">Depends on target system and implementation of
-ficlTextOut()</font>
-<li>
-<b>character-aligned address requirements (3.1.3.3 Addresses)</b>; </li>
-
-<br><font color="#000000">Ficl characters are one byte each. There are
-no alignment requirements.</font>
-<li>
-<b>character-set-extensions matching characteristics (3.4.2 Finding definition
-n<font color="#000000">ames)</font></b><font color="#000000">; </font></li>
-
-<br><font color="#000000">No special processing is performed on characters
-beyond case-folding. Therefore, extended characters will not match their
-unaccented counterparts.</font>
-<li>
-<b>conditions under which control characters match a space delimiter (3.4.1.1
-Delimiters)</b>;<font color="#FF6666"> </font></li>
-
-<br><font color="#000000">Ficl uses the Standard C function isspace() to
-distinguish space characters. The rest is up to your library vendor.</font>
-<li>
-<b>format of the control-flow stack (3.2.3.2 Control-flow stack)</b>; </li>
-
-<br><font color="#000000">Uses the data stack</font>
-<li>
-<b>conversion of digits larger than thirty-five (3.2.1.2 Digit conversion)</b>; </li>
-
-<br><font color="#000000">The maximum supported value of <tt>BASE</tt>
-is 36. Ficl will assertion fail in function ltoa of vm.c if the base is
-found to be larger than 36 or smaller than 2. There will be no effect if
-NDEBUG is defined</font>, however, other than possibly unexpected behavior.
-<li>
-<b>display after input terminates in 6.1.0695 ACCEPT and 6.2.1390 EXPECT</b>; </li>
-
-<br><font color="#000000">Target system dependent</font>
-<li>
-<b>exception abort sequence (as in 6.1.0680 ABORT")</b>; </li>
-
-<br><font color="#000000">Does <tt>ABORT</tt></font>
-<li>
-<b>input line terminator (3.2.4.1 User input device)</b>;<font color="#FF0000"> </font></li>
-
-<br><font color="#000000">Target system dependent (implementation of outer
-loop that calls ficlExec)</font>
-<li>
-<b>maximum size of a counted string, in characters (3.1.3.4 Counted strings,
-6.1.2450 WORD)</b>; </li>
-
-<br><font color="#000000">255</font>
-<li>
-<b>maximum size of a parsed string (3.4.1 Parsing)</b>; </li>
-
-<br>Limited by available memory and the maximum unsigned value that can
-fit in a CELL (2<sup>32</sup>-1).
-<li>
-<b>maximum size of a definition name, in characters (3.3.1.2 Definition
-names)</b>; </li>
-
-<br><font color="#000000">Ficl stores the first 31 characters of a definition
-name.</font>
-<li>
-<b>maximum string length for 6.1.1345 ENVIRONMENT?, in characters</b>; </li>
-
-<br><font color="#000000">Same as maximum definition name length</font>
-<li>
-<b>method of selecting 3.2.4.1 User input device</b>; </li>
-
-<br>None supported. This is up to the target system
-<li>
-<b>method of selecting 3.2.4.2 User output device</b>; </li>
-
-<br>None supported. This is up to the target system
-<li>
-<b>methods of dictionary compilation (3.3 The Forth dictionary)</b>; </li>
-
-<li>
-<b>number of bits in one address unit (3.1.3.3 Addresses)</b>; </li>
-
-<br><font color="#000000">Target system dependent. Ficl generally supports
-processors that can address 8 bit quantities, but there is no dependency
-that I'm aware of.</font>
-<li>
-<b>number representation and arithmetic (3.2.1.1 Internal number representation)</b>; </li>
-
-<br>System dependent. Ficl represents a CELL internally as a union that
-can hold INT32 (a signed 32 bit scalar value), UNS32 (32 bits unsigned),
-and an untyped pointer. No specific byte ordering is assumed.
-<li>
-<b>ranges for n, +n, u, d, +d, and ud (3.1.3 Single-cell types, 3.1.4 Cell-pair
-types)</b>; </li>
-
-<br>Assuming a 32 bit implementation, range for signed single-cell values
-is -2<sup>31</sup>..2<sup>31</sup>-1. Range for unsigned single cell values
-is 0..2<sup>32</sup>-1. Range for signed double-cell values is -2<sup>63</sup>..2<sup>63</sup>-1.
-Range for unsigned single cell values is 0..2<sup>64</sup>-1.
-<li>
-<b>read-only data-space regions (3.3.3 Data space)</b>;</li>
-
-<br>None
-<li>
-<b>size of buffer at 6.1.2450 WORD (3.3.3.6 Other transient regions)</b>; </li>
-
-<br>Default is 255. Depends on the setting of nPAD in ficl.h.
-<li>
-<b>size of one cell in address units (3.1.3 Single-cell types)</b>; </li>
-
-<br><font color="#000000">System dependent, generally four.</font>
-<li>
-<b>size of one character in address units (3.1.2 Character types)</b>; </li>
-
-<br><font color="#000000">System dependent, generally one.</font>
-<li>
-<b>size of the keyboard terminal input buffer (3.3.3.5 Input buffers)</b>; </li>
-
-<br><font color="#000000">This buffer is supplied by the host program.
-Ficl imposes no practical limit.</font>
-<li>
-<b>size of the pictured numeric output string buffer (3.3.3.6 Other transient
-regions)</b>; </li>
-
-<br>Default is 255 characters. Depends on the setting of nPAD in ficl.h.
-<li>
-<b>size of the scratch area whose address is returned by 6.2.2000 PAD (3.3.3.6
-Other transient regions)</b>; </li>
-
-<br>Not presently supported
-<li>
-<b>system case-sensitivity characteristics (3.4.2 Finding definition names)</b>; </li>
-
-<br><font color="#000000">Ficl is not case sensitive</font>
-<li>
-<b>system prompt (3.4 The Forth text interpreter, 6.1.2050 QUIT)</b>; </li>
-
-<br><font color="#000000">"ok>"</font>
-<li>
-<b>type of division rounding (3.2.2.1 Integer division, 6.1.0100 */, 6.1.0110
-*/MOD, 6.1.0230 /, 6.1.0240 /MOD, 6.1.1890 MOD)</b>; </li>
-
-<br><font color="#000000">Symmetric</font>
-<li>
-<b>values of 6.1.2250 STATE when true</b>; </li>
-
-<br><font color="#000000">One (no others)</font>
-<li>
-<b>values returned after arithmetic overflow (3.2.2.2 Other integer operations)</b>; </li>
-
-<br>System dependent. Ficl makes no special checks for overflow.
-<li>
-<b>whether the current definition can be found after 6.1.1250 DOES> (6.1.0450
-:)</b>. </li>
-
-<br><font color="#000000">No. Definitions are unsmudged after ; only, and
-only then if no control structure matching problems have been detected.</font></ul>
-
-<h3>
-Ambiguous Conditions</h3>
-A system shall document the system action taken upon each of the general
-or specific ambiguous conditions identified in this Standard. See 3.4.4
-Possible actions on an ambiguous condition.
-<p>The following general ambiguous conditions could occur because of a
-combination of factors:
-<ul>
-<dl>
-<li>
-<b>a name is neither a valid definition name nor a valid number during
-text interpretation (3.4 The Forth text interpreter)</b>; </li>
-
-<br><font color="#000000">Ficl does <tt>ABORT</tt> and prints the name
-followed by " not found".</font>
-<li>
-<b>a definition name exceeded the maximum length allowed (3.3.1.2 Definition
-names)</b>; </li>
-
-<br><font color="#000000">Ficl stores the first 31 characters of the definition
-name, and uses all characters of the name in computing its hash code. The
-actual length of the name, up to 255 characters, is stored in the definition's
-length field.</font>
-<li>
-<b>addressing a region not listed in 3.3.3 Data Space</b>; </li>
-
-<br><font color="#000000">No problem: all addresses in ficl are absolute.
-You can reach any 32 bit address in Ficl's address space.</font>
-<li>
-<b>argument type incompatible with specified input parameter, e.g., passing
-a flag to a word expecting an n (3.1 Data types)</b>; </li>
-
-<br><font color="#000000">Ficl makes no check for argument type compatibility.
-Effects of a mismatch vary widely depending on the specific problem and
-operands.</font></dl>
-
-<li>
-<b>attempting to obtain the execution token, (e.g., with 6.1.0070 ', 6.1.1550
-FIND, etc.) of a definition with undefined interpretation semantics</b>; </li>
-
-<br><font color="#000000">Ficl returns a valid token, but the result of
-executing that token while interpreting may be undesirable.</font>
-<li>
-<b>dividing by zero (6.1.0100 */, 6.1.0110 */MOD, 6.1.0230 /, 6.1.0240
-/MOD, 6.1.1561 FM/MOD, 6.1.1890 MOD, 6.1.2214 SM/REM, 6.1.2370 UM/MOD,
-8.6.1.1820 M*/)</b>;</li>
-
-<br><font color="#000000">Results are target procesor dependent. Generally,
-Ficl makes no check for divide-by-zero. The target processor will probably
-throw an exception.</font>
-<li>
-<b>insufficient data-stack space or return-stack space (stack overflow)</b>; </li>
-
-<br><font color="#000000">With FICL_ROBUST (sysdep.h) set >= 2, most parameter
-stack operations are checked for underflow and overflow. Ficl does not
-check the return stack.</font>
-<li>
-<b>insufficient space for loop-control parameters</b>; </li>
-
-<br><font color="#000000">No check - Evil results.</font>
-<li>
-<b>insufficient space in the dictionary</b>; </li>
-
-<br><font color="#000000">Ficl generates an error message if the dictionary
-is too full to create a definition header. It checks <tt>ALLOT</tt> as
-well, but it is possible to make an unchecked allocation request that overflows
-the dictionary.</font>
-<li>
-<b>interpreting a word with undefined interpretation semantics</b>; </li>
-
-<br><font color="#000000">Ficl protects all ANS Forth words with undefined
-interpretation semantics from being executed while in interpret state.
-It is possible to defeat this protection using ' (tick) and <tt>EXECUTE</tt>,
-though.</font>
-<li>
-<b>modifying the contents of the input buffer or a string literal (3.3.3.4
-Text-literal regions, 3.3.3.5 Input buffers)</b>; </li>
-
-<br><font color="#000000">Varies depending on the nature of the buffer.
-The input buffer is supplied by ficl's host function, and may reside in
-read-only memory. If so, writing the input buffer can ganerate an exception.
-String literals are stored in the dictionary, and are writable.</font>
-<li>
-<b>overflow of a pictured numeric output string</b>;</li>
-
-<br>In the unlikely event you are able to construct a pictured numeric
-string of more than 255 characters, the system will be corrupted unpredictably.
-The buffer area that holds pictured numeric output is at the end of the
-virtual machine. Whatever is mapped after the offending VM in memory will
-be trashed, along with the heap structures that contain it.
-<li>
-<b>parsed string overflow</b>;</li>
-
-<br>Ficl does not copy parsed strings unless asked to. Ordinarily, a string
-parsed from the input buffer during normal interpretation is left in-place,
-so there is no possibility of overflow. If you ask to parse a string into
-the dictionary, as in <tt>SLITERAL</tt>, you need to have enough room for
-the string, otherwise bad things may happen. This is not usually a problem.
-<li>
-<b>producing a result out of range, e.g., multiplication (using *) results
-in a value too big to be represented by a single-cell integer (6.1.0090
-*, 6.1.0100 */, 6.1.0110 */MOD, 6.1.0570 >NUMBER, 6.1.1561 FM/MOD, 6.1.2214
-SM/REM, 6.1.2370 UM/MOD, 6.2.0970 CONVERT, 8.6.1.1820 M*/)</b>; </li>
-
-<br><font color="#000000">Value will be truncated</font>
-<li>
-<b>reading from an empty data stack or return stack (stack underflow)</b>; </li>
-
-<br><font color="#000000">Most stack underflows are detected and prevented
-if FICL_ROBUST (sysdep.h) is set to 2 or greater. Otherwise, the stack
-pointer and size are likely to be trashed.</font>
-<li>
-<b>unexpected end of input buffer, resulting in an attempt to use a zero-length
-string as a name</b>; </li>
-
-<br><font color="#000000">Ficl returns for a new input buffer until a non-empty
-one is supplied.</font></ul>
-The following specific ambiguous conditions are noted in the glossary entries
-of the relevant words:
-<ul>
-<li>
-<b>>IN greater than size of input buffer (3.4.1 Parsing)</b></li>
-
-<br>Bad Things occur - unpredictable bacause the input buffer is supplied
-by the host program's outer loop.
-<li>
-<b>6.1.2120 RECURSE appears after 6.1.1250 DOES></b></li>
-
-<br>It finds the address of the definition before <tt>DOES></tt>
-<li>
-<b>argument input source different than current input source for 6.2.2148
-RESTORE-INPUT</b></li>
-
-<br>Not implemented
-<li>
-<b>data space containing definitions is de-allocated (3.3.3.2 Contiguous
-regions)</b></li>
-
-<br>This is OK until the cells are overwritten with something else. The
-dictionary maintains a hash table, and the table must be updated in order
-to de-allocate words without corruption.
-<li>
-<b>data space read/write with incorrect alignment (3.3.3.1 Address alignment)</b></li>
-
-<br>Target processor dependent. Consequences include: none (Intel), address
-error exception (68K).
-<li>
-<b>data-space pointer not properly aligned (6.1.0150 ,, 6.1.0860 C,)</b></li>
-
-<br>See above on data space read/write alignment
-<li>
-<b>less than u+2 stack items (6.2.2030 PICK, 6.2.2150 ROLL)</b></li>
-
-<br>Ficl detects a stack underflow and reports it, executing <tt>ABORT,</tt>
-as long as FICL_ROBUST is two or larger.
-<li>
-<b>loop-control parameters not available ( 6.1.0140 +LOOP, 6.1.1680 I,
-6.1.1730 J, 6.1.1760 LEAVE, 6.1.1800 LOOP, 6.1.2380 UNLOOP)</b></li>
-
-<br>Loop initiation words are responsible for checking the stack and guaranteeing
-that the control parameters are pushed. Any underflows will be detected
-early if FICL_ROBUST is set to two or greater. Note however that Ficl only
-checks for return stack underflows at the end of each line of text.
-<li>
-<b>most recent definition does not have a name (6.1.1710 IMMEDIATE)</b></li>
-
-<br>No problem.
-<li>
-<b>name not defined by 6.2.2405 VALUE used by 6.2.2295 TO</b></li>
-
-<br>Ficl's version of <tt>TO</tt> works correctly with <tt>VALUE</tt>s,
-<tt>CONSTANT</tt>s
-and <tt>VARIABLE</tt>s.
-<li>
-<b>name not found (6.1.0070 ', 6.1.2033 POSTPONE, 6.1.2510 ['], 6.2.2530
-[COMPILE])</b></li>
-
-<br>Ficl prints an error message and does <tt>ABORT</tt>
-<li>
-<b>parameters are not of the same type (6.1.1240 DO, 6.2.0620 ?DO, 6.2.2440
-WITHIN)</b></li>
-
-<br>No check. Results vary depending on the specific problem.
-<li>
-<b>6.1.2033 POSTPONE or 6.2.2530 [COMPILE] applied to 6.2.2295 TO</b></li>
-
-<br>The word is postponed correctly.
-<li>
-<b>string longer than a counted string returned by 6.1.2450 WORD</b></li>
-
-<br>Ficl stores the first FICL_STRING_MAX-1 chars in the destination buffer.
-(The extra character is the trailing space required by the standard. Yuck.)
-<li>
-<b>u greater than or equal to the number of bits in a cell (6.1.1805 LSHIFT,
-6.1.2162 RSHIFT)</b></li>
-
-<br>Depends on target process or and C runtime library implementations
-of the << and >> operators on unsigned values. For I386, the processor
-appears to shift modulo the number of bits in a cell.
-<li>
-<b>word not defined via 6.1.1000 CREATE (6.1.0550 >BODY, 6.1.1250 DOES>)</b></li>
-
-<br><b>words improperly used outside 6.1.0490 <# and 6.1.0040 #> (6.1.0030
-#, 6.1.0050 #S, 6.1.1670 HOLD, 6.1.2210 SIGN)</b>
-<br>Don't. <tt>CREATE</tt> reserves a field in words it builds for <tt>DOES></tt>to
-fill in. If you use <tt>DOES></tt> on a word not made by <tt>CREATE</tt>,
-it will overwrite the first cell of its parameter area. That's probably
-not what you want. Likewise, pictured numeric words assume that there is
-a string under construction in the VM's scratch buffer. If that's not the
-case, results may be unpleasant.</ul>
-
-<h3>
-Locals Implementation-defined options</h3>
-
-<ul>
-<li>
-<b>maximum number of locals in a definition (13.3.3 Processing locals,
-13.6.2.1795 LOCALS|)</b></li>
-
-<br>Default is 16. Change by redefining FICL_MAX_LOCALS, defined in sysdep.h</ul>
-
-<h3>
-Locals Ambiguous conditions</h3>
-
-<ul>
-<li>
-<b>executing a named local while in interpretation state (13.6.1.0086 (LOCAL))</b></li>
-
-<br>Locals can be found in interpretation state while in the context of
-a definition under construction. Under these circumstances, locals behave
-correctly. Locals are not visible at all outside the scope of a definition.
-<li>
-<b>name not defined by VALUE or LOCAL (13.6.1.2295 TO)</b></li>
-
-<br>See the CORE ambiguous conditions, above (no change)</ul>
-
-<h3>
-Programming Tools Implementation-defined options</h3>
-
-<ul>
-<li>
-<b>source and format of display by 15.6.1.2194 SEE</b></li>
-
-<br>SEE de-compiles definitions from the dictionary. Because Ficl words
-are threaded by their header addresses, it is very straightforward to print
-the name and other characteristics of words in a definition. Primitives
-are so noted. Colon definitions are decompiled, but branch target labels
-are not reconstructed. Literals and string literals are so noted, and their
-contents displayed.</ul>
-
-<h3>
-Search Order Implementation-defined options</h3>
-
-<ul>
-<li>
-<b>maximum number of word lists in the search order (16.3.3 Finding definition
-names, 16.6.1.2197 SET-ORDER)</b> </li>
-
-<br>Defaults to 16. Can be changed by redefining FICL_DEFAULT_VOCS, declared
-in sysdep.h
-<li>
-<b>minimum search order (16.6.1.2197 SET-ORDER, 16.6.2.1965 ONLY)</b> </li>
-
-<br>Equivalent to <tt>FORTH-WORDLIST 1 SET-ORDER</tt></ul>
-
-<h3>
-Search Order Ambiguous conditions</h3>
-
-<ul>
-<li>
-<b>changing the compilation word list (16.3.3 Finding definition names)</b></li>
-
-<br>Ficl stores a link to the current definition independently of the compile
-wordlist while it is being defined, and links it into the compile wordlist
-only after the definition completes successfully. Changing the compile
-wordlist mid-definition will cause the definition to link into the <i>new</i>
-compile wordlist.
-<li>
-<b>search order empty (16.6.2.2037 PREVIOUS)</b></li>
-
-<br>Ficl prints an error message if the search order underflows, and resets
-the order to its default state.
-<li>
-<b>too many word lists in search order (16.6.2.0715 ALSO)</b></li>
-
-<br>Ficl prints an error message if the search order overflows, and resets
-the order to its default state.</ul>
- </td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><b>ANS Forth System</b> <br>
+ <b>Providing names from the Core Extensions word
+ set </b> <br>
+ <b>Providing the Exception word set</b> <br>
+ <b>Providing names from the Exception Extensions word set</b>
+ <br>
+ <b>Providing the Locals word set </b> <br>
+ <b>Providing the Locals Extensions word set </b> <br>
+ <b>Providing the Memory Allocation word set</b> <br>
+ <b>Providing the Programming-Tools word set</b> <br>
+ <b>Providing names from the Programming-Tools Extensions
+ word set</b> <br>
+ <b>Providing the Search-Order word set</b> <br>
+ <b>Providing the Search-Order Extensions word set</b> <h3>Implementation-defined
+ Options</h3>
+ <p>The implementation-defined items in the following list
+ represent characteristics and choices left to the
+ discretion of the implementor, provided that the
+ requirements of the Standard are met. A system shall
+ document the values for, or behaviors of, each
+ item. </p>
+ <ul>
+ <li><b>aligned address requirements (3.1.3.3
+ Addresses);</b> </li>
+ <li><br>
+ <font color="#000000">System dependent. You can
+ change the default address alignment by defining
+ FICL_ALIGN on your compiler's command line. The
+ default value is set to 2 in sysdep.h. This
+ causes dictionary entries and <tt>ALIGN</tt> and <tt>ALIGNED</tt>
+ to align on 4 byte boundaries. To align on <b>2</b><sup><b>n</b></sup>
+ byte boundaries, set FICL_ALIGN to <b>n</b>. </font>
+ </li>
+ <li><b>behavior of 6.1.1320 EMIT for non-graphic
+ characters</b>; </li>
+ <li><br>
+ <font color="#000000">Depends on target system, C
+ runtime library, and your implementation of
+ ficlTextOut().</font> </li>
+ <li><b>character editing of 6.1.0695 ACCEPT and
+ 6.2.1390 EXPECT</b>; </li>
+ <li><br>
+ <font color="#000000">None implemented in the
+ versions supplied in words.c. Because ficlExec()
+ is supplied a text buffer externally, it's up to
+ your system to define how that buffer will be
+ obtained.</font> </li>
+ <li><b>character set (3.1.2 Character types, 6.1.1320
+ EMIT, 6.1.1750 KEY)</b>; </li>
+ <li><br>
+ <font color="#000000">Depends on target system
+ and implementation of ficlTextOut()</font> </li>
+ <li><b>character-aligned address requirements
+ (3.1.3.3 Addresses)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl characters are one
+ byte each. There are no alignment requirements.</font>
+ </li>
+ <li><b>character-set-extensions matching
+ characteristics (3.4.2 Finding definition n</b><font
+ color="#000000"><b>ames)</b>; </font></li>
+ <li><br>
+ <font color="#000000">No special processing is
+ performed on characters beyond case-folding.
+ Therefore, extended characters will not match
+ their unaccented counterparts.</font> </li>
+ <li><b>conditions under which control characters
+ match a space delimiter (3.4.1.1 Delimiters)</b>;<font
+ color="#FF6666"> </font></li>
+ <li><br>
+ <font color="#000000">Ficl uses the Standard C
+ function isspace() to distinguish space
+ characters. The rest is up to your library
+ vendor.</font> </li>
+ <li><b>format of the control-flow stack (3.2.3.2
+ Control-flow stack)</b>; </li>
+ <li><br>
+ <font color="#000000">Uses the data stack</font> </li>
+ <li><b>conversion of digits larger than thirty-five
+ (3.2.1.2 Digit conversion)</b>; </li>
+ <li><br>
+ <font color="#000000">The maximum supported value
+ of <tt>BASE</tt> is 36. Ficl will assertion fail
+ in function ltoa of vm.c if the base is found to
+ be larger than 36 or smaller than 2. There will
+ be no effect if NDEBUG is defined</font>,
+ however, other than possibly unexpected
+ behavior. </li>
+ <li><b>display after input terminates in 6.1.0695
+ ACCEPT and 6.2.1390 EXPECT</b>; </li>
+ <li><br>
+ <font color="#000000">Target system dependent</font>
+ </li>
+ <li><b>exception abort sequence (as in 6.1.0680
+ ABORT")</b>; </li>
+ <li><br>
+ <font color="#000000">Does <tt>ABORT</tt></font> </li>
+ <li><b>input line terminator (3.2.4.1 User input
+ device)</b>;<font color="#FF0000"> </font></li>
+ <li><br>
+ <font color="#000000">Target system dependent
+ (implementation of outer loop that calls
+ ficlExec)</font> </li>
+ <li><b>maximum size of a counted string, in
+ characters (3.1.3.4 Counted strings, 6.1.2450
+ WORD)</b>; </li>
+ <li><br>
+ <font color="#000000">255</font> </li>
+ <li><b>maximum size of a parsed string (3.4.1
+ Parsing)</b>; </li>
+ <li><br>
+ Limited by available memory and the maximum
+ unsigned value that can fit in a CELL (2<sup>32</sup>-1).
+ </li>
+ <li><b>maximum size of a definition name, in
+ characters (3.3.1.2 Definition names)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl stores the first 31
+ characters of a definition name.</font> </li>
+ <li><b>maximum string length for 6.1.1345
+ ENVIRONMENT?, in characters</b>; </li>
+ <li><br>
+ <font color="#000000">Same as maximum definition
+ name length</font> </li>
+ <li><b>method of selecting 3.2.4.1 User input device</b>; </li>
+ <li><br>
+ None supported. This is up to the target
+ system </li>
+ <li><b>method of selecting 3.2.4.2 User output device</b>; </li>
+ <li><br>
+ None supported. This is up to the target
+ system </li>
+ <li><b>methods of dictionary compilation (3.3 The
+ Forth dictionary)</b>; </li>
+ <li><b>number of bits in one address unit (3.1.3.3
+ Addresses)</b>; </li>
+ <li><br>
+ <font color="#000000">Target system dependent.
+ Ficl generally supports processors that can
+ address 8 bit quantities, but there is no
+ dependency that I'm aware of.</font> </li>
+ <li><b>number representation and arithmetic (3.2.1.1
+ Internal number representation)</b>; </li>
+ <li><br>
+ System dependent. Ficl represents a CELL
+ internally as a union that can hold INT32 (a
+ signed 32 bit scalar value), UNS32 (32 bits
+ unsigned), and an untyped pointer. No specific
+ byte ordering is assumed. </li>
+ <li><b>ranges for n, +n, u, d, +d, and ud (3.1.3
+ Single-cell types, 3.1.4 Cell-pair types)</b>; </li>
+ <li><br>
+ Assuming a 32 bit implementation, range for
+ signed single-cell values is -2<sup>31</sup>..2<sup>31</sup>-1.
+ Range for unsigned single cell values is 0..2<sup>32</sup>-1.
+ Range for signed double-cell values is -2<sup>63</sup>..2<sup>63</sup>-1.
+ Range for unsigned single cell values is 0..2<sup>64</sup>-1.
+ </li>
+ <li><b>read-only data-space regions (3.3.3 Data
+ space)</b>;</li>
+ <li><br>
+ None </li>
+ <li><b>size of buffer at 6.1.2450 WORD (3.3.3.6 Other
+ transient regions)</b>; </li>
+ <li><br>
+ Default is 255. Depends on the setting of nPAD in
+ ficl.h. </li>
+ <li><b>size of one cell in address units (3.1.3
+ Single-cell types)</b>; </li>
+ <li><br>
+ <font color="#000000">System dependent, generally
+ four.</font> </li>
+ <li><b>size of one character in address units (3.1.2
+ Character types)</b>; </li>
+ <li><br>
+ <font color="#000000">System dependent, generally
+ one.</font> </li>
+ <li><b>size of the keyboard terminal input buffer
+ (3.3.3.5 Input buffers)</b>; </li>
+ <li><br>
+ <font color="#000000">This buffer is supplied by
+ the host program. Ficl imposes no practical
+ limit.</font> </li>
+ <li><b>size of the pictured numeric output string
+ buffer (3.3.3.6 Other transient regions)</b>; </li>
+ <li><br>
+ Default is 255 characters. Depends on the setting
+ of nPAD in ficl.h. </li>
+ <li><b>size of the scratch area whose address is
+ returned by 6.2.2000 PAD (3.3.3.6 Other transient
+ regions)</b>; </li>
+ <li><br>
+ Not presently supported </li>
+ <li><b>system case-sensitivity characteristics (3.4.2
+ Finding definition names)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl is not case sensitive</font>
+ </li>
+ <li><b>system prompt (3.4 The Forth text interpreter,
+ 6.1.2050 QUIT)</b>; </li>
+ <li><br>
+ <font color="#000000">"ok>"</font> </li>
+ <li><b>type of division rounding (3.2.2.1 Integer
+ division, 6.1.0100 */, 6.1.0110 */MOD, 6.1.0230
+ /, 6.1.0240 /MOD, 6.1.1890 MOD)</b>; </li>
+ <li><br>
+ <font color="#000000">Symmetric</font> </li>
+ <li><b>values of 6.1.2250 STATE when true</b>; </li>
+ <li><br>
+ <font color="#000000">One (no others)</font> </li>
+ <li><b>values returned after arithmetic overflow
+ (3.2.2.2 Other integer operations)</b>; </li>
+ <li><br>
+ System dependent. Ficl makes no special checks
+ for overflow. </li>
+ <li><b>whether the current definition can be found
+ after 6.1.1250 DOES> (6.1.0450 :)</b>. </li>
+ <li><br>
+ <font color="#000000">No. Definitions are
+ unsmudged after ; only, and only then if no
+ control structure matching problems have been
+ detected.</font></li>
+ </ul>
+ <h3>Ambiguous Conditions</h3>
+ <p>A system shall document the system action taken upon
+ each of the general or specific ambiguous conditions
+ identified in this Standard. See 3.4.4 Possible actions
+ on an ambiguous condition. </p>
+ <p>The following general ambiguous conditions could occur
+ because of a combination of factors: </p>
+ <ul>
+ <li><dl>
+ </dl>
+ </li>
+ <li><b>a name is neither a valid definition name nor
+ a valid number during text interpretation (3.4
+ The Forth text interpreter)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl does <tt>ABORT</tt>
+ and prints the name followed by " not
+ found".</font> </li>
+ <li><b>a definition name exceeded the maximum length
+ allowed (3.3.1.2 Definition names)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl stores the first 31
+ characters of the definition name, and uses all
+ characters of the name in computing its hash
+ code. The actual length of the name, up to 255
+ characters, is stored in the definition's length
+ field.</font> </li>
+ <li><b>addressing a region not listed in 3.3.3 Data
+ Space</b>; </li>
+ <li><br>
+ <font color="#000000">No problem: all addresses
+ in ficl are absolute. You can reach any 32 bit
+ address in Ficl's address space.</font> </li>
+ <li><b>argument type incompatible with specified
+ input parameter, e.g., passing a flag to a word
+ expecting an n (3.1 Data types)</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl makes no check for
+ argument type compatibility. Effects of a
+ mismatch vary widely depending on the specific
+ problem and operands.</font> </li>
+ <li><b>attempting to obtain the execution token,
+ (e.g., with 6.1.0070 ', 6.1.1550 FIND, etc.) of a
+ definition with undefined interpretation
+ semantics</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl returns a valid token,
+ but the result of executing that token while
+ interpreting may be undesirable.</font> </li>
+ <li><b>dividing by zero (6.1.0100 */, 6.1.0110 */MOD,
+ 6.1.0230 /, 6.1.0240 /MOD, 6.1.1561 FM/MOD,
+ 6.1.1890 MOD, 6.1.2214 SM/REM, 6.1.2370 UM/MOD,
+ 8.6.1.1820 M*/)</b>;</li>
+ <li><br>
+ <font color="#000000">Results are target procesor
+ dependent. Generally, Ficl makes no check for
+ divide-by-zero. The target processor will
+ probably throw an exception.</font> </li>
+ <li><b>insufficient data-stack space or return-stack
+ space (stack overflow)</b>; </li>
+ <li><br>
+ <font color="#000000">With FICL_ROBUST (sysdep.h)
+ set >= 2, most parameter stack operations are
+ checked for underflow and overflow. Ficl does not
+ check the return stack.</font> </li>
+ <li><b>insufficient space for loop-control parameters</b>; </li>
+ <li><br>
+ <font color="#000000">No check - Evil results.</font>
+ </li>
+ <li><b>insufficient space in the dictionary</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl generates an error
+ message if the dictionary is too full to create a
+ definition header. It checks <tt>ALLOT</tt> as
+ well, but it is possible to make an unchecked
+ allocation request that overflows the dictionary.</font>
+ </li>
+ <li><b>interpreting a word with undefined
+ interpretation semantics</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl protects all ANS Forth
+ words with undefined interpretation semantics
+ from being executed while in interpret state. It
+ is possible to defeat this protection using '
+ (tick) and <tt>EXECUTE</tt>, though.</font> </li>
+ <li><b>modifying the contents of the input buffer or
+ a string literal (3.3.3.4 Text-literal regions,
+ 3.3.3.5 Input buffers)</b>; </li>
+ <li><br>
+ <font color="#000000">Varies depending on the
+ nature of the buffer. The input buffer is
+ supplied by ficl's host function, and may reside
+ in read-only memory. If so, writing the input
+ buffer can ganerate an exception. String literals
+ are stored in the dictionary, and are writable.</font>
+ </li>
+ <li><b>overflow of a pictured numeric output string</b>;</li>
+ <li><br>
+ In the unlikely event you are able to construct a
+ pictured numeric string of more than 255
+ characters, the system will be corrupted
+ unpredictably. The buffer area that holds
+ pictured numeric output is at the end of the
+ virtual machine. Whatever is mapped after the
+ offending VM in memory will be trashed, along
+ with the heap structures that contain it. </li>
+ <li><b>parsed string overflow</b>;</li>
+ <li><br>
+ Ficl does not copy parsed strings unless asked
+ to. Ordinarily, a string parsed from the input
+ buffer during normal interpretation is left
+ in-place, so there is no possibility of overflow.
+ If you ask to parse a string into the dictionary,
+ as in <tt>SLITERAL</tt>, you need to have enough
+ room for the string, otherwise bad things may
+ happen. This is not usually a problem. </li>
+ <li><b>producing a result out of range, e.g.,
+ multiplication (using *) results in a value too
+ big to be represented by a single-cell integer
+ (6.1.0090 *, 6.1.0100 */, 6.1.0110 */MOD,
+ 6.1.0570 >NUMBER, 6.1.1561 FM/MOD, 6.1.2214
+ SM/REM, 6.1.2370 UM/MOD, 6.2.0970 CONVERT,
+ 8.6.1.1820 M*/)</b>; </li>
+ <li><br>
+ <font color="#000000">Value will be truncated</font>
+ </li>
+ <li><b>reading from an empty data stack or return
+ stack (stack underflow)</b>; </li>
+ <li><br>
+ <font color="#000000">Most stack underflows are
+ detected and prevented if FICL_ROBUST (sysdep.h)
+ is set to 2 or greater. Otherwise, the stack
+ pointer and size are likely to be trashed.</font>
+ </li>
+ <li><b>unexpected end of input buffer, resulting in
+ an attempt to use a zero-length string as a name</b>; </li>
+ <li><br>
+ <font color="#000000">Ficl returns for a new
+ input buffer until a non-empty one is supplied.</font></li>
+ </ul>
+ <p>The following specific ambiguous conditions are noted
+ in the glossary entries of the relevant words: </p>
+ <ul>
+ <li><b>>IN greater than size of input buffer
+ (3.4.1 Parsing)</b></li>
+ <li><br>
+ Bad Things occur - unpredictable bacause the
+ input buffer is supplied by the host program's
+ outer loop. </li>
+ <li><b>6.1.2120 RECURSE appears after 6.1.1250
+ DOES></b></li>
+ <li><br>
+ It finds the address of the definition before <tt>DOES></tt>
+ </li>
+ <li><b>argument input source different than current
+ input source for 6.2.2148 RESTORE-INPUT</b></li>
+ <li><br>
+ Not implemented </li>
+ <li><b>data space containing definitions is
+ de-allocated (3.3.3.2 Contiguous regions)</b></li>
+ <li><br>
+ This is OK until the cells are overwritten with
+ something else. The dictionary maintains a hash
+ table, and the table must be updated in order to
+ de-allocate words without corruption. </li>
+ <li><b>data space read/write with incorrect alignment
+ (3.3.3.1 Address alignment)</b></li>
+ <li><br>
+ Target processor dependent. Consequences include:
+ none (Intel), address error exception
+ (68K). </li>
+ <li><b>data-space pointer not properly aligned
+ (6.1.0150 ,, 6.1.0860 C,)</b></li>
+ <li><br>
+ See above on data space read/write
+ alignment </li>
+ <li><b>less than u+2 stack items (6.2.2030 PICK,
+ 6.2.2150 ROLL)</b></li>
+ <li><br>
+ Ficl detects a stack underflow and reports it,
+ executing <tt>ABORT,</tt> as long as FICL_ROBUST
+ is two or larger. </li>
+ <li><b>loop-control parameters not available (
+ 6.1.0140 +LOOP, 6.1.1680 I, 6.1.1730 J, 6.1.1760
+ LEAVE, 6.1.1800 LOOP, 6.1.2380 UNLOOP)</b></li>
+ <li><br>
+ Loop initiation words are responsible for
+ checking the stack and guaranteeing that the
+ control parameters are pushed. Any underflows
+ will be detected early if FICL_ROBUST is set to
+ two or greater. Note however that Ficl only
+ checks for return stack underflows at the end of
+ each line of text. </li>
+ <li><b>most recent definition does not have a name
+ (6.1.1710 IMMEDIATE)</b></li>
+ <li><br>
+ No problem. </li>
+ <li><b>name not defined by 6.2.2405 VALUE used by
+ 6.2.2295 TO</b></li>
+ <li><br>
+ Ficl's version of <tt>TO</tt> works correctly
+ with <tt>VALUE</tt>s, <tt>CONSTANT</tt>s and <tt>VARIABLE</tt>s.
+ </li>
+ <li><b>name not found (6.1.0070 ', 6.1.2033 POSTPONE,
+ 6.1.2510 ['], 6.2.2530 [COMPILE])</b></li>
+ <li><br>
+ Ficl prints an error message and does <tt>ABORT</tt>
+ </li>
+ <li><b>parameters are not of the same type (6.1.1240
+ DO, 6.2.0620 ?DO, 6.2.2440 WITHIN)</b></li>
+ <li><br>
+ No check. Results vary depending on the specific
+ problem. </li>
+ <li><b>6.1.2033 POSTPONE or 6.2.2530 [COMPILE]
+ applied to 6.2.2295 TO</b></li>
+ <li><br>
+ The word is postponed correctly. </li>
+ <li><b>string longer than a counted string returned
+ by 6.1.2450 WORD</b></li>
+ <li><br>
+ Ficl stores the first FICL_STRING_MAX-1 chars in
+ the destination buffer. (The extra character is
+ the trailing space required by the standard.
+ Yuck.) </li>
+ <li><b>u greater than or equal to the number of bits
+ in a cell (6.1.1805 LSHIFT, 6.1.2162 RSHIFT)</b></li>
+ <li><br>
+ Depends on target process or and C runtime
+ library implementations of the << and
+ >> operators on unsigned values. For I386,
+ the processor appears to shift modulo the number
+ of bits in a cell. </li>
+ <li><b>word not defined via 6.1.1000 CREATE (6.1.0550
+ >BODY, 6.1.1250 DOES>)</b></li>
+ <li><br>
+ <b>words improperly used outside 6.1.0490 <#
+ and 6.1.0040 #> (6.1.0030 #, 6.1.0050 #S,
+ 6.1.1670 HOLD, 6.1.2210 SIGN)</b> <br>
+ Don't. <tt>CREATE</tt> reserves a field in words
+ it builds for <tt>DOES></tt>to fill in. If you
+ use <tt>DOES></tt> on a word not made by <tt>CREATE</tt>,
+ it will overwrite the first cell of its parameter
+ area. That's probably not what you want.
+ Likewise, pictured numeric words assume that
+ there is a string under construction in the VM's
+ scratch buffer. If that's not the case, results
+ may be unpleasant.</li>
+ </ul>
+ <h3>Locals Implementation-defined options</h3>
+ <ul>
+ <li><b>maximum number of locals in a definition
+ (13.3.3 Processing locals, 13.6.2.1795 LOCALS|)</b></li>
+ <li><br>
+ Default is 16. Change by redefining
+ FICL_MAX_LOCALS, defined in sysdep.h</li>
+ </ul>
+ <h3>Locals Ambiguous conditions</h3>
+ <ul>
+ <li><b>executing a named local while in
+ interpretation state (13.6.1.0086 (LOCAL))</b></li>
+ <li><br>
+ Locals can be found in interpretation state while
+ in the context of a definition under
+ construction. Under these circumstances, locals
+ behave correctly. Locals are not visible at all
+ outside the scope of a definition. </li>
+ <li><b>name not defined by VALUE or LOCAL
+ (13.6.1.2295 TO)</b></li>
+ <li><br>
+ See the CORE ambiguous conditions, above (no
+ change)</li>
+ </ul>
+ <h3>Programming Tools Implementation-defined options</h3>
+ <ul>
+ <li><b>source and format of display by 15.6.1.2194
+ SEE</b></li>
+ <li><br>
+ SEE de-compiles definitions from the dictionary.
+ Because Ficl words are threaded by their header
+ addresses, it is very straightforward to print
+ the name and other characteristics of words in a
+ definition. Primitives are so noted. Colon
+ definitions are decompiled, but branch target
+ labels are not reconstructed. Literals and string
+ literals are so noted, and their contents
+ displayed.</li>
+ </ul>
+ <h3>Search Order Implementation-defined options</h3>
+ <ul>
+ <li><b>maximum number of word lists in the search
+ order (16.3.3 Finding definition names,
+ 16.6.1.2197 SET-ORDER)</b> </li>
+ <li><br>
+ Defaults to 16. Can be changed by redefining
+ FICL_DEFAULT_VOCS, declared in sysdep.h </li>
+ <li><b>minimum search order (16.6.1.2197 SET-ORDER,
+ 16.6.2.1965 ONLY)</b> </li>
+ <li><br>
+ Equivalent to <tt>FORTH-WORDLIST 1 SET-ORDER</tt></li>
+ </ul>
+ <h3>Search Order Ambiguous conditions</h3>
+ <ul>
+ <li><b>changing the compilation word list (16.3.3
+ Finding definition names)</b></li>
+ <li><br>
+ Ficl stores a link to the current definition
+ independently of the compile wordlist while it is
+ being defined, and links it into the compile
+ wordlist only after the definition completes
+ successfully. Changing the compile wordlist
+ mid-definition will cause the definition to link
+ into the <i>new</i> compile wordlist. </li>
+ <li><b>search order empty (16.6.2.2037 PREVIOUS)</b></li>
+ <li><br>
+ Ficl prints an error message if the search order
+ underflows, and resets the order to its default
+ state. </li>
+ <li><b>too many word lists in search order
+ (16.6.2.0715 ALSO)</b></li>
+ <li><br>
+ Ficl prints an error message if the search order
+ overflows, and resets the order to its default
+ state.</li>
+ </ul>
+ </td>
+ </tr>
</table>
-<h2>
+<hr>
-<hr WIDTH="100%"><a NAME="links"></a>For more information</h2>
+<p><a name="links"></a></p>
-<ul>
-<li>
-<a href="http://www.taygeta.com/ficl.html">Web home of ficl</a></li>
+<p>For more information </p>
-<li>
-<b><a href="ftp://ftp.taygeta.com/pub/Forth/Compilers/native/misc/ficl203/ficl203.zip">Download
-ficl 2.03</a></b></li>
-
-<li>
-<a href="ficlddj.pdf">Manuscript of Ficl article for January 1999 Dr. Dobb's
-Journal</a></li>
-
-<li>
-<a href="jwsforml.pdf">1998 FORML Conference paper</a></li>
-
-<li>
-<a href="http://www.taygeta.com/forthlit.html">Forth literature</a></li>
-
<ul>
-<li>
-<a href="http://www.softsynth.com/pforth/pf_tut.htm">Phil Burk's Forth
-Tutorial</a></li>
-
-<li>
-<a href="http://www.taygeta.com/forth/dpans.html">Draft Proposed American
-National Standard for Forth</a></li>
+ <li><a href="http://www.taygeta.com/ficl.html">Web home of
+ ficl</a></li>
+ <li><a
+ href="ftp://ftp.taygeta.com/pub/Forth/Compilers/native/misc/ficl204/ficl204.zip"><b>Download
+ ficl 2.04</b></a></li>
+ <li><a
+ href="ftp://ftp.taygeta.com/pub/Forth/Compilers/native/misc/ficl204/ficlwin.zip"><b>Download
+ ficlWin</b></a><b> (not for resale. please contact me for
+ resale license arrangements)</b></li>
+ <li><a href="ficlddj.pdf">Manuscript of Ficl article for
+ January 1999 Dr. Dobb's Journal</a></li>
+ <li><a href="jwsforml.pdf">1998 FORML Conference paper</a></li>
+ <li><a href="http://www.taygeta.com/forthlit.html">Forth
+ literature</a></li>
+ <li><ul>
+ <li><a
+ href="http://www.softsynth.com/pforth/pf_tut.htm">Phil
+ Burk's Forth Tutorial</a></li>
+ <li><a href="http://www.taygeta.com/forth/dpans.html">Draft
+ Proposed American National Standard for Forth</a></li>
+ </ul>
+ </li>
+ <li><a href="http://www.forth.org">Forth Interest Group</a></li>
</ul>
-<li>
-<a href="http://www.forth.org">Forth Interest Group</a></li>
-</ul>
+<h2><a name="includesficl"></a>Some software that uses ficl</h2>
-<h2>
-<a NAME="includesficl"></a>Some software that uses ficl</h2>
-
<ul>
-<li>
-<a href="http://www.freebsd.org/">FreeBSD</a> boot loader</li>
-
-<li>
-<a href="http://www.pagesz.net/~sessoms/debuffer/">Palm Pilot Debuffer</a>
-(Eric Sessoms)</li>
-
-<li>
-<a href="http://www.swcp.com/~jchavez/osmond.html">Mac PC Board Layout
-tool</a> (J Chavez)</li>
-
-<li>
-<a href="http://www.netcomsystems.com">NetCom Systems</a> ML7710 (Martin
-Usher)</li>
+ <li><a href="http://www.freebsd.org/">FreeBSD</a> boot loader</li>
+ <li><a href="http://www.pagesz.net/~sessoms/debuffer/">Palm
+ Pilot Debuffer</a> (Eric Sessoms)</li>
+ <li><a href="http://www.swcp.com/~jchavez/osmond.html">Mac PC
+ Board Layout tool</a> (J Chavez)</li>
+ <li><a href="http://www.netcomsystems.com">NetCom Systems</a>
+ ML7710 (Martin Usher)</li>
</ul>
-<h2>
+<hr>
-<hr WIDTH="100%"></h2>
-
-<table BORDER=0 CELLSPACING=3 COLS=1 WIDTH="600" >
-<tr>
-<td>
-<h2>
-<a NAME="lawyerbait"></a>DISCLAIMER OF WARRANTY and LICENSE</h2>
-<i>Ficl is freeware. Use it in any way that you like, with the understanding
-that the code is not supported.</i>
-<p>Any third party may reproduce, distribute, or modify the ficl software
-code or any derivative works thereof without any compensation or license,
-provided that the original author information and this disclaimer text
-are retained in the source code files. The ficl software code is provided
-on an "as is" basis without warranty of any kind, including, without limitation,
-the implied warranties of merchantability and fitness for a particular
-purpose and their equivalents under the laws of any jurisdiction.
-<p>I am interested in hearing from anyone who uses ficl. If you have a
-problem, a success story, a defect, an enhancement request, or if you would
-like to contribute to the ficl release (yay!), please <a href="mailto:john_sadler@alum.mit.edu">send
-me email</a>. </td>
-</tr>
+<table border="0" cellspacing="3" width="600" cols="1">
+ <tr>
+ <td><h2><a name="lawyerbait"></a>DISCLAIMER OF WARRANTY
+ and LICENSE</h2>
+ <p><i>Ficl is freeware. Use it in any way that you like,
+ with the understanding that the code is not supported.</i>
+ </p>
+ <p>Any third party may reproduce, distribute, or modify
+ the ficl software code or any derivative works thereof
+ without any compensation or license, provided that the
+ original author information and this disclaimer text are
+ retained in the source code files. The ficl software code
+ is provided on an "as is" basis without
+ warranty of any kind, including, without limitation, the
+ implied warranties of merchantability and fitness for a
+ particular purpose and their equivalents under the laws
+ of any jurisdiction. </p>
+ <p>The FiclWin distribution, a derivative work of the
+ ficl source code, is hereby licensed for unrestricted
+ non-commercial use under the ficl license provided the
+ user notifies the author (John Sadler) in writing or by
+ electronic mail or their intended use of the FiclWin
+ sources. You may freely redistribute the FiclWin
+ distribution provided it contains this notice and adheres
+ to all other provisions of this license. </p>
+ <p>Reselling the FiclWin source code, executable, or
+ works derived from the FiclWin source code is prohibited
+ under this license. Please contact me directly in order
+ to discuss license terms for commercial use and
+ distribution.</p>
+ <p>I am interested in hearing from anyone who uses ficl.
+ If you have a problem, a success story, a defect, an
+ enhancement request, or if you would like to contribute
+ to the ficl release, please <a
+ href="mailto:john_sadler@alum.mit.edu">send me email</a>. </p>
+ </td>
+ </tr>
</table>
-
</body>
</html>
--- a/ficl.c
+++ b/ficl.c
@@ -122,6 +122,38 @@
/**************************************************************************
+ f i c l F r e e V M
+** Removes the VM in question from the system VM list and deletes the
+** memory allocated to it. This is an optional call, since ficlTermSystem
+** will do this cleanup for you. This function is handy if you're going to
+** do a lot of dynamic creation of VMs.
+**************************************************************************/
+void ficlFreeVM(FICL_VM *pVM)
+{
+ FICL_VM *pList = vmList;
+
+ assert(pVM != 0);
+
+ if (vmList == pVM)
+ {
+ vmList = vmList->link;
+ }
+ else for (pList; pList != 0; pList = pList->link)
+ {
+ if (pList->link == pVM)
+ {
+ pList->link = pVM->link;
+ break;
+ }
+ }
+
+ if (pList)
+ vmDelete(pVM);
+ return;
+}
+
+
+/**************************************************************************
f i c l B u i l d
** Builds a word into the dictionary.
** Preconditions: system must be initialized, and there must
@@ -141,6 +173,7 @@
int err = ficlLockDictionary(TRUE);
if (err) return err;
+ assert(dictCellsAvail(dp) > sizeof (FICL_WORD) / sizeof (CELL));
dictAppendWord(dp, name, code, flags);
ficlLockDictionary(FALSE);
@@ -328,7 +361,7 @@
vmThrow(pVM, except);
}
break;
- }
+ }
pVM->pState = oldState;
return (except);
--- a/ficl.dsp
+++ b/ficl.dsp
@@ -1,5 +1,5 @@
# Microsoft Developer Studio Project File - Name="ficl" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Console Application" 0x0103
@@ -22,6 +22,7 @@
!MESSAGE
# Begin Project
+# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
@@ -41,7 +42,7 @@
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
# ADD CPP /nologo /W4 /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
-# SUBTRACT CPP /YX
+# SUBTRACT CPP /Fr /YX
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /d "NDEBUG"
BSC32=bscmake.exe
@@ -65,7 +66,7 @@
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Za /W4 /Gm /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
+# ADD CPP /nologo /Za /W4 /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /d "_DEBUG"
--- a/ficl.dsw
+++ b/ficl.dsw
@@ -1,4 +1,4 @@
-Microsoft Developer Studio Workspace File, Format Version 5.00
+Microsoft Developer Studio Workspace File, Format Version 6.00
# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
###############################################################################
@@ -7,10 +7,6 @@
Package=<5>
{{{
- begin source code control
- "$/Pamela/firmware/common/ficl", AUEAAAAA
- .
- end source code control
}}}
Package=<4>
--- a/ficl.h
+++ b/ficl.h
@@ -217,7 +217,7 @@
/*
** the Good Stuff starts here...
*/
-#define FICL_VER "2.03"
+#define FICL_VER "2.04"
#if !defined (FICL_PROMPT)
#define FICL_PROMPT "ok> "
#endif
@@ -227,7 +227,7 @@
** complement of false... that unifies logical and bitwise operations
** nicely.
*/
-#define FICL_TRUE (0xffffffffL)
+#define FICL_TRUE ((unsigned long)~(0L))
#define FICL_FALSE (0)
#define FICL_BOOL(x) ((x) ? FICL_TRUE : FICL_FALSE)
@@ -334,7 +334,7 @@
FICL_UNS nCells; /* size of the stack */
CELL *pFrame; /* link reg for stack frame */
CELL *sp; /* stack pointer */
- CELL base[1]; /* Bottom of the stack */
+ CELL base[1]; /* Top of stack */
} FICL_STACK;
/*
@@ -515,11 +515,17 @@
STRINGINFO vmGetWord0(FICL_VM *pVM);
int vmGetWordToPad(FICL_VM *pVM);
STRINGINFO vmParseString(FICL_VM *pVM, char delimiter);
+STRINGINFO vmParseStringEx(FICL_VM *pVM, char delimiter, char fSkipLeading);
+CELL vmPop(FICL_VM *pVM);
+void vmPush(FICL_VM *pVM, CELL c);
void vmPopIP (FICL_VM *pVM);
void vmPushIP (FICL_VM *pVM, IPTYPE newIP);
void vmQuit (FICL_VM *pVM);
void vmReset (FICL_VM *pVM);
void vmSetTextOut(FICL_VM *pVM, OUTFUNC textOut);
+#if FICL_WANT_DEBUGGER
+void vmStep(FICL_VM *pVM);
+#endif
void vmTextOut(FICL_VM *pVM, char *text, int fNewline);
void vmThrow (FICL_VM *pVM, int except);
void vmThrowErr(FICL_VM *pVM, char *fmt, ...);
@@ -531,15 +537,15 @@
** The inner interpreter - coded as a macro (see note for
** INLINE_INNER_LOOP in sysdep.h for complaints about VC++ 5
*/
-#define M_INNER_LOOP(pVM) \
- for (;;) \
- { \
+#define M_VM_STEP(pVM) \
FICL_WORD *tempFW = *(pVM)->ip++; \
(pVM)->runningWord = tempFW; \
tempFW->code(pVM); \
- }
+#define M_INNER_LOOP(pVM) \
+ for (;;) { M_VM_STEP(pVM) }
+
#if INLINE_INNER_LOOP != 0
#define vmInnerLoop(pVM) M_INNER_LOOP(pVM)
#else
@@ -761,6 +767,16 @@
** Precondition: successful execution of ficlInitSystem
*/
FICL_VM *ficlNewVM(void);
+
+/*
+** Force deletion of a VM. You do not need to do this
+** unless you're creating and discarding a lot of VMs.
+** For systems that use a constant pool of VMs for the life
+** of the system, ficltermSystem takes care of VM cleanup
+** automatically.
+*/
+void ficlFreeVM(FICL_VM *pVM);
+
/*
** Set the stack sizes (return and parameter) to be used for all
--- a/math64.c
+++ b/math64.c
@@ -3,7 +3,8 @@
** Forth Inspired Command Language - 64 bit math support routines
** Author: John Sadler (john_sadler@alum.mit.edu)
** Created: 25 January 1998
-**
+** Rev 2.03: Support for 128 bit DP math. This file really ouught to
+** be renamed!
*******************************************************************/
#include "ficl.h"
@@ -12,9 +13,9 @@
/**************************************************************************
m 6 4 A b s
-** Returns the absolute value of an INT64
+** Returns the absolute value of an DPINT
**************************************************************************/
-INT64 m64Abs(INT64 x)
+DPINT m64Abs(DPINT x)
{
if (m64IsNegative(x))
x = m64Negate(x);
@@ -51,7 +52,7 @@
** 10 -7 3 -1
** -10 -7 -3 1
**************************************************************************/
-INTQR m64FlooredDivI(INT64 num, INT32 den)
+INTQR m64FlooredDivI(DPINT num, FICL_INT den)
{
INTQR qr;
UNSQR uqr;
@@ -71,7 +72,7 @@
signQuot = -signQuot;
}
- uqr = ficlLongDiv(m64CastIU(num), (UNS32)den);
+ uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den);
qr = m64CastQRUI(uqr);
if (signQuot < 0)
{
@@ -92,9 +93,9 @@
/**************************************************************************
m 6 4 I s N e g a t i v e
-** Returns TRUE if the specified INT64 has its sign bit set.
+** Returns TRUE if the specified DPINT has its sign bit set.
**************************************************************************/
-int m64IsNegative(INT64 x)
+int m64IsNegative(DPINT x)
{
return (x.hi < 0);
}
@@ -103,15 +104,15 @@
/**************************************************************************
m 6 4 M a c
** Mixed precision multiply and accumulate primitive for number building.
-** Multiplies UNS64 u by UNS32 mul and adds UNS32 add. Mul is typically
+** Multiplies DPUNS u by FICL_UNS mul and adds FICL_UNS add. Mul is typically
** the numeric base, and add represents a digit to be appended to the
** growing number.
** Returns the result of the operation
**************************************************************************/
-UNS64 m64Mac(UNS64 u, UNS32 mul, UNS32 add)
+DPUNS m64Mac(DPUNS u, FICL_UNS mul, FICL_UNS add)
{
- UNS64 resultLo = ficlLongMul(u.lo, mul);
- UNS64 resultHi = ficlLongMul(u.hi, mul);
+ DPUNS resultLo = ficlLongMul(u.lo, mul);
+ DPUNS resultHi = ficlLongMul(u.hi, mul);
resultLo.hi += resultHi.lo;
resultHi.lo = resultLo.lo + add;
@@ -126,11 +127,11 @@
/**************************************************************************
m 6 4 M u l I
-** Multiplies a pair of INT32s and returns an INT64 result.
+** Multiplies a pair of FICL_INTs and returns an DPINT result.
**************************************************************************/
-INT64 m64MulI(INT32 x, INT32 y)
+DPINT m64MulI(FICL_INT x, FICL_INT y)
{
- UNS64 prod;
+ DPUNS prod;
int sign = 1;
if (x < 0)
@@ -155,9 +156,9 @@
/**************************************************************************
m 6 4 N e g a t e
-** Negates an INT64 by complementing and incrementing.
+** Negates an DPINT by complementing and incrementing.
**************************************************************************/
-INT64 m64Negate(INT64 x)
+DPINT m64Negate(DPINT x)
{
x.hi = ~x.hi;
x.lo = ~x.lo;
@@ -171,21 +172,21 @@
/**************************************************************************
m 6 4 P u s h
-** Push an INT64 onto the specified stack in the order required
+** Push an DPINT onto the specified stack in the order required
** by ANS Forth (most significant cell on top)
** These should probably be macros...
**************************************************************************/
-void i64Push(FICL_STACK *pStack, INT64 i64)
+void i64Push(FICL_STACK *pStack, DPINT i64)
{
- stackPushINT32(pStack, i64.lo);
- stackPushINT32(pStack, i64.hi);
+ stackPushINT(pStack, i64.lo);
+ stackPushINT(pStack, i64.hi);
return;
}
-void u64Push(FICL_STACK *pStack, UNS64 u64)
+void u64Push(FICL_STACK *pStack, DPUNS u64)
{
- stackPushINT32(pStack, u64.lo);
- stackPushINT32(pStack, u64.hi);
+ stackPushINT(pStack, u64.lo);
+ stackPushINT(pStack, u64.hi);
return;
}
@@ -192,23 +193,23 @@
/**************************************************************************
m 6 4 P o p
-** Pops an INT64 off the stack in the order required by ANS Forth
+** Pops an DPINT off the stack in the order required by ANS Forth
** (most significant cell on top)
** These should probably be macros...
**************************************************************************/
-INT64 i64Pop(FICL_STACK *pStack)
+DPINT i64Pop(FICL_STACK *pStack)
{
- INT64 ret;
- ret.hi = stackPopINT32(pStack);
- ret.lo = stackPopINT32(pStack);
+ DPINT ret;
+ ret.hi = stackPopINT(pStack);
+ ret.lo = stackPopINT(pStack);
return ret;
}
-UNS64 u64Pop(FICL_STACK *pStack)
+DPUNS u64Pop(FICL_STACK *pStack)
{
- UNS64 ret;
- ret.hi = stackPopINT32(pStack);
- ret.lo = stackPopINT32(pStack);
+ DPUNS ret;
+ ret.hi = stackPopINT(pStack);
+ ret.lo = stackPopINT(pStack);
return ret;
}
@@ -215,12 +216,12 @@
/**************************************************************************
m 6 4 S y m m e t r i c D i v
-** Divide an INT64 by an INT32 and return an INT32 quotient and an INT32
-** remainder. The absolute values of quotient and remainder are not
+** Divide an DPINT by a FICL_INT and return a FICL_INT quotient and a
+** FICL_INT remainder. The absolute values of quotient and remainder are not
** affected by the signs of the numerator and denominator (the operation
** is symmetric on the number line)
**************************************************************************/
-INTQR m64SymmetricDivI(INT64 num, INT32 den)
+INTQR m64SymmetricDivI(DPINT num, FICL_INT den)
{
INTQR qr;
UNSQR uqr;
@@ -240,7 +241,7 @@
signQuot = -signQuot;
}
- uqr = ficlLongDiv(m64CastIU(num), (UNS32)den);
+ uqr = ficlLongDiv(m64CastIU(num), (FICL_UNS)den);
qr = m64CastQRUI(uqr);
if (signRem < 0)
qr.rem = -qr.rem;
@@ -254,39 +255,51 @@
/**************************************************************************
m 6 4 U M o d
-** Divides an UNS64 by base (an UNS16) and returns an UNS16 remainder.
-** Writes the quotient back to the original UNS64 as a side effect.
-** This operation is typically used to convert an UNS64 to a text string
+** Divides a DPUNS by base (an UNS16) and returns an UNS16 remainder.
+** Writes the quotient back to the original DPUNS as a side effect.
+** This operation is typically used to convert an DPUNS to a text string
** in any base. See words.c:numberSignS, for example.
** Mechanics: performs 4 ficlLongDivs, each of which produces 16 bits
-** of the quotient. C does not provide a way to divide an UNS32 by an
-** UNS16 and get an UNS32 quotient (ldiv is closest, but it's signed,
+** of the quotient. C does not provide a way to divide an FICL_UNS by an
+** UNS16 and get an FICL_UNS quotient (ldiv is closest, but it's signed,
** unfortunately), so I've used ficlLongDiv.
**************************************************************************/
-UNS16 m64UMod(UNS64 *pUD, UNS16 base)
+#if (BITS_PER_CELL == 32)
+
+#define UMOD_SHIFT 16
+#define UMOD_MASK 0x0000ffff
+
+#elif (BITS_PER_CELL == 64)
+
+#define UMOD_SHIFT 32
+#define UMOD_MASK 0x00000000ffffffff
+
+#endif
+
+UNS16 m64UMod(DPUNS *pUD, UNS16 base)
{
- UNS64 ud;
+ DPUNS ud;
UNSQR qr;
- UNS64 result;
+ DPUNS result;
result.hi = result.lo = 0;
ud.hi = 0;
- ud.lo = pUD->hi >> 16;
- qr = ficlLongDiv(ud, (UNS32)base);
- result.hi = qr.quot << 16;
+ ud.lo = pUD->hi >> UMOD_SHIFT;
+ qr = ficlLongDiv(ud, (FICL_UNS)base);
+ result.hi = qr.quot << UMOD_SHIFT;
- ud.lo = (qr.rem << 16) | (pUD->hi & 0x0000ffff);
- qr = ficlLongDiv(ud, (UNS32)base);
- result.hi |= qr.quot & 0x0000ffff;
+ ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->hi & UMOD_MASK);
+ qr = ficlLongDiv(ud, (FICL_UNS)base);
+ result.hi |= qr.quot & UMOD_MASK;
- ud.lo = (qr.rem << 16) | (pUD->lo >> 16);
- qr = ficlLongDiv(ud, (UNS32)base);
- result.lo = qr.quot << 16;
+ ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo >> UMOD_SHIFT);
+ qr = ficlLongDiv(ud, (FICL_UNS)base);
+ result.lo = qr.quot << UMOD_SHIFT;
- ud.lo = (qr.rem << 16) | (pUD->lo & 0x0000ffff);
- qr = ficlLongDiv(ud, (UNS32)base);
- result.lo |= qr.quot & 0x0000ffff;
+ ud.lo = (qr.rem << UMOD_SHIFT) | (pUD->lo & UMOD_MASK);
+ qr = ficlLongDiv(ud, (FICL_UNS)base);
+ result.lo |= qr.quot & UMOD_MASK;
*pUD = result;
@@ -293,4 +306,219 @@
return (UNS16)(qr.rem);
}
+
+/**************************************************************************
+** Contributed by
+** Michael A. Gauland gaulandm@mdhost.cse.tek.com
+**************************************************************************/
+#if PORTABLE_LONGMULDIV != 0
+/**************************************************************************
+ m 6 4 A d d
+**
+**************************************************************************/
+DPUNS m64Add(DPUNS x, DPUNS y)
+{
+ DPUNS result;
+ int carry;
+
+ result.hi = x.hi + y.hi;
+ result.lo = x.lo + y.lo;
+
+
+ carry = ((x.lo | y.lo) & CELL_HI_BIT) && !(result.lo & CELL_HI_BIT);
+ carry |= ((x.lo & y.lo) & CELL_HI_BIT);
+
+ if (carry)
+ {
+ result.hi++;
+ }
+
+ return result;
+}
+
+
+/**************************************************************************
+ m 6 4 S u b
+**
+**************************************************************************/
+DPUNS m64Sub(DPUNS x, DPUNS y)
+{
+ DPUNS result;
+
+ result.hi = x.hi - y.hi;
+ result.lo = x.lo - y.lo;
+
+ if (x.lo < y.lo)
+ {
+ result.hi--;
+ }
+
+ return result;
+}
+
+
+/**************************************************************************
+ m 6 4 A S L
+** 64 bit left shift
+**************************************************************************/
+DPUNS m64ASL( DPUNS x )
+{
+ DPUNS result;
+
+ result.hi = x.hi << 1;
+ if (x.lo & CELL_HI_BIT)
+ {
+ result.hi++;
+ }
+
+ result.lo = x.lo << 1;
+
+ return result;
+}
+
+
+/**************************************************************************
+ m 6 4 A S R
+** 64 bit right shift (unsigned - no sign extend)
+**************************************************************************/
+DPUNS m64ASR( DPUNS x )
+{
+ DPUNS result;
+
+ result.lo = x.lo >> 1;
+ if (x.hi & 1)
+ {
+ result.lo |= CELL_HI_BIT;
+ }
+
+ result.hi = x.hi >> 1;
+ return result;
+}
+
+
+/**************************************************************************
+ m 6 4 O r
+** 64 bit bitwise OR
+**************************************************************************/
+DPUNS m64Or( DPUNS x, DPUNS y )
+{
+ DPUNS result;
+
+ result.hi = x.hi | y.hi;
+ result.lo = x.lo | y.lo;
+
+ return result;
+}
+
+
+/**************************************************************************
+ m 6 4 C o m p a r e
+** Return -1 if x < y; 0 if x==y, and 1 if x > y.
+**************************************************************************/
+int m64Compare(DPUNS x, DPUNS y)
+{
+ int result;
+
+ if (x.hi > y.hi)
+ {
+ result = +1;
+ }
+ else if (x.hi < y.hi)
+ {
+ result = -1;
+ }
+ else
+ {
+ /* High parts are equal */
+ if (x.lo > y.lo)
+ {
+ result = +1;
+ }
+ else if (x.lo < y.lo)
+ {
+ result = -1;
+ }
+ else
+ {
+ result = 0;
+ }
+ }
+
+ return result;
+}
+
+
+/**************************************************************************
+ f i c l L o n g M u l
+** Portable versions of ficlLongMul and ficlLongDiv in C
+** Contributed by:
+** Michael A. Gauland gaulandm@mdhost.cse.tek.com
+**************************************************************************/
+DPUNS ficlLongMul(FICL_UNS x, FICL_UNS y)
+{
+ DPUNS result = { 0, 0 };
+ DPUNS addend;
+
+ addend.lo = y;
+ addend.hi = 0; /* No sign extension--arguments are unsigned */
+
+ while (x != 0)
+ {
+ if ( x & 1)
+ {
+ result = m64Add(result, addend);
+ }
+ x >>= 1;
+ addend = m64ASL(addend);
+ }
+ return result;
+}
+
+
+/**************************************************************************
+ f i c l L o n g D i v
+** Portable versions of ficlLongMul and ficlLongDiv in C
+** Contributed by:
+** Michael A. Gauland gaulandm@mdhost.cse.tek.com
+**************************************************************************/
+UNSQR ficlLongDiv(DPUNS q, FICL_UNS y)
+{
+ UNSQR result;
+ DPUNS quotient;
+ DPUNS subtrahend;
+ DPUNS mask;
+
+ quotient.lo = 0;
+ quotient.hi = 0;
+
+ subtrahend.lo = y;
+ subtrahend.hi = 0;
+
+ mask.lo = 1;
+ mask.hi = 0;
+
+ while ((m64Compare(subtrahend, q) < 0) &&
+ (subtrahend.hi & CELL_HI_BIT) == 0)
+ {
+ mask = m64ASL(mask);
+ subtrahend = m64ASL(subtrahend);
+ }
+
+ while (mask.lo != 0 || mask.hi != 0)
+ {
+ if (m64Compare(subtrahend, q) <= 0)
+ {
+ q = m64Sub( q, subtrahend);
+ quotient = m64Or(quotient, mask);
+ }
+ mask = m64ASR(mask);
+ subtrahend = m64ASR(subtrahend);
+ }
+
+ result.quot = quotient.lo;
+ result.rem = q.lo;
+ return result;
+}
+
+#endif
--- a/math64.h
+++ b/math64.h
@@ -24,6 +24,10 @@
** a problem, a success story, a defect, an enhancement request, or
** if you would like to contribute to the ficl release (yay!), please
** send me email at the address above.
+**
+** NOTE: this file depends on sysdep.h for the definition
+** of PORTABLE_LONGMULDIV and several abstract types.
+**
*/
#if !defined (__MATH64_H__)
@@ -33,24 +37,36 @@
extern "C" {
#endif
-INT64 m64Abs(INT64 x);
-int m64IsNegative(INT64 x);
-UNS64 m64Mac(UNS64 u, UNS32 mul, UNS32 add);
-INT64 m64MulI(INT32 x, INT32 y);
-INT64 m64Negate(INT64 x);
-INTQR m64FlooredDivI(INT64 num, INT32 den);
-void i64Push(FICL_STACK *pStack, INT64 i64);
-INT64 i64Pop(FICL_STACK *pStack);
-void u64Push(FICL_STACK *pStack, UNS64 u64);
-UNS64 u64Pop(FICL_STACK *pStack);
-INTQR m64SymmetricDivI(INT64 num, INT32 den);
-UNS16 m64UMod(UNS64 *pUD, UNS16 base);
+DPINT m64Abs(DPINT x);
+int m64IsNegative(DPINT x);
+DPUNS m64Mac(DPUNS u, FICL_UNS mul, FICL_UNS add);
+DPINT m64MulI(FICL_INT x, FICL_INT y);
+DPINT m64Negate(DPINT x);
+INTQR m64FlooredDivI(DPINT num, FICL_INT den);
+void i64Push(FICL_STACK *pStack, DPINT i64);
+DPINT i64Pop(FICL_STACK *pStack);
+void u64Push(FICL_STACK *pStack, DPUNS u64);
+DPUNS u64Pop(FICL_STACK *pStack);
+INTQR m64SymmetricDivI(DPINT num, FICL_INT den);
+UNS16 m64UMod(DPUNS *pUD, UNS16 base);
+
+#if PORTABLE_LONGMULDIV != 0 /* see sysdep.h */
+DPUNS m64Add(DPUNS x, DPUNS y);
+DPUNS m64ASL( DPUNS x );
+DPUNS m64ASR( DPUNS x );
+int m64Compare(DPUNS x, DPUNS y);
+DPUNS m64Or( DPUNS x, DPUNS y );
+DPUNS m64Sub(DPUNS x, DPUNS y);
+#endif
+
#define i64Extend(i64) (i64).hi = ((i64).lo < 0) ? -1L : 0
-#define m64CastIU(i64) (*(UNS64 *)(&(i64)))
-#define m64CastUI(u64) (*(INT64 *)(&(u64)))
+#define m64CastIU(i64) (*(DPUNS *)(&(i64)))
+#define m64CastUI(u64) (*(DPINT *)(&(u64)))
#define m64CastQRIU(iqr) (*(UNSQR *)(&(iqr)))
#define m64CastQRUI(uqr) (*(INTQR *)(&(uqr)))
+
+#define CELL_HI_BIT (1L << (BITS_PER_CELL-1))
#ifdef __cplusplus
}
--- a/softwords/classes.fr
+++ b/softwords/classes.fr
@@ -68,6 +68,16 @@
c-4byte => set
;
+ \ force the pointer to be null
+ : clr-ptr
+ 0 -rot c-ptr => .addr c-4byte => set
+ ;
+
+ \ return flag indicating null-ness
+ : ?null ( inst class -- flag )
+ c-ptr => get-ptr 0=
+ ;
+
\ increment the pointer in place
: inc-ptr ( inst class -- )
2dup 2dup ( i c i c i c )
--- a/softwords/ficlclass.fr
+++ b/softwords/ficlclass.fr
@@ -74,37 +74,3 @@
end-class
-\ ** C - S T R I N G
-\ counted string, size set at creation time (if by NEW)
-\ Can also be ref instantiated to wrap an existing string
-\ No check for bounds overrun...
-\ Creation example:
-\ 80 c-string --> new str80
-\ s" arf arf!!" str80 --> set
-\ str80 --> type cr
-\
-object subclass c-string
- c-byte obj: .count
- char: .text
-
- : type ( inst class -- )
- 2dup --> .text
- -rot --> .count --> get
- type ;
-
- : init ( size inst class -- )
- rot allot object => init ;
-
- : set ( c-addr u inst class )
- locals| class inst |
- dup
- inst class --> .count --> set
- inst class --> .text swap move ;
-
- : get ( inst class -- c-addr u )
- 2dup
- --> .text -rot
- --> .count --> get
- ;
-
-end-class
--- a/softwords/forml.fr
+++ b/softwords/forml.fr
@@ -19,9 +19,9 @@
--> .length --> get
;
- : set-name { c-addr u inst class -- }
- u inst class --> .length --> set
- c-addr inst class --> .name u move
+ : set-name { c-addr u 2this -- }
+ u 2this --> .length --> set
+ c-addr 2this --> .name u move
;
: ? ( inst class ) c-example => get-name type cr ;
@@ -47,16 +47,16 @@
object subclass c-led
c-byte obj: .state
- : on { led# inst class -- }
- inst class --> .state --> get
+ : on { led# 2this -- }
+ 2this --> .state --> get
1 led# lshift or dup !oreg
- inst class --> .state --> set
+ 2this --> .state --> set
;
- : off { led# inst class -- }
- inst class --> .state --> get
+ : off { led# 2this -- }
+ 2this --> .state --> get
1 led# lshift invert and dup !oreg
- inst class --> .state --> set
+ 2this --> .state --> set
;
end-class
@@ -64,7 +64,9 @@
object subclass c-switch
- : ?on { bit# inst class -- bit }
+ : ?on { bit# 2this -- flag }
+
+ 1 bit# lshift
;
end-class
--- a/softwords/jhlocal.fr
+++ b/softwords/jhlocal.fr
@@ -9,6 +9,8 @@
\ locstate: 0 = looking for | or -- or }}
\ 1 = found |
\ 2 = found --
+\ 3 = found }
+\ 4 = end of line
hide
0 constant zero
@@ -19,16 +21,18 @@
: ?| ( c-addr u -- c-addr u flag )
2dup s" |" compare 0= ;
+\ examine name and push true if it's a 2local
+\ (starts with '2'), false otherwise.
+: ?2loc ( c-addr u -- c-addr n flag )
+ over c@ [char] 2 = if true else false endif ;
+
: ?delim ( c-addr u -- state | c-addr u 0 )
- ?| if
- 2drop 1
- else
- ?-- if
- 2drop 2
- else
- ?} if 2drop 3 else 0 endif
- endif
- endif
+ ?| if 2drop 1 exit endif
+ ?-- if 2drop 2 exit endif
+ ?} if 2drop 3 exit endif
+ dup 0=
+ if 2drop 4 exit endif
+ 0
;
set-current
@@ -45,7 +49,9 @@
repeat
\ now unstack the locals
- 0 do (local) loop \ ( )
+ 0 do
+ ?2loc if (2local) else (local) endif
+ loop \ ( )
\ zero locals until -- or }
locstate 1 = if
@@ -53,7 +59,11 @@
parse-word
?delim dup to locstate
0= while
- postpone zero (local)
+ ?2loc if
+ postpone zero postpone zero (2local)
+ else
+ postpone zero (local)
+ endif
repeat
endif
--- a/softwords/oo.fr
+++ b/softwords/oo.fr
@@ -216,6 +216,10 @@
\ instance of the class. This word gets compiled into
\ the wordlist of every class by the SUB method.
\ PRECONDITION: current-class contains the class address
+\ why use a state variable instead of the stack?
+\ >> Stack state is not well-defined during compilation (there are
+\ >> control structure match codes on the stack, of undefined size
+\ >> easiest way around this is use of this thread-local variable
\
: do-do-instance ( -- )
s" : .do-instance does> [ current-class @ ] literal ;"
@@ -232,7 +236,8 @@
\
:noname
wordlist
- create immediate
+ create
+ immediate
0 , \ NULL parent class
dup , \ wid
3 cells , \ instance size
@@ -300,7 +305,7 @@
locals| meta class |
class meta metaclass => get-size allocate ( -- addr fail-flag )
abort" allocate failed " ( -- addr )
- class
+ class 2dup --> init
;
\ Create an anonymous array of initialized instances from the heap
--- a/softwords/softcore.bat
+++ b/softwords/softcore.bat
@@ -1,1 +1,1 @@
-\perl\bin\perl.exe softcore.pl softcore.fr jhlocal.fr marker.fr oo.fr classes.fr >..\softcore.c
+\perl\bin\perl.exe softcore.pl softcore.fr jhlocal.fr marker.fr oo.fr classes.fr string.fr >..\softcore.c
--- a/softwords/softcore.fr
+++ b/softwords/softcore.fr
@@ -33,7 +33,8 @@
postpone if
postpone ."
postpone cr
- postpone abort
+ [ -2 ] literal ,
+ postpone throw
postpone endif
; immediate
@@ -41,8 +42,8 @@
\ ** CORE EXT
0 constant false
-1 constant true
-: <> = invert ;
-: 0<> 0= invert ;
+: <> = 0= ;
+: 0<> 0= 0= ;
: compile, , ;
: erase ( addr u -- ) 0 fill ;
: nip ( y x -- x ) swap drop ;
@@ -64,6 +65,8 @@
; immediate
: local ( name -- ) bl word count (local) ; immediate
+
+: 2local ( name -- ) bl word count (2local) ; immediate
: end-locals ( -- ) 0 0 (local) ; immediate
--- a/softwords/softcore.pl
+++ b/softwords/softcore.pl
@@ -29,17 +29,23 @@
while (<>) {
s"\n$""; # remove EOL
- s"\t" "g; # replace each tab with 4 spaces
s/\"/\\\"/g; # escape quotes
- next if /^\s*\\\s*$/;# toss empty comments
- next if /^\s*$/; # toss empty lines
+ #
+ # ignore empty lines and lines containing
+ # only empty comments
+ #
+ next if /^\s*\\\s*$/;
+ next if /^\s*$/;
- if (/^\\\s\*\*/) { # emit / ** lines as C comments
+ #
+ # emit lines beginnning with "\ **" as C comments
+ #
+ if (/^\\\s\*\*/) {
s"^\\ "";
if ($commenting == 0) {
- print "/*\n";
- }
+ print "/*\n";
+ }
$commenting = 1;
print "$_\n";
next;
@@ -46,31 +52,36 @@
}
if ($commenting == 1) {
- print "*/\n";
+ print "*/\n";
}
$commenting = 0;
- if (/^\\\s#/) { # pass commented preprocessor directives
+ #
+ # pass commented preprocessor directives
+ # == lines starting with "\ #"
+ # (supports single line directives only)
+ #
+ if (/^\\\s#/) {
s"^\\ "";
print "$_\n";
next;
}
- next if /^\s*\\ /; # toss all other comments
- s"\\\s+.*$"" ; # lop off trailing \ comments
- s"\s+$" "; # remove trailing space
+ next if /^\s*\\ /; # toss all other \ comment lines
+ s"\\\s+.*$"" ; # lop off trailing \ comments
+ s"\s+\(\s.*?\)""g; # delete ( ) comments
+ s"^\s+""; # remove leading spaces
+ s"\s+$""; # remove trailing spaces
+
#
- # emit all other lines as quoted string fragments
+ # emit whatever's left as quoted string fragments
#
- $out = " \"" . $_ . " \\n\"";
+# $out = " \"" . $_ . " \\n\"";
+ $out = " \"" . $_ . " \"";
print "$out\n";
}
-if ($commenting == 1) {
- print "*/\n";
-}
-
print <<EOF
"quit ";
@@ -77,7 +88,8 @@
void ficlCompileSoftCore(FICL_VM *pVM)
{
- int ret = ficlExec(pVM, softWords);
+ int ret = sizeof (softWords);
+ ret = ficlExec(pVM, softWords);
if (ret == VM_ERREXIT)
assert(FALSE);
return;
--- a/stack.c
+++ b/stack.c
@@ -196,12 +196,12 @@
return (*--pStack->sp).p;
}
-UNS32 stackPopUNS32(FICL_STACK *pStack)
+FICL_UNS stackPopUNS(FICL_STACK *pStack)
{
return (*--pStack->sp).u;
}
-INT32 stackPopINT32(FICL_STACK *pStack)
+FICL_INT stackPopINT(FICL_STACK *pStack)
{
return (*--pStack->sp).i;
}
@@ -222,12 +222,12 @@
*pStack->sp++ = LVALUEtoCELL(ptr);
}
-void stackPushUNS32(FICL_STACK *pStack, UNS32 u)
+void stackPushUNS(FICL_STACK *pStack, FICL_UNS u)
{
*pStack->sp++ = LVALUEtoCELL(u);
}
-void stackPushINT32(FICL_STACK *pStack, INT32 i)
+void stackPushINT(FICL_STACK *pStack, FICL_INT i)
{
*pStack->sp++ = LVALUEtoCELL(i);
}
--- a/sysdep.c
+++ b/sysdep.c
@@ -84,10 +84,7 @@
void *ficlRealloc(void *p, size_t size)
{
- if (p)
- free(p);
-
- return malloc(size);
+ return realloc(p, size);
}
/*
@@ -169,10 +166,14 @@
void *ficlRealloc(void *p, size_t size)
{
+ void *pv = malloc(size);
if (p)
+ {
+ memcpy(pv, p, size)
free(p);
+ }
- return malloc(size);
+ return pv;
}
@@ -259,10 +260,7 @@
void *ficlRealloc(void *p, size_t size)
{
- if (p)
- free(p);
-
- return malloc(size);
+ return realloc(p, size);
}
--- a/sysdep.h
+++ b/sysdep.h
@@ -138,6 +138,14 @@
#endif
/*
+** FICL_WANT_DEBUGGER
+** Includes ficl code necesary to single step the VM. Turned on in ficlWin.
+*/
+#if !defined (FICL_WANT_DEBUGGER)
+#define FICL_WANT_DEBUGGER 0
+#endif
+
+/*
** PORTABLE_LONGMULDIV causes ficlLongMul and ficlLongDiv to be
** defined in C in sysdep.c. Use this if you cannot easily
** generate an inline asm definition
--- a/test/ficltest.fr
+++ b/test/ficltest.fr
@@ -27,3 +27,14 @@
{ 1 -5 5 within -> true }
{ 33000 32000 34000 within -> true }
{ 0x80000000 0x7f000000 0x81000000 within -> true }
+
+testing exception words
+: exc1 1 throw ;
+: exctest1 [ ' exc1 ] literal catch ;
+: exc2 exctest1 1 = if 2 throw endif ;
+: exctest2 [ ' exc2 ] literal catch ;
+: exctest? ' catch ;
+
+{ exctest1 -> 1 }
+{ exctest2 -> 2 }
+{ exctest? abort -> -1 }
--- a/testmain.c
+++ b/testmain.c
@@ -6,6 +6,7 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
+#include <time.h>
#ifdef WIN32
#include <direct.h>
#endif
@@ -169,7 +170,7 @@
cp[len] = '\0';
result = ficlExec(pVM, cp);
- if (result >= VM_ERREXIT)
+ if (result != VM_OUTOFTEXT)
{
pVM->sourceID = id;
fclose(fp);
@@ -178,7 +179,7 @@
}
}
/*
- ** Pass an empty line with SOURCE-ID == 0 to flush
+ ** Pass an empty line with SOURCE-ID == -1 to flush
** any pending REFILLs (as required by FILE wordset)
*/
pVM->sourceID.i = -1;
@@ -245,14 +246,46 @@
return;
}
+static void ficlClock(FICL_VM *pVM)
+{
+ clock_t now = clock();
+ stackPushUNS(pVM->pStack, (UNS32)now);
+ return;
+}
+
+static void clocksPerSec(FICL_VM *pVM)
+{
+ stackPushUNS(pVM->pStack, CLOCKS_PER_SEC);
+ return;
+}
+
+
+static void execxt(FICL_VM *pVM)
+{
+ FICL_WORD *pFW;
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 1, 0);
+#endif
+
+ pFW = stackPopPtr(pVM->pStack);
+ ficlExecXT(pVM, pFW);
+
+ return;
+}
+
+
void buildTestInterface(void)
{
ficlBuild("break", ficlBreak, FW_DEFAULT);
+ ficlBuild("clock", ficlClock, FW_DEFAULT);
ficlBuild("cd", ficlChDir, FW_DEFAULT);
+ ficlBuild("execxt", execxt, FW_DEFAULT);
ficlBuild("load", ficlLoad, FW_DEFAULT);
ficlBuild("pwd", ficlGetCWD, FW_DEFAULT);
ficlBuild("system", ficlSystem, FW_DEFAULT);
ficlBuild("spewhash", spewHash, FW_DEFAULT);
+ ficlBuild("clocks/sec",
+ clocksPerSec, FW_DEFAULT);
return;
}
@@ -259,10 +292,10 @@
#if !defined (_WINDOWS)
-
+#define nINBUF 256
int main(int argc, char **argv)
{
- char in[256];
+ char in[nINBUF];
FICL_VM *pVM;
ficlInitSystem(10000);
@@ -283,7 +316,7 @@
for (;;)
{
int ret;
- gets(in);
+ fgets(in, nINBUF, stdin);
ret = ficlExec(pVM, in);
if (ret == VM_USEREXIT)
{
--- a/vm.c
+++ b/vm.c
@@ -112,6 +112,7 @@
}
#endif
+
/**************************************************************************
v m G e t S t r i n g
** Parses a string out of the VM input buffer and copies up to the first
@@ -122,7 +123,7 @@
**************************************************************************/
char *vmGetString(FICL_VM *pVM, FICL_STRING *spDest, char delimiter)
{
- STRINGINFO si = vmParseString(pVM, delimiter);
+ STRINGINFO si = vmParseStringEx(pVM, delimiter, 0);
if (SI_COUNT(si) > FICL_STRING_MAX)
{
@@ -223,6 +224,11 @@
** trailing delimiter.
**************************************************************************/
STRINGINFO vmParseString(FICL_VM *pVM, char delim)
+{
+ return vmParseStringEx(pVM, delim, 1);
+}
+
+STRINGINFO vmParseStringEx(FICL_VM *pVM, char delim, char fSkipLeading)
{
STRINGINFO si;
char *pSrc = vmGetInBuf(pVM);
@@ -229,8 +235,11 @@
char *pEnd = vmGetInBufEnd(pVM);
char ch;
- while ((pSrc != pEnd) && (*pSrc == delim)) /* skip lead delimiters */
- pSrc++;
+ if (fSkipLeading)
+ { /* skip lead delimiters */
+ while ((pSrc != pEnd) && (*pSrc == delim))
+ pSrc++;
+ }
SI_SETPTR(si, pSrc); /* mark start of text */
@@ -254,6 +263,27 @@
/**************************************************************************
+ v m P o p
+**
+**************************************************************************/
+CELL vmPop(FICL_VM *pVM)
+{
+ return stackPop(pVM->pStack);
+}
+
+
+/**************************************************************************
+ v m P u s h
+**
+**************************************************************************/
+void vmPush(FICL_VM *pVM, CELL c)
+{
+ stackPush(pVM->pStack, c);
+ return;
+}
+
+
+/**************************************************************************
v m P o p I P
**
**************************************************************************/
@@ -355,6 +385,18 @@
return;
}
+
+
+/**************************************************************************
+ v m S t e p
+** Single step the vm - equivalent to "step into" - used for debugging
+**************************************************************************/
+#if FICL_WANT_DEBUGGER
+void vmStep(FICL_VM *pVM)
+{
+ M_VM_STEP(pVM);
+}
+#endif
/**************************************************************************
--- a/words.c
+++ b/words.c
@@ -45,6 +45,7 @@
static FICL_WORD *pIfParen = NULL;
static FICL_WORD *pInterpret = NULL;
static FICL_WORD *pLitParen = NULL;
+static FICL_WORD *pTwoLitParen = NULL;
static FICL_WORD *pLoopParen = NULL;
static FICL_WORD *pPLoopParen = NULL;
static FICL_WORD *pQDoParen = NULL;
@@ -55,14 +56,21 @@
#if FICL_WANT_LOCALS
static FICL_WORD *pGetLocalParen= NULL;
+static FICL_WORD *pGet2LocalParen= NULL;
static FICL_WORD *pGetLocal0 = NULL;
static FICL_WORD *pGetLocal1 = NULL;
static FICL_WORD *pToLocalParen = NULL;
+static FICL_WORD *pTo2LocalParen = NULL;
static FICL_WORD *pToLocal0 = NULL;
static FICL_WORD *pToLocal1 = NULL;
static FICL_WORD *pLinkParen = NULL;
static FICL_WORD *pUnLinkParen = NULL;
static int nLocals = 0;
+static CELL *pMarkLocals = NULL;
+
+static void doLocalIm(FICL_VM *pVM);
+static void do2LocalIm(FICL_VM *pVM);
+
#endif
@@ -217,6 +225,18 @@
}
+static void ficlIsNum(FICL_VM *pVM)
+{
+ STRINGINFO si;
+ FICL_INT ret;
+
+ SI_SETLEN(si, stackPopINT(pVM->pStack));
+ SI_SETPTR(si, stackPopPtr(pVM->pStack));
+ ret = isNumber(pVM, si) ? FICL_TRUE : FICL_FALSE;
+ stackPushINT(pVM->pStack, ret);
+ return;
+}
+
/**************************************************************************
a d d & f r i e n d s
**
@@ -895,7 +915,7 @@
*/
static void commentHang(FICL_VM *pVM)
{
- vmParseString(pVM, ')');
+ vmParseStringEx(pVM, ')', 0);
return;
}
@@ -1131,6 +1151,22 @@
/**************************************************************************
+ h a s h
+** hash ( c-addr u -- code)
+** calculates hashcode of specified string and leaves it on the stack
+**************************************************************************/
+
+static void hash(FICL_VM *pVM)
+{
+ STRINGINFO si;
+ SI_SETLEN(si, stackPopUNS(pVM->pStack));
+ SI_SETPTR(si, stackPopPtr(pVM->pStack));
+ stackPushUNS(pVM->pStack, hashHashCode(si));
+ return;
+}
+
+
+/**************************************************************************
i n t e r p r e t
** This is the "user interface" of a Forth. It does the following:
** while there are words in the VM's Text Input Buffer
@@ -1272,7 +1308,18 @@
return;
}
+static void twoLitParen(FICL_VM *pVM)
+{
+#if FICL_ROBUST > 1
+ vmCheckStack(pVM, 0, 2);
+#endif
+ stackPushINT(pVM->pStack, *((FICL_INT *)(pVM->ip)+1));
+ stackPushINT(pVM->pStack, *(FICL_INT *)(pVM->ip));
+ vmBranchRelative(pVM, 2);
+ return;
+}
+
/**************************************************************************
l i t e r a l I m
**
@@ -1293,6 +1340,18 @@
}
+static void twoLiteralIm(FICL_VM *pVM)
+{
+ FICL_DICT *dp = ficlGetDict();
+ assert(pTwoLitParen);
+
+ dictAppendCell(dp, LVALUEtoCELL(pTwoLitParen));
+ dictAppendCell(dp, stackPop(pVM->pStack));
+ dictAppendCell(dp, stackPop(pVM->pStack));
+
+ return;
+}
+
/**************************************************************************
l i s t W o r d s
**
@@ -2035,8 +2094,6 @@
char *pDest = pVM->pad;
char ch;
- pSrc = skipSpace(pSrc, pEnd);
-
for (ch = *pSrc; (pEnd != pSrc) && (ch != ')'); ch = *++pSrc)
*pDest++ = ch;
@@ -2540,6 +2597,19 @@
}
+static void againCoIm(FICL_VM *pVM)
+{
+ FICL_DICT *dp = ficlGetDict();
+
+ assert(pBranchParen);
+ dictAppendCell(dp, LVALUEtoCELL(pBranchParen));
+
+ /* expect "begin" branch marker */
+ resolveBackBranch(dp, pVM, destTag);
+ return;
+}
+
+
/**************************************************************************
c h a r & f r i e n d s
** 6.1.0895 CHAR CORE ( "<spaces>name" -- char )
@@ -2718,6 +2788,7 @@
return;
}
+
/**************************************************************************
t y p e
** Pop count and char address from stack and print the designated string.
@@ -2766,7 +2837,7 @@
char delim = (char)stackPopINT(pVM->pStack);
STRINGINFO si;
- si = vmParseString(pVM, delim);
+ si = vmParseStringEx(pVM, delim, 1);
if (SI_COUNT(si) > nPAD-1)
SI_SETLEN(si, nPAD-1);
@@ -2807,27 +2878,12 @@
**************************************************************************/
static void parse(FICL_VM *pVM)
{
- char *pSrc = vmGetInBuf(pVM);
- char *pEnd = vmGetInBufEnd(pVM);
- char *cp;
- FICL_UNS count;
- char delim = (char)stackPopINT(pVM->pStack);
+ STRINGINFO si;
+ char delim = (char)stackPopINT(pVM->pStack);
- cp = pSrc; /* mark start of text */
-
- while ((pSrc != pEnd) && (*pSrc != delim))
- {
- pSrc++; /* find next delimiter or end */
- }
-
- count = pSrc - cp; /* set length of result */
-
- if ((pSrc != pEnd) && (*pSrc == delim)) /* gobble trailing delimiter */
- pSrc++;
-
- vmUpdateTib(pVM, pSrc);
- stackPushPtr(pVM->pStack, cp);
- stackPushUNS(pVM->pStack, count);
+ si = vmParseStringEx(pVM, delim, 0);
+ stackPushPtr(pVM->pStack, SI_PTR(si));
+ stackPushUNS(pVM->pStack, SI_COUNT(si));
return;
}
@@ -2886,6 +2942,7 @@
}
+
/**************************************************************************
f m S l a s h M o d
** f-m-slash-mod CORE ( d1 n1 -- n2 n3 )
@@ -3498,16 +3555,22 @@
FICL_WORD *pFW;
#if FICL_WANT_LOCALS
- FICL_DICT *pLoc = ficlGetLoc();
if ((nLocals > 0) && (pVM->state == COMPILE))
{
+ FICL_DICT *pLoc = ficlGetLoc();
pFW = dictLookup(pLoc, si);
- if (pFW)
+ if (pFW && (pFW->code == doLocalIm))
{
dictAppendCell(dp, LVALUEtoCELL(pToLocalParen));
dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
return;
}
+ else if (pFW && pFW->code == do2LocalIm)
+ {
+ dictAppendCell(dp, LVALUEtoCELL(pTo2LocalParen));
+ dictAppendCell(dp, LVALUEtoCELL(pFW->param[0]));
+ return;
+ }
}
#endif
@@ -3669,7 +3732,6 @@
**************************************************************************/
static void localParen(FICL_VM *pVM)
{
- static CELL *pMark = NULL;
FICL_DICT *pDict = ficlGetDict();
STRINGINFO si;
SI_SETLEN(si, stackPopUNS(pVM->pStack));
@@ -3676,7 +3738,7 @@
SI_SETPTR(si, (char *)stackPopPtr(pVM->pStack));
if (SI_COUNT(si) > 0)
- { /* add a local to the dict and update nLocals */
+ { /* add a local to the **locals** dict and update nLocals */
FICL_DICT *pLoc = ficlGetLoc();
if (nLocals >= FICL_MAX_LOCALS)
{
@@ -3690,7 +3752,7 @@
{ /* compile code to create a local stack frame */
dictAppendCell(pDict, LVALUEtoCELL(pLinkParen));
/* save location in dictionary for #locals */
- pMark = pDict->here;
+ pMarkLocals = pDict->here;
dictAppendCell(pDict, LVALUEtoCELL(nLocals));
/* compile code to initialize first local */
dictAppendCell(pDict, LVALUEtoCELL(pToLocal0));
@@ -3709,7 +3771,7 @@
}
else if (nLocals > 0)
{ /* write nLocals to (link) param area in dictionary */
- *(FICL_INT *)pMark = nLocals;
+ *(FICL_INT *)pMarkLocals = nLocals;
}
return;
@@ -3716,6 +3778,83 @@
}
+static void get2LocalParen(FICL_VM *pVM)
+{
+ FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
+ stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
+ stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
+ return;
+}
+
+
+static void do2LocalIm(FICL_VM *pVM)
+{
+ FICL_DICT *pDict = ficlGetDict();
+ int nLocal = pVM->runningWord->param[0].i;
+
+ if (pVM->state == INTERPRET)
+ {
+ stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal]);
+ stackPush(pVM->pStack, pVM->rStack->pFrame[nLocal+1]);
+ }
+ else
+ {
+ dictAppendCell(pDict, LVALUEtoCELL(pGet2LocalParen));
+ dictAppendCell(pDict, LVALUEtoCELL(nLocal));
+ }
+ return;
+}
+
+
+static void to2LocalParen(FICL_VM *pVM)
+{
+ FICL_INT nLocal = *(FICL_INT *)(pVM->ip++);
+ pVM->rStack->pFrame[nLocal+1] = stackPop(pVM->pStack);
+ pVM->rStack->pFrame[nLocal] = stackPop(pVM->pStack);
+ return;
+}
+
+
+static void twoLocalParen(FICL_VM *pVM)
+{
+ FICL_DICT *pDict = ficlGetDict();
+ STRINGINFO si;
+ SI_SETLEN(si, stackPopUNS(pVM->pStack));
+ SI_SETPTR(si, (char *)stackPopPtr(pVM->pStack));
+
+ if (SI_COUNT(si) > 0)
+ { /* add a local to the **locals** dict and update nLocals */
+ FICL_DICT *pLoc = ficlGetLoc();
+ if (nLocals >= FICL_MAX_LOCALS)
+ {
+ vmThrowErr(pVM, "Error: out of local space");
+ }
+
+ dictAppendWord2(pLoc, si, do2LocalIm, FW_COMPIMMED);
+ dictAppendCell(pLoc, LVALUEtoCELL(nLocals));
+
+ if (nLocals == 0)
+ { /* compile code to create a local stack frame */
+ dictAppendCell(pDict, LVALUEtoCELL(pLinkParen));
+ /* save location in dictionary for #locals */
+ pMarkLocals = pDict->here;
+ dictAppendCell(pDict, LVALUEtoCELL(nLocals));
+ }
+
+ dictAppendCell(pDict, LVALUEtoCELL(pTo2LocalParen));
+ dictAppendCell(pDict, LVALUEtoCELL(nLocals));
+
+ nLocals += 2;
+ }
+ else if (nLocals > 0)
+ { /* write nLocals to (link) param area in dictionary */
+ *(FICL_INT *)pMarkLocals = nLocals;
+ }
+
+ return;
+}
+
+
#endif
/**************************************************************************
setParentWid
@@ -4039,21 +4178,28 @@
**
** More comments can be found throughout catch's code.
**
-** BUGS: do not handle locals unnesting correctly... I think...
-**
** Daniel C. Sobral Jan 09/1999
+** sadler may 2000 -- revised to follow ficl.c:ficlExecXT.
**************************************************************************/
static void ficlCatch(FICL_VM *pVM)
{
- int except;
+ static FICL_WORD *pQuit = NULL;
+
+ int except;
jmp_buf vmState;
FICL_VM VM;
FICL_STACK pStack;
FICL_STACK rStack;
FICL_WORD *pFW;
- IPTYPE exitIP;
+ if (!pQuit)
+ pQuit = ficlLookup("exit-inner");
+
+ assert(pVM);
+ assert(pQuit);
+
+
/*
** Get xt.
** We need this *before* we save the stack pointer, or
@@ -4090,63 +4236,42 @@
*/
except = setjmp(vmState);
- /*
- ** And now, choose what to do depending on except.
- */
+ switch (except)
+ {
+ /*
+ ** Setup condition - push poison pill so that the VM throws
+ ** VM_INNEREXIT if the XT terminates normally, then execute
+ ** the XT
+ */
+ case 0:
+ vmPushIP(pVM, &pQuit); /* Open mouth, insert emetic */
+ vmExecute(pVM, pFW);
+ vmInnerLoop(pVM);
+ break;
- /* Things having gone wrong... */
- if(except)
- {
+ /*
+ ** Normal exit from XT - lose the poison pill,
+ ** restore old setjmp vector and push a zero.
+ */
+ case VM_INNEREXIT:
+ vmPopIP(pVM); /* Gack - hurl poison pill */
+ pVM->pState = VM.pState; /* Restore just the setjmp vector */
+ stackPushINT(pVM->pStack, 0); /* Push 0 -- everything is ok */
+ break;
+
+ /*
+ ** Some other exception got thrown - restore pre-existing VM state
+ ** and push the exception code
+ */
+ default:
/* Restore vm's state */
memcpy((void*)pVM, (void*)&VM, sizeof(FICL_VM));
memcpy((void*)pVM->pStack, (void*)&pStack, sizeof(FICL_STACK));
memcpy((void*)pVM->rStack, (void*)&rStack, sizeof(FICL_STACK));
- /* Push error */
- stackPushINT(pVM->pStack, except);
-
- }
- else /* Things being ok... */
- {
- /*
- * We need to know when to exit the inner loop
- * Colonp, the "code" for colon words, just pushes
- * the word's IP onto the RP, and expect the inner
- * interpreter to do the rest. Well, I'd rather have
- * it done *before* I return from this function,
- * losing the automatic variables I'm using to save
- * state. Sure, I could save this on dynamic memory
- * and save state on RP, or I could even implement
- * the poor man's version of this word in Forth with
- * sp@, sp!, rp@ and rp!, but we have a lot of state
- * neatly tucked away in pVM, so why not save it?
- */
- exitIP = pVM->ip;
-
- /* Execute the xt -- inline code for vmExecute */
-
- pVM->runningWord = pFW;
- pFW->code(pVM);
-
- /*
- ** Run the inner loop until we get back to exitIP
- */
- for (; pVM->ip != exitIP;)
- {
- pFW = *pVM->ip++;
-
- /* Inline code for vmExecute */
- pVM->runningWord = pFW;
- pFW->code(pVM);
- }
-
-
- /* Restore just the setjmp vector */
- pVM->pState = VM.pState;
-
- /* Push 0 -- everything is ok */
- stackPushINT(pVM->pStack, 0);
- }
+ stackPushINT(pVM->pStack, except);/* Push error */
+ break;
+ }
}
/*
@@ -4407,6 +4532,7 @@
dictAppendWord(dp, ".(", dotParen, FW_DEFAULT);
dictAppendWord(dp, ":noname", colonNoName, FW_DEFAULT);
dictAppendWord(dp, "?do", qDoCoIm, FW_COMPIMMED);
+ dictAppendWord(dp, "again", againCoIm, FW_COMPIMMED);
dictAppendWord(dp, "parse", parse, FW_DEFAULT);
dictAppendWord(dp, "pick", pick, FW_DEFAULT);
dictAppendWord(dp, "roll", roll, FW_DEFAULT);
@@ -4435,6 +4561,14 @@
ficlSetEnv("stack-cells", FICL_DEFAULT_STACK);
/*
+ ** DOUBLE word set (partial)
+ */
+ dictAppendWord(dp, "2constant", twoConstant, FW_IMMEDIATE);
+ dictAppendWord(dp, "2literal", twoLiteralIm, FW_IMMEDIATE);
+ dictAppendWord(dp, "dnegate", dnegate, FW_DEFAULT);
+
+
+ /*
** EXCEPTION word set
*/
dictAppendWord(dp, "catch", ficlCatch, FW_DEFAULT);
@@ -4467,6 +4601,12 @@
dictAppendWord(dp, "(toLocal1)",toLocal1, FW_COMPILE);
dictAppendWord(dp, "(local)", localParen, FW_COMPILE);
+ pGet2LocalParen =
+ dictAppendWord(dp, "(@2local)", get2LocalParen, FW_COMPILE);
+ pTo2LocalParen =
+ dictAppendWord(dp, "(to2Local)",to2LocalParen, FW_COMPILE);
+ dictAppendWord(dp, "(2local)", twoLocalParen, FW_COMPILE);
+
ficlSetEnv("locals", FICL_TRUE);
ficlSetEnv("locals-ext", FICL_TRUE);
ficlSetEnv("#locals", FICL_MAX_LOCALS);
@@ -4531,15 +4671,15 @@
dictAppendWord(dp, ".hash", dictHashSummary,FW_DEFAULT);
dictAppendWord(dp, ".ver", ficlVersion, FW_DEFAULT);
dictAppendWord(dp, "-roll", minusRoll, FW_DEFAULT);
- dictAppendWord(dp, "2constant", twoConstant, FW_IMMEDIATE); /* DOUBLE */
dictAppendWord(dp, ">name", toName, FW_DEFAULT);
dictAppendWord(dp, "body>", fromBody, FW_DEFAULT);
dictAppendWord(dp, "compare", compareString, FW_DEFAULT); /* STRING */
dictAppendWord(dp, "compile-only",
compileOnly, FW_DEFAULT);
- dictAppendWord(dp, "dnegate", dnegate, FW_DEFAULT); /* DOUBLE */
dictAppendWord(dp, "endif", endifCoIm, FW_COMPIMMED);
dictAppendWord(dp, "forget-wid",forgetWid, FW_DEFAULT);
+ dictAppendWord(dp, "hash", hash, FW_DEFAULT);
+ dictAppendWord(dp, "number?", ficlIsNum, FW_DEFAULT);
dictAppendWord(dp, "parse-word",parseNoCopy, FW_DEFAULT);
dictAppendWord(dp, "sliteral", sLiteralCoIm, FW_COMPIMMED); /* STRING */
dictAppendWord(dp, "wid-set-super",
@@ -4560,6 +4700,8 @@
dictAppendWord(dp, "(;)", semiParen, FW_COMPILE);
pLitParen =
dictAppendWord(dp, "(literal)", literalParen, FW_COMPILE);
+ pTwoLitParen =
+ dictAppendWord(dp, "(2literal)",twoLitParen, FW_COMPILE);
pStringLit =
dictAppendWord(dp, "(.\")", stringLit, FW_COMPILE);
pIfParen =