A hand-written tokenizer and recursive-descent parser converts the raw source text directly into the typed `Program` AST defined in `src/ast.rs`. RPG IV keywords are case-insensitive and the parser handles mixed-case source naturally.
Unrecognised constructs produce `Statement::Unimplemented` or placeholder declaration variants rather than hard errors, so the compiler continues to lower the parts it understands.
The typed `Program` is handed to the code generator, which uses [`inkwell`](https://crates.io/crates/inkwell) (safe Rust bindings to LLVM 21) to build an LLVM IR module:
- Each `DCL-PROC … END-PROC` becomes an LLVM function.
- An exported procedure named `main` (or the first exported procedure) is wrapped in a C `main()` entry point so the resulting binary is directly executable.
-`DCL-S` standalone variables are allocated as `alloca` stack slots inside their owning function, or as LLVM global variables for module-scope declarations.
- String literals are stored as null-terminated byte arrays in `.rodata`.
-`DSPLY expr;` is lowered to a call to `rpg_dsply(ptr, len)` (or `rpg_dsply_i64` / `rpg_dsply_f64` for numeric types) provided by the runtime library.
- Control-flow constructs (`IF`, `DOW`, `DOU`, `FOR`, `SELECT`) are lowered to LLVM basic blocks and conditional / unconditional branches.
-`LEAVE` / `ITER` are lowered to `br` to the loop-exit / loop-header block respectively, tracked via a `FnState` per function.
The module is then compiled to a native `.o` object file for the host target via LLVM's target machine API, with optional optimisation passes (`-O0` through `-O3`).
The object file is linked into a standalone ELF executable by invoking the system C compiler (`cc`). The executable is linked against `librpgrt.so`.
### Runtime library (`rpgrt/`)
`rpgrt` is a separate Cargo crate built as a `cdylib`, producing `librpgrt.so`. It is written in Rust and exports a C ABI used by compiled RPG programs:
| Symbol | Signature | Purpose |
|--------|-----------|---------|
| `rpg_dsply` | `(ptr: *const u8, len: i64)` | Display a fixed-length `CHAR` field (trims trailing spaces) |
| `rpg_dsply_cstr` | `(ptr: *const c_char)` | Display a null-terminated C string |
| `rpg_dsply_i64` | `(n: i64)` | Display a signed 64-bit integer |