The '#' operator in macro replacement is now checked at macro definition instead of macro expansion.
This commit is contained in:
@@ -1663,7 +1663,8 @@ static unsigned SubstMacroArgs (unsigned NameIdx, StrBuf* Target, MacroExp* E, M
|
|||||||
NextChar ();
|
NextChar ();
|
||||||
SkipWhitespace (0);
|
SkipWhitespace (0);
|
||||||
if (!IsSym (Ident) || (ParamIdx = FindMacroParam (M, Ident)) < 0) {
|
if (!IsSym (Ident) || (ParamIdx = FindMacroParam (M, Ident)) < 0) {
|
||||||
PPError ("'#' is not followed by a macro parameter");
|
/* Should not happen, but still */
|
||||||
|
Internal ("'#' is not followed by a macro parameter");
|
||||||
} else {
|
} else {
|
||||||
/* Make a valid string from Replacement */
|
/* Make a valid string from Replacement */
|
||||||
MacroExp* A = ME_GetOriginalArg (E, ParamIdx);
|
MacroExp* A = ME_GetOriginalArg (E, ParamIdx);
|
||||||
@@ -2052,6 +2053,96 @@ Loop:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int ParseMacroReplacement (StrBuf* Source, Macro* M)
|
||||||
|
/* Check correctness of macro definition while squeezing old and new style
|
||||||
|
** comments and other non-newline whitespace sequences. Return 1 on success
|
||||||
|
** or 0 on failure.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Switch to the new input source */
|
||||||
|
StrBuf* OldSource = InitLine (Source);
|
||||||
|
int HasWhiteSpace = 0;
|
||||||
|
unsigned Len;
|
||||||
|
ident Ident;
|
||||||
|
|
||||||
|
/* Skip whitespace before the macro replacement */
|
||||||
|
SkipWhitespace (0);
|
||||||
|
|
||||||
|
/* Check for ## at start */
|
||||||
|
if (CurC == '#' && NextC == '#') {
|
||||||
|
/* Diagnose and bail out */
|
||||||
|
PPError ("'##' cannot appear at start of macro expansion");
|
||||||
|
goto Error_Handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop removing ws and comments */
|
||||||
|
while (CurC != '\0') {
|
||||||
|
if (HasWhiteSpace) {
|
||||||
|
SB_AppendChar (&M->Replacement, ' ');
|
||||||
|
} else if (IsQuote (CurC)) {
|
||||||
|
CopyQuotedString (&M->Replacement);
|
||||||
|
} else {
|
||||||
|
if (M->ParamCount >= 0 && GetPunc (Ident)) {
|
||||||
|
Len = strlen (Ident);
|
||||||
|
/* Check for # */
|
||||||
|
if (Len == 1 && Ident[0] == '#') {
|
||||||
|
HasWhiteSpace = SkipWhitespace (0);
|
||||||
|
|
||||||
|
/* Check next pp-token */
|
||||||
|
if (!IsSym (Ident) || FindMacroParam (M, Ident) < 0) {
|
||||||
|
PPError ("'#' is not followed by a macro parameter");
|
||||||
|
goto Error_Handler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make the replacement */
|
||||||
|
SB_AppendChar (&M->Replacement, '#');
|
||||||
|
if (HasWhiteSpace) {
|
||||||
|
SB_AppendChar (&M->Replacement, ' ');
|
||||||
|
}
|
||||||
|
SB_AppendStr (&M->Replacement, Ident);
|
||||||
|
} else {
|
||||||
|
SB_AppendBuf (&M->Replacement, Ident, Len);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
SB_AppendChar (&M->Replacement, CurC);
|
||||||
|
NextChar ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HasWhiteSpace = SkipWhitespace (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for ## at end */
|
||||||
|
Len = SB_GetLen (&M->Replacement);
|
||||||
|
if (Len >= 2) {
|
||||||
|
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");
|
||||||
|
goto Error_Handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Terminate the new input line */
|
||||||
|
SB_Terminate (&M->Replacement);
|
||||||
|
|
||||||
|
/* Switch back to the old source */
|
||||||
|
InitLine (OldSource);
|
||||||
|
|
||||||
|
/* Success */
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
Error_Handler:
|
||||||
|
|
||||||
|
/* Switch back to the old source */
|
||||||
|
InitLine (OldSource);
|
||||||
|
|
||||||
|
/* Failure */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void DoDefine (void)
|
static void DoDefine (void)
|
||||||
/* Process #define directive */
|
/* Process #define directive */
|
||||||
{
|
{
|
||||||
@@ -2059,7 +2150,6 @@ static void DoDefine (void)
|
|||||||
Macro* M = 0;
|
Macro* M = 0;
|
||||||
Macro* Existing;
|
Macro* Existing;
|
||||||
int C89;
|
int C89;
|
||||||
unsigned Len;
|
|
||||||
|
|
||||||
/* Read the macro name */
|
/* Read the macro name */
|
||||||
SkipWhitespace (0);
|
SkipWhitespace (0);
|
||||||
@@ -2150,38 +2240,17 @@ static void DoDefine (void)
|
|||||||
NextChar ();
|
NextChar ();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Skip whitespace before the macro replacement */
|
|
||||||
SkipWhitespace (0);
|
|
||||||
|
|
||||||
/* Remove whitespace and comments from the line, store the preprocessed
|
/* Remove whitespace and comments from the line, store the preprocessed
|
||||||
** line into the macro replacement buffer.
|
** line into the macro replacement buffer.
|
||||||
*/
|
*/
|
||||||
TranslationPhase3 (Line, &M->Replacement);
|
if (ParseMacroReplacement (Line, M) == 0) {
|
||||||
|
goto Error_Handler;
|
||||||
/* Remove whitespace from the end of the line */
|
|
||||||
while (IsSpace (SB_LookAtLast (&M->Replacement))) {
|
|
||||||
SB_Drop (&M->Replacement, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
|
printf ("%s: <%.*s>\n", M->Name, SB_GetLen (&M->Replacement), SB_GetConstBuf (&M->Replacement));
|
||||||
#endif
|
#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");
|
|
||||||
goto Error_Handler;
|
|
||||||
} 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");
|
|
||||||
goto Error_Handler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get an existing macro definition with this name */
|
/* Get an existing macro definition with this name */
|
||||||
Existing = FindMacro (M->Name);
|
Existing = FindMacro (M->Name);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user