HGPPascal is a small Pascal compiler written in Clojure. It currently compiles
a Turbo Pascal-style subset into portable C99, textual Pascal P-Code, or JVM
.class files, and can build native M3/arm64 or x86_64 executables through
generated C and GCC.
The project is designed as a GitHub-ready starting point for a larger Turbo Pascal-compatible compiler, with a real lexer, parser, AST, code generators, runnable examples, tests, CI, and a legal notice separating compatibility work from any Borland-owned material.
See FEATURES.md for the fuller feature matrix and compatibility roadmap.
See docs/ARCHITECTURE.md for the SECD/Visitor/Descriptor direction.
See docs/BACKEND_STANDARDS.md for C, JVM, and P-Code debug/profile contracts.
uses clauses, unit/interface/implementation, const, var, begin ... end.if ... then ... else, while, repeat ... until, and for ... to/downto{ ... }, (* ... *), and // ...nil, @, and pointer dereference with ^object types with fields, methods, Self^, and method callscapture, and higher-order callssqrt, pow, round, mod, trigonometric, logarithmic, and rounding functionsnew/dispose+, -, *, /, div, mod, and, or, not, comparisonswrite, writeln, readln, inc, dec, new, dispose, haltcase, with, goto, labels, packed types, file typesCompile Pascal to C:
clojure -M:run examples/hello.pas -o out/hello.c
Then compile the generated C with your system compiler:
cc out/hello.c -o out/hello
./out/hello
Generate Pascal P-Code:
clojure -M:run examples/hello.pas --target pcode -o out/hello.pcode
The P-Code format is documented in docs/P_CODE.md. It uses a readable
stack-machine IR plus explicit HGPPascal extensions for runtime services,
arrays with Pascal lower bounds, and Turbo Pascal-style built-ins.
Generate JVM class files:
clojure -M:run examples/hello.pas --target jvm -o out/classes
java -cp out/classes Hello
The same bytecode backend is also available as --target bytecode,
--target java-bytecode, or --target jvm-bytecode.
The JVM backend is documented in docs/JVM_BACKEND.md. It generates Java as
an internal lowering step and uses the JDK compiler to produce real .class
files.
Compile a program that uses a source-backed Pascal unit:
clojure -M:run examples/unit_uses_demo.pas --target c -o out/unit_uses_demo.c
The compiler resolves uses MathUtil; by loading MathUtil.pas next to the
main source file. Programmatic callers can pass unit source strings through the
:unit-sources compile option.
Build a native executable through C and GCC:
clojure -M:run examples/hello.pas --target native-m3 -o out/hello-m3
clojure -M:run examples/hello.pas --target native-x86_64 -o out/hello-x86_64
clojure -M:run examples/numeric_runtime.pas --target native-m3 -o out/numeric-runtime-m3
The native pipeline is lexer -> parser -> AST -> unit resolver -> C code ->
GCC. On Apple platforms the generated GCC command uses -arch arm64 for M3 and
-arch x86_64 for x86_64. Use --gcc <command> to select a GCC-compatible
compiler and --native-source out/hello.c to keep the generated C file.
The generated C and JVM outputs include the SECD/SSTD/NUMERIC/HEAP runtime
support inside the artifact. P-Code carries a RUNTIME_BLOCK hgppascal_runtime block so a future P-Code executable host can discover and
invoke the attached runtime engines.
Enable the optional backend optimization triple:
clojure -M:run examples/hello.pas --target pcode --backend-optimizations -o out/hello.opt.pcode
Or enable a canonical-order subset:
clojure -M:run examples/hello.pas --target c --backend-optimization-passes register-allocation,peephole -o out/hello.opt.c
Run the test suite:
clojure -M:test
Or use Leiningen:
lein test
lein run examples/hello.pas --target c -o out/hello.c
See docs/EXAMPLES.md for the full example guide.
| Example | Feature Focus |
|---|---|
examples/hello.pas |
Basic program, loop, output |
examples/control_flow.pas |
for, if, repeat, inc, dec |
examples/record_fields.pas |
Record type and field access |
examples/record_pointer.pas |
Typed pointers, @, ^, nil |
examples/pointer_new_dispose.pas |
new, dispose, nil-after-dispose |
examples/precedence_numeric_tower.pas |
Operator precedence and real division |
examples/runtime_calls.pas |
Runtime built-ins |
examples/function_call_table.pas |
User functions and call-table metadata |
examples/object_methods.pas |
Turbo Pascal 5.5-style objects, Self^, and method calls |
examples/higher_order_lambda.pas |
Function type aliases, capture, and higher-order lambdas |
examples/unit_uses_demo.pas |
uses, source-backed units, and unit initialization |
The test suite compiles every example through the C, P-Code, and JVM backends.
program Hello;
var
i: integer;
begin
writeln('HGPPascal');
for i := 1 to 3 do
writeln('line ', i);
end.
HGPPascal is independent. It aims for source compatibility with Pascal features
historically associated with Turbo Pascal, but it does not include Borland
source code, manuals, binaries, or copyrighted assets. See NOTICE.md.