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++.
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:
Until (c) Copyright 1994, 1995 All Rights Reserved Norman E. Smith Version 2.5 June 01, 1995 Until> Welcome to UNTIL 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 hello
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:
(*funct)();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.
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.
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.
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.
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