# Step 2 — Scalars + MC64 backend (tag: `step2`) Commit `eee1504` — "step2: scalars + MC64 backend — SymTab, MGen emitter, 25/25 tests green; fix bit_in operand order" (88 files, +4980/−132). ## Goal Full scalar subset of Modula-2 compiling to runnable MC64 images: `CONST`/`TYPE`/`VAR`, complete expression hierarchy, all structured statements, static type checking, exact error codes. ## What was built - `m2c/SymTab.def/.mod` — symbol table + type checker, ported from the proven Test1 design: scopes, aliases/subranges/enums/arrays/ records/sets/pointers descriptors, `InvalidType` cascade suppression; codes 200/201/202, 210–224; plus `PendCount`/ `PendName` for VAR-list emission. - `m2c/MGen.def/.mod` — MC64 image emitter: one 8-byte slot per global, literal `CONST`s as startup stores, stack-machine expressions (`A6/A7/A8/B8/A9/AA/B9`, signed `B2–B5` compares, `D5–D9` reals, `E6/E8/B6` logic), `E0/E1` jumps with fixups, `LOOP/EXIT` stack, `CASE` as compare-chains, `FOR` with hidden temp global, `SET`s via `power2`/`build_field_mask`/`bit_in`/`A0`, embedded decimal-print helper. Test convention: a global `VAR ExitCode : INTEGER` is printed as decimal + CRLF. - `m2c/M2c.atg` — full scalar grammar (~900 lines): type checking identical to the reference rules; backend lowers scalars + sets, everything else parses but gets error 230. - `m2c/run_tests.sh` — extended: `expect_run` compiles, runs the `.MC4` (name derived from the `MODULE` line, not `ls -t`) under `mcint`, and compares the printed value. ## Tests — 25/25 14 run tests (7, 15, 42, 20, 103, 55, 55, 7, 85, 31, 97, 1, 74, sets 15) + 6 rejections (one 210, rest 230-only, no cascades) + 4 phase-0 + 1 silent-minimal. All negatives produce exactly one error each. ## Bugs found and fixed 1. Image writer skipped the 64-byte file header (shifted image). 2. `ParseCard` used `10H`/`16H` (hex 16/22!) for decimal bases — multi-digit literals wrong, single digits accidentally right. 3. `ParseReal` overlaid 8 bytes of gm2's 80-bit-extended `LONGREAL` — switched to 8-byte `REAL` like the VM's own `Stack.mod`. 4. **`bit_in` (`0E7H`) operands swapped in `mc64/Interpreter.mod`** vs both the spec prose and the original Turbo MCode (`op := Pop(); Push(Pop() IN BITSET(op))`) — fixed (2 lines), MC64 suite re-verified 24/24. 5. Runner used same-second `ls -t` ties + non-portable `$'\r'` stripping — deterministic names + `tr -d '\r'`. ## Known limits (in `M2c.atg` header) Truncating DIV/MOD, signed compares for CARDINAL, eager AND/OR, literal-only CONST/BY, REAL as binary64, no procedures yet.