docs: The Dictionary of v4 -- every live word, alphabetical, its stack notation and description; built and published with every release (#157) [skip ci]

make dictionary -> build/docs/Dictionary.pdf (20 pages): mkdictionary.py checks docs/reference/v4-dictionary.tsv against the booted system's words first, so a stale dictionary fails the build; then Markdown, pandoc, docs/book/dictionary.tex (the books' preamble, its own title page: version and commit). Quoted FORTH tokens set as code, so their quotes print straight. The nightly's docs stage builds it; publish sends classifier dictionary; the Gitea release attaches it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
Claude
2026-11-10 11:31:07 +00:00
parent 135cccb37d
commit 1a9b142d80
6 changed files with 93 additions and 6 deletions
+5 -1
View File
@@ -78,7 +78,7 @@ BOARD_DIR := $(if $(TARGET),$(BOARD_DIR_$(TARGET)))
SUBMAKE := $(MAKE) --no-print-directory
.DEFAULT_GOAL := all
.PHONY: all boot_image boot_images write_stick docs fabric clean clean-docs kernel boards help help-hosted sbom sbom-board \
.PHONY: all boot_image boot_images write_stick docs fabric dictionary clean clean-docs kernel boards help help-hosted sbom sbom-board \
qemu qemu-esp qemu-gdb init
# ARCH given on the command line and no TARGET: `clean` is the kernel's for that
@@ -207,6 +207,10 @@ docs:
fabric:
@$(SUBMAKE) -f docs/book/Makefile fabric
# dictionary -- The Dictionary of v4 (#157): build/docs/Dictionary.pdf
dictionary:
@$(SUBMAKE) -f docs/book/Makefile dictionary
clean-docs:
rm -rf build/docs
+35 -1
View File
@@ -63,9 +63,18 @@ FABRIC_DIR := $(OUT)/fabric
FABRIC_PDF := $(OUT)/BookOfFabric.pdf
FABRIC_FRAGS := $(foreach n,fabric-0 fabric-1 fabric-2 fabric-3 fabric-3-5 fabric-3-6 fabric-3-7 fabric-4,$(GEN)/$(n).tex)
.PHONY: all fabric tools FORCE
# The Dictionary of v4 (#157): every live word, alphabetical, with its stack
# notation and description -- `make dictionary` -> build/docs/Dictionary.pdf.
# Its names are the booted system's (v4/tools/mkdictionary.py); the check
# refuses a table that has fallen behind them.
DICT_DIR := $(OUT)/dictionary
DICT_PDF := $(OUT)/Dictionary.pdf
DICT_TSV := docs/reference/v4-dictionary.tsv
.PHONY: all fabric dictionary tools FORCE
all: $(PDF)
fabric: $(FABRIC_PDF)
dictionary: $(DICT_PDF)
tools:
@missing=""; \
@@ -113,6 +122,8 @@ $(VAR_DIR)/meta.tex: FORCE
$(meta_cmds)
$(FABRIC_DIR)/meta.tex: FORCE
$(meta_cmds)
$(DICT_DIR)/meta.tex: FORCE
$(meta_cmds)
FORCE:
@@ -137,3 +148,26 @@ $(FABRIC_PDF): $(BOOK_DIR)/fabric.tex $(BOOK_DIR)/preamble.tex $(FABRIC_FRAGS) $
echo "Error: LaTeX failed; full log: $(FABRIC_DIR)/fabric.log"; exit 1; }
@cp $(FABRIC_DIR)/fabric.pdf $@
@echo " PDF $@"
# the live word list needs the hosted v4; the check fails the build on a word with no entry, an
# unfinished entry, or an entry for a word the system no longer has
$(GEN)/dictionary-words.md: $(DICT_TSV) v4/tools/mkdictionary.py FORCE | tools
@mkdir -p $(GEN)
@$(MAKE) --no-print-directory -C v4 hosted >/dev/null
@python3 v4/tools/mkdictionary.py check $(DICT_TSV)
@python3 v4/tools/mkdictionary.py md $(DICT_TSV) $@
$(GEN)/dictionary-words.tex: $(GEN)/dictionary-words.md $(PANDOC_FILTERS) | tools
@echo " PANDOC $< -> $@"
@$(PANDOC) $(PANDOC_FLAGS) --id-prefix=dictionary- $< -o $@
TEXINPUTS_DICT := $(abspath $(DICT_DIR)):$(abspath $(GEN)):$(abspath $(BOOK_DIR)):
$(DICT_PDF): $(BOOK_DIR)/dictionary.tex $(BOOK_DIR)/preamble.tex $(GEN)/dictionary-words.tex $(GEN)/pandoc-highlighting.tex $(DICT_DIR)/meta.tex | tools
@echo " LATEXMK $(BOOK_DIR)/dictionary.tex -> $@"
@TEXINPUTS=$(TEXINPUTS_DICT) $(LATEXMK) -xelatex -interaction=nonstopmode -halt-on-error \
-file-line-error -outdir=$(DICT_DIR) $(BOOK_DIR)/dictionary.tex > $(DICT_DIR)/latexmk.log 2>&1 || { \
grep -A4 -E '^(.*:[0-9]+:|!)' $(DICT_DIR)/dictionary.log | head -40; \
echo "Error: LaTeX failed; full log: $(DICT_DIR)/dictionary.log"; exit 1; }
@cp $(DICT_DIR)/dictionary.pdf $@
@echo " PDF $@"
+42
View File
@@ -0,0 +1,42 @@
% docs/book/dictionary.tex -- master file of The Dictionary of v4 (#157):
% every word StarForth v4 boots with, alphabetical, with its stack notation,
% a description and where it is defined (Captain Bob, 2026-11-08: "a
% 'dictionary' document with the word, stack notations and descriptions.
% Alphabetical."; v4's words only).
%
% Built by `make dictionary` (docs/book/Makefile): v4/tools/mkdictionary.py
% checks docs/reference/v4-dictionary.tsv against the live system and writes
% the Markdown that pandoc turns into the fragment input below.
\documentclass[11pt,openany]{book}
\input{preamble}
\title{The Dictionary of StarForth v4\\[0.5em]\large Every word, its stack notation, and what it does}
\author{Robert A. James (Captain Bob)}
\date{Version \texttt{\bookversion}\\Built \bookdate{} from commit \texttt{\bookcommit}}
\begin{document}
\frontmatter
\maketitle
\chapter{How to read it}
Every word of the dictionary StarForth v4 boots with is here, in
alphabetical order. The names are not typed by hand: they are the booted
system's own list (\texttt{WORDS}, and the kernel's words of the node), and
the build refuses a dictionary that has fallen behind it.
\textbf{Stack notation.} \texttt{( before -{}- after )}: the values a word
takes from the stack, the top on the right, and what it leaves there.
\texttt{( R: ... )} is the return stack. \texttt{n} a signed number,
\texttt{u} an unsigned one, \texttt{d} and \texttt{ud} double-cell numbers,
\texttt{q} a Q48.16 fixed-point number, \texttt{x} any cell, \texttt{flag}
a truth value (0 false, -1 true), \texttt{c} a character, \texttt{addr} a
cell address, \texttt{baddr} a byte address, \texttt{xt} an execution token.
\textbf{xxx.} Where a word reads a name or text from the input stream, the
description shows it, as \texttt{' xxx} or \texttt{.\textquotedbl{} text\textquotedbl}.
\mainmatter
\input{dictionary-words}
\end{document}
@@ -15,9 +15,9 @@ Captain Bob, 2026-11-10: "Do it" -- the rest of alpha.4 that lives in the tree,
## #157 -- the dictionary of v4, and the .com's Documents page
- [x] the live word list of the built system (318 words): `v4/tools/mkdictionary.py words` -- the hosted v4's `WORDS` (317) plus the kernel's `sk_v4_words[]` (`MINT-ZUSE`)
- [~] the table in the tree, `docs/reference/v4-dictionary.tsv`: drafted for all 318 (`mkdictionary.py draft`; the source gave a stack comment for 54, a description for 105); the rest written by hand in batches, alphabetical -- next: batch 1
- [x] the check: `mkdictionary.py check` -- every live word has a finished entry, every entry a live word (fails on all 318 drafts today, as it should); not yet in the build
- [ ] the PDF, alphabetical; `make dictionary`; the nightly's docs stage, classifier `dictionary`
- [x] the table in the tree, `docs/reference/v4-dictionary.tsv`: all 318 entries, written in three alphabetical batches against v4's own definitions (the source gave 54 stacks and 105 descriptions to start from); `check` passes
- [x] the check: `mkdictionary.py check` -- every live word has a finished entry, every entry a live word; run by `make dictionary`, so a stale table fails the build and the nightly
- [x] the PDF, alphabetical: `make dictionary` -> `build/docs/Dictionary.pdf` (20 pages; `docs/book/dictionary.tex`); the nightly's docs stage builds it, `publish` sends classifier `dictionary`, the release attaches it
- [ ] the Documents page: canvas artboard, then `site/com`
## #126 -- the Downloads page live
+5 -1
View File
@@ -43,6 +43,7 @@
# (make -C docs/formal doxygen), into build/nightly-docs/.
# scripts/nightly.sh publish-docs <URL>
# org.starship:documentation:<VERSION>: classifier book, fabric (The Book of Fabric, #138),
# dictionary (The Dictionary of v4, #157 -- it fails the stage if a live word has no entry),
# vol1, vol2, vol3, api (pdf).
#
# VERSION is <LITHOS_VERSION>-SNAPSHOT, or NIGHTLY_VERSION when set (a release sets it from its
@@ -175,9 +176,11 @@ docs)
rm -rf "$DOCS"; mkdir -p "$DOCS"
make --no-print-directory docs
make --no-print-directory fabric
make --no-print-directory dictionary
make --no-print-directory -C docs/formal vols doxygen
cp build/docs/LithosAnanke.pdf "$DOCS/book.pdf"
cp build/docs/BookOfFabric.pdf "$DOCS/fabric.pdf"
cp build/docs/Dictionary.pdf "$DOCS/dictionary.pdf"
for v in 1 2 3; do cp "docs/formal/build/vol$v/main.pdf" "$DOCS/vol$v.pdf"; done
cp docs/formal/build/doxygen/StarForth-API-Reference.pdf "$DOCS/api.pdf"
(cd "$DOCS" && sha256sum ./*.pdf | tee SHA256SUMS)
@@ -220,8 +223,9 @@ print(json.dumps(notes.strip() + "\n\n## Checksums (SHA-256)\n\n```\n" + sums.st
;;
publish-docs)
url=${2:-}; [ -n "$url" ] || usage
need "$DOCS/book.pdf" "$DOCS/fabric.pdf" "$DOCS/vol1.pdf" "$DOCS/vol2.pdf" "$DOCS/vol3.pdf" "$DOCS/api.pdf"
need "$DOCS/book.pdf" "$DOCS/fabric.pdf" "$DOCS/dictionary.pdf" "$DOCS/vol1.pdf" "$DOCS/vol2.pdf" "$DOCS/vol3.pdf" "$DOCS/api.pdf"
deploy "$url" documentation "$DOCS/book.pdf" pdf book "$DOCS/fabric.pdf" pdf fabric \
"$DOCS/dictionary.pdf" pdf dictionary \
"$DOCS/vol1.pdf" pdf vol1 "$DOCS/vol2.pdf" pdf vol2 "$DOCS/vol3.pdf" pdf vol3 \
"$DOCS/api.pdf" pdf api
;;
+3
View File
@@ -160,6 +160,9 @@ def main():
stack, desc = table.get(w, ("", ""))
rel = defs.get(w, ("", "", ""))[0]
cell = lambda x: x.replace("|", "\\|")
# a token with a quote in it is FORTH (." text" S" ABORT"): set as code, so its
# quotes print straight, not as typographic ones
desc = re.sub(r'(\S*"\S*)', lambda mm: "`" + mm.group(1) + "`", desc)
f.write(f"| `{cell(w)}` | `{cell(stack)}` | {cell(desc)} | `{rel}` |\n")
print(f"mkdictionary: {out}, {len(words)} words")
return