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:
commit
12b9b10355
@ -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
25
test/val/bug1822-pptest.c
Normal 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;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user