Spec M5.5 — fixes from the M3/M5 reviews + core pieces M6 needs
A. Fixes (M3 review) #
- Lexer: escape
\0inside a string literal is an error ("\0 not allowed in a string"); in a char literal it stays valid. Reason:S_CSTRING_LITERALSmakesldmerge C-string literals, which would corrupt"a\0b"vs"a". Document indocs/core-language.md(one line). #include:path_joinnormalizes.and..lexically (no filesystem access) before the once-only check. Test:a/b.mcincluding../c.mcplus the root includingc.mc→ only one inclusion.- Token carries a file:
Token.file;node_new/err_atuse the file of the token that gave the line, not the lexer's current file. Test:frag.mcwithi64 helper(i64 x) {left unclosed → the error citesfrag.mc. #definevs name: declaring a local, parameter, global, or function with the name of an existing#defineis the errorname already defined by #define.- Safe reductions in
gen_arm64.c(dump viarrrtables, an ld/st table, a unifiedmem_op, a name-resolution helper) — target ≈ −25 lines, without changing the generated code (verify withcmpon the.oof every test, before/after).
B. Fixes (M5) #
- Section order in the load commands:
__text,__cstring,__data,__bss(whichever exist) and only then the custom ones, in order of first appearance.#sectionregisters into a table; actual creation happens ingen_sections. Recheckotool -lfor 030.
C. New core pieces (requested by M4) #
- Global array initializer:
type name[N] = { e1, e2, ... };andtype name[] = { ... }(N inferred). Elements: folded constants (written with the type's width) or, foruptr, a string literal → 8 zero bytes +R_UNSIGNED(len 3, pcrel 0, extern 1) forl_strN. Goes into__data(or a custom non-zerofill section), aligned to 16; N > count pads with zeros; count > N is an error. Does it support#opcode? No. Test:uptr names[] = {"zero","one","two"};withputs(ld64(names + 8*i))→ stdoutone;u32 t[4] = {1,2,3};→ld32(t+8) == 3. - Unsigned division:
/and%with au8/u16/u32/u64/uptrleft operand →udiv/msub;foldmirrors this. Test:(u64) 0xFFFFFFFFFFFFFFFF / 2=0x7FFFFFFFFFFFFFFF. - Prototype:
type name(params);at top level registers a signature; a later definition must match it (return type and arity); a prototype with neither a definition nor an extern is an error at the end. Makefile: targetcheck-lex(scripts/check-lex.sh build/mc0);make testunchanged.CLAUDE.md§ State: M3, M4, M5 and M5.5 closed; next is M6.
Acceptance #
make stage0 with no warnings, stage0-san, budget (report it), test (mc0 and mc0-san),
check-lex; before/after reproductions for A1–A4; cmp of the .o files before/after A5 for
every test (except the ones affected by B6, whose only difference is section order); new tests
040-arrinit.mc, 041-udiv.mc, 042-proto.mc, 043-include-norm.mc (+ helper files under
tests/inc/).