| | {{infobox |
| | | title = MALBR |
| - | | image = [[File:alb-logo-grid-mosaic.png|center|220px|AdaLogic BASIC — the language MALBR compiles]] |
| + | | image = [[File:malbr-logo.png|center|300px|The MALBR logo — rusted gears and metal lettering]] |
| | | name = MALBR — Micro ALB Rust |
| | | type = compiler — ALB to Rust source |
| | | written_in = [[Ada Programming Language|Ada]] (malbr.adb + emit_native_micro_rust.adb) |
| | | emits = `#![no_std]` / `#![no_main]` Rust + a `support.rs` runtime |
| | | companion = [[MALB]] — the same compiler written in ALB itself |
| | | memory_model = deterministic statics — fixed arena, no heap, no crates |
| | | status = draft spec freeze candidate — bootstrap compiler for MALB |
| | | repository = [https://github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language github.com/rockyoliver454/AdaLogic-BASIC] |
| | }} |
| | |
| | **MALBR** — *Micro ALB Rust* — is the second compiler in the AdaLogic BASIC |
| | toolchain, and the path by which ALB reaches machines its reference |
| | compiler cannot. Where [[ALB FASM backend|albt]] is a complete, |
| | batteries-included compiler that assembles FASM directly and serves the |
| | retro backends, MALBR is deliberately small: it translates ALB source into |
| | clean, deterministic `#![no_std]` Rust and hands the result to rustc, which |
| | brings cross-compilation to dozens of targets, a mature optimizer, bare-metal |
| | support, and an enormous linker ecosystem. MALBR does not try to be smarter |
| | than rustc — it emits predictable code and lets the backend machinery do |
| | what it was built to do. |
| | |
| | Its sibling is **MALB**: the same ALB→Rust compiler written in ALB itself, |
| | roughly 3,900 lines of it, compiled first by MALBR and then by itself — |
| | proven self-hosting through a byte-identical bootstrap fixpoint. Together |
| | they move ALB toward a two-flagship toolchain: `albt` as the reference |
| | compiler, and the MALBR/MALB pair as the road to embedded targets, foreign |
| | operating systems, and a compiler maintained in the language it compiles. |
| | |
| | ## Why a second compiler |
| | |
| | `albt` knows the whole language — the full builtin set, the special blocks, |
| | the sixteen targets from native x86-64 down to 6502 assembly. What it cannot |
| | easily do is reach the places ALB increasingly wants to go: small boards, |
| | embedded targets, toolchains the project does not own. A FASM-centric |
| | pipeline cannot piggyback on someone else's backend ecosystem. |
| | |
| | MALBR was created to fix exactly that gap. Rust already solves |
| | cross-compilation, optimization, and `no_std` bare-metal deployment — so |
| | MALBR emits Rust source rather than machine code, keeping itself small and |
| | auditable while inheriting everything rustc knows about target triples, |
| | linking, and code generation. The trade is explicit: one more language in |
| | the pipeline, in exchange for the widest backend reach a modern toolchain |
| | offers. |
| | |
| | ## What the output looks like |
| | |
| | Every MALBR program compiles to a crate with a fixed shape: |
| | |
| | ```frame The generated crate skeleton |
| | #![no_std] // every generated crate — embedded first |
| | #![no_main] |
| | #![allow(unused_unsafe)] // static-mut access nests unsafe blocks |
| | #![allow(unconditional_panic)] // bounds panics route to fault 101 |
| | #![allow(unused_parens)] |
| | ``` |
| | |
| | The program body lands in `fn _alb_main_body()`, behind a |
| | `#[no_mangle] pub extern "C" fn main()` that calls it and exits through |
| | `support::_alb_exit(0)`. File-scope `LET` declarations become `static mut` |
| | with `unsafe` access; routine-local `LET`s stay ordinary `let mut`s. |
| | String handling runs through a **static arena** — 64 KiB by default, |
| | resizable with `--arena <bytes>` — with `CLAIM`, `SWEEP`, and `DROP` as |
| | checkpoint/rewind/release controls. There is no heap and no crates.io |
| | dependency: the binary can be audited byte-for-byte and flashed directly. |
| | |
| | ### Fault codes — one trap door |
| | |
| | Every runtime trap in generated code funnels into a single function, |
| | `support::_alb_fault(code)` — the override point embedded ports replace: |
| | |
| | | Code | Trap | |
| | |------|------| |
| | | 21 | `REQUIRE` contract violated | |
| | | 22 | `ENSURE` contract violated | |
| | | 23 | range-type bound violated | |
| | | 24 | checked `+` `−` `*` overflow | |
| | | 25 | checked `/` `MOD` — division by zero or `MIN/-1` | |
| | | 26 | unset routine-typed field invoked | |
| | | 27 | `ASSERT` failed | |
| | | 74 | `--strict-io` I/O failure | |
| | | 101 | panic — bounds, arena exhaustion, unreachable | |
| | |
| | A bare-metal port can hang, log over UART, or blink an LED on any of these — |
| | the generated code never decides the policy. |
| | |
| | ## The support ABI — porting is six functions |
| | |
| | MALBR's runtime boundary is `support.rs`, a three-file facade: |
| | |
| | | File | Role | |
| | |------|------| |
| | | `support.rs` | facade — `ALB_ABI_VERSION = 1` plus two `include!`s; never edited | |
| | | `alb_core.rs` | **tier 1 — the port**: `_alb_putchar`, `_alb_print_*`, `_alb_exit`, `_alb_fault` | |
| | | `alb_host.rs` | tier 2 — files (memfs by default, hostfs via `--hostfs`), stdin, args, env, exec, clock, dir | |
| | |
| | To take ALB to a new board you replace tier 1 — roughly six functions — |
| | and optionally tier 2 for environment services. Generated code only ever |
| | talks to `support::_alb_*`, so a port never touches emitted source. This is |
| | the same strategy small language ports have used since the early byte-code |
| | machines: separate *what the program means* from *what the machine can do*. |
| | |
| | ## Semantics are the spec |
| | |
| | MALBR's contract is behavioral, not structural. The test suite diffs real |
| | program *output* — a semantic drift is a test failure, not a shrug. The |
| | details it guarantees are the ones a user would notice: |
| | |
| | - `|` stays string concatenation (and `&` its alias); bitwise work uses |
| | `AND`/`OR`/`XOR` keywords, `^` is exponentiation |
| | - `NOT` keeps classic-BASIC precedence — looser than comparisons, tighter |
| | than `AND`; `NOT x = 5` means `NOT (x = 5)` |
| | - `AND`/`OR` never short-circuit; `ANDALSO`/`ORELSE` do |
| | - `PRINT` truncates floats to six decimals — display only, not the value |
| | - `READ(h, 0)` reads the rest of the file; both `ELSEIF` and `ELSIF` parse |
| | - reserved words error with line/column instead of cascading parse failures |
| | |
| | ```fact Pipe is still concat |
| | In MALBR-generated Rust, `a | b` compiles to string concatenation — the |
| | compiler emits a PIPE-AS-CONCAT warning only when a `|` expression feeds a |
| | numeric assignment with two integer operands, the one pattern that could |
| | mean bitwise OR in other languages. |
| | ``` |
| | |
| | ## Float math without a standard library |
| | |
| | `#![no_std]` means no libm, so MALBR carries its own: Cody–Waite argument |
| | reduction plus minimax polynomials give `sin`, `cos`, `atan`, `exp`, and |
| | `ln` to about 1 ulp, with `tan`, `asin`, `acos`, `atan2`, and `pow` in the |
| | 2–3 ulp range. `floor`, `ceil`, `trunc`, `round`, and `sqrt` are integer |
| | casts with Newton fixups — the core intrinsics would pull in `std`. For an |
| | embedded BASIC, that is an unusually serious numerics story: see |
| | [[Scientific notation]] and [[History of Mathematics]] for why floating |
| | point conventions mattered enough to standardize. |
| | |
| | ## MALB — ALB written in ALB |
| | |
| | Once MALBR could compile real programs, one question became inevitable: can |
| | ALB compile its own compiler? **MALB** (`MALBR_BS/malb.alb`, about 3,900 |
| | lines) is the answer — a complete ALB→Rust compiler written in the language |
| | it compiles. The self-hosting claim is proven the hard way, not asserted: |
| | |
| | ```flow The three-stage bootstrap — a byte-identical fixpoint |
| | malbr.exe builds malb.exe (stage 1 — Ada backend) |
| | malb.exe compiles malb.alb -> malb2.rs (stage 2) |
| | malb2.exe compiles malb.alb -> malb3.rs (stage 3) |
| | |
| | malb2.rs == malb3.rs — identical, byte for byte |
| | ``` |
| | |
| | When a compiler's own 3,900-line source is the test program and the |
| | stage-2 and stage-3 outputs agree exactly, "almost right" has nowhere to |
| | hide. This is the same fixpoint argument classic self-hosting |
| | compilers — from Pascal's P-system to GCC's three-stage build — have used |
| | to demonstrate correctness; see [[Compilers]] for the tradition. |
| | |
| | ## Coverage and status |
| | |
| | MALB currently passes **209 of 209 output-verified fixtures** — emit → |
| | rustc → run → diff — including MD5, FFT, Jaro–Winkler, N-queens, maze |
| | generation, FFI calls into kernel32, and the semantics regression tests |
| | (short-circuit behavior, `NOT` precedence, checked overflow, contracts). |
| | The language coverage is full: modules and `INCLUDE`, contracts |
| | (`REQUIRE`/`ENSURE`/`OLD`), structs, enums, bitfields, range types, routine |
| | references and `REF`, floats, multi-dimensional arrays, `SELECT`, |
| | `ENABLE RUST`, and the complete builtin set. |
| | |
| | ```alb |
| | malb input.alb [output.rs] |
| | ``` |
| | |
| | The CLI is deliberately boring. MALB is in early access; the roadmap's |
| | priorities are performance of the self-built binary, `--map`-style audit |
| | output, and then the point of the exercise — `malbr.adb` freezing forever |
| | as the bootstrap compiler, with ALB's compiler maintained in ALB from that |
| | day forward. |
| | |
| | ## Where it sits in the toolchain |
| | |
| | | Compiler | Written in | Emits | Role | |
| | |----------|-----------|-------|------| |
| | | `albt` | Ada | FASM, C, and 14 more targets | reference compiler — batteries included | |
| | | `malbr` | Ada | `#![no_std]` Rust | embedded/foreign targets — rustc does the rest | |
| | | `malb` | **ALB** | Rust | self-hosted twin of malbr — early access | |
| | |
| | ```tip Port instead of patch |
| | Shipping ALB to a microcontroller? Write six `_alb_*` functions in |
| | `alb_core.rs` — putchar, print, exit, fault — and every MALBR program |
| | follows. Never edit generated code. |
| | ``` |
| | |
| | ## See also |
| | |
| | - [[AdaLogic BASIC]] — the language these compilers serve |
| | - [[ALB Ada backend]] — sibling backend in the same Ada toolchain |
| | - [[ALB FASM backend]] — the workhorse native x86-64 target |
| | - [[Rust]] — the language MALBR emits |
| | - [[Ada Programming Language]] — the language both `albt` and `malbr` are written in |
| | - [[Compilers]] — self-hosting and bootstrap traditions |
| | - [[Forth]] — another language that took tiny, auditable toolchains to telescopes and space probes |
| | |
| | ## References |
| | |
| | 1. "Update: MALBR and MALB — a second compiler, and ALB written in ALB," ALB repository, `docs/updates/2026-10-malbr-malb-announcement.md` (October 2026). |
| | 2. *MALBR Dialect Specification — Micro ALB*, ALB repository, `docs/MALBR_SPEC.md` — the normative dialect contract. |
| | 3. *MALBR Internals — what the generated Rust actually looks like*, `docs/MALBR_INTERNALS.md`. |
| | 4. *MALBR Porting Guide — taking ALB to a new target*, `docs/MALBR_PORTING.md`. |
| | 5. *MALBR ABI*, `docs/MALBR_ABI.md` — the `support.rs` two-tier contract. |
| | 6. *MALBR Roadmap — Micro ALB compiler → production*, `docs/MALBR_ROADMAP.md`. |
| | 7. ALB source — [github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language](https://github.com/rockyoliver454/AdaLogic-BASIC-ALB-Programming-Language) — Apache 2.0, including `src/malbr.adb`, `src/EMITTER/emit_native_micro_rust.adb`, and `MALBR_BS/malb.alb`. |
| | 8. ALB Handbook — [alb-lang.org/handbook](/handbook) — the language reference shared by every backend. |
| | |
| | ## Quiz — MALBR and MALB |
| | |
| | - [ ] What does "MALBR" stand for, and what language does it emit? |
| | - [ ] Why does ALB need a second compiler when `albt` already targets sixteen backends? |
| | - [ ] What two attributes appear at the top of every MALBR-generated crate? |
| | - [ ] How large is MALBR's default string arena, and which flag resizes it? |
| | - [ ] Name the function every runtime trap routes through, and give three fault codes. |
| | - [ ] How many functions does a minimal MALBR board port require, and in which file do they live? |
| | - [ ] In ALB, what does `|` mean — and how does MALBR treat it in generated Rust? |
| | - [ ] Which ALB keywords provide short-circuit logic, since `AND`/`OR` do not? |
| | - [ ] Approximately how accurate are MALBR's `sin`/`cos`/`exp`/`ln` implementations? |
| | - [ ] What is MALB, and roughly how many lines of ALB is it? |
| | - [ ] Describe the three stages of the MALB bootstrap and what equality proves. |
| | - [ ] How many output-verified fixtures does MALB currently pass? |
| | |
| | ```hide Answers |
| | MALBR = Micro ALB Rust; it emits Rust source. albt cannot piggyback on |
| | rustc's cross-compilation, optimizer, and no_std ecosystem — MALBR fills |
| | that gap. Every crate starts `#![no_std]`/`#![no_main`. The arena is |
| | 64 KiB by default, resized with `--arena`. All traps route through |
| | `support::_alb_fault(code)` — e.g. 21 REQUIRE, 24 overflow, 101 panic. A |
| | minimal port is about six functions in `alb_core.rs`. `|` is string |
| | concatenation, and MALBR preserves that in Rust. `ANDALSO` and `ORELSE` |
| | short-circuit. The libm-grade functions are ~1 ulp (2–3 for the rest). |
| | MALB is the ALB→Rust compiler written in ALB, about 3,900 lines. |
| | Bootstrap: malbr builds malb.exe; malb.exe compiles malb.alb into |
| | malb2.rs/malb2.exe; malb2.exe compiles malb.alb into malb3.rs; and |
| | malb2.rs == malb3.rs byte-for-byte — the fixpoint that proves the |
| | compiler implements the language correctly. The suite: 209/209. |
| | ``` |
| | |
| | {{date|2026-10-14}} |
| | |
| | [[Category:AdaLogic BASIC]] |
| | [[Category:Backends]] |
| | [[Category:Programming]] |
| | |