GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Add a macro expander that uses hide sets · Issue #742 · cppcheck-opensource/simplecpp

Add a macro expander that uses hide sets #742

New issue
Copy link
New issue
Copy link
Open
6 / 76 of 7 issues completed
Open
Add a macro expander that uses hide sets#742
6 / 76 of 7 issues completed
Copy link

Description

@danmar
danmar
opened on Nov 8, 2026
Issue body actions

Part of the macro expansion rewrite (#708, step 4).

Problems with the current macro expansion

The standard describes macro expansion in translation phase 4 (C11 6.10.3.4, C++ [cpp.rescan]): the replacement list is rescanned together with the rest of the source, and a macro name found inside its own expansion is not replaced. simplecpp's Macro::expand() doesn't model these rules directly. It approximates them, and that causes bugs and makes the code hard to change:

  • No model of "painted" tokens. Recursion is prevented with an expandedmacros set that is copied down the call stack, together with per-token "expanded from" markers. A "temporary amnesia" step removes the current macro from the set again while its arguments are expanded.
  • The same rule in three places. "The expansion ends with the name of a function-like macro and its arguments follow in the source" is implemented three times: in the public Macro::expand(), in expandTrailingCalls(), and in a callback in expandArg().
  • Arguments are expanded each time they are used, not once before substitution. For example, macro usage is reported twice for B(A) with #define B(x) x A.
  • Hard to change. It is about 1000 lines, and fixes are added as special cases.

Wrong results that follow from this:

Input gcc simplecpp
#define f(x) x / f(f)(1) f(1) 1
#define R() / R at the end of the file R error: wrong number of parameters
ELLIP_FUNC(F LPAREN 'a', 'b' RPAREN) (clang macro_rescan_varargs.c) 'a' + 'b' F ( 'a' , 'b' )

Proposed solution

Use the established algorithm for this: Prosser's hide-set algorithm, as used by mcpp, ucpp and chibicc. It implements the standard's rules directly:

  • Each token has a hide set: the macros it must not be expanded into.
  • An object-like macro adds itself to the hide set of its result. For a function-like macro, the result's hide set is the intersection of the hide sets of the name and the ), plus the macro.
  • Each argument is fully expanded once, except where it is an operand of # or ##.
  • The result is pushed back onto the input and scanned again. A call whose arguments follow in the source is found by normal rescanning, so no special code is needed for it.

The new expander is written next to the old one and selected with DUI::hideSetExpansion, so both can be compared on real code and in cppcheck before the old one is removed. Functions are broken out of the old code and shared where possible (argument splitting and count check, __FILE__/__LINE__/__COUNTER__, defined, #, the ## checks).

Activity

  1. danmar
    added a parent issue on Nov 8, 2026
    • Restructure the preprocessor to follow the standard's translation phases #708
  2. danmar
    added sub-issues on Nov 10, 2026
    • Add regression tests for macro expansion #744
    • Refactoring: Split expandHashHash and expandHash into check and build helpers #746
    • Move the argument count check into Macro::getMacroParameters() #748
    • Extract expandBuiltin, expandDefined and copyMacroCall #750
    • Add TokenList::setLocation() for setting the location of all tokens #752
    • hash: keep the space after an operator of two characters #754
    • hash hash: pasting a name or number with a string or character literal is an error #756
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402520 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.