Decompiler: propagate labels through nested statement lists

This commit is contained in:
Yan 2026-07-29 09:44:31 +00:00
parent 76b0981a76
commit e958d1dde4
2 changed files with 47 additions and 4 deletions

View file

@ -906,21 +906,38 @@ class CStatements(CStatement):
self.addr = addr
def c_repr_chunks(self, indent=0, asexpr=False):
yield from self._c_repr_chunks(indent=indent, asexpr=asexpr, terminate_trailing_label=True)
def _c_repr_chunks(self, indent=0, asexpr=False, *, terminate_trailing_label):
indent_str = self.indent_str(indent)
if self.codegen.display_block_addrs:
yield indent_str, None
yield f"/* Block {hex(self.addr) if self.addr is not None else 'unknown'} */", None
yield "\n", None
for stmt in self.statements:
yield from stmt.c_repr_chunks(indent=indent, asexpr=asexpr)
if isinstance(stmt, CStatements):
# CStatements may be a transparent sequence nested inside another sequence. A label at the end of
# the inner sequence still labels the next statement in the outer sequence.
yield from stmt._c_repr_chunks(indent=indent, asexpr=asexpr, terminate_trailing_label=False)
else:
yield from stmt.c_repr_chunks(indent=indent, asexpr=asexpr)
if asexpr:
yield ", ", None
if not asexpr and self.statements and isinstance(self.statements[-1], CLabel):
# A C label prefixes a statement; it is not a complete statement itself. Finish a trailing label run
# locally so that the next statement in an outer sequence cannot become its labeled statement.
if not asexpr and terminate_trailing_label and isinstance(self._last_nonempty_statement(), CLabel):
# A C label prefixes a statement; it is not a complete statement itself. Finish it only at the boundary
# of the enclosing sequence, after looking through transparent nested sequences.
yield indent_str, None
yield ";\n", None
def _last_nonempty_statement(self) -> CStatement | None:
for stmt in reversed(self.statements):
if isinstance(stmt, CStatements):
stmt = stmt._last_nonempty_statement()
if stmt is None:
continue
return stmt
return None
class CAILBlock(CStatement):
"""

View file

@ -57,6 +57,32 @@ def test_trailing_label_run_has_one_null_statement():
assert _render(statements, indent=4) == "LABEL_400000:\nLABEL_400010:\n ;\n"
def test_nested_trailing_label_prefixes_next_outer_statement():
codegen = _codegen()
statements = CStatements(
[
CStatements([CLabel("LABEL_400000", codegen=codegen)], codegen=codegen),
CReturn(None, codegen=codegen),
],
codegen=codegen,
)
assert _render(statements) == "LABEL_400000:\nreturn;\n"
def test_nested_terminal_label_has_null_statement():
codegen = _codegen()
statements = CStatements(
[
CStatements([CLabel("LABEL_400000", codegen=codegen)], codegen=codegen),
CStatements([], codegen=codegen),
],
codegen=codegen,
)
assert _render(statements, indent=4) == "LABEL_400000:\n ;\n"
def test_trailing_label_does_not_capture_outer_statement():
codegen = _codegen()
conditional = CIfElse(