Forth Inspired Command Language | |
Author: John Sadler (john_sadler@alum.mit.edu) | |
Created: 19 July 1997 | |
Revision 2.04: 20 May 2000 |
What's new in version 2.04ficlwin
ficl bugs vanquished
ficl enhancements
|
What's new in version 2.03This is the first version of Ficl that includes contributed code. Thanks especially to Daniel Sobral, Michael Gauland for contributions and bug finding. New words
Bugs Fixed
Ficlwin Enhancements
Ficl Enhancements
|
What's new in version 2.02New words
Bugs Fixed
Enhancements (IMHO)
|
What's new in version 2.01
|
What's new in version 2.0
|
What is ficl?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 software that includes ficl. |
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++...). |
Ficl Design goals
|
Application Programming InterfaceSee the comments in ficl.c and ficl.h for additional information, and the example in file testmain.c.
|
Local VariablesLocally 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. Ficl includes support for LOCALS and LOCALS EXT 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 -ROT as : -rot 2 -roll ; )
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. 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:
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. In ficl 2.04 and later, this facilty can also declare double cell locals (this is handy for OOP, 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. 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:
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): : -rot ( a b c -- c a b ) Search OrderFicl implements many of the search order words in
terms of two primitives called >SEARCH
and SEARCH>. As
their names suggest (assuming you're familiar with
Forth), they push and pop the search order stack. See the
list of Ficl extras for
details. Soft WordsMany 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. |
Object Oriented Programming in ficlFicl 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 (below) 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. Design goals of Ficl OO syntaxFicl'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.
|
Ficl Object ModelAll classes in Ficl are derived from the common base class OBJECT. All classes are instances of METACLASS. This means that classes are objects, too. METACLASS 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:
In the figure below, METACLASS and OBJECT 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. Note for the curious: METACLASS 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 METACLASS as an
instance of itself. |
Tutorial (finally!)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 references, 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 ONLY), type:
To start, we'll work with the two base classes OBJECT and METACLASS. Try this:
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 METACLASS, METACLASS 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 methods. 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.
Causes base-class OBJECT to derive from itself a new class called c-foo. Now we'll add some instance variables and methods to the new class...
The first two lines add named instance variables to the class, and create a method for each. Untyped instance variable methods (like those created by cell: cells: char: and chars:) 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 init 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. The init method is special for Ficl objects:
whenever you create an initialized instance using new
or new-array, Ficl calls the class's init
method for you on that instance. The default init
method supplied by class object clears the
instance, so we didn't really need to override it in this
case (see the source code in ficl/softwords/oo.fr).
And try a few things...
Or you could type this with the same effect:
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 init, 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:
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 metaclass. Here's an example from the definition of metaclass in oo.fr (don't paste this into ficlWin - it's already there):
Try this...
Decompiling the method with SEE 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. 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 ref from this class, supplying
the address of the structure. After that, the ref
instance behaves as a Ficl object, but its instance
variables take on the values in the existing structure.
Example (from ficlclass.fr):
In this case, c-wordlist describes Ficl's wordlist structure; named-wid creates a wordlist and binds it to a ref instance of c-wordlist. The fancy footwork with POSTPONE and early binding is required because classes are immediate. An equivalent way to define named-wid with late binding is:
To do the same thing at run-time (and call it my-wordlist):
Now you can deal with the wordlist through the ref instance:
Ficl can also model linked lists and other structures that contain pointers to structures of the same or different types. The class constructor word ref: makes an aggregate reference to a particular class. See the instance variable glossary for an example. Ficl can make arrays of instances, and aggregate arrays into class descripions. The class methods array and new-array create uninitialized and initialized arrays, respectively, of a class. In order to initialize an array, the class must define (or inherit) a reasonable init method. New-array invokes it on each member of the array in sequence from lowest to highest. Array instances and array members use the object methods index, next, and prev to navigate. Aggregate a member array of objects using array:. The objects are not automatically initialized in this case - your class initializer has to call array-init explicitly if you want this behavior. 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. |
Ficl String classesc-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"). Examples of use: c-string --> new homer s" In this house, " homer --> set s" we obey the laws of thermodynamics!" homer --> cat homer --> type |
object base-class Methods GlossaryThese are methods that are defined for all instances by the base class object. The methods include default initialization, array manipulations, aliases of class methods, upcasting, and programming tools.
|
User variables
Miscellaneous
FiclWin Extras (defined in testmain.c)
|
ANS Required Information
ANS Forth System Providing names from the Core Extensions word set Providing the Exception word set Providing names from the Exception Extensions word set Providing the Locals word set Providing the Locals Extensions word set Providing the Memory Allocation word set Providing the Programming-Tools word set Providing names from the Programming-Tools Extensions word set Providing the Search-Order word set Providing the Search-Order Extensions word set Implementation-defined OptionsThe 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.
Ambiguous ConditionsA 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. The following general ambiguous conditions could occur because of a combination of factors:
The following specific ambiguous conditions are noted in the glossary entries of the relevant words:
Locals Implementation-defined options
Locals Ambiguous conditions
Programming Tools Implementation-defined options
Search Order Implementation-defined options
Search Order Ambiguous conditions
|
For more information
DISCLAIMER OF WARRANTY and LICENSEFicl is freeware. Use it in any way that you like, with the understanding that the code is not supported. 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. 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. 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. 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 send me email. |