This section keeps track of the changes made in each version of Until. The manual was first written for Version 1.3, so the update list begins with that version. The initial release of Until was Version 1.2 in Write Your Own Programming Language Using C++.

Changed word names from the book to Forth. i.e. m{ }m to : ; etc.
Implement forget and several bug fixes. New words added include forget, expect, cls, ftell, fseek, d+, d-, d<. BUG fixes include changing ascii to immediate. Partial implementation of <# # #> AND associated other words.
First Beta release. Continue bug fixes as found. Finish implementing number formatting words (<# # #>, ETC). Corrected hex number problems.
Second Beta release. New features include ability to run multiple interpreters after startup. Add LOCAL.C, etc. to have a clear separation of where Until stops and an application starts. Continue bug fixes as found. Some of the words added/modified include [, ], ['], compile [compile], and allot.
1.6.1 - 1.6.4
First cut at adding some of the hard words such as , and does>.
Added atol, converted tib, pstack, rstack, and here from arrays to pointers. These changes should make it easy to expand their default sizes at run time. The same changes need to be made for pad and pfa_list. Vectored most of the screen I/O words
Added vocabulary words, and other minor enhancements.
Minor bug corrections and several changes suggested by Doug Philips.
General code cleanup. Made changes suggested by Richard Secrist that prevents stack overflow/underflow from crashing Until.
Stop compilation from a file when a compile error occurs. This also helps prevent system crashes. Also changed C string words so returning the completion code optional.
Folded modifications from S-Engine kernel back into Until.
Fixed nested file compilation. Added both a default .BIN and .APP file automatically loading at startup. Added -f and -w command line options. -f specifies the file to load and -w specifies the word to run.
Made " state smart.
Beta release
First publicly released version. Added a generic version of the Borland fnsplit() function. The S-Engine kernel will be upgraded to use this version of Until. Version 1.4 was used previously.
Fixed minor bugs.
Added unseal
Rewrote word to use C strtok() functions instead of stepping through tib one character at a time.
The major change was porting Until to Unix. The supplied makefile works on several Unix systems with little or no change. It works with Sun Sparc ANS C and SGI ANS C with no changes and with GCC on the Sparc by changing the compiler flag from 'cc' to 'gcc'. Added SEARCH.C which implements rough equivalents of AWK's sub and gsub functions. FILTER.APP, a skeleton file filter program, is also new. Reverted to old version of word() after ran into problems with backslash.
Reworked UNTIL.C to make Until easier to embed and wrote instructions. Replaced help() with code contributed by Michael Mundrane. Modified get_stdin() to call fgets() instead of gets() and make EOF from the keyboard exit Until instead of generating an error per a suggestion by Michael Mundrane. Cleaned up code by removing unreferenced variables per suggestions by Akira Kida. This eliminates most of the warning messages generated while compiling Until. Akira also contributed a working version of shell() for Unix systems. Moved file descriptor stack from UNTIL.H to IO.H.
Bug fix where stacks were not being malloc()'d properly.
Initial floating point and printf implementations. Not released.
Merged V2.3 with Skip Carter's C-level I/O redirection code, added error checking for all malloc() calls, backslash quoted characters in " ..." string constants, getenv, case, and the S-Engine SGML document interpreter. Treated as a working update and not released.
Public release of the changes since V2.2.2 including updated documentation. Release prepared for the 1995 Rochester Forth Conference.


Installing Until is quite simple. Simply unzip the files into a directory on your system, such as \until. You must compile Until if you are running on a Unix system. In either case copy the Until executable file (until.exe for MS-DOS or Until for Unix) to a directory in your path. If you are using MS-DOS, you are ready to run.


Until uses several files in addition to UNTIL.EXE. The other files are optional. The files and the order that they load are:

HELP.APP is not actually loaded at startup; it is used by the word help to provide on-line help information.

The execution begins setting up all of the primitive words defined in the USER.C file. The primitives are fixed at compile time.

Next, UNTIL.BIN is loaded. During development, it generally contains words that always compile. These in effect become part of your personal development environment. At the end of development, your application can be 'sealed' into binary form. This is a convenient way to distribute applications without source. If UNTIL.BIN does not exist, an error message is generated.

Application code is contained in APPLIC.APP, by default. It is compiled after UNTIL.BIN. No error message is given if this file does not exist. Note: The need for APPLIC.APP is an artifact left over from pre V2 Until. Using APPLIC is now an obsolete feature; expect it to be removed in a future release.

One or more additional files may be loaded from the command line using the -f flag. Multiple files may be loaded by specifying multiple -f options. The format for specifying a file this way is:


Where name.app is the name of the file to load. If the file extension is .BIN, the file is processed as a sealed file. Otherwise, the file is compiled as a normal ASCII source file.

An additional command line option, -w, is also provided to allow a different word than the outer interpreter to execute. The format is:


Where Any_word is any Until word. The word executes, then Until exits.

Type UNTIL at the DOS prompt to run Until. The following screen is displayed:

                          (c) Copyright 1994, 1995
                             All Rights Reserved
                               Norman E. Smith

                                 Version 2.5
                                 June 01, 1995

Until> Welcome to UNTIL


Stack contents are displayed in the upper right hand corner of the screen every time through the Outer Interpreter loop (DOS only). Type bye to exit Until and return to DOS.


The following is the default listing for what is sealed into UNTIL.BIN.

<<<<<< update!!!
(  until.app )

: hello
   ." Welcome to UNTIL" cr cr

-1 constant true
 0 constant false

: d.           ( d --- )
   drop .

: >here                 ( 'string --- )  ( copy string to here )
   here 20 0 fill
   count here swap cmove

true null_strings
false string_returns



Versions Until has been successfully ported to the following computers/operating systems:

  OS             COMPILER
  ==             ========
  MS-DOS         Borland C/C++ *+
  MS-DOS         Symantic C++ 6.1*
  MS-DOS         Mix Power C
  Linux          GCC 2.5.8
  Coherent 3.2   C
  VAX/VMS        VAX C *
  OSF/1          DEC C +
  RT-11          DEC PDP-11 C +
  IRIX           SGI ANS C *
  IRIX           GCC *
  Solaris 2.3    Sun ANS C *
  Solaris 2.3    GCC *
  Mips           ANS C *
  Mips           GCC *

* Current port, V2.5 compiles
+ V1.8 compiled

This list is subject to change and indicates the ease with which porting Until to new C compilers can be done.

I tried compiling Until with PCC (aka DeSmet C) without any luck. The first barrier was the K&R function arguments vs ANSI C function argument declarations. That was solved with some painful editing. The problem I could not get around was calling a function via pointer. The statement:

to call a function via pointer gave a fatal compile error. This is used several times in Until. If someone could solve that, then PCC would compile a minimal version of Until.

Porting Approach

Until was written with portability in mind. This section identifies some of the problems that have been encountered in porting Until from the original base Borland C++ implementation.

The general approach to porting from C++ to C is:

All of the compilers are not verified each time a change is made to Until. So, some minor modifications may be required to when porting back to a non-baseline version. Every attempt is made not to `break' an existing port, but it does happen sometimes. All development is done on a PC using Borland C++. The file COMPILER.H attempts to detect the C compiler being used and automatically set #DEFINES accordingly.

Porting Problems

There are several problems were encountered, depending on the target compiler. These include:

A porting problem that took some time to track down was the difference between malloc() and new. When strings are allocated using new, space is allocated for the trailing null. This is not the case with malloc(). Especially with small model compilers, the problem showed itself by locking up the computer. It was solved by adding two to the length in the malloc() call when allocating memory for strings such as the word name.

One problem that showed up when using small model compilers was the way constants are passed in argument lists. Until uses a 32-bit parameter stack, so all values are cast to long before being pushed. Integer constants are treated as 16-bit integers. Hence, in functions like three() that push a constant. The value was not what was expected. This was fixed by casting all constants in the call to pushsp().

The prototype declarations are considerably different between ANSI and K&R C. This was not a tough problem to find, but a real pain to fix with about 200 functions to modify. I ended up making separate source code copies for use with K&R C compilers, notably Coherent C.

The Borland C++ version of Until uses kbhit() and several screen manipulation functions (wherex(), wherey(), etc.) that are not normally part of ANS C. These functions are in a separate module, CONSOLE.C.

Selection of system and compiler is done via COMPILER.H. Automatic selection is done when possible as well in COMPILER.H.

PC Memory Models

The PC, with its segmented memory architecture, has caused some ``interesting'' anomalies in Until. This section identifies bugs/features I have discovered in the PC version of Until. The problems fall into two broad categories, small model compilers and addresses.

The small model problems show up primarily with Borland C/C++. Small model in other compilers (Coherent and Mix Power C) do not show this problem, although they have not been tested extensively. High level words store everything in the dictionary (PFA field) as a DictHeader*. Constants compiled into a word are screwed up. My solution for the short term is use compact model or larger when using Borland C++. The only other small model compiler that was convenient to check was Coherent and the problem was not there. Here is an example of the problem:

  : problem  10 0 do i . loop ;

This causes garbage to be used in place of 10 with Borland C++ using the small model at execution time. The value compiled into the dictionary appears to be correct.

Addresses displayed by dump and .s seem really strange; they are very large, 10 digit integers. This is well above the address space of my PC. The first byte of the dump is always prints as 00, but the ASCII representation is correct. The address printing problems only show up on the PC. VAX and DECstation versions work correctly. I assume that addresses are in some weird format, maybe paragraph number and offset, that displaying them as simple long integers does not handle properly.

Another problem was discovered with PC memory models. Roger Hauck reported a problem when trying to combine Until with a large memory model Fortran subroutine library. I could not duplicate his problem. Several weeks later I had another problem with a C string compare failing in a portion of Until that I had not changed. This problem was tracked down to having to use far versions of all the string functions when compiling large model programs. The quick fix of redefining the string functions to _f... versions in COMPILER.H has held up for some months now and will be left alone baring further problems.

At this point, always use large model or greater when compiling Until with any PC compiler. This may also apply to Unix C compilers as well where memory model is an option.


This section discusses general considerations for porting Until to other operating systems. It is not necessarily specific to Until, but certainly affects it.

Forth does direct console I/O. This is not portable in C on many systems. C console I/O is buffered by default. Even though you call getc() to read a single character, C buffers the entire line before returning from the getc() call. Therefore, implementing Forth console I/O words is system specific.

The present solution is that Until uses getc() for key and always returns TRUE when ?terminal is executed. Future versions of Until plan to add raw mode console I/O so that key and ?terminal function identically across operating systems.

Another area of potential portability problems is screen I/O. Until uses a small number of Borland C++ specific screen functions for cursor positioning and such. Several possibilities exist for ways around this. A partial solution is implementing versions of some functions, such as gotoxy using ANS terminal escape sequences, A more complete solution, with some associated overhead, is curses. The choice of implementation solution will be determined later.

System include files frequently require tweaking from system to system and compiler to compiler.

The final major portability area of concern is signal handling. Signal processing is not very portable. A broad subset of common signals will be implemented as part of a future Until release.


This section describes the principle differences between Until and the Forth-83 standard. The primary differences include words not yet implemented and the approach taken to interfacing with the operating system. This section also describes the use of pfa_list[] in compiling words and describes the possible approaches to implementing comma and c-comma.

General Differences

This section describes the general differences between Until and a typical Forth implementation, whatever that is. My opinion is that any Forth that implements the Forth-83 Handy Reference Card is a `typical' Forth. Differences include:

Table of Contents
Next Section