Using only a shell (and Emacs and Qemu 🤫), statically and dynamically linked ELF files are built that can load an assembler and cross compiler to rebuild themselves.
Copyright (C) 2020-2024 Nolan Eakins, SemanticGap(TM). All rights reserved.
SemanticGap is a trademark of Nolan Eakins. All rights reserved.
Arm(R) is a registered trademark of Arm Limited (or its subsidaries) in the US and/or elsewhere. This program’s only association to Arm is that it executes on Arm processors.
- One of:
- Termux on Android
- GNU/Linux
- Thumb capable ARM, with Thumb 2 preferred
- Or qemu-arm.
- Bash but not 5.1.4 which has a memory leak.
- Make
- Git
Building with the shell script is quite slow.
The prebuilt binaries under ./bootstrap/
can be used to skip steps.
make quick
will copy bootstrap/interp.elf
to bin/
but you may want one of:
./bootstrap/interp.static.elf
- Only requires a Linux kernel, but can not load dynamic libraries.
./bootstrap/interp.android.elf
- Is built to use Android’s dynamic linker.
./bootstrap/interp.gnueabi.elf
- Is built to use the GNU dynamic linker found on desktops.
Termux may set $LD_PRELOAD
which requires unsetting it: LD_PRELOAD='' ./bin/interp.elf
I cheated: make
is the preferred build tool. If you’re on a
different architecture from your target, you will to set binfmt up to
execute using Qemu.
The default task, make all
, will use Bash to boot strap a static
executable: bin/interp.elf
.
Run the following to start the build on an X86-64 host, targeting a Thumb device with static linking:
make all HOST=x86_64-linux-static TARGET=thumb-linux-static
Be prepared to wait.
To skip the Bash build. use make quick
or:
make all QUICK=1 HOST=x86_64-linux-static TARGET=thumb-linux-static
make targets
will print a full list of HOST
and TARGET
strings,
and to view information about the host and target there is make env
.
bin/interp.elf
will then be used to rebuild itself as
bin/interp.${linker}.1.elf
and bin/builder.${linker}.1.elf
which
then builds a dynamically linked versions with the 2.elf
and 3.elf
suffixes. ${linker}
may be any or all of static
, android
, and
gnueabi
. The HOST
, TARGET
, OUT_TARGETS
Make variables control
and define the platform triples. STAGE
controls what stage is
building.
The build scripts / top level programs found in src/bin/
can be
built by running make bin/${app}.elf
. This build will be done with
Bash. make bin/${app}.1.elf
will use
bin/interp.${linker}.${stage}.elf
. The $stage
can be changed to
any value of 1, 2, and 3.
make boot
will rebuild ./bootstrap/
from a clean clone of the
repository.
All executables built can be found in ./bin/
.
./src/bash/forth.sh
is Forth writen for Bash. It is used before any
binary is available. ./bin/fforth
is a shortcut capable of loading
./bin/fforth.dict
for a fast initial state. make bin/fforth.dict
will build that.
load-core
will load the compiling words. This load step can be
skipped by using ./bin/fforth
after running make bin/fforth.dict
.
Build scripts under src/bin/
can be cat
into it and writen to a
file: cat src/bin/interp.4th | ./src/bash/forth.sh > interp.elf
This describes any of the ./bin/interp*
executables.
These will need Qemu or suitable emulator if compiled for a different platform.
A list of words can be printed with words
. Compiling words with iwords
.
Once running, various sets of functionality can be loaded with the following words:
- load-core
- Very essential functions mostly found in
./src/interp/boot/core.4th
. - load-debug
- Collection of value printers found in
./src/interp/boot/debug/
. - load-thumb-asm
- Words to assemble Thumb code and cross compile.
- load-runner
- Starts the self build of the ops needed for an interpreter.
- load-interp
- Loads the bare interpreter when building.
src/bin/interp.4th
- of course
src/bin/scanner.4th
- Scans source files and has dictionaries for stats, highlighting in HTML, etc.
If https://github.com/sneakin/north has been cloned to ../north
, the
following demos can be loaded:
src/demos/tty/drawing.4th
- exercises the drawing routines. Load and
execute
demo-tty-line
,demo-tty-circle
,demo-tty-ellipse
, ordemo-tty-blit
. src/demos/tty/clock.4th
- has three clocks for the terminal:
tty-raw-clock-loop
,tty-buffer-clock
, andtty-analog-clock
. Each takes a timezone argument in the form of an offset in seconds. src/demos/tty/raycast.4th
- is ray caster like Wolfenstein 3d and
Ken’s Labryinth. Load and execute
raycaster-init
. Thenworld0
toworld9
are defined.raycaster-turn
will render and interact one screen and input line at a time.raycaster-real
uses epoll and threads for a bore interactive experience.
./bin/interp.elf
./bin/builder.elf
- load
- load/2
- load-string
- ( comments )
- defcol
- exit
- def
- exit-frame
- return
- :
- alias>
- immediate
- IF
- UNLESS
- ELSE
- THEN
- loop
- repeat-frame
- ‘
- literal
- pointer
- “
- s”
- c”
- d”
- tmp”
- var>
- poke
- peek
- const>
- string-const>
- symbol>
- :
- defcol
- def
- defvar>
- defconst>
- cross-immediate
- out-immediate
- out’
- out-off’