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. Thenworld0toworld9are defined.raycaster-turnwill render and interact one screen and input line at a time.raycaster-realuses 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’