# M2S compiles clean under V3 (compatibility additions) Tag `v3-m2s-clean`. Main suite 110/110 (new `t_compat`). With this, **`SymTab`, `QbeGen` and `M2S` (the Coco/R scanner) all compile clean under V3.** `M2P`/`M2` remain (see below). ## Items knocked out (the 3 remaining, plus what they uncovered) The three known `M2S` items — and, once those parsed, a few more GNU-isms in CR's *generated* scanner tables: 1. **`LENGTH`** — accepted as an alias of `LEN`. 2. **Empty statement bodies** — `IF … THEN ELSIF/ELSE`, `WHILE … DO`, `REPEAT`, `LOOP`, `FOR` and `CASE` alternatives may now have empty bodies (`StatSeq` optional), matching CR's generated code. 3. **`&` = `AND`, `~` = `NOT`** — GNU/classic synonyms. 4. **Octal character literals** — new `charConst` token (`0C`, `03C`, `012C`) handled by `NormLit` → `CHAR` value (`0C` = NUL). 5. **`ORDL`** — alias of `ORD`. 6. **`CAP`** — new builtin, branchless UPCASE (`q := a - 32*(a>='a' AND a<='z')`, since QBE has no `select`). Also fixed a latent bug found via `CAP`: **`ABS` (and now `CAP`) wrote their result to a temp but `Fact` never copied it back to `q`**, so `ABS` silently returned its operand. Both now `CopyOp(qa, q)`. ## Verification - `tests/t_compat.mod` (exit 42) exercises `&`, `~`, `LENGTH`, `CAP`, `ORDL`, `0C`, and empty THEN/ELSE. - `M2S.def` + `M2S.mod` under V3: **0 errors**. - `SymTab` / `QbeGen` under V3: still 0 errors. - `tools/m2make` unaffected; main suite 110/110. ## Remaining (M2P, M2) `M2P.mod` (the Coco/R parser) is 107 errors, dominated by 102 `undeclared identifier` — **within-module forward procedure calls** in CR's generated recursive-descent parser (gm2 hoists these; ISO wants declaration-before-use or `FORWARD`). Also `BITSET{…}` constructors and `symSet[0,0]` nested-array assignment. This is the next self-hosting chunk; the driver `M2.mod` additionally needs nested procedure values (`Error := StoreError`, `StoreError` nested in `ListHandler`) which the current proc-type support doesn't yet provide (static link). ## Where the compatibility additions came from `&`, `0C`, empty bodies and forward refs are all emitted by the CR binary's built-in scanner/parser templates — not by our `scanner.frm` (which has none of them). So V3 accepting them is the only way to self-host CR's output short of patching the toolchain. ## Files `compiler/src/{M2.atg,QbeGen.def,QbeGen.mod}`, `compiler/tests/t_compat.mod`, `compiler/run_tests.sh`.