This repository contains a native compiler for the 1981 IBM Pascal dialect. It targets LLVM IR, the System V AMD64 ABI, and NVIDIA NVPTX.
If you write Pascal in this repository, read
docs/dialect_notes.mdfirst. The notes cover what the vintage and extended dialects each provide. They show the width of each integer type. They list the constructs that fail without an error. For example,TRUNCnarrows the result to 16 bits.
Install these packages before you build the toolchain (for example, on Debian or Ubuntu Linux x86_64):
clang(C compiler and linker)make(build tool)libllvm-20-dev/llvm-20(LLVM 20 library and headers)libcjson-dev(cJSON library and headers)indent(C code formatting tool)python3andpip3with the reference compiler package:pip3 install 'https://github.com/jamesmcclain/pascal-1981/archive/5fe71893fd8b16a415a6c67c2fad12bd729e7279.zip'
src/: Native compiler stages and driver in Pascal (lexer.pas,parser.pas,typechecker.pas,codegen.pas,driver.pas,jsonutil.pas,jsonutil.inc). The codegen stage is a composition root over fourteen separately compiled units. Each unit has a.incinterface and a.pasimplementation. The units layer lowest first. Each unit depends only on units at a lower layer:argparse: command-line argument parsing (shared by parser, typechecker, and codegen).features: shared language-feature resolution for the two dialects.cg_base: shared compiler state, LLVM-C and libc prototypes, constants and record types.cg_util: diagnostics, depth guards, string and pointer-array helpers.cg_types: the type registry, sizing and layout, constant folding, SysV classification.cg_symbols: symbol, scope and routine tables.cg_expr_shape: type-only expression-shape queries. It emits no IR.cg_expr_sets: set operations on already-evaluated operands.cg_expr_support: leaf expression-lowering helpers. It never evaluates an AST node.cg_expr_literals: leaf lowering for assignments from compile-time string literals.cg_expr_vector: lowering forVECTOR [n] OF scalaroperations.cg_expr: expression lowering.cg_io: WRITE/READ lowering.cg_stmt: statement lowering.cg_decl: declaration lowering.
runtime/: C runtime static library and headers (libpascalrt.a,pascalrt.h).bin/: Compiler driver (pascal1981-native, aliaspascal1981) and stage binaries (lexer,parser,typechecker,codegen).scripts/: Build scripts (build-stage.sh), formatting scripts (beautify.sh), and git hooks (scripts/hooks). To enable the pre-commit formatting hook, rungit config core.hooksPath scripts/hooksonce per clone. This setting is local config. A fresh checkout does not enable the hook. The rootMakefiledrives the multi-generation bootstrap with thebootstraptarget. It is not a standalone script.tests/: Test suites (golden files, unit tests, integration tests, dialect fixtures).docs/: The EBNF grammar of the dialect. The dialect notes cover widths, literals, and silent failure modes.
To build the runtime, the driver, and all compiler stages (bootstrap):
makeBy default, the build uses llvm-config to determine the LLVM linker flags and libraries. If llvm-config is not in PATH, the build uses llvm-config-20. You can override the default by setting LLVM_CONFIG:
LLVM_CONFIG=llvm-config-20 makeYou can also override the C compiler/linker (default clang) with CC:
CC=clang-20 makeTo rebuild only the four compiler stages, run:
make bootstrapThen build the installed Pascal driver from the fixed-point stages:
make driverThe bootstrap process has four steps:
- Generation 1 (Hybrid): Builds the native compiler stages with the Python reference compiler (
pascal1981). - Generation 2 (Self-hosted): Recompiles all native compiler stages with the Generation 1 binaries.
- Generation 3 (Self-hosted): Recompiles all native compiler stages with the Generation 2 binaries.
- Generation 4 (Fixed Point): Recompiles all native compiler stages with the Generation 3 binaries and verifies binary identity (
cmp).make driverthen compilessrc/driver.paswith the fixed-point stages and installs it asbin/pascal1981-native(withbin/pascal1981as its alias).
To compile a Pascal program with the native compiler, run:
bin/pascal1981-native hello.pas -o hello
./helloSupported options:
-o <file>: Set output path-c: Compile to object file (.o)-S: Emit LLVM IR (.ll)-O0,-O1,-O2,-O3: Set optimization level--dialect <vintage|extended>: Select the language dialect (defaultvintage)--target-cpu <cpu>: Host target CPU, e.g.x86-64-v3(LLVMtarget-cpuattribute; default baseline x86-64)--target-features <list>: Host target features, comma-separated, e.g.+avx2,+fma--emit-ptx: Emit NVPTX assembly for device kernels-v: Print pipeline commands
Run the routine test suites:
make testThis target runs the driver, sysutil, native, proxy, and pre-commit-hook test groups. The test runners do not require pytest. The proxy tests need python3.
This target does not run the reference-parity, bootstrap, or Emacs tests.
Use these targets for a specific test group:
| Target | Test group |
|---|---|
make test-driver |
Driver, golden-file, and IR/PTX-text directive tests. No Python needed. |
make test-native |
Routine native compiler tests |
make test-sysutil |
POSIX filesystem and process primitives, exercised from Pascal |
make test-proxy |
Differential conformance for the completion proxy (needs python3) |
make test-gpu |
CUDA compilation and execution on an NVIDIA GPU |
make test-reference-parity |
Native compiler parity with the Python reference compiler |
make test-elisp |
Emacs major-mode ERT tests |
make test-bootstrap |
Clean bootstrap and fixed-point comparison |
If a CUDA prerequisite is not available, the test-gpu target skips the test.
The test-reference-parity target requires Python and pytest. The test-elisp target requires Emacs and builds the compiler stages first.
See tests/README.md. It describes the compiler test suites.
To run all available test groups, run:
make test-bootstrap test test-gpu test-reference-parity test-elisp