A FORTRAN-66 / DEC FORTRAN-10 interpreter in Python
Project description
forterp
Software Architecture, Design & Engineering by Nicholas J. Kisseberth.
Code Synthesized via Anthropic Claude Code / Opus 4.8.
Automated Code Review via OpenAI Codex / ChatGPT 5.5.
A configurable FORTRAN-66 interpreter in Python: the machine value model and the front-end dialect are both pluggable, so one core runs FORTRAN against whatever representation you select.
The value model is a Target — integer word width and overflow, the logical-truth
convention, and how characters pack into words. Two ship:
NATIVE(the default) — a clean 64-bit host machine for running standard FORTRAN-66 portably: 64-bit two's-complement integers, 8-bit ASCII,.TRUE.=1 with boolean logical operators.import forterp; forterp.run_source(...)uses this.PDP10— the DEC FORTRAN-10 model: 36-bit two's-complement words, 5×7-bit packed character storage,.TRUE.=−1 with bit-wise logicals. Select withEngine(..., target=forterp.PDP10).
The PDP-10 target was extracted from an interpreter built to run real 1970s DEC FORTRAN unmodified, so it is exercised against real period code — not just toy snippets — and validated against the DEC FORTRAN-10 V5 manual and the FCVS conformance corpus.
Install
pip install forterp # (once published)
# or, from a checkout:
pip install -e .
Quick start
import forterp
# The default dialect is strict ANSI F66; FORTRAN10 enables the DEC niceties
# (here the quoted-string FORMAT -- F66 itself uses Hollerith nH). Note fixed form:
# the statement label sits in columns 1-5 and the body starts in column 7.
eng = forterp.run_source(''' PROGRAM HELLO
WRITE(6,10)
10 FORMAT(' HELLO, WORLD')
END
''', dialect=forterp.FORTRAN10, printer=print)
Lower-level building blocks (the expert surface lives under forterp.runtime):
units = forterp.parse_source(src) # {name: ProgramUnit}
eng = forterp.runtime.make_engine(units) # Engine with the FORTRAN-10 runtime installed
eng.run_program("MAIN") # or run_program() for the first unit
The package root exposes only the focused names above; the rest is organized into
namespaces: forterp.runtime (the Engine and builders), forterp.frontend (lexer/parser
stages), forterp.format (the FORMAT engine), forterp.ast (AST nodes), forterp.hostlib
(host-builtin marshalling), and forterp.debug (the interactive tracer/profiler and the
out-of-bounds census — forterp.debug.oob_census() counts or logs the faithful unchecked-array
accesses without changing them).
Command line
Installing puts three commands on your PATH — thin dialect front-ends over the engine
(like g77/gfortran over gcc):
pyf66 prog.for # run as strict ANSI FORTRAN-66 (rejects DEC extensions)
pyfortran10 prog.for # run as DEC FORTRAN-10 (the superset: octal, IMPLICIT, '...', …)
forterp --std fortran10 prog.for # general driver; --std f66|fortran10 (default: f66)
--target native|pdp10|vax selects the value model and --program NAME picks the main
unit. --check parses and lists every diagnostic without running (a compile-check) — so
pyf66 --check prog.for is a strict-ANSI-F66 conformance linter. --version prints the
version, --help the usage. Before install, use python -m forterp ….
Pass several source files and they are linked together by unit name, the way a compiler links separately-compiled units — so a driver and a separately-held library run as one program:
forterp main.for lib.for # main.for's PROGRAM calls SUBROUTINEs in lib.for
Launched with no file, each command drops into an interactive command processor (a small,
FORTRAN-focused descendant of the TOPS-10 . prompt — it operates on whole source
files, not a statement REPL, since F66 has no incremental-execution model):
f66> RUN prog.for # compile + run (alias EXECUTE); CHECK = parse-only
f66> SET STD fortran10 # switch dialect, target, or main unit between runs
f10> LOAD prog.for # parse into the session; START runs it
f10> SHOW /BLOCK/ # inspect a COMMON block after a run; SHOW = settings
f10> !cmd @file HELP EXIT
The command set is identical across the three commands; only the starting dialect
differs (pyf66 → f66, pyfortran10 → fortran10), and SET STD flips it.
IMMEDIATE (alias REPL) drops into interactive FORTRAN — statements run as you type,
a DO loop is collected across lines, and a bare expression is evaluated (so typing a
name inspects it). After a LOAD, the REPL can call straight into the program:
f66* NFAC = 1
f66* DO 10 I=1,5
cont> NFAC = NFAC * I
cont> 10 CONTINUE
f66* NFAC # -> 120
f66* ISQ(9) # call a function from the LOADed program -> 81
f66* 2 + 3 * 4 # calculator -> 14
(COMMON/EQUIVALENCE need a full program unit — put those in a file and LOAD it;
F66 has no incremental model for control flow, so the unit of work is a statement or a
DO block, never a bare GOTO.)
The command processor also debugs and profiles a RUN/START. BREAK <line> + STEP drop into
a (dbg) prompt where you step (step/next/cont), backtrace (where), and inspect
any expression by typing it; TRACE echoes each statement; PROFILE/COVERAGE report
per-line execution counts and which lines were reached. The profiler counts statements
(deterministic), not wall-clock seconds. All of it rides one off-by-default hook, so a
plain run pays nothing:
f66> BREAK 6
f66> RUN fac.for
-- stopped at FAC:6 (Assign)
(dbg) NF # inspect a variable by name -> 1
(dbg) where # backtrace -> #0 FAC:6
(dbg) cont
f66> PROFILE # 5 FAC:6 (the loop body ran 5 times)
What's pluggable
- Machine target —
forterp.Target(word_bits, chars_per_word, logical_true, bitwise_logic, bits_per_char, little_endian, truth)fixes the value model.forterp.NATIVE(64-bit, 8-bit ASCII, boolean logicals) is the default;forterp.PDP10(36-bit, 5×7-bit packed,.TRUE.=−1, bit-wise logicals) is the DEC target;forterp.VAX(32-bit, little-endian, low-bit logical) is a provisional, unvalidated guess. PassEngine(..., target=...). - Front-end dialect —
forterp.FORTRAN10(DEC extensions on) vsforterp.F66(ANSI). Threaded through the source reader and lexer. - OPEN devices —
eng.register_device(name, handler)plugs in special devices. - Unformatted I/O codec —
forterp.runtime.install_runtime(eng)wires the FOROTS binary-record + DEC-10 float codec used by binaryREAD/WRITE.
Supported language
Standard FORTRAN-66 (arithmetic/logical/relational expressions, the full control-flow
set, DO loops with F66 one-trip semantics, COMMON/EQUIVALENCE storage association,
DATA, subprograms + ENTRY, statement functions), formatted + list-directed +
unformatted I/O with the complete FORMAT edit-descriptor set, ENCODE/DECODE, and
the DEC FORTRAN-10 extensions (octal literals, Hollerith, IAND/IOR/shift intrinsics,
tab-format source, random-access READ(u'r)). See docs/.
Examples & demos
Two directories of runnable material:
examples/— short Python scripts showing how to use forterp as a library: running source and capturing output, choosing a dialect or target, feeding input viareadline, and reading results back out ofCOMMON. Start withexamples/run_and_capture.py.demos/— genuine 1970s FORTRAN to run through the interpreter: verbatim netlib numerical libraries (EISPACK, LINPACK, FFT, RKF45) each with a small driver, DECsystem-10 sources recovered from DECUS tapes, and a 1971 Game of Life. Every one is real period source, run as-is — the corpus that flushes out interpreter gaps.
Tests & lint
pip install -e ".[dev]"
pytest
ruff check # lint (config in pyproject.toml)
ruff format --check # formatting — run `ruff format` to apply
The suite is the interpreter's unit tests plus the FCVS (FORTRAN Compiler Validation System) conformance corpus — the standard-conformance audits — exercised through the real source-reader → lexer → parser → engine pipeline.
Security & trust model
forterp is an interpreter, not a sandbox. A program it runs executes with the full
privileges of the invoking process: FORTRAN OPEN/READ/WRITE reach the real
filesystem, and an absolute path or one containing .. reads or writes files outside
the save_root base directory. There is no network access, Python eval, or subprocess
reachable from a FORTRAN program — but file access alone means you should not run
untrusted source expecting containment. To run code you don't trust, confine the process
at the OS level (an unprivileged user, a container, a read-only filesystem, seccomp).
Two guards keep an accidental or hostile program from taking down the host, each raising a
clean error rather than hanging or OOM-ing: a statement budget (eng.max_steps, default
50M) bounds execution, and max_array_words (default 50M, settable on the Engine /
make_engine) bounds array/COMMON allocation — including DATA repetition counts and
EQUIVALENCE extension, not just a bare DIMENSION. INCLUDE resolves only within its base
directory (the CLI uses the source file's own directory; the library default is the current
directory), and its 'FILE/SWITCH' target is split on /, so it cannot escape via an
absolute or .. path. These bound resource use; they are not a security sandbox — file
access via OPEN is unrestricted, so still confine genuinely untrusted source at the OS
level.
The interactive command processor additionally offers a ! shell escape and @file command scripts
(not reachable from a running FORTRAN program); these run with your shell's privileges, so
treat a command script as trusted input and don't wire the command processor to an untrusted source.
Authorship & attribution
- Software Architecture, Design & Engineering by Nicholas J. Kisseberth.
- Code Synthesized via Anthropic Claude Code / Opus 4.8.
- Automated Code Review via OpenAI Codex / ChatGPT 5.5.
License
© 2026 Nicholas J. Kisseberth · forterp is MIT-licensed.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file forterp-0.1.0.tar.gz.
File metadata
- Download URL: forterp-0.1.0.tar.gz
- Upload date:
- Size: 585.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ccad8a4aef626c229cd9ccd2f77eb5fe63ef9633bd2081c8be138a3ba7710469
|
|
| MD5 |
bc70e4caf92048a5acfbc35495b870c0
|
|
| BLAKE2b-256 |
87ae4e1dda995df2664467b34cf021568cea2a1edf0a338bcaac62d88ba4dc09
|
Provenance
The following attestation bundles were made for forterp-0.1.0.tar.gz:
Publisher:
release.yml on nyxcraft/forterp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forterp-0.1.0.tar.gz -
Subject digest:
ccad8a4aef626c229cd9ccd2f77eb5fe63ef9633bd2081c8be138a3ba7710469 - Sigstore transparency entry: 1940320043
- Sigstore integration time:
-
Permalink:
nyxcraft/forterp@7a47e11ed40aed69ca284124d97ad5057d857387 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nyxcraft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7a47e11ed40aed69ca284124d97ad5057d857387 -
Trigger Event:
push
-
Statement type:
File details
Details for the file forterp-0.1.0-py3-none-any.whl.
File metadata
- Download URL: forterp-0.1.0-py3-none-any.whl
- Upload date:
- Size: 121.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5c071f3a19a6ec33c77baaac779854e91ca0ff50807814fe556fa0be2d892979
|
|
| MD5 |
31e65d7fc89d803295d5d86ce7ca4679
|
|
| BLAKE2b-256 |
cce76be01231fba9e21af83b46a7eaa44ea938a948c18e079587a0a014a3a7e7
|
Provenance
The following attestation bundles were made for forterp-0.1.0-py3-none-any.whl:
Publisher:
release.yml on nyxcraft/forterp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
forterp-0.1.0-py3-none-any.whl -
Subject digest:
5c071f3a19a6ec33c77baaac779854e91ca0ff50807814fe556fa0be2d892979 - Sigstore transparency entry: 1940320121
- Sigstore integration time:
-
Permalink:
nyxcraft/forterp@7a47e11ed40aed69ca284124d97ad5057d857387 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/nyxcraft
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@7a47e11ed40aed69ca284124d97ad5057d857387 -
Trigger Event:
push
-
Statement type: