c, and ,

One of the consequences of implementing Until with a non-linear dictionary is words that normally manipulate here must be modified. Words that simply use here are little affected. Words that use here as a pointer, such as c, and ,, are the primary problem.

Several approaches exist to provide equivalent functionality in Until, so c, and , are not absolutely necessary for new code. Examples include:

Each is relatively simple to implement. The problem with all these is compatibility with existing Forth code. There are two potential approaches for implementing , and c, that have merit, allocating a fixed buffer for all comma operations to reference and dynamically allocating memory as entries are added. Each approach is discussed in the following sections. I am leaning toward dynamic allocation.

Both approaches affect allot. Instead of simply allocating a memory buffer, allot must allocate/manipulate a data structure to keep track of the current offset in the buffer and the end of the buffer. Other uses of allot can be oblivious to the changes.

There are two primary uses of , and c,, building small tables and compiling values into the dictionary. The following code is typical of building a table:

  create esc_sequence  27 c, ascii [ c, ascii 2 c,

The problem with this is when to copy the pfa_list array into the dictionary. ; normally triggers this action.

A traditional definition of constant illustrates a typical use of ,:

  : constant create ,  does> @ ;

This use of , is not valid in Until. For the time being does> is not implemented, which would break similar code anyway.


Compiling Definitions

Until must take a different approach to compiling words too. Memory for each word is allocated dynamically. The PFA of colon definitions is constructed in a fixed array named pfa_list[], then the actual amount of memory used by the word allocated by ;, and the contents copied. The primary advantage to this technique is only the amount of memory required for a word is allocated, rather than a large fixed amount.

Beware when modifying code that manipulates pfa_list[] because it is used all over the compiler!! However, a C macro was added in V2.5 that adds a value to the next location in pfa_list[] and increments pfa_offset called COMPILE_ADDR. All references to pfa_list[] do not reference the macro yet. Consider it a hook for a completely new dictionary structure in some future version.


Known Bugs

Most systems of any size have some known bugs. This section identifies the known bugs in Until. The list is given in no particular order.


Unimplemented Words

A number of normal Forth-83 words have not been implemented in Until yet. This is mostly because I have not needed them in my applications. Laziness also enters into it. The missing words can be divided into several groups; memory allocation words, defining words, disk words, and other words. The following words are not yet implemented in Until:

The memory allocation words are trivial to write. There are some tough decisions to make about exactly how to write them since Until uses a non-linear dictionary. Does the memory get compiled into the last word defined? Do you change the CFA of that word from whatever it is to do_comma or do_allot. There are several reasonable solutions, but compatibility with existing code would be poor. I am afraid that there will be no good solution here. See the section on , and c,.

Until does not implement the disk word set. I much prefer files to disk blocks, so this is not a great loss to me. However, it is possible to implement the disk word set completely in high level Until code using the supplied file word set.

The defining words were just skipped completely in the initial implementation. I did not even try to implement them. (I like the name <builds from Fig-Forth for defining words by the way.) Much of the need for compiling words goes away because it is so simple to implement a new word type as a C primitive. Thus, this capability can be implemented in other ways within the C/Forth Until environment. It does not help compatibility with other Forth code though. (See Getting Along Without DOES> for ways to get around the lack of defining words in Until.)

True double number words were left out because Until is 32-bit, so all integers are effectively double when compared to normal 16-bit Forth implementations.

Most of the missing words are not a big deal from developing applications stand point. This is not true from a compatibility standpoint. Most of the missing words I have rarely used so did not think they would be missed all that much. I have since changed my mind on some of them.


Planned Enhancements

This section identifies planned, well at least thought about, enhancements to Until. These include:

The most obvious enhancements are adding the missing words. Most of the missing words are needed for compatibility with what Forth programmers are used to using. Each group had some minor problem associated with them that required some decisions and a great deal of thought. I put both off and got started using Until for projects that required a minimal Forth capability. The bottom line is that I never got around to adding them. In hindsight, the usability of Until for general programming is limited only slightly at the present time because of the missing words.

Catching C signals is not required, but will make interactive operation more convenient, especially on non-DOS platforms. For example, <Ctrl>-C is trapped by C and can be handled in the program rather than forcing an exit to the operating system. Signal handling also provides the hooks to use a cut down version of Until as a run-time C debugging package.

Multiple interpreters are very easy to do in Until, but I have never seen this feature in any other Forth implementation. One interpreter can be used at startup to compile all the primitives and macros, then a different one used to interpret a text file, and so on. (See the discussion of text processing applications in Section 4.3.)

Integrating more operating system features into Until will take it a step or two closer to being a general purpose language. The capability of interactively calling any system function that can be called from C is a powerful tool that can make learning and using advanced OS features much easier.

Bottom line is V3.0 will be an even more major upgrade than the V2.5 upgrade is.


Extensions

This section describes extensions beyond the Forth-83 Standard that are included in Until. The primary extensions in Until at the present time are:

A good subset of each of these already exists. These word sets add much in the way of convenience to development with Until. These words are one way that Until takes advantage of the underlying operating system instead of simply tolerating it. Another point is the words listed here are very portable. Only one word, shell, does not operate the way I think it should under one operating system, OSF/1. I have run Until under four operating systems to date. More words will be added as the need arises and time permits.


6. SOURCE CODE

Until is organized as modules. This section describes the C modules and identifies the contents of each. The approach to using Until as an embedded application language is also touched on. There is also a complete book already written on the subject. [SMITH2] The source files are:

These files comprise over 13,000 lines of code. Until has grown considerably since the first published version in [SMITH1], which was approximately 4000 lines of code.

COMPILER.H
As Until has been ported to other computers, conditional compilation statements have been added to the code. This header file defines the compiler for the rest of the compile. Select the appropriate #define that closest matches the compiler you are using.

FUNCTS.H
Function prototypes are all placed in this header file.

IO.H
This header file contains the file descriptor stack and associated pointers. It is referenced only by IO.C.

SEARCH.H
This file contains data structures used by SEARCH.C.

UNTIL.H
This header file includes definitions of all the global data structures and variables used in Until.

CALL.C
This module contains the compiler. If you ever wanted to compile C or Basic or whatever instead of Forth, simply replace CALL.C with your own compiler.

CASE.C
This module contains the code for the case construct.

CONSOLE.C
This module contains console and screen I/O functions. These types of functions tend to be compiler specific. They are grouped here for ease of maintenance.

FILE.C
This module contains interface modules to C I/O functions such as fopen() and fgets().

FLOAT.C
This module contains floating point implementation. The symbol FLOATING_POINT in COMPILER.H activates floating point words.

HELP.C
This module is self contained. The code for the Until help facility is in this file.

IO.C
This module contains Forth type I/O and internal Until I/O functions.

MATH.C
The primitives related to math and logic can be found in math.c.

OUTER.C
The interpreters are included in this module. There are two, one interactive and one for using Until as an embedded application or macro language.

PRIM.C
The C functions that execute the primitive words are in this module. This is by far the largest module in Until.

QUOTE.C
This module contains the code for " and the Forth implementation of printf.

SEAL.C
This module has the code to 'seal' an application source file.

SENGINE.C
This module contains the code for the S-Engine SGML document interpreter. Define the SENGINE symbol in COMPILER.H to activate.

SEARCH.C
The search and replace functions are contained in this module.

SHARP.C
This module contains the code for the Forth <# formatting words.

SYSTEM.C
This module contains the code for interfacing with the operating system such as getenv().

UNTIL.C
This module contains the main function. It can be used as an example of calling Until from another C function.

USER.C
This module builds the dictionary of primitives. It essentially ties Forth words to C functions. For example, when the word cls is executed by the interpreter, the C function clr() executes. Adding a new primitive is simply a matter of writing the C function, the adding a new line in USER.C. There is a section in Write Your Own Programming Language Using C++ about adding new Until primitives.

VECTORS.C
This module contains the vectored execution I/O primitive word definitions. These, of course, are C functions.

VOCAB.C
This module contains the code that implements vocabularies.

The times I have used Until as an embedded application language, C code specific to the application have been included in a module named LOCAL.C. This isolates Until code from the application code.

There are several modules in the Until source code. The reasons include reduced compile time when changes are made to a small section of code and allow for possible custom configuration by leaving out the modules not needed for a particular application. Some of the configuration can be accomplished via #define statements in COMPILER.H. Future versions of Until will include as many configuration options as practical.


Until Internals

The internal operation of Until is described in Write Your Own Programming Language Using C++, [smith1]. This section documents changes made to the internal data structures since the book was published.


Compiling Until

Compiling Until is relatively easy. Batch files are included to handle a variety of operating systems and C compilers with a minimal of manual configuration. Much of the compiler selection is built into COMPILER.H.


MS-DOS

Until compiles under Borland C++ and Turbo C++. A Borland project file is not included in the distribution. The primary reason is that the location of the compiler related files is embedded in the project file. So if I included a project file with the compiler installed on D: and your compiler is installed on C:, the first time you tried to compile Until a ton of errors would be generated. Since creating a new project file from scratch is a 30 second job, no project file is included. Be sure to specify large model.

Type tc or bc at the DOS prompt to start Turbo C++ or Borland C++ respectively. Create a project file the first time you compile Until. The simply press Alt-CM to begin the compile. The Unix makefile can be used as a starting point for a makefile for the Borland tcc or bcc command line compiler.

There is also a Borland compatible makefile in the distribution called makefile.bcc. If you have the command line version of Borland/Turbo C++ installed, you can simply type make and Until will compile.


Unix

A fairly generic makefile is included with the Until distribution. It works on systems identified in the Ports section. (These include Sparc and SGI ANS C and gcc compiler.) The makefile is set up to use 'cc' as the compiler. If you use gcc, change the value of CC to 'gcc'. Type make to build Until. The executable file name is Until to prevent a name collision with the shell's until.


Table of Contents
Next Section