Skip to content

Commit

Permalink
ImportC: support #define IDENT ( expression ) (#15871)
Browse files Browse the repository at this point in the history
  • Loading branch information
WalterBright committed Dec 5, 2023
1 parent faa773d commit 807373a
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 29 deletions.
94 changes: 66 additions & 28 deletions compiler/src/dmd/cparse.d
Original file line number Diff line number Diff line change
Expand Up @@ -4272,6 +4272,7 @@ final class CParser(AST) : Parser!AST
case TOK.rightParenthesis:
case TOK.rightBracket:
case TOK.endOfFile:
case TOK.endOfLine:
if (!any)
return false;
break;
Expand Down Expand Up @@ -5794,47 +5795,50 @@ final class CParser(AST) : Parser!AST
buf.writeByte(0);
auto slice = buf.peekChars()[0 .. length];
resetDefineLines(slice); // reset lexer
auto save = eSink;
auto eLatch = new ErrorSinkLatch();
eSink = eLatch;

const(char)* endp = &slice[length - 7];

size_t[void*] defineTab; // hash table of #define's turned into Symbol's
// indexed by Identifier, returns index into symbols[]
// The memory for this is leaked

void addVar(AST.VarDeclaration v)
void addVar(AST.Dsymbol s)
{
//printf("addVar() %s\n", v.toChars());
v.isCmacro(true); // mark it as coming from a C #define
//printf("addVar() %s\n", s.toChars());
if (auto v = s.isVarDeclaration())
v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
* definition
*/
if (size_t* pd = cast(void*)v.ident in defineTab)
if (size_t* pd = cast(void*)s.ident in defineTab)
{
//printf("replacing %s\n", v.toChars());
(*symbols)[*pd] = v;
(*symbols)[*pd] = s;
return;
}
defineTab[cast(void*)v.ident] = symbols.length;
symbols.push(v);
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
}

Token n;

while (p < endp)
{
if (p[0 .. 7] == "#define")
{
p += 7;
scan(&n);
//printf("%s\n", n.toChars());
if (n.value == TOK.identifier)
nextToken();
//printf("define %s\n", token.toChars());
if (token.value == TOK.identifier)
{
auto id = n.ident;
scan(&n);
auto id = token.ident;
const params = *p == '(';
nextToken();

AST.Type t;

switch (n.value)
switch (token.value)
{
case TOK.endOfLine: // #define identifier
nextDefineLine();
Expand All @@ -5847,9 +5851,9 @@ final class CParser(AST) : Parser!AST
case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger;

Linteger:
const intvalue = n.intvalue;
scan(&n);
if (n.value == TOK.endOfLine)
const intvalue = token.intvalue;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = intvalue;
Expand All @@ -5870,9 +5874,9 @@ final class CParser(AST) : Parser!AST
case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat;

Lfloat:
const floatvalue = n.floatvalue;
scan(&n);
if (n.value == TOK.endOfLine)
const floatvalue = token.floatvalue;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = floatvalue;
Expand All @@ -5886,11 +5890,11 @@ final class CParser(AST) : Parser!AST
break;

case TOK.string_:
const str = n.ustring;
const len = n.len;
const postfix = n.postfix;
scan(&n);
if (n.value == TOK.endOfLine)
const str = token.ustring;
const len = token.len;
const postfix = token.postfix;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = "string";
Expand All @@ -5903,6 +5907,39 @@ 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
nextToken();
eLatch.sawErrors = false;
auto exp = cparseExpression();
if (eLatch.sawErrors) // parsing errors
break; // abandon this #define
if (token.value != TOK.rightParenthesis)
break;
nextToken();
if (token.value != TOK.endOfLine)
break;
auto ret = new AST.ReturnStatement(exp.loc, exp);
auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
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;
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
AST.TemplateParameters* tpl = new AST.TemplateParameters();
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
addVar(tempdecl);
nextDefineLine();
continue;

default:
break;
}
Expand All @@ -5911,15 +5948,16 @@ final class CParser(AST) : Parser!AST
}
else
{
scan(&n);
if (n.value != TOK.endOfLine)
scan(&token);
if (token.value != TOK.endOfLine)
{
skipToNextLine();
}
}
nextDefineLine();
}

eSink = save;
defines = buf;
}

Expand Down
14 changes: 14 additions & 0 deletions compiler/src/dmd/errorsink.d
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ class ErrorSinkNull : ErrorSink
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
}

/*****************************************
* Ignores the messages, but sets `sawErrors` for any calls to `error()`
*/
class ErrorSinkLatch : ErrorSinkNull
{
nothrow:
extern (C++):
override:

bool sawErrors;

void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
}

/*****************************************
* Simplest implementation, just sends messages to stderr.
* See also: ErrorSinkCompiler.
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dmd/lexer.d
Original file line number Diff line number Diff line change
Expand Up @@ -3263,7 +3263,7 @@ class Lexer
while (1)
{
printf("%s ", (*tk).toChars());
if (tk.value == TOK.endOfFile)
if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine)
break;
tk = peek(tk);
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/test/compilable/imports/defines.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9");

#define SSS "hello"
_Static_assert(SSS[0] == 'h', "10");

#define ABC 12
#define GHI (size) abbadabba
#define DEF (ABC + 5)
3 changes: 3 additions & 0 deletions compiler/test/compilable/testdefines.d
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ static assert(F64 == 8.0);
static assert(F80 == 9.0L);

static assert(SSS == "hello");

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

0 comments on commit 807373a

Please sign in to comment.