Skip to content

Commit

Permalink
Merge pull request #4184 from masatake/cpreprocessor--gnuext-variadic…
Browse files Browse the repository at this point in the history
…-args

CPreProcessor: support variadic macros with GNU cpp extension syntax
  • Loading branch information
masatake authored Jan 28, 2025
2 parents 5f8901a + b82d655 commit d2c536c
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 6 deletions.
1 change: 1 addition & 0 deletions Units/parser-cxx.r/complex-macros.d/args.ctags
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
-D DECLARE_FUNCTION_2(_ret,_name)=_ret _name();
-D DECLARE_FUNCTION_3(_ret,_name,...)=_ret _name(__VA_ARGS__);
-D DEPRECATED(...)=__VA_ARGS__ __attribute__((deprecated))
-D ENUM_GNUX(n,e...)=enum n { e }
-D DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2)=DECLARE_FUNCTION_2(int,_prefix1 ## a) DECLARE_FUNCTION_2(int,_prefix2 ## a)
-D STRINGIFY(token)=#token
-D IMPLEMENT_FUNCTIONS(_prefix)=void _prefix ## a(){ }; void _prefix ## b(){ };
Expand Down
7 changes: 7 additions & 0 deletions Units/parser-cxx.r/complex-macros.d/expected.tags
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ a input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref
b input.cpp /^DECLARE_FUNCTION_3(int,p3,int a,int b);$/;" z prototype:p3 typeref:typename:int file:
DEPRECATED input.cpp /^#define DEPRECATED(/;" d file: signature:(...)
p4 input.cpp /^DEPRECATED(int p4());$/;" p typeref:typename:int file: signature:() properties:deprecated
n input.cpp /^#define ENUM_GNUX(n,e...) enum n { e }$/;" D macro:ENUM_GNUX
e input.cpp /^#define ENUM_GNUX(n,e...) enum n { e }$/;" D macro:ENUM_GNUX
ENUM_GNUX input.cpp /^#define ENUM_GNUX(/;" d file: signature:(n,e...)
color input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" g file:
red input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
blue input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
green input.cpp /^ENUM_GNUX(color, red, blue, green);$/;" e enum:color file:
_prefix1 input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \\$/;" D macro:DECLARE_TWO_VERSIONS_OF_FUNCTIONS
_prefix2 input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \\$/;" D macro:DECLARE_TWO_VERSIONS_OF_FUNCTIONS
DECLARE_TWO_VERSIONS_OF_FUNCTIONS input.cpp /^#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(/;" d file: signature:(_prefix1,_prefix2)
Expand Down
4 changes: 4 additions & 0 deletions Units/parser-cxx.r/complex-macros.d/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ DECLARE_FUNCTION_3(int,p3,int a,int b);

DEPRECATED(int p4());

#define ENUM_GNUX(n,e...) enum n { e }

ENUM_GNUX(color, red, blue, green);

// Recursive macro expansion

#define DECLARE_TWO_VERSIONS_OF_FUNCTIONS(_prefix1,_prefix2) \
Expand Down
45 changes: 39 additions & 6 deletions parsers/cpreprocessor.c
Original file line number Diff line number Diff line change
Expand Up @@ -215,12 +215,12 @@ static int externalParserBlockNestLevel;
*/
static bool BraceFormat = false;

void cppPushExternalParserBlock(void)
extern void cppPushExternalParserBlock(void)
{
externalParserBlockNestLevel++;
}

void cppPopExternalParserBlock(void)
extern void cppPopExternalParserBlock(void)
{
externalParserBlockNestLevel--;
}
Expand Down Expand Up @@ -527,13 +527,13 @@ extern void cppUngetc (const int c)
Cpp.ungetDataSize++;
}

int cppUngetBufferSize(void)
extern int cppUngetBufferSize(void)
{
return Cpp.ungetBufferSize;
}

/* This puts an entire string back into the input queue for the input File. */
void cppUngetString(const char * string,int len)
extern void cppUngetString(const char * string,int len)
{
if(!string)
return;
Expand Down Expand Up @@ -985,7 +985,28 @@ static int directiveDefine (const int c, bool undef)

if (vStringLength (param) > 0)
{
int r = makeParamTag (param, nth++, vStringChar(param, 0) == '.');
bool gnuext_placeholder = false;
if (vStringLength (param) > 3
&& strcmp(vStringValue (param) + vStringLength (param) - 3,
"...") == 0)
{
/* args... in GNU cpp extension
*
* #define debug(format, args...) fprintf (stderr, format, args)
*
* In this case, args should be tagged. However the signature field
* for debug must be "(format,args...)".
*/
vString *nodots = vStringNewNInit (vStringValue (param),
vStringLength (param) - 3);
makeParamTag (nodots, nth, false);
vStringDelete (nodots);
gnuext_placeholder = true;
}

int r = makeParamTag (param, nth++,
vStringChar(param, 0) == '.'
|| gnuext_placeholder);
intArrayAdd (params, r);
vStringClear (param);
}
Expand Down Expand Up @@ -1346,7 +1367,7 @@ static int skipOverDComment (void)
return c;
}

const vString * cppGetLastCharOrStringContents (void)
extern const vString * cppGetLastCharOrStringContents (void)
{
CXX_DEBUG_ASSERT(Cpp.charOrStringContents,"Shouldn't be called when CPP is not initialized");
return Cpp.charOrStringContents;
Expand Down Expand Up @@ -2410,13 +2431,25 @@ static cppMacroInfo * saveMacro(hashTable *table, const char * macro)

if(
(
/* #define debug(format, ...) fprintf (stderr, format, __VA_ARGS__) */
bIsVarArg &&
(paramLen == 3) &&
(strncmp(paramBegin[i],"...",3) == 0)
) || (
/* #define debug(MSG) fputs(MSG, stderr) */
(!bIsVarArg) &&
(paramLen == tokenLen) &&
(strncmp(paramBegin[i],tokenBegin,paramLen) == 0)
) || (
/* GNU cpp extension:
* #define debug(format, args...) fprintf (stderr, format, args)
*/
(!bIsVarArg) &&
(paramLen == tokenLen + 3) &&
(strncmp(paramBegin[i] + tokenLen, "...", 3) == 0) &&
(strncmp(paramBegin[i], tokenBegin, tokenLen) == 0) &&
/* Let's have a side effect */
(bIsVarArg = true)
)
)
{
Expand Down

0 comments on commit d2c536c

Please sign in to comment.