NitroPascal
NitroPascal is a full-featured Object Pascal compiler built entirely on top of Parse() - the compiler construction toolkit. It exists to prove a point: a complete, production-quality language can be built with Parse() without touching a parser generator, a lexer generator, or a custom pipeline.
Install / Use
/learn @tinyBigGAMES/NitroPascalREADME

What is NitroPascal?
NitroPascal is Object Pascal. It compiles to native binaries via C++23.
NitroPascal is a full-featured Object Pascal compiler built entirely on top of Parse() - the compiler construction toolkit. It exists to prove a point: a complete, production-quality language can be built with Parse() without touching a parser generator, a lexer generator, or a custom pipeline. Every stage - tokenization, Pratt parsing, semantic analysis, C++23 code generation, and native compilation via Zig - is driven through a single Parse() configuration object.
program Hello;
begin
WriteLn('Hello from NitroPascal!');
end.
NitroPascal is not a toy. It is a working Pascal compiler that handles programs, procedures, functions, typed variables, arrays, sets, pointers, records, string manipulation, math, and memory management - all the things you would expect from a real Pascal implementation. The generated output is clean C++23, compiled to a native Win64 or Linux64 binary by the Zig/Clang backend that ships with ParseKit.
NitroPascal is the reference showcase for the Parse() Compiler Construction Toolkit. If you want to see what a full language looks like when built on Parse(), this is it. Read the source. Every grammar rule, every semantic check, every code emitter is a Parse() registration call - nothing more.
🚧 Under Construction
NitroPascal is actively developed. The foundation is solid and the core language works. More features are being added continuously.
✅ What Works Today
- Program structure -
program,var,const,type,begin..end. - Primitive types -
Integer,Double,Boolean,Char,String - Procedures and functions - full declarations, parameters (
const,var,out),Resultreturn convention - Control flow -
if/then/else,while/do,for/to/downto,repeat/until,case/of,break,continue,exit - Arrays - fixed arrays with arbitrary index bounds, dynamic arrays,
SetLength - Sets - Pascal set types,
Include,Exclude,inoperator - Pointers - typed pointer declarations,
^T,@expr, dereference, pointer type aliases - Records - field declarations, nested records, pass by value/ref/out, functions returning records
- Literals - integer, real, string, char (
#65), hex ($FF), boolean,nil - Intrinsics -
Inc,Dec,Ord,Chr,Succ,Pred,Odd,Assigned,Length,Copy,Pos,UpperCase,LowerCase,Trim,IntToStr,StrToInt,StrToIntDef,StringOfChar,Abs,Sqr,Sqrt,Max,Min,Round,Trunc,New,Dispose - I/O -
WriteLn,Write
🔜 Planned / In Progress
- Classes and objects with inheritance and virtual dispatch
- Exception handling (
try/except/finally) - Enumerations
- Units and
usesclause - String escape sequences and extended string handling
- More intrinsics and RTL coverage
- Linux64 cross-compile support
🎯 Why NitroPascal?
NitroPascal serves two audiences.
If you write Pascal, NitroPascal gives you a path from .pas source to a native binary without a legacy toolchain. Write standard Object Pascal, get a fast, small native executable. Just the NitroPascal compiler and the bundled Zig backend.
If you build languages, NitroPascal is the definitive answer to "can Parse() handle a real language?" Browse src/NitroPascal.Lexer.pas, src/NitroPascal.Grammar.pas, src/NitroPascal.Semantics.pas, and src/NitroPascal.CodeGen.pas. Every feature maps directly to Parse() API calls. There is no magic, no custom parser, no hand-rolled AST infrastructure. If NitroPascal can implement full Pascal on Parse(), your language can too.
🔄 How It Works
NitroPascal is four source files and Parse():
NitroPascal.Lexer.pas - keyword and operator registration
NitroPascal.Grammar.pas - Pratt grammar rules (prefix + infix + statement handlers)
NitroPascal.Semantics.pas - type assignment and symbol resolution rules
NitroPascal.CodeGen.pas - C++23 emitters for every AST node kind
Each file is a set of AParse.Config().Register*() calls. That is the entire compiler. Parse() provides the tokenizer, the Pratt parser engine, the scope-aware semantic walker, the C++23 IR builder, and the Zig compilation backend. NitroPascal provides the language definition.
Pascal source
|
v
+-----------+ tokens +----------+ AST +------------+
| Lexer | --------> | Parser | -----------> | Semantics |
| (Parse()) | | (Parse())| | (Parse()) |
+-----------+ +----------+ +------------+
|
enriched AST (type, scope, decl)
|
v
+-----------+
| CodeGen | --> .h + .cpp
| (Parse()) |
+-----------+
|
v
+---------+
| Zig | --> native binary
+---------+
🚀 Getting Started
Prerequisites: Directory Layout
NitroPascal requires the ParseKit sources to be present as a sibling directory alongside NitroPascal. The Delphi project references ParseKit's source directly. The required layout is:
C:\Dev\ <- or any root you choose
ParseKit\ <- ParseKit repo root (contains src\, bin\, etc.)
NitroPascal\ <- NitroPascal repo root (contains src\, bin\, etc.)
Both repos must share the same parent directory. If they do not, the Delphi project will not compile.
Step 1: Get ParseKit
Option 1: Download ParseKit ZIP
Option 2: Git clone
git clone https://github.com/tinyBigGAMES/ParseKit.git
Place (or clone) it so the folder structure matches the layout above.
Step 2: Get NitroPascal
Option 1: Download NitroPascal ZIP
Option 2: Git clone
git clone https://github.com/tinyBigGAMES/NitroPascal.git
Step 3: Download the Toolchain
The toolchain must be downloaded separately. It contains the Zig compiler and C++ runtime that NitroPascal uses to compile generated code to native binaries. Without it, the pipeline cannot produce binaries.
Download parsekit-toolchain.zip
Unzip the toolchain directly into the root of your NitroPascal directory:
NitroPascal\ <- repo root
bin\ <- toolchain contents go here (zig\, res\, etc.)
src\
...
This is a permanent release entry. The URL will never change. When the toolchain is updated, the same release entry is replaced in place. You always download from the same link.
System Requirements
| | Requirement |
|---|---|
| Host OS | Windows 10/11 x64 |
| Linux target | WSL2 + Ubuntu (wsl --install -d Ubuntu) |
| Delphi | Delphi 11 Alexandria or later (to build from source) |
Step 4: Open in Delphi and Build
- Open
src\NitroPascal.groupprojin Delphi - Build all projects in the group (
NitroPascal,Testbed) - The
Testbedproject compiles and runs all tests inbin\res\tests\and prints colour-coded pass/fail results
Step 5: Compile a Pascal Program
cd NitroPascal\bin
testbed
Or call the compiler programmatically:
uses
NitroPascal;
var
LCompiler: TNitroPascal;
begin
LCompiler := TNitroPascal.Create();
try
LCompiler.SetSourceFile('hello.pas');
LCompiler.SetOutputPath('output');
if LCompiler.Compile(True) then
WriteLn('Done.')
else
WriteLn('Failed: ', LCompiler.GetLastError());
finally
LCompiler.Free();
end;
end;
📖 Language Sample
program Showcase;
var
i: Integer;
s: String;
arr: array[1..5] of Integer;
flags: set of (0..7);
function Factorial(const AValue: Integer): Integer;
begin
if AValue <= 1 then
Result := 1
else
Result := AValue * Factorial(AValue - 1);
end;
begin
// Arithmetic and string intrinsics
s := 'Hello, NitroPascal!';
WriteLn(UpperCase(s));
WriteLn('Length: ', IntToStr(Length(s)));
// Arrays (1-based indexing)
for i := 1 to 5 do
arr[i] := i * i;
WriteLn('Squares: ', arr[1], ' ', arr[2], ' ', arr[3], ' ', arr[4], ' ', arr[5]);
// Sets
flags := [1, 3, 5];
Include(flags, 7);
if 3 in flags then
WriteLn('3 is in flags');
// Recursion
for i := 1 to 7 do
WriteLn(IntToStr(i) + '! = ' + IntToStr(Factorial(i)));
end.
🤝 Contributing
NitroPascal is an open project. Whether you are fixing a bug, improving documentation, adding a language feature, or writing a new test case, contributions are welcome.
- Report bugs: Open an issue with a minimal reproduction. The smaller the example, the faster the fix.
- Suggest features: Describe the use
