Dive
A single-page technical overview of PXX, verified against this checkout. The rest of the documentation, linked at the end, covers each topic in depth.
Overview
PXX is a from-scratch, self-hosting Pascal compiler. It emits Linux ELF executables directly: no external assembler, no external linker, and no libc dependency in the default build path. The lexer, parser, intermediate representation, all six backends, the runtime library, and the GTK-based component library are original code written for this project. The dialect follows Free Pascal's naming and semantics where practical, but the implementation is independent — nothing is copied or ported from FPC, Borland, or elsewhere.
Example
program hello;
begin
writeln('Hello, world!');
end.
./pxx hello.pas hello
./hello
Hello, world!
This produces a complete static ELF binary in one step, with no external assembler, linker, or C compiler invoked during the build.
Design points
-
Self-hosting. The compiler is written in its own dialect, and every change is gated on it compiling itself to a byte-identical fixed point: the compiler builds the compiler, that result builds the compiler again, and the two must be equal to the byte. This runs natively, at the default optimisation level; the other self-hosting targets are covered by the cross-target suites in the test matrix rather than by the per-change gate.
-
Two string ABIs. The default build uses managed, reference-counted strings. Compiling with
-uPXX_MANAGED_STRINGselects an older frozen-string ABI with no dynamic allocation for strings. For ahello worldthat is onewriteln, the difference is about 15x:executable default (managed strings) 68,376 bytes -uPXX_MANAGED_STRING(frozen)4,408 bytes, statically linked Measured 2026-09-05 at commit
ce19e5482and identical under the pinned compiler, so re-running it is the check: compileprogram hello; begin writeln('hello world'); end.both ways and compare. Both binaries are already stripped;stripchanges neither. Expect these numbers to move as the RTL does — they are a ratio worth knowing, not a guarantee. See Types. -
Six code-generating targets, one compiler. x86-64, i386, aarch64, and arm32 self-host byte-identical. riscv32 covers both bare-metal ESP32-C3 and hosted 32-bit RISC-V Linux, whose binaries run under
qemu-riscv32; xtensa targets the ESP32-S2/S3. The three cross self-hosts are proved by a triple-stage check — cross-compile the compiler, run that binary under QEMU to compile the compiler again,cmpthe two — and are run in the managed-string build, which thecross-bootstraprule states is required for them; the native fixedpoint passes no build flags at all. Same property, two configurations, worth naming because "all four self-host" reads as one gate and is two.--target=selects the backend, and Targets is the table that stays current. -
Multiple frontends. The same backend also compiles a C frontend (tested against real-world C, including SQLite and Lua sources), a statically-typed Python-like dialect (Nil Python,
.npy), and an assembly-source frontend. -
It boots. PXX compiles a BusyBox userland — as separate translation units, matching a GCC build of the same sources over a differential case list — and links it with no C library at all.
tools/mkminimal.shpackages that shell, a stock Linux kernel and the compiler itself into one BIOS+EFI ISO: a system whose entire userland is PXX output, and on which the compiler compiles and runs both Pascal and C — the latter against PXX's own C runtime, measured in the guest. Two things that image is not — the kernel is not ours, and it ships no compiler sources, so the self-host fixed point is proved in a separate, larger VM image rather than on the ISO. See A minimal Linux system.
<details markdown="1"> <summary>Compilation pipeline</summary>
Compilation proceeds through five stages, with no external tools invoked:
- Lexer — source text to tokens. Dispatched by file extension:
.pasPascal,.cC,.npyNil Python,.basearly BASIC. - Parser — tokens to an AST. Frontends share expression-parsing and type-checking where their semantics overlap.
- IR — the AST lowers to a linear, target-agnostic intermediate representation.
- Codegen — the IR lowers to target machine bytes. Six backends share one IR.
- ELF writer — the compiler's own linker. Static output by default;
PT_DYNAMIC/DT_NEEDED/GOT/PLT are added automatically when a C library is imported.
Optimization runs at -O2 by default (peephole passes, procedure inlining,
and dead-code elimination, tiered by -O level); -O0 disables it. The
self-host fixedpoint is proved at the default level, not at -O0 — the
compiler rebuilds itself with no -O flag at all, so "it reproduces itself" is a
statement about one optimisation level. There is no whole-program or
SSA-based optimizer — the passes are local and the emitted code stays close to
the source. See the command-line reference
for the -O levels.
See Architecture for the full pipeline. </details>
<details markdown="1"> <summary>Current status</summary>
Established: the core Pascal language — classes, interfaces, generics,
exceptions, managed strings, dynamic arrays — compiles on all four Linux
self-host targets. A minimal class-based program was verified to build
cleanly on x86-64, i386, aarch64, and arm32 while writing this page. The C
and Nil Python frontends compile against real-world C headers and libraries.
DWARF debug information (-g) is available on all four Linux targets.
Known gaps: xtensa and riscv32 are not self-host targets — the compiler emits
for them but does not compile itself with them (though classes with virtual
dispatch now work on both).
Optimization is local only — there is no whole-program or SSA-based pass.
Integer overflow, range, and IO checking exist but are opt-in per region
({$Q+}, {$R+}, {$I+}); the lax default wraps and does not range-check.
Member visibility (private/protected/strict) is enforced only under
--strict-visibility; the lax default parses the markers but grants access
anywhere. Nil Python has no pointer syntax of its own. See Limits for the
complete list.
PXX is early, experimental software. It should not be used for security-sensitive, safety-sensitive, financial, legal, or medical work. </details>
<details markdown="1"> <summary>Licensing</summary>
PXX is open source, licensed per directory: the compiler is MPL 2.0, the
runtime and libraries (lib/**, compiler/builtin/) are zlib, examples are
0BSD, and these docs are CC BY 4.0. Because the zlib-licensed runtime is what
gets embedded into every binary, programs you compile with PXX carry no license
obligations from the toolchain. See Licensing for
the full table and rationale, or
LICENSE.md for the
binding terms.
</details>