Skip to content

feat(cc): function-pointer typedefs/params + positional struct initializers#492

Merged
bboe merged 2 commits into
mainfrom
bboe/cc-fnptr-typedef-positional-struct
May 24, 2026
Merged

feat(cc): function-pointer typedefs/params + positional struct initializers#492
bboe merged 2 commits into
mainfrom
bboe/cc-fnptr-typedef-positional-struct

Conversation

@bboe
Copy link
Copy Markdown
Owner

@bboe bboe commented May 24, 2026

Summary

Two parser/codegen additions, each Phase 6 enablement for compiling
user/libbboeos/ through cc.py.

  • Function-pointer typedef aliases (Commit 1): typedef <ret> (*<alias>)(<args>); registers <alias> as a typedef-aliased
    spelling for the opaque "function_pointer" type cc.py already
    uses for local function-pointer variables and function-pointer
    parameters (b2ccf5d). Unblocks <signal.h> (sighandler_t)
    and the cast-based SIG_DFL / SIG_IGN macros, plus the
    <stdlib.h> qsort/bsearch/atexit prototypes that use named
    callback typedefs.

  • Positional struct initializers (Commit 2): struct T x = {a, b, c}; is the positional form of brace initialization — fields
    fill in declaration order. Pre-patch, cc.py only accepted {0}
    zero-init and the designated {.field = expr, ...} form.
    Codegen extended on both sides: local VarDecl reuses the existing
    zero-store + per-field MemberAssign path; file-scope struct
    globals now emit per-field directives walked from the struct
    layout (db/dw/dd matched to field width). Forcing
    function: user/libbboeos/stdio.c line 14 declares static FILE _stderr = {0, 0, 2};.

Test plan

  • python3 -m pytest tests/unit/ tests/test_ccobj.py tests/test_ccld.py tests/test_ccar.py -x -q — 559 passed
  • python3 tests/test_cc_bits.py — 112/112 pass
  • Probe cc.py user/libbboeos/stdio.c parses past line 14
    (stops at line 451 on an unrelated identifier-as-label issue)
  • Probe cc.py user/libbboeos/stdlib.c parses past the
    qsort/bsearch prototypes (the file's remaining blocker is
    static void (*_atexit_fns[N])(void); — an array of
    function pointers at file scope, not covered by this PR)
  • cc.py user/libbboeos/signal.c still hits the pre-existing
    stringify-operator (#x) limitation in the preprocessor at
    <syscalls.h>; the typedef/cast/parameter parse cleanly in
    isolation, confirmed via direct signal.h probes
  • ./make_os.sh — full image build succeeds
  • timeout 240 python3 tests/test_asm.py — 42 passed, 0 failed

🤖 Generated with Claude Code

@bboe bboe force-pushed the bboe/cc-fnptr-typedef-positional-struct branch 2 times, most recently from 458c6fd to c13b670 Compare May 24, 2026 07:59
bboe and others added 2 commits May 24, 2026 01:55
``typedef <ret> (*<alias>)(<args>);`` registers ``<alias>`` as a
typedef-aliased spelling for the opaque ``"function_pointer"``
type cc.py already uses for local function-pointer variables and
function-pointer parameters (b2ccf5d).  The inner argument list
is parsed and discarded — cc.py has no per-typedef callable
machinery yet, so calling through a typedef'd function pointer
still requires the local-variable shape; but the alias is enough
for parameter types, return types, and casts, which is what
``<signal.h>`` and the ``<stdlib.h>`` qsort/bsearch/atexit
prototypes need.

Forcing function: ``user/libbboeos/include/signal.h`` declares
``typedef void (*sighandler_t)(int);`` and consumers use the
alias as a parameter type, return type, and inside a cast
(``#define SIG_DFL ((sighandler_t)0)``).  Pre-patch, cc.py
rejected the typedef with ``expected typedef alias name, got
LPAREN``.  Post-patch, the alias resolves through the existing
``typedef_aliases`` map and Cast is identity codegen for
non-struct-pointer targets, so every use site Just Works.

Phase 6 enablement: shrinks the libbboeos-on-cc.py gap by one
header (``<signal.h>``) and removes a blocker for compiling
``user/libbboeos/stdlib.h`` and ``stdio.h`` prototypes that
take callback function-pointer parameters.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
``struct T x = {a, b, c};`` is the positional form of brace
initialization — fields fill in declaration order, matching
standard C.  Pre-patch, ``_parse_designated_struct_initializer``
hard-rejected any non-``.field``, non-``{0}`` shape; post-patch
it dispatches by leading token: ``DOT`` keeps the designated
path, anything else parses positional values into the existing
``StructInitializer.positional`` slot.

Codegen sides:

* Local struct VarDecl: ``_emit_struct_initializer`` already
  zero-stores the slot then emits per-field MemberAssigns.  The
  positional branch zips field-name order from
  ``struct_layouts[tag]`` with the value list and reuses the
  same MemberAssign synthesis.

* File-scope struct global: previously rejected because
  ``_constant_expression(StructInitializer)`` returns None.  The
  guard now lets brace initializers through for struct-typed
  globals; a new ``_validate_struct_global_initializer`` checks
  every field value is constant, and the global-emission loop
  walks the layout to emit a width-appropriate directive per
  field (``db``/``dw``/``dd`` matched to the field width).

Forcing function: ``user/libbboeos/stdio.c`` declares ``static
FILE _stderr = {0, 0, 2};`` on line 14.  Phase 6 enablement —
``stdio.c`` now parses past line 14 (stops at line 451 on an
unrelated ``L`` identifier issue).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@bboe bboe force-pushed the bboe/cc-fnptr-typedef-positional-struct branch from c13b670 to 71cb6ed Compare May 24, 2026 08:55
@bboe bboe merged commit fae1aba into main May 24, 2026
27 checks passed
@bboe bboe deleted the bboe/cc-fnptr-typedef-positional-struct branch May 24, 2026 09:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant