1
0
mirror of https://github.com/cc65/cc65.git synced 2024-12-23 04:30:10 +00:00

Merge pull request #1832 from acqn/PPDefineFix

[cc65] Preprocessor directive #define fixes
This commit is contained in:
Bob Andrews 2022-08-20 14:27:25 +02:00 committed by GitHub
commit 12b9b10355
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 180 additions and 126 deletions

View File

@ -809,131 +809,6 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine)
static void DefineMacro (void)
/* Handle a macro definition. */
{
ident Ident;
Macro* M;
Macro* Existing;
int C89;
/* Read the macro name */
SkipWhitespace (0);
if (!MacName (Ident)) {
return;
}
/* Remember if we're in C89 mode */
C89 = (IS_Get (&Standard) == STD_C89);
/* Get an existing macro definition with this name */
Existing = FindMacro (Ident);
/* Create a new macro definition */
M = NewMacro (Ident);
/* Check if this is a function like macro */
if (CurC == '(') {
/* Skip the left paren */
NextChar ();
/* Set the marker that this is a function like macro */
M->ArgCount = 0;
/* Read the formal parameter list */
while (1) {
/* Skip white space and check for end of parameter list */
SkipWhitespace (0);
if (CurC == ')') {
break;
}
/* The next token must be either an identifier, or - if not in
** C89 mode - the ellipsis.
*/
if (!C89 && CurC == '.') {
/* Ellipsis */
NextChar ();
if (CurC != '.' || NextC != '.') {
PPError ("'...' expected");
ClearLine ();
return;
}
NextChar ();
NextChar ();
/* Remember that the macro is variadic and use __VA_ARGS__ as
** the argument name.
*/
AddMacroArg (M, "__VA_ARGS__");
M->Variadic = 1;
} else {
/* Must be macro argument name */
if (MacName (Ident) == 0) {
return;
}
/* __VA_ARGS__ is only allowed in C89 mode */
if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) {
PPWarning ("'__VA_ARGS__' can only appear in the expansion "
"of a C99 variadic macro");
}
/* Add the macro argument */
AddMacroArg (M, Ident);
}
/* If we had an ellipsis, or the next char is not a comma, we've
** reached the end of the macro argument list.
*/
SkipWhitespace (0);
if (M->Variadic || CurC != ',') {
break;
}
NextChar ();
}
/* Check for a right paren and eat it if we find one */
if (CurC != ')') {
PPError ("')' expected");
ClearLine ();
return;
}
NextChar ();
}
/* Skip whitespace before the macro replacement */
SkipWhitespace (0);
/* Insert the macro into the macro table and allocate the ActualArgs array */
InsertMacro (M);
/* Remove whitespace and comments from the line, store the preprocessed
** line into the macro replacement buffer.
*/
TranslationPhase3 (Line, &M->Replacement);
/* Remove whitespace from the end of the line */
while (IsSpace (SB_LookAtLast (&M->Replacement))) {
SB_Drop (&M->Replacement, 1);
}
#if 0
printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
#endif
/* If we have an existing macro, check if the redefinition is identical.
** Print a diagnostic if not.
*/
if (Existing && MacroCmp (M, Existing) != 0) {
PPError ("Macro redefinition is not identical");
}
}
/*****************************************************************************/ /*****************************************************************************/
/* Preprocessing */ /* Preprocessing */
/*****************************************************************************/ /*****************************************************************************/
@ -1161,6 +1036,160 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine)
static void DoDefine (void)
/* Process #define directive */
{
ident Ident;
Macro* M;
Macro* Existing;
int C89;
unsigned Len;
/* Read the macro name */
SkipWhitespace (0);
if (!MacName (Ident)) {
return;
}
/* Remember if we're in C89 mode */
C89 = (IS_Get (&Standard) == STD_C89);
/* Check for forbidden macro names */
if (strcmp (Ident, "defined") == 0) {
PPError ("'%s' cannot be used as a macro name", Ident);
return;
}
/* Create a new macro definition */
M = NewMacro (Ident);
/* Check if this is a function like macro */
if (CurC == '(') {
/* Skip the left paren */
NextChar ();
/* Set the marker that this is a function like macro */
M->ArgCount = 0;
/* Read the formal parameter list */
while (1) {
/* Skip white space and check for end of parameter list */
SkipWhitespace (0);
if (CurC == ')') {
break;
}
/* The next token must be either an identifier, or - if not in
** C89 mode - the ellipsis.
*/
if (!C89 && CurC == '.') {
/* Ellipsis */
NextChar ();
if (CurC != '.' || NextC != '.') {
PPError ("'...' expected");
ClearLine ();
return;
}
NextChar ();
NextChar ();
/* Remember that the macro is variadic and use __VA_ARGS__ as
** the argument name.
*/
AddMacroArg (M, "__VA_ARGS__");
M->Variadic = 1;
} else {
/* Must be macro argument name */
if (MacName (Ident) == 0) {
return;
}
/* __VA_ARGS__ is only allowed in post-C89 mode */
if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) {
PPWarning ("'__VA_ARGS__' can only appear in the expansion "
"of a C99 variadic macro");
}
/* Add the macro argument */
AddMacroArg (M, Ident);
}
/* If we had an ellipsis, or the next char is not a comma, we've
** reached the end of the macro argument list.
*/
SkipWhitespace (0);
if (M->Variadic || CurC != ',') {
break;
}
NextChar ();
}
/* Check for a right paren and eat it if we find one */
if (CurC != ')') {
PPError ("')' expected");
ClearLine ();
return;
}
NextChar ();
}
/* Skip whitespace before the macro replacement */
SkipWhitespace (0);
/* Remove whitespace and comments from the line, store the preprocessed
** line into the macro replacement buffer.
*/
TranslationPhase3 (Line, &M->Replacement);
/* Remove whitespace from the end of the line */
while (IsSpace (SB_LookAtLast (&M->Replacement))) {
SB_Drop (&M->Replacement, 1);
}
#if 0
printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
#endif
/* Check for ## at start or end */
Len = SB_GetLen (&M->Replacement);
if (Len >= 2) {
if (SB_LookAt (&M->Replacement, 0) == '#' &&
SB_LookAt (&M->Replacement, 1) == '#') {
/* Diagnose and bail out */
PPError ("'##' cannot appear at start of macro expansion");
FreeMacro (M);
return;
} else if (SB_LookAt (&M->Replacement, Len - 1) == '#' &&
SB_LookAt (&M->Replacement, Len - 2) == '#') {
/* Diagnose and bail out */
PPError ("'##' cannot appear at end of macro expansion");
FreeMacro (M);
return;
}
}
/* Get an existing macro definition with this name */
Existing = FindMacro (M->Name);
/* If we have an existing macro, check if the redefinition is identical.
** Print a diagnostic if not.
*/
if (Existing != 0) {
if (MacroCmp (M, Existing) != 0) {
PPError ("Macro redefinition is not identical");
}
/* Undefine the existing macro anyways */
UndefineMacro (Existing->Name);
}
/* Insert the new macro into the macro table */
InsertMacro (M);
}
static int PushIf (int Skip, int Invert, int Cond) static int PushIf (int Skip, int Invert, int Cond)
/* Push a new if level onto the if stack */ /* Push a new if level onto the if stack */
{ {
@ -1443,7 +1472,7 @@ static int ParseDirectives (int InArgList)
case PP_DEFINE: case PP_DEFINE:
if (!PPSkip) { if (!PPSkip) {
DefineMacro (); DoDefine ();
} }
break; break;

25
test/val/bug1822-pptest.c Normal file
View File

@ -0,0 +1,25 @@
/* Bug #1822 - Redefined macros failed to be all undefined with a single #undef */
#undef F
#undef F
#define F 1
#define F 1
#undef F
#if defined F
#error #undef F fails!
#endif
#define F 0
#include <stdio.h>
int main(void)
{
if (F != 0)
{
printf("failed: F = %d\n", F);
}
return F;
}