# SAI3.o2bas audit ## Summary The host Oxygen Basic syntax is mostly valid. The main failures are interpreter bugs in token handling, function entry/return bookkeeping, IF/ELSE skipping, comparison parsing, and debug output contamination. ## Defects found 1. Keyword classification uses `INT identPtr at strptr ident` with `select identPtr` and string literals. - Effect: only the first 4 bytes are reliably compared; long keywords can misclassify on shared prefixes. - Original lines: 173-192. - Fix: compare full strings with `if/elseif`. 2. Function header parser never consumes the first token after `(` before collecting parameters. - Effect: parameters are never registered correctly and `StartPos` is wrong. - Original lines: 372-385. - Fix: after reading `(`, fetch the first param token, parse params, then save body start after `)`. 3. Function-call return position is saved after an extra `GetToken()`. - Effect: caller skips the token immediately following `)`. - Original lines: 268-295 and 463-492. - Fix: when arg parsing stops on `TK_RPAREN`, save `IJ.Pos` directly and call `GetToken()` only once after return. 4. Unknown function call leaves parser out of sync. - Effect: `name(...)` with an undefined function does not consume the argument list. - Original lines: 263-299 and 459-495. - Fix: either raise an error or consume through `)`. 5. Comparison parsing uses `Term()` on the right-hand side instead of full additive expressions. - Effect: `1 < 2 + 3` parses incorrectly. - Original lines: 323-349. - Fix: parse additive expressions on both sides of comparisons. 6. `IF` true branch skips the first statement. - Effect: extra `GetToken()` moves past the first token in the block. - Original lines: 387-393. - Fix: remove that extra `GetToken()`. 7. False `IF` cannot land on `ELSE`. - Effect: `SkipBlock(KW_IF, KW_ENDIF)` jumps to `ENDIF`, so the `ELSE` branch never executes. - Original lines: 392 and 352-362. - Fix: add a dedicated `SkipToElseOrEndif()` helper. 8. `ELSE` and `ENDIF` are not consumed inside `Statement()`. - Effect: true IF paths can hang once the parser reaches `ELSE` or `ENDIF`. - Original lines: 365-442. - Fix: handle both keywords explicitly, plus a default keyword case that consumes unknown keywords. 9. Unhandled keywords can loop forever. - Effect: keywords such as `RETURN`, `ENDFUNC`, `TO` can leave the parser stationary in the generic statement dispatcher. - Original lines: 365-442. - Fix: add `case else : GetToken()` in the inner keyword select. 10. Debug prints corrupt interpreted output. - Effect: runtime output is mixed with traces like `VAR-NAME`, `FN-NAME`, and `FUNCTION:`. - Original lines: 250, 253, 264, 373, 511-520. - Fix: remove or guard behind a debug flag. 11. Function parameters overwrite globals instead of shadowing them. - Effect: `SetVar()` modifies existing names, so globals are mutated by call setup. - Original lines: 278-281 and 475-478. - Fix: append new local variable slots for params and restore `VarCount` on return. 12. `PRINT` ignores string tokens. - Effect: `print "hello"` is not handled correctly even though the tokenizer emits `TK_STRING`. - Original lines: 368-370 and 194-204. - Fix: print `CurrToken.Text` directly when `TK_STRING` is current. 13. Unknown characters are silently converted to `TK_EOF`. - Effect: lexical errors terminate interpretation instead of surfacing as errors. - Original lines: 228-230. - Fix: add an error token or explicit skip/error path. 14. `SkipBlock()` misses a nested block opener when that opener is the very first skipped token. - Effect: a false `IF` or `WHILE` whose first statement is another `IF` / `WHILE` / `FUNCTION` can desynchronize nesting depth. - Original lines: 352-362. - Fix: inspect the current token before advancing, not only after `GetToken()`. ## Valid Oxygen constructs confirmed - `$ filename "SAI3.exe"` - multiline continuation with `_` - `type ... end type` - arrays in declarations such as `string ParamNames[9]` - overlays / `at strptr(...)` - numeric `select/case` ## Files - Original: `SAI3.zip` - Patched best-effort source: `SAI3_fixed.o2bas`