mirror of
https://github.com/Ed94/pikuma_ps1.git
synced 2026-08-25 02:20:33 +00:00
Redesign: Not making local var in MipsAtom_Proc_ or MipsAtomComp_Proc_ have sym tied to proc name. Adjusted parser as well base do that.
This commit is contained in:
+148
-1
@@ -2681,4 +2681,151 @@ function M.project_emission(body_text, component_index, word_counts, components)
|
||||
})
|
||||
end
|
||||
|
||||
return M
|
||||
-------------------------------------------------------------------------------
|
||||
-- find_function_decl_for — backward walk for MipsAtomComp_Proc_ name extraction.
|
||||
--
|
||||
-- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name
|
||||
-- is derived from the preceding `FI_ Slice_MipsCode ac_X(args)` function
|
||||
-- declaration. This function walks backward from `before_pos` to find it.
|
||||
--
|
||||
-- Returns (raw_name, args_inner) or (nil, nil).
|
||||
-- raw_name — e.g. "ac_load_word_imm"
|
||||
-- args_inner — e.g. "AtomBuilder_R ab, Reg dst, U4 imm"
|
||||
--
|
||||
-- The walk finds the LAST "Slice_MipsCode" before before_pos, then skips
|
||||
-- whitespace + qualifiers (FI_, atom_dbg_skip, comments) until it finds an
|
||||
-- ident followed by "(". That ident is the function name; the parens contents
|
||||
-- are the args.
|
||||
-------------------------------------------------------------------------------
|
||||
function M.find_function_decl_for(source, before_pos, slice_mips_code_len)
|
||||
local search_pos = 1
|
||||
local last_match = nil
|
||||
while true do
|
||||
local found = source:find("Slice_MipsCode", search_pos, true)
|
||||
if not found or found >= before_pos then break end
|
||||
last_match = found
|
||||
search_pos = found + slice_mips_code_len
|
||||
end
|
||||
if not last_match then return nil, nil end
|
||||
|
||||
local pos = last_match + slice_mips_code_len
|
||||
while pos < before_pos do
|
||||
-- skip whitespace
|
||||
while pos <= #source do
|
||||
local c = source:sub(pos, pos)
|
||||
if c == " " or c == "\t" or c == "\n" or c == "\r" then
|
||||
pos = pos + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if pos > #source then break end
|
||||
-- skip line comments
|
||||
if source:sub(pos, pos + 1) == "//" then
|
||||
while pos <= #source and source:sub(pos, pos) ~= "\n" do pos = pos + 1 end
|
||||
pos = pos + 1
|
||||
goto continue
|
||||
end
|
||||
-- skip block comments
|
||||
if source:sub(pos, pos + 1) == "/*" then
|
||||
local close = source:find("*/", pos + 2, true)
|
||||
if not close then break end
|
||||
pos = close + 2
|
||||
goto continue
|
||||
end
|
||||
-- try to read an ident
|
||||
local ident, ident_end = M.read_ident(source, pos)
|
||||
if not ident then break end
|
||||
-- check if the next non-ws char after ident is "("
|
||||
local next_pos = M.skip_ws_and_cmt(source, ident_end)
|
||||
if source:sub(next_pos, next_pos) == "(" then
|
||||
local inner = M.read_parens(source, next_pos)
|
||||
if inner then
|
||||
return ident, inner
|
||||
end
|
||||
end
|
||||
-- ident not followed by "(" — it's a qualifier (FI_, atom_dbg_skip, etc); skip it
|
||||
pos = ident_end
|
||||
::continue::
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- find_atom_proc_decl_for — backward walk for MipsAtom_Proc_ name extraction.
|
||||
--
|
||||
-- After the `sym` arg was dropped from MipsAtom_Proc_, the atom name is
|
||||
-- derived from the preceding `MipsAtom* X_proc(args)` function declaration.
|
||||
-- This function walks backward from `before_pos` to find it.
|
||||
--
|
||||
-- Returns (raw_name, args_inner) or (nil, nil).
|
||||
-- raw_name — e.g. "normalize_v3s4" (the _proc suffix is stripped)
|
||||
-- args_inner — e.g. "AtomArena_R aa, U4 r_scratch, ..."
|
||||
--
|
||||
-- The walk finds the LAST "MipsAtom*" before before_pos, then skips
|
||||
-- whitespace + qualifiers (internal, I_, FI_, comments) until it finds an
|
||||
-- ident followed by "(". That ident is the function name (with _proc suffix);
|
||||
-- the suffix is stripped to get raw_name. The parens contents are the args.
|
||||
-------------------------------------------------------------------------------
|
||||
function M.find_atom_proc_decl_for(source, before_pos, mips_atom_ptr_len)
|
||||
local search_pos = 1
|
||||
local last_match = nil
|
||||
while true do
|
||||
-- plain=true: "*" is literal, no escaping needed
|
||||
local found = source:find("MipsAtom*", search_pos, true)
|
||||
if not found or found >= before_pos then break end
|
||||
last_match = found
|
||||
search_pos = found + mips_atom_ptr_len
|
||||
end
|
||||
if not last_match then return nil, nil end
|
||||
|
||||
local pos = last_match + mips_atom_ptr_len
|
||||
while pos < before_pos do
|
||||
-- skip whitespace
|
||||
while pos <= #source do
|
||||
local c = source:sub(pos, pos)
|
||||
if c == " " or c == "\t" or c == "\n" or c == "\r" then
|
||||
pos = pos + 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
if pos > #source then break end
|
||||
-- skip line comments
|
||||
if source:sub(pos, pos + 1) == "//" then
|
||||
while pos <= #source and source:sub(pos, pos) ~= "\n" do pos = pos + 1 end
|
||||
pos = pos + 1
|
||||
goto continue
|
||||
end
|
||||
-- skip block comments
|
||||
if source:sub(pos, pos + 1) == "/*" then
|
||||
local close = source:find("*/", pos + 2, true)
|
||||
if not close then break end
|
||||
pos = close + 2
|
||||
goto continue
|
||||
end
|
||||
-- try to read an ident
|
||||
local ident, ident_end = M.read_ident(source, pos)
|
||||
if not ident then break end
|
||||
-- check if the next non-ws char after ident is "("
|
||||
local next_pos = M.skip_ws_and_cmt(source, ident_end)
|
||||
if source:sub(next_pos, next_pos) == "(" then
|
||||
local inner = M.read_parens(source, next_pos)
|
||||
if inner then
|
||||
-- strip the _proc suffix to get the atom name
|
||||
local proc_suffix = "_proc"
|
||||
if #ident > #proc_suffix and ident:sub(-#proc_suffix) == proc_suffix then
|
||||
return ident:sub(1, #ident - #proc_suffix), inner
|
||||
end
|
||||
-- no _proc suffix — return as-is
|
||||
return ident, inner
|
||||
end
|
||||
end
|
||||
-- ident not followed by "(" — it's a qualifier; skip it
|
||||
pos = ident_end
|
||||
::continue::
|
||||
end
|
||||
return nil, nil
|
||||
end
|
||||
|
||||
return M
|
||||
|
||||
@@ -96,48 +96,21 @@ local M = {}
|
||||
-- so this file reads it forward rather than re-walking the source.
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
--- Find the args of the function declaration that immediately precedes a `MipsAtomComp_Proc_` invocation of the given name.
|
||||
--- Find the args of the function declaration that immediately precedes a `MipsAtomComp_Proc_` invocation.
|
||||
--- Returns the args string (e.g., `"U4 off, U4 code, U1 r, U1 g, U1 b"`) or nil if no function declaration is found.
|
||||
---
|
||||
--- Convention: function form is
|
||||
--- `FI_ Slice_MipsCode ac_X(args) MipsAtomComp_Proc_(ac_X, { body })`
|
||||
--- We find the LAST occurrence of `"ac_X("` before `before_pos` and extract the args from inside the parens.
|
||||
--- We then verify the preceding context ends with `Slice_MipsCode`
|
||||
--- (the function-decl keyword with possible qualifiers between).
|
||||
--- After the `sym` arg was dropped from MipsAtomComp_Proc_, the component name
|
||||
--- and the args both come from the preceding `FI_ Slice_MipsCode ac_X(args)`
|
||||
--- declaration. The shared `duffle.find_function_decl_for` helper does the
|
||||
--- backward walk; this function returns just the args.
|
||||
---
|
||||
--- @param source string
|
||||
--- @param name string
|
||||
--- @param name string (retained for signature stability; unused — the walk derives the name)
|
||||
--- @param before_pos integer
|
||||
--- @return string|nil
|
||||
local function find_function_args_for(source, name, before_pos)
|
||||
-- Find the LAST occurrence of `name + "("` in `source[1..before_pos]`.
|
||||
local name_open = name .. "("
|
||||
local last_idx = nil
|
||||
local scan_pos = 1
|
||||
while true do
|
||||
-- Pass `before_pos + 1` so string.find only returns positions < before_pos + 1
|
||||
-- (string.find's 4th arg `plain` is true; we use the 3rd arg `init` for the upper bound).
|
||||
local found = source:find(name_open, scan_pos, true)
|
||||
if not found or found >= before_pos then break end
|
||||
last_idx = found
|
||||
scan_pos = found + #name_open
|
||||
end
|
||||
if not last_idx then return nil end
|
||||
|
||||
-- Verify the preceding context ends with "MipsAtom" (with possible qualifiers between).
|
||||
local before = source:sub(1, last_idx - 1)
|
||||
local trimmed = duffle.trim(before)
|
||||
if trimmed:sub(-#MIPS_ATOM) ~= MIPS_ATOM then
|
||||
-- Preceding context is not a function declaration.
|
||||
return nil
|
||||
end
|
||||
|
||||
local open_paren = last_idx + #name -- position of "("
|
||||
-- scan: MipsAtom ac_X(
|
||||
local inner = duffle.read_parens(source, open_paren)
|
||||
-- scan: MipsAtom ac_X(<args>)
|
||||
if not inner then return nil end
|
||||
return inner
|
||||
local _, args_inner = duffle.find_function_decl_for(source, before_pos, #MIPS_ATOM)
|
||||
return args_inner
|
||||
end
|
||||
|
||||
-- ════════════════════════════════════════════════════════════════════════════
|
||||
|
||||
@@ -137,6 +137,16 @@ local QUALIFIER_KEYWORDS = {
|
||||
local AC_PREFIX = "ac_"
|
||||
local AC_PREFIX_LEN = 3
|
||||
|
||||
-- The function-decl keyword that precedes a MipsAtomComp_Proc_ call.
|
||||
-- Used by the backward walk in duffle.find_function_decl_for.
|
||||
local SLICE_MIPS_CODE = "Slice_MipsCode"
|
||||
local SLICE_MIPS_CODE_LEN = #SLICE_MIPS_CODE
|
||||
|
||||
-- The return type that precedes a MipsAtom_Proc_ function declaration.
|
||||
-- Used by the backward walk in duffle.find_atom_proc_decl_for.
|
||||
local MIPS_ATOM_PTR = "MipsAtom*"
|
||||
local MIPS_ATOM_PTR_LEN = #MIPS_ATOM_PTR
|
||||
|
||||
--- Strip the "ac_" prefix from a component name.
|
||||
--- Returns the input unchanged if it doesn't start with the prefix.
|
||||
--- @param raw_name string
|
||||
@@ -1357,7 +1367,11 @@ local function parse_mips_atom_comp_proc(source, pos, ident_end, line_of, out)
|
||||
local body, close_pos = duffle.read_braces(inner, last_brace_pos)
|
||||
if close_pos > #inner + 1 then return after_paren end
|
||||
|
||||
local raw_name = inner:match("^%s*([%w_]+)") or "?"
|
||||
-- The component name is derived from the preceding function declaration
|
||||
-- (`FI_ Slice_MipsCode ac_X(...)`), not from the first macro arg (which
|
||||
-- is now `ab`). The backward walk finds the function decl before open_paren.
|
||||
local raw_name = duffle.find_function_decl_for(source, open_paren, SLICE_MIPS_CODE_LEN)
|
||||
if not raw_name then raw_name = "?" end
|
||||
local name = strip_ac_prefix(raw_name)
|
||||
-- Position of body[1] in source = open_paren + 1 (start of inner) + last_brace_pos + 1 (past '{').
|
||||
local body_off = open_paren + 2 + last_brace_pos
|
||||
@@ -1398,9 +1412,12 @@ local function parse_mips_atom_proc(source, pos, ident_end, line_of, out)
|
||||
local body, close_pos = duffle.read_braces(inner, last_brace_pos)
|
||||
if close_pos > #inner + 1 then return after_paren end
|
||||
|
||||
-- The atom name is the FIRST ident of the args (matches MipsAtomComp_Proc_'s "first ident" rule).
|
||||
-- MipsAtom_Proc_ has no `ac_` prefix; `strip_ac_prefix` is a no-op for unprefixed names.
|
||||
local raw_name = inner:match("^%s*([%w_]+)") or "?"
|
||||
-- The atom name is derived from the preceding function declaration
|
||||
-- (`internal MipsAtom* X_proc(...)`), not from the first macro arg (which
|
||||
-- is now `aa`). The backward walk finds the function decl before open_paren
|
||||
-- and strips the `_proc` suffix.
|
||||
local raw_name = duffle.find_atom_proc_decl_for(source, open_paren, MIPS_ATOM_PTR_LEN)
|
||||
if not raw_name then raw_name = "?" end
|
||||
local name = strip_ac_prefix(raw_name)
|
||||
-- Position of body[1] in source = open_paren + 1 (start of inner) + last_brace_pos + 1 (past '{').
|
||||
local body_off = open_paren + 2 + last_brace_pos
|
||||
|
||||
Reference in New Issue
Block a user