Skip to content

Commit

Permalink
fix bugzilla Issue 24397 ImportC: support function-like macros
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Feb 17, 2024
1 parent e9cacc3 commit 8bd9815
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 1 deletion.
92 changes: 91 additions & 1 deletion compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -5834,6 +5834,8 @@ final class CParser(AST) : Parser!AST
{
if (!defines || defines.length < 10) // minimum length of a #define line
return;
if (!symbols)
symbols = new AST.Dsymbols();
OutBuffer* buf = defines;
defines = null; // prevent skipToNextLine() and parseSpecialTokenSequence()
// from appending to slice[]
Expand Down Expand Up @@ -5884,6 +5886,7 @@ final class CParser(AST) : Parser!AST

AST.Type t;

Lswitch:
switch (token.value)
{
case TOK.endOfLine: // #define identifier
Expand Down Expand Up @@ -5956,13 +5959,14 @@ final class CParser(AST) : Parser!AST
break;

case TOK.leftParenthesis:
{
/* Look for:
* #define ID ( expression )
* and rewrite it to a template function:
* auto ID()() { return expression; }
*/
if (params)
break; // no parameters
goto caseFunctionLike; // version with parameters
nextToken();
eLatch.sawErrors = false;
auto exp = cparseExpression();
Expand All @@ -5987,6 +5991,92 @@ final class CParser(AST) : Parser!AST
addVar(tempdecl);
nextDefineLine();
continue;
}

caseFunctionLike:
{
/* Parse `( a, b ) expression`
* Create template function:
* auto id(__MP1, __MP2)(__MP1 a, __MP1 b) { return expression; }
*/
//printf("functionlike %s\n", id.toChars());

// Capture the parameter list
VarArg varargs = VarArg.none;
auto parameters = new AST.Parameters();
nextToken(); // skip past `(`
Lwhile:
while (1)
{
if (token.value == TOK.rightParenthesis)
break;
if (token.value == TOK.dotDotDot)
{
static if (0) // variadic macros not supported yet
{
varargs = AST.VarArg.variadic; // C-style variadics
nextToken();
if (token.value == TOK.rightParenthesis)
break Lwhile;
}
break Lswitch;
}

if (token.value != TOK.identifier)
break Lswitch;
auto param = new AST.Parameter(token.loc, 0, null, token.ident, null, null);
parameters.push(param);
nextToken();
if (token.value == TOK.comma)
{
nextToken();
continue;
}
break;
}
if (token.value != TOK.rightParenthesis)
break;
nextToken();
auto parameterList = AST.ParameterList(parameters, varargs, 0);
/* Create a type for each parameter. Add it to the template parameter list,
* and the parameter list.
*/
auto tpl = new AST.TemplateParameters();
foreach (param; (*parameters)[])
{
auto idtype = Identifier.generateId("__MP");
auto loc = param.loc;
auto tp = new AST.TemplateTypeParameter(loc, idtype, null, null);
tpl.push(tp);

auto at = new AST.TypeIdentifier(loc, idtype);
param.type = at;
}

eLatch.sawErrors = false;
auto exp = cparseExpression();
if (eLatch.sawErrors) // parsing errors
break; // abandon this #define

if (token.value != TOK.endOfLine)
break;

// Generate function
auto ret = new AST.ReturnStatement(exp.loc, exp);
StorageClass stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;

// Wrap it in an eponymous template
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
addVar(tempdecl);

nextDefineLine();
continue;
}

default:
break;
Expand Down
3 changes: 3 additions & 0 deletions compiler/test/compilable/imports/defines.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,6 @@ _Static_assert(SSS[0] == 'h', "10");
#define ABC 12
#define GHI (size) abbadabba
#define DEF (ABC + 5)

#define ADD(a, b) a + b
#define SUB() 3 - 2
3 changes: 3 additions & 0 deletions compiler/test/compilable/testdefines.d
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,6 @@ static assert(SSS == "hello");

static assert(ABC == 12);
static assert(DEF == 17);

static assert(ADD(3, 4) == 7);
static assert(SUB() == 1);

0 comments on commit 8bd9815

Please sign in to comment.