PP: More clearly distinguish funtion-like and object-like macros

This commit is contained in:
John Kessenich 2018-11-07 17:14:46 -07:00
parent 0a339ec20c
commit 4ee2f75294
4 changed files with 17 additions and 15 deletions

View File

@ -35,9 +35,9 @@ ERROR: 0:155: '#else' : unexpected tokens following directive
ERROR: 0:158: '#else' : #else after #else ERROR: 0:158: '#else' : #else after #else
ERROR: 0:160: '#endif' : unexpected tokens following directive ERROR: 0:160: '#endif' : unexpected tokens following directive
ERROR: 0:164: '#define' : duplicate macro parameter ERROR: 0:164: '#define' : duplicate macro parameter
ERROR: 0:173: '#define' : Macro redefined; different number of arguments: m4 ERROR: 0:173: '#define' : Macro redefined; function-like versus object-like: m4
ERROR: 0:178: '#define' : Macro redefined; different number of arguments: m5 ERROR: 0:177: '#define' : Macro redefined; function-like versus object-like: m5
ERROR: 0:182: '#define' : Macro redefined; different number of arguments: m6 ERROR: 0:181: '#define' : Macro redefined; different number of arguments: m6
ERROR: 0:185: '#define' : Macro redefined; different substitutions: m7 ERROR: 0:185: '#define' : Macro redefined; different substitutions: m7
ERROR: 0:192: '#define' : Macro redefined; different substitutions: m8 ERROR: 0:192: '#define' : Macro redefined; different substitutions: m8
ERROR: 0:196: '#define' : Macro redefined; different argument names: m9 ERROR: 0:196: '#define' : Macro redefined; different argument names: m9

4
Test/cppSimple.vert Normal file → Executable file
View File

@ -170,7 +170,7 @@ int a = length("aoenatuh"); // ERROR
// ERROR // ERROR
#define m4(b) #define m4(b)
#define m4 (b) #define m4
// ERROR // ERROR
#define m5 (b) #define m5 (b)
@ -178,7 +178,7 @@ int a = length("aoenatuh"); // ERROR
// ERROR // ERROR
#define m6(a) #define m6(a)
#define m6 #define m6(a,b)
// ERROR (whitespace) // ERROR (whitespace)
#define m7 (a) #define m7 (a)

View File

@ -109,11 +109,12 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
// save the macro name // save the macro name
const int defAtom = atomStrings.getAddAtom(ppToken->name); const int defAtom = atomStrings.getAddAtom(ppToken->name);
TSourceLoc defineLoc = ppToken->loc; // because ppToken might go to the next line before we report errors
// gather parameters to the macro, between (...) // gather parameters to the macro, between (...)
token = scanToken(ppToken); token = scanToken(ppToken);
if (token == '(' && ! ppToken->space) { if (token == '(' && !ppToken->space) {
mac.emptyArgs = 1; mac.functionLike = 1;
do { do {
token = scanToken(ppToken); token = scanToken(ppToken);
if (mac.args.size() == 0 && token == ')') if (mac.args.size() == 0 && token == ')')
@ -123,7 +124,6 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
return token; return token;
} }
mac.emptyArgs = 0;
const int argAtom = atomStrings.getAddAtom(ppToken->name); const int argAtom = atomStrings.getAddAtom(ppToken->name);
// check for duplication of parameter name // check for duplication of parameter name
@ -149,7 +149,6 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
} }
// record the definition of the macro // record the definition of the macro
TSourceLoc defineLoc = ppToken->loc; // because ppToken is going to go to the next line before we report errors
while (token != '\n' && token != EndOfInput) { while (token != '\n' && token != EndOfInput) {
mac.body.putToken(token, ppToken); mac.body.putToken(token, ppToken);
token = scanToken(ppToken); token = scanToken(ppToken);
@ -164,7 +163,9 @@ int TPpContext::CPPdefine(TPpToken* ppToken)
// Already defined -- need to make sure they are identical: // Already defined -- need to make sure they are identical:
// "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number, // "Two replacement lists are identical if and only if the preprocessing tokens in both have the same number,
// ordering, spelling, and white-space separation, where all white-space separations are considered identical." // ordering, spelling, and white-space separation, where all white-space separations are considered identical."
if (existing->args.size() != mac.args.size() || existing->emptyArgs != mac.emptyArgs) if (existing->functionLike != mac.functionLike)
parseContext.ppError(defineLoc, "Macro redefined; function-like versus object-like:", "#define", atomStrings.getString(defAtom));
else if (existing->args.size() != mac.args.size())
parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom)); parseContext.ppError(defineLoc, "Macro redefined; different number of arguments:", "#define", atomStrings.getString(defAtom));
else { else {
if (existing->args != mac.args) if (existing->args != mac.args)
@ -1190,13 +1191,14 @@ MacroExpandResult TPpContext::MacroExpand(TPpToken* ppToken, bool expandUndef, b
TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error TSourceLoc loc = ppToken->loc; // in case we go to the next line before discovering the error
in->mac = macro; in->mac = macro;
if (macro->args.size() > 0 || macro->emptyArgs) { if (macro->functionLike) {
int token = scanToken(ppToken); int token = scanToken(ppToken);
if (newLineOkay) { if (newLineOkay) {
while (token == '\n') while (token == '\n')
token = scanToken(ppToken); token = scanToken(ppToken);
} }
if (token != '(') { if (token != '(') {
// function-like macro called with object-like syntax: okay, don't expand
UngetToken(token, ppToken); UngetToken(token, ppToken);
delete in; delete in;
return MacroExpandNotStarted; return MacroExpandNotStarted;

View File

@ -267,12 +267,12 @@ public:
// //
struct MacroSymbol { struct MacroSymbol {
MacroSymbol() : emptyArgs(0), busy(0), undef(0) { } MacroSymbol() : functionLike(0), busy(0), undef(0) { }
TVector<int> args; TVector<int> args;
TokenStream body; TokenStream body;
unsigned emptyArgs : 1; unsigned functionLike : 1; // 0 means object-like, 1 means function-like
unsigned busy : 1; unsigned busy : 1;
unsigned undef : 1; unsigned undef : 1;
}; };
typedef TMap<int, MacroSymbol> TSymbolMap; typedef TMap<int, MacroSymbol> TSymbolMap;