Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

History

393 Commits

Repository files navigation

CL-Forth

Common Lisp implementation of the Forth 2012 Standard, CL-Forth

Supported Platforms

CL-Forth is fully supported by CCL v1.12.2-82 or later.

CL-Forth is fully supported by SBCL 2.1.0 or later.

CL-Forth is fully supported by LispWorks 8.0.1 or later.

CL-Forth supports ECL 26.3.27 or later. However, at present, there are two failing tests in the String word set tests which are not yet understood.

Supported Operating Systems

CL-Forth is supported on macOS, Linux, and Windows.

On macOS, it has been verified to run on macOS Ventura or later.

On Linux, it has been verified to run on distributions with 5.10.162 kernels or later.

On Windows, it has been verified to run on Windows 10 or later.

License

CL-Forth is made available under the terms of the MIT License.

Usage

CL-Forth is defined using ASDF and is dependent on the CFFI and trivial-gray-streams libraries.

To fetch a copy of CL-Forth and the Forth 2012 Test Suite configured to only run tests for those word sets implemented by CL-Forth.

git clone https://github.com/gmpalter/cl-forth.git --recurse-submodules

QuickLisp is probably the simplest way to fetch the CFFI and trivial-gray-streams libraries. Follow the instructions on the QuickLisp webpage to download, install, and add QuickLisp to your Lisp's init file. To install the libraries, evaluate the following forms. (You only have to do this one time.)

(ql:quickload '#:cffi)
(ql:quickload '#:trivial-gray-streams)

To load CL-Forth into Lisp

(require'#:asdf)
(load"cl-forth.asd")
(asdf:load-system '#:cl-forth)

You can run the Forth 2012 Test Suite

(asdf:test-system '#:cl-forth)

To start the CL-Forth interpreter loop

(forth:run)

CL-Forth is case-insensitive.

Building a Standalone CL-Forth

You can build a standalone CL-Forth application.

Launch Lisp and evaluate the forms

(require'#:asdf)
(load"cl-forth.asd")
(asdf:load-system '#:cl-forth/application)
(forth-app:save-application "cl-forth")

This will create an executable named cl-forth. When you run cl-forth, it will startup directly into the Forth interpreter loop.

./cl-forth
CL-Forth Version 1.3
Running under Clozure Common Lisp Version 1.13 (v1.13) DarwinX8664
11 + .
2 OK.
: hello-world ." Hello World!" cr ;
OK.
hello-world
Hello World!
OK.
see hello-world
Source code for hello-world:
(DEFUN FORTH-WORDS::HELLO-WORLD (FS &REST PARAMETERS)
(DECLARE (IGNORABLE PARAMETERS))
(WITH-FORTH-SYSTEM (FS)
(TAGBODY (WRITE-STRING "Hello World!")
(TERPRI)
:EXIT)))
OK.
bye
In this session:
1 definition created
240 bytes of object code generated

The application recognizes these command line arguments

‑‑interpret EXPR, ‑i EXPREvaluate EXPR before entering the Forth interpreter loop. EXPR may need to be quoted to avoid interpretation by the shell. This argument may be used multiple times.
‑‑transcript PATHRecord a timestamped transcript of this session in the file PATH
‑‑help, ‑hDisplay the available command line arguments and exit
‑‑version, ‑VDisplay the version of CL-Forth and exit

Missing Words

CL-Forth does not implement the optional Block word set.

CL-Forth does not implement the optional Extended-Character word set.

CL-Forth does not implement KEY which is part of the Core word set.

The following words that are part of the optional Facility and Facility extensions word set are not implemented.

AT-XYKEY?PAGEEKEYEKEY>CHAR
EKEY>FKEYEKEY?EMIT?K-ALT-MASKK-CTRL-MASK
K-DELETEK-DOWNK-ENDK-F1K-F10
K-F11K-F12K-F2K-F3K-F4
K-F5 K-F6K-F7K-K8K-F9
K-HOMEK-INSERTK-LEFTK-NEXTK-PRIOR
K-RIGHTK-SHIFT-MASKK-UP

Foreign Function Interface

CL-Forth includes a foreign function interface (FFI) loosely based on the External Library Interface in SwiftForth. See FFI.md for details.

Optimization

CL-Forth includes an experimental optimizer which tries to simplify the code generated by CL-Forth by eliminating as much use of the data stack as possible. There are additional optimizations applied to eliminate unnecessary validity checks when those checks can be shown to be redundant. (E.g, checking that the character count given to TYPE is not negative.)

The optimizer is controlled by a boolean flag whose address is stored in the OPTIMIZER variable. You change the value of this flag using the words ON and OFF.

To turn the optimizer on, execute OPTIMIZER ON and to turn it off, execute OPTIMIZER OFF.

By default, the optimizer is off.

Under SBCL, the Forth test suite runs approximately 33% faster and generates approximately 25% less object code.

Some examples of the optimizer's effect on code generated by CL-Forth follows.

CL-Forth Version 1.4.1
Running under Clozure Common Lisp Version 1.13 (v1.13) DarwinX8664
show-code on
OK.
variable x variable y variable z
OK.
optimizer off
OK.
: test1 x @ y @ 256 + + z ! ;
Source code for test1:
(DEFUN FORTH-WORDS::TEST1 (FS PARAMETERS)
(DECLARE (IGNORABLE PARAMETERS))
(WITH-FORTH-SYSTEM (FS)
(TAGBODY (STACK-PUSH DATA-STACK 4503599627370496)
(STACK-PUSH DATA-STACK (CELL-SIGNED (MEMORY-CELL MEMORY (STACK-POP DATA-STACK))))
(STACK-PUSH DATA-STACK 4503599627370504)
(STACK-PUSH DATA-STACK (CELL-SIGNED (MEMORY-CELL MEMORY (STACK-POP DATA-STACK))))
(STACK-PUSH DATA-STACK 256)
(STACK-PUSH DATA-STACK
(CELL-SIGNED (+ (CELL-SIGNED (STACK-POP DATA-STACK))
(CELL-SIGNED (STACK-POP DATA-STACK)))))
(STACK-PUSH DATA-STACK
(CELL-SIGNED (+ (CELL-SIGNED (STACK-POP DATA-STACK))
(CELL-SIGNED (STACK-POP DATA-STACK)))))
(STACK-PUSH DATA-STACK 4503599627370512)
(SETF (MEMORY-CELL MEMORY (STACK-POP DATA-STACK)) (STACK-POP DATA-STACK))
:EXIT)))
OK.
optimizer on
OK.
: test1opt x @ y @ 256 + + z ! ;
Source code for test1opt:
(DEFUN FORTH-WORDS::TEST1OPT (FS PARAMETERS)
(DECLARE (IGNORABLE PARAMETERS))
(WITH-FORTH-SYSTEM (FS)
(TAGBODY (SETF (MEMORY-CELL MEMORY 4503599627370512)
(CELL-SIGNED (+ (CELL-SIGNED (+ 256
(CELL-SIGNED (MEMORY-CELL
MEMORY
4503599627370504))))
(CELL-SIGNED (MEMORY-CELL MEMORY 4503599627370496)))))
:EXIT)))
OK.
optimizer off
OK.
: test2 x 128 type cr ;
Source code for test2:
(DEFUN FORTH-WORDS::TEST2 (FS PARAMETERS)
(DECLARE (IGNORABLE PARAMETERS))
(WITH-FORTH-SYSTEM (FS)
(TAGBODY (STACK-PUSH DATA-STACK 4503599627370496)
(STACK-PUSH DATA-STACK 128)
(LET ((COUNT (STACK-POP DATA-STACK)) (ADDRESS (STACK-POP DATA-STACK)))
(WHEN (MINUSP COUNT)
(FORTH-EXCEPTION
:INVALID-NUMERIC-ARGUMENT
"Count to TYPE can't be negative"))
(MULTIPLE-VALUE-BIND (FORTH-MEMORY OFFSET)
(MEMORY-DECODE-ADDRESS MEMORY ADDRESS COUNT)
(WRITE-STRING (FORTH-STRING-TO-NATIVE FORTH-MEMORY OFFSET COUNT))))
(TERPRI)
:EXIT)))
OK.
optimizer on
OK.
: test2opt x 128 type cr ;
Source code for test2opt:
(DEFUN FORTH-WORDS::TEST2OPT (FS PARAMETERS)
(DECLARE (IGNORABLE PARAMETERS))
(WITH-FORTH-SYSTEM (FS)
(TAGBODY (LET ((COUNT 128) (ADDRESS 4503599627370496))
(DECLARE (IGNORABLE COUNT ADDRESS))
(MULTIPLE-VALUE-BIND (FORTH-MEMORY OFFSET)
(MEMORY-DECODE-ADDRESS MEMORY 4503599627370496 128)
(WRITE-STRING (FORTH-STRING-TO-NATIVE FORTH-MEMORY OFFSET 128))))
(TERPRI)
:EXIT)))
OK.
bye
In this session:
7 definitions created
3920 bytes of object code generated
24 bytes of memory allocated

Additional Words

CL-Forth includes a number of words defined by other implementation that are not part of the Forth 2012 Standard.

These words are specific to CL-Forth.

.SFDisplay the contents of the floating-point stack
.SRDisplay the contents of the return stack
ABOUTDisplays the documentation, if any, for a word
ALL-WORDSDisplay all words in all word lists in the search order
BREAKEnter a Lisp break loop
INLINEABLEMark that the most recent definition's code may be inlined
;INLINEAdds Lisp code to the current definition. Local variables (i.e., {: ... :}) are available in the LOCALS package
NOTINTERPRETEDMark that the most recent definition must only appear in definitions
OPTIMIZERReturn the address of the flag that controls whether generated code is optimized (EXPERIMENTAL)
P.Display the top cell of the data stack as a pointer (i.e., 16 hex digits)
RELOADReload a predefined definition (i.e., created by define-word)
REMOVEErase a single word
SETINLINEABLEEnable/disable inlining of an existing word
SHOW-BACKTRACESReturn the address of the flag that controls whether exceptions display the return and data stacks
SHOW-CODEReturn the address of the flag that controls whether completing a definition shows the generated code
STATISTICSReport some useful statistics about this CL-Forth session

These words are defined as "Common Usage" in the Forth Programmer's Manual, 3rd Edition.

,"2+2-C+!CONTEXT
CURRENTCVARIABLEM-M/NOT
NUMBERNUMBER?VOCABULARY

These words are defined by SwiftForth.

-?EMPTYGILDOFFONOPTIONAL
SILENTVERBOSEWARNING\\{

Implementation

TO BE SUPPLIED

Native Code Support

CL-Forth implements CODE and ;CODE to allow the definition of words written in Lisp rather than Forth. The terminator for the Lisp code block is ;ENDCODE.

Here is an example of using native code.

\ ( c-addr1u-c-addr2u)
\ ConvertsthestringatC-ADDR1UtouppercaseandleavestheresultintransientspaceatC-ADDR2U.
CODEUPCASE
(let ((count (cell-signed (stack-popdata-stack)))
(address (stack-popdata-stack)))
(unless (pluspcount)
(forth-exception :invalid-numeric-argument"Count to UPCASE must be positive"))
(multiple-value-bind (dataoffset)
(memory-decode-addressmemoryaddresscount)
(let* ((original (forth-string-to-nativedataoffsetcount))
(upcased (string-upcaseoriginal))
(string-space (reserve-string-spacememory))
(address (transient-space-base-addressmemorystring-space)))
(ensure-transient-space-holdsmemorystring-spacecount)
(multiple-value-bind (dataoffset)
(memory-decode-addressmemoryaddresscount)
(native-into-forth-stringupcaseddataoffset)
(seal-transient-spacememorystring-space)
(stack-pushdata-stackaddress)
(stack-pushdata-stackcount)))))
;ENDCODE

About

Common Lisp implementation of the Forth 2012 Standard

Topics

Resources

Stars

144 stars

Watchers

14 watching

Forks

Releases

Packages

Contributors

Languages