diff --git a/code/duffle/gen/lottes_tape.offsets.h b/code/duffle/gen/lottes_tape.offsets.h index 47d3b71..8b02143 100644 --- a/code/duffle/gen/lottes_tape.offsets.h +++ b/code/duffle/gen/lottes_tape.offsets.h @@ -1,50 +1,12 @@ // Auto-generated by gen_atom_offsets.lua — DO NOT EDIT // Source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h -#ifndef LOTTES_TAPE_OFFSETS_H -#define LOTTES_TAPE_OFFSETS_H +#pragma once #pragma region lottes_tape -// Override the placeholder atom_offset() to dispatch via token pasting. +// Dispatch macro: token-pastes _ to the enum name #undef atom_offset -#define atom_offset(name) atom_offset_##name - -// --- atom: sym (8 words) --- - - -// --- atom: tape_exit (2 words) --- - - -// --- atom: yield (4 words) --- - - -// --- atom: mips_flush_icache (13 words) --- - - -// --- atom: sync_prim_cursor (6 words) --- - - -// --- atom: set_gte_world (22 words) --- - - -// --- atom: rbind_cube_tri (6 words) --- - - -// --- atom: cube_tri (74 words) --- - - -// --- atom: rbind_floor_tri (6 words) --- - - -// --- atom: diag_yield (4 words) --- - - -// --- atom: diag_color (28 words) --- - - -// --- atom: diag_gte (34 words) --- - +#define atom_offset(tag, name) atom_offset_##tag##_##name #pragma endregion lottes_tape -#endif // LOTTES_TAPE_OFFSETS_H diff --git a/code/duffle/lottes_tape.h b/code/duffle/lottes_tape.h index 9ba1039..3f5e559 100644 --- a/code/duffle/lottes_tape.h +++ b/code/duffle/lottes_tape.h @@ -62,7 +62,8 @@ FI_ void tape_run(Slice_U4 tape) { register U4* tp rgcc(R_TapePtr) = tape.ptr; a typedef Relative_(FArena) Struct_(TapeBuilder) { U4 ptr; U4 capacity; U4 used; }; FI_ void tb_init(TapeBuilder* tb, FArena* arena) { tb->ptr = arena->start; tb->used = 0; } -FI_ TapeBuilder tb_make( FArena* arena) { return (TapeBuilder){ arena->start, 0 }; } +FI_ TapeBuilder tb_make_old( FArena* arena) { return (TapeBuilder){ arena->start, 0 }; } +FI_ TapeBuilder tb_make(Slice mem) { return (TapeBuilder){ mem.ptr, mem.len, 0 }; } #define tb_emit_(tb, atom) tb_emit(tb, tmpl(code,atom)) FI_ void tb_emit(TapeBuilder* tb, MipsCode* atom) { u4_r(tb->ptr)[tb->used] = u4_(atom); ++ tb->used; } diff --git a/code/gte_hello/gen/hello_gte_tape.offsets.h b/code/gte_hello/gen/hello_gte_tape.offsets.h index fb1811c..ab28d43 100644 --- a/code/gte_hello/gen/hello_gte_tape.offsets.h +++ b/code/gte_hello/gen/hello_gte_tape.offsets.h @@ -1,18 +1,22 @@ // Auto-generated by gen_atom_offsets.lua — DO NOT EDIT // Source: C:\projects\Pikuma\ps1\code\gte_hello\hello_gte_tape.c -#ifndef HELLO_GTE_TAPE_OFFSETS_H -#define HELLO_GTE_TAPE_OFFSETS_H +#pragma once #pragma region hello_gte_tape -// Override the placeholder atom_offset() to dispatch via token pasting. +// Dispatch macro: token-pastes _ to the enum name #undef atom_offset -#define atom_offset(name) atom_offset_##name +#define atom_offset(tag, name) atom_offset_##tag##_##name -// --- atom: floor_tri (49 words) --- +// --- atom: floor_tri (51 words) --- -#define atom_offset_floor_tri_exit (17) +#define _atom_offset_culling_floor_tri_exit 17 +#define _atom_offset_bounds_chk_floor_tri_exit 3 + +enum { + atom_offset_culling_floor_tri_exit = _atom_offset_culling_floor_tri_exit, + atom_offset_bounds_chk_floor_tri_exit = _atom_offset_bounds_chk_floor_tri_exit, +}; #pragma endregion hello_gte_tape -#endif // HELLO_GTE_TAPE_OFFSETS_H diff --git a/code/gte_hello/hello_gte.c b/code/gte_hello/hello_gte.c index 882d744..70cb939 100644 --- a/code/gte_hello/hello_gte.c +++ b/code/gte_hello/hello_gte.c @@ -246,7 +246,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf) U4 prim_cursor = prim_base + pa->used; LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape)); - TapeBuilder tb = tb_make(&tape_arena); tb_scope(& tb) { + TapeBuilder tb = tb_make_old(&tape_arena); tb_scope(& tb) { tb_emit(& tb, code_rbind_cube_tri); tb_data(& tb, prim_cursor); tb_data(& tb, u4_(static_mem.cube.faces)); @@ -334,12 +334,11 @@ void update(PrimitiveArena* pa, U4* ordering_buf) U4 prim_cursor = prim_base + pa->used; // Prepare the tape. - LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape)); - TapeBuilder tb = tb_make(&tape_arena); tb_scope(& tb) { + LP_ U4 mem_temp_tape[512]; + TapeBuilder tb = tb_make(slice_ut_arr(mem_temp_tape)); tb_scope(& tb) { // Push "Protocol" to tape tb_emit(& tb, code_rbind_floor_tri); - // Note(Ed): This is technically argument shuffle and would be better if we did a single reference at most to a global batch context. - // Note(Ed): We can technically allocate a single ptr with the global offset to the working context instead of utilizing the tape for this stack of refs. + // TODO(Ed): Just use a single context struct ref tb_data(& tb, prim_cursor); tb_data(& tb, u4_(static_mem.floor.faces)); tb_data(& tb, u4_(static_mem.floor.verts)); @@ -367,7 +366,7 @@ void update(PrimitiveArena* pa, U4* ordering_buf) if (0) { LP_ U4 mem_temp_tape[512]; FArena tape_arena; farena_init(& tape_arena, slice_ut_arr(mem_temp_tape)); - TapeBuilder tb = tb_make(& tape_arena); tb_scope(& tb) { + TapeBuilder tb = tb_make_old(& tape_arena); tb_scope(& tb) { // Skip set_gte_world atom for diagnostics to isolate the triangle loop for (U4 i = 0; i < Floor_num_faces; i++) { // ======================================================= diff --git a/code/gte_hello/hello_gte_tape.c b/code/gte_hello/hello_gte_tape.c index 0b4b17a..edeafc2 100644 --- a/code/gte_hello/hello_gte_tape.c +++ b/code/gte_hello/hello_gte_tape.c @@ -5,7 +5,7 @@ # include "gen/hello_gte_tape.offsets.h" #endif -#pragma region MACs +#pragma region MACs (Mips Atom components) /* Words: 3; High: 0x20/B, Low: G/R */ #define mac_format_f3_color(color_hi, color_lo) \ @@ -24,17 +24,25 @@ internal MipsAtom_(floor_tri) { // T0-T2 allocated - mac_load_tri_indices(R_T0, R_T1, R_T2), - mac_load_tri_verts( R_T0, R_T1, R_T2), + // mac_load_tri_indices(R_T0, R_T1, R_T2), + load_half_u(R_T0, R_FaceCur, 0 * S_(S2)) + , load_half_u(R_T1, R_FaceCur, 1 * S_(S2)) + , load_half_u(R_T2, R_FaceCur, 2 * S_(S2)) + , + // mac_load_tri_verts( R_T0, R_T1, R_T2), + shift_ll(R_AT, R_T0, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY0), gte_mt(R_V1, C2_VZ0) + , shift_ll(R_AT, R_T1, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY1), gte_mt(R_V1, C2_VZ1) + , shift_ll(R_AT, R_T2, 3), add_u(R_AT, R_AT, R_VertBase), load_word(R_V0, R_AT, 0), load_word(R_V1, R_AT, 4), gte_mt(R_V0, C2_VXY2), gte_mt(R_V1, C2_VZ2) + , /* 3. Execute Math */ nop, nop, gte_cmdw_rotate_translate_perspective_triple, nop, nop, gte_cmdw_nclip, nop, nop, - /* 4. Culling (Branch forward 29 instructions if Backface) */ + /* 4. Culling (Branch forward if Backface) */ gte_mf(R_T0, C2_MAC0), - nop, branch_le_zero(R_T0, atom_offset(floor_tri_exit)), + nop, branch_le_zero(R_T0, atom_offset(culling, floor_tri_exit)), nop, /* 5. Format Primitive */ @@ -45,10 +53,10 @@ internal MipsAtom_(floor_tri) { nop, nop, gte_avg_sort_z3, nop, nop, gte_mf(R_T1, C2_OTZ), - /* 7. Bounds Check OTZ < 2048 (Branch forward 13 instructions to skip insertion) */ + /* 7. Bounds Check OTZ < 2048 (Branch forward to skip insertion) */ add_ui( R_AT, R_0, OrderingTbl_Len), slt_u( R_AT, R_T1, R_AT), - branch_equal(R_AT, R_0, 13), + branch_equal(R_AT, R_0, atom_offset(bounds_chk, floor_tri_exit)), nop, /* 8. Insert into Ordering Table Linked List */ diff --git a/scripts/tape_attom.offset_gen.meta.lua b/scripts/tape_attom.offset_gen.meta.lua index d5e8ac3..3c8e1c4 100644 --- a/scripts/tape_attom.offset_gen.meta.lua +++ b/scripts/tape_attom.offset_gen.meta.lua @@ -1,10 +1,23 @@ #!/usr/bin/env lua --- gen_atom_offsets.lua +-- gen_atom_offsets.lua — hand-rolled, no patterns, no regex, no region pragmas. -- -- Finds every `MipsAtom_(name) { ... }` declaration in the given sources, -- counts the words in each body using the WORD_COUNT manifest, computes --- branch offsets for atom_label(name)/atom_offset(name) markers, and writes --- one header per source into `/gen/.offsets.h`. +-- branch offsets for atom_label(name) / atom_offset(tag, name) markers, +-- and writes one header per source into /gen/.offsets.h +-- +-- Generated header layout (per source): +-- #pragma region +-- #undef atom_offset +-- #define atom_offset(tag, name) atom_offset_##tag##_##name +-- // --- atom: ( words) --- +-- #define atom_offset__ (N) // preprocessor form +-- #undef atom_offset__ // (so enum can reuse) +-- enum { +-- atom_offset__ = N, // C enum form +-- }; +-- #define atom_offset__ (N) // re-define for preprocessor +-- #pragma endregion -- -- Usage: -- lua gen_atom_offsets.lua [source2 ...] @@ -56,7 +69,7 @@ local function ensure_dir(path) end -- ============================================================ --- String primitives (no patterns) +-- String primitives -- ============================================================ local function trim(s) @@ -144,7 +157,7 @@ local function pad_right(s, width) end -- ============================================================ --- Skip whitespace and comments +-- Lexer helpers -- ============================================================ local function skip_ws_and_comments(source, i) @@ -171,10 +184,6 @@ local function skip_ws_and_comments(source, i) return i end --- ============================================================ --- Read identifier --- ============================================================ - local function read_ident(source, i) if not is_alpha(source:sub(i, i)) then return nil, i end local a = i @@ -183,11 +192,6 @@ local function read_ident(source, i) return source:sub(a, i - 1), i end --- ============================================================ --- Read balanced (open_char, close_char) group, return inner + new pos --- Skips strings and comments inside. --- ============================================================ - local function read_balanced(source, open_char, close_char, i) if source:sub(i, i) ~= open_char then return nil, i end i = i + 1 @@ -235,28 +239,19 @@ local function read_balanced(source, open_char, close_char, i) return source:sub(a, i - 1), i + 1 end -local function read_parens(source, i) return read_balanced(source, "(", ")", i) end -local function read_braces(source, i) return read_balanced(source, "{", "}", i) end +local function read_parens(source, i) return read_balanced(source, "(", ")", i) end +local function read_braces(source, i) return read_balanced(source, "{", "}", i) end local function read_brackets(source, i) return read_balanced(source, "[", "]", i) end --- ============================================================ --- Scan forward from `start`, skipping balanced (), [], {}, strings, comments. --- Returns position of first occurrence of `target` char at top level, or nil. --- ============================================================ - local function scan_to_char(source, target, start) local len = #source local i = start while i <= len do local c = source:sub(i, i) - if c == target then - return i - elseif c == "(" then - local _, after = read_parens(source, i); i = after - elseif c == "{" then - local _, after = read_braces(source, i); i = after - elseif c == "[" then - local _, after = read_brackets(source, i); i = after + if c == target then return i + elseif c == "(" then local _, a = read_parens(source, i); i = a + elseif c == "{" then local _, a = read_braces(source, i); i = a + elseif c == "[" then local _, a = read_brackets(source, i); i = a elseif c == '"' then i = i + 1 while i <= len do @@ -290,7 +285,37 @@ local function scan_to_char(source, target, start) end -- ============================================================ --- Load WORD_COUNT manifest from metadata.h +-- Extract comma-separated identifier args from a parenthesized group +-- after a function-like macro call. +-- ============================================================ + +local function extract_ident_args(token, after_ident) + local arg_start = skip_ws_and_comments(token, after_ident) + if token:sub(arg_start, arg_start) ~= "(" then return {}, nil end + local inner, after_paren = read_parens(token, arg_start) + + local args = {} + local n = 1 + local len = #inner + while n <= len do + n = skip_ws_and_comments(inner, n) + if n > len then break end + local ident, after = read_ident(inner, n) + if ident and ident ~= "" then + table.insert(args, ident) + n = after + else + n = n + 1 + end + n = skip_ws_and_comments(inner, n) + if n <= len and inner:sub(n, n) == "," then n = n + 1 end + end + + return args, after_paren +end + +-- ============================================================ +-- Load WORD_COUNT manifest -- ============================================================ local function load_word_counts(metadata_path) @@ -304,17 +329,14 @@ local function load_word_counts(metadata_path) local line_end = nl or (len + 1) local line = content:sub(i, line_end - 1) local trimmed = trim(line) - if starts_with(trimmed, prefix) and ends_with(trimmed, ")") then local inner = trimmed:sub(#prefix + 1, #trimmed - 1) local comma = find_byte(inner, ",", 1) if comma then - local name = trim(inner:sub(1, comma - 1)) - local cnt = trim(inner:sub(comma + 1)) - counts[name] = tonumber(cnt) + counts[trim(inner:sub(1, comma - 1))] = + tonumber(trim(inner:sub(comma + 1))) end end - i = line_end + 1 end return counts @@ -352,12 +374,9 @@ local function split_top_level_commas(body) local token_start = 1 while i <= len do local c = body:sub(i, i) - if c == "(" then - local _, after = read_parens(body, i); i = after - elseif c == "{" then - local _, after = read_braces(body, i); i = after - elseif c == "[" then - local _, after = read_brackets(body, i); i = after + if c == "(" then local _, a = read_parens(body, i); i = a + elseif c == "{" then local _, a = read_braces(body, i); i = a + elseif c == "[" then local _, a = read_brackets(body, i); i = a elseif c == '"' then i = i + 1 while i <= len do @@ -392,14 +411,13 @@ local function split_top_level_commas(body) end end local last = body:sub(token_start, len) - if trim(last) ~= "" then - table.insert(tokens, last) - end + if trim(last) ~= "" then table.insert(tokens, last) end return tokens end -- ============================================================ --- Scan an atom body for atom_label/atom_offset markers, count words +-- Scan token for atom_label/atom_offset markers, walking through +-- balanced groups transparently (so nested calls are found) -- ============================================================ local function scan_for_atom_markers(token, at_pos, labels, branches) @@ -410,7 +428,6 @@ local function scan_for_atom_markers(token, at_pos, labels, branches) if i > len then break end local c = token:sub(i, i) if c == '"' then - -- Skip string literal i = i + 1 while i <= len do if token:sub(i, i) == "\\" then i = i + 2 @@ -418,7 +435,6 @@ local function scan_for_atom_markers(token, at_pos, labels, branches) else i = i + 1 end end elseif c == "'" then - -- Skip char literal i = i + 1 while i <= len do if token:sub(i, i) == "\\" then i = i + 2 @@ -438,36 +454,33 @@ local function scan_for_atom_markers(token, at_pos, labels, branches) end elseif is_alpha(c) then local ident, after = read_ident(token, i) - if ident == "atom_label" or ident == "atom_offset" then - local arg_start = skip_ws_and_comments(token, after) - if token:sub(arg_start, arg_start) == "(" then - local inner, after_paren = read_parens(token, arg_start) - local n = 1 - while n <= #inner and is_space(inner:sub(n, n)) do n = n + 1 end - local ns = n - while n <= #inner and is_alnum(inner:sub(n, n)) do n = n + 1 end - local name = inner:sub(ns, n - 1) - if name ~= "" then - if ident == "atom_label" then - labels[name] = at_pos - else - table.insert(branches, {pos = at_pos, target = name}) - end - end - i = after_paren - else - i = arg_start + if ident == "atom_label" then + local args, after_paren = extract_ident_args(token, after) + if #args >= 1 then labels[args[1]] = at_pos end + if after_paren then i = after_paren else i = after end + elseif ident == "atom_offset" then + local args, after_paren = extract_ident_args(token, after) + if #args >= 2 then + table.insert(branches, { + pos = at_pos, + target = args[2], + tag = args[1] + }) end + if after_paren then i = after_paren else i = after end else i = after end else - -- Anything else (parens, brackets, braces, commas, operators) — walk past i = i + 1 end end end +-- ============================================================ +-- Scan atom body, count words, find markers +-- ============================================================ + local function scan_atom_body(body, word_counts) local pos = 0 local labels = {} @@ -492,13 +505,17 @@ local function scan_atom_body(body, word_counts) end -- ============================================================ --- Token classification for atom detection +-- Find every MipsAtom_(name) { ... } in a source -- ============================================================ --- Skip past storage-class / qualifier noise. These appear before MipsCode --- in raw expanded forms: `static`, `const`, the user's `internal`/`LP_`/ --- `global` macros (which all expand to `static`), `RO_` (which expands to --- a section attribute), plus standard C qualifiers. +local function has_prefix(s, prefix) + if #s < #prefix then return false end + for i = 1, #prefix do + if s:sub(i, i) ~= prefix:sub(i, i) then return false end + end + return true +end + local function skip_qualifiers(source, i) local keywords = { ["static"]=true, ["const"]=true, ["volatile"]=true, @@ -510,60 +527,37 @@ local function skip_qualifiers(source, i) i = skip_ws_and_comments(source, i) local ident, after = read_ident(source, i) if not ident then return i end - if keywords[ident] then - i = after - else - return i - end + if keywords[ident] then i = after else return i end end end --- Test whether `s` starts with literal `prefix` (no patterns). -local function has_prefix(s, prefix) - if #s < #prefix then return false end - for i = 1, #prefix do - if s:sub(i, i) ~= prefix:sub(i, i) then return false end - end - return true -end - --- ============================================================ --- Find every atom declaration in a source, both wrapped and raw --- ============================================================ - local function find_atoms(source_text) local atoms = {} local len = #source_text local i = 1 - -- First, scan inside source_text normally - local function try_wrapped_form(ident_pos) - local paren_pos = skip_ws_and_comments(source_text, ident_pos) - if source_text:sub(paren_pos, paren_pos) ~= "(" then - return nil -- not a MipsAtom_() call - end + local function try_wrapped(after_pos) + local paren_pos = skip_ws_and_comments(source_text, after_pos) + if source_text:sub(paren_pos, paren_pos) ~= "(" then return nil end local inner, after_paren = read_parens(source_text, paren_pos) - -- Extract name (first identifier from inner) local n = 1 while n <= #inner and is_space(inner:sub(n, n)) do n = n + 1 end local ns = n while n <= #inner and is_alnum(inner:sub(n, n)) do n = n + 1 end local name = inner:sub(ns, n - 1) if name == "" then return nil end - local brace_pos = scan_to_char(source_text, "{", after_paren) if not brace_pos then return nil end local body, after_brace = read_braces(source_text, brace_pos) return {name = name, body = body, after_brace = after_brace} end - local function try_raw_form(after_type_pos) - local next_pos = skip_ws_and_comments(source_text, after_type_pos) + local function try_raw(after_pos) + local next_pos = skip_ws_and_comments(source_text, after_pos) local next_ident, next_after = read_ident(source_text, next_pos) if not next_ident then return nil end if not has_prefix(next_ident, "code_") then return nil end - if #next_ident <= 5 then return nil end -- bare "code_" — not an atom - + if #next_ident <= 5 then return nil end local atom_name = next_ident:sub(6) local brace_pos = scan_to_char(source_text, "{", next_after) if not brace_pos then return nil end @@ -574,8 +568,6 @@ local function find_atoms(source_text) while i <= len do i = skip_ws_and_comments(source_text, i) if i > len then break end - - -- Skip past storage-class noise i = skip_qualifiers(source_text, i) if i > len then break end @@ -583,34 +575,30 @@ local function find_atoms(source_text) if not ident then i = i + 1 elseif ident == "MipsAtom_" then - local atom = try_wrapped_form(after) + local atom = try_wrapped(after) if atom then table.insert(atoms, {name = atom.name, body = atom.body}) i = atom.after_brace else - i = i + 1 -- not actually MipsAtom_(), skip and continue + i = i + 1 end elseif ident == "MipsCode" then - local atom = try_raw_form(after) + local atom = try_raw(after) if atom then table.insert(atoms, {name = atom.name, body = atom.body}) i = atom.after_brace else - i = after -- some other MipsCode use; skip just this token + i = after end else - -- Anything else: skip just this identifier. The next loop - -- iteration will see whatever follows (might be more qualifiers, - -- another type keyword, etc.). i = after end end - return atoms end -- ============================================================ --- Compute branch offsets: target - branch - 1 +-- Compute branch offsets (target - branch - 1) -- ============================================================ local function compute_offsets(labels, branches) @@ -618,9 +606,14 @@ local function compute_offsets(labels, branches) for _, br in ipairs(branches) do local target = labels[br.target] if not target then - error("Branch target '" .. br.target .. "' has no atom_label (at word " .. br.pos .. ")") + error("Branch target '" .. br.target .. + "' has no atom_label (at word " .. br.pos .. ")") end - table.insert(results, {target = br.target, offset = target - br.pos - 1}) + table.insert(results, { + target = br.target, + tag = br.tag, + offset = target - br.pos - 1 + }) end return results end @@ -631,36 +624,59 @@ end local function generate_header(source_path, atoms_data) local basename = basename_no_ext(source_path) - local guard = to_alnum_underscore(to_upper(basename)) .. "_OFFSETS_H" + local guard = to_alnum_underscore(to_upper(basename)) .. "_OFFSETS_H" local lines = {} local function add(s) table.insert(lines, s) end add("// Auto-generated by gen_atom_offsets.lua — DO NOT EDIT") add("// Source: " .. source_path) - add("#ifndef " .. guard) - add("#define " .. guard) + add("#pragma once") add("") add("#pragma region " .. basename) add("") - add("// Override the placeholder atom_offset() to dispatch via token pasting.") + add("// Dispatch macro: token-pastes _ to the enum name") add("#undef atom_offset") - add("#define atom_offset(name) atom_offset_##name") + add("#define atom_offset(tag, name) atom_offset_##tag##_##name") add("") for _, atom in ipairs(atoms_data) do - add("// --- atom: " .. atom.name .. " (" .. atom.total_words .. " words) ---") - add("") - for _, r in ipairs(atom.offsets) do - local const_name = "atom_offset_" .. r.target - add("#define " .. pad_right(const_name, 40) .. " (" .. r.offset .. ")") + if #atom.offsets > 0 then + add("// --- atom: " .. atom.name .. " (" .. atom.total_words .. " words) ---") + add("") + + -- Build constant list once + local consts = {} + for _, r in ipairs(atom.offsets) do + table.insert(consts, { + macro_name = "_atom_offset_" .. r.tag .. "_" .. r.target, + enum_name = "atom_offset_" .. r.tag .. "_" .. r.target, + value = r.offset + }) + end + + -- Macro form: single source of truth for the literal value. + -- Underscore prefix keeps it out of the C namespace so the + -- enum can use the same identifier name without conflict. + for _, c in ipairs(consts) do + add("#define " .. pad_right(c.macro_name, 44) .. " " .. c.value .. "") + end + add("") + + -- Enum form: C code uses the natural name, value comes + -- from the underscore-prefixed macro so the literal is + -- defined in exactly one place. + add("enum {") + for _, c in ipairs(consts) do + add(" " .. c.enum_name .. " = " .. c.macro_name .. ",") + end + add("};") + add("") end - add("") end add("#pragma endregion " .. basename) add("") - add("#endif // " .. guard) return table.concat(lines, "\n") .. "\n" end @@ -699,7 +715,7 @@ local function process_source(source_path, word_counts) print(" " .. basename .. ": " .. #atoms_data .. " atom(s), " .. total_branches .. " branch(es)") for _, a in ipairs(atoms_data) do for _, r in ipairs(a.offsets) do - print(" " .. a.name .. " -> " .. r.target .. " : " .. r.offset) + print(" " .. a.name .. " -> " .. r.tag .. ":" .. r.target .. " : " .. r.offset) end end end @@ -713,11 +729,9 @@ local function main(args) print("Usage: gen_atom_offsets.lua [source2 ...]") os.exit(1) end - local metadata_path = args[1] local sources = {} for i = 2, #args do table.insert(sources, args[i]) end - local word_counts = load_word_counts(metadata_path) for _, src in ipairs(sources) do process_source(src, word_counts) end end