1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-07 23:29:39 +00:00

Preprocessor directives can now appear in the argument list of function-like macro calls.

#pragma PP-tokens can now be macro replaced.
#include header names directly enclosed in <> are free of macro replacement.
Preprocess-only mode (-E) now outputs with #line as source info.
Moved testcases for #760 and #1357.
Added testcase for #1643.
This commit is contained in:
acqn 2022-07-26 21:10:38 +08:00
parent 80fc8cd11e
commit 2f357ba9b2
9 changed files with 420 additions and 144 deletions

View File

@ -425,6 +425,9 @@ void Compile (const char* FileName)
/* Generate the code generator preamble */ /* Generate the code generator preamble */
g_preamble (); g_preamble ();
/* Init preprocessor */
InitPreprocess ();
/* Open the input file */ /* Open the input file */
OpenMainFile (FileName); OpenMainFile (FileName);
@ -497,6 +500,9 @@ void Compile (const char* FileName)
} }
/* Done with preprocessor */
DonePreprocess ();
if (Debug) { if (Debug) {
PrintMacroStats (stdout); PrintMacroStats (stdout);
} }

View File

@ -108,6 +108,29 @@ void FreeMacro (Macro* M)
Macro* CloneMacro (const Macro* M)
/* Clone a macro definition. The function is not insert the macro into the
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
** Use FreeMacro for that.
*/
{
Macro* New = NewMacro (M->Name);
unsigned I;
for (I = 0; I < CollCount (&M->FormalArgs); ++I) {
/* Copy the argument */
const char* Arg = CollAtUnchecked (&M->FormalArgs, I);
CollAppend (&New->FormalArgs, xstrdup (Arg));
}
New->ArgCount = M->ArgCount;
New->Variadic = M->Variadic;
SB_Copy (&New->Replacement, &M->Replacement);
return New;
}
void DefineNumericMacro (const char* Name, long Val) void DefineNumericMacro (const char* Name, long Val)
/* Define a macro for a numeric constant */ /* Define a macro for a numeric constant */
{ {

View File

@ -82,6 +82,12 @@ void FreeMacro (Macro* M);
** table, use UndefineMacro for that. ** table, use UndefineMacro for that.
*/ */
Macro* CloneMacro (const Macro* M);
/* Clone a macro definition. The function is not insert the macro into the
** macro table, thus the cloned instance cannot be freed with UndefineMacro.
** Use FreeMacro for that.
*/
void DefineNumericMacro (const char* Name, long Val); void DefineNumericMacro (const char* Name, long Val);
/* Define a macro for a numeric constant */ /* Define a macro for a numeric constant */

View File

@ -67,9 +67,6 @@
/* Set when the preprocessor calls expr() recursively */
static unsigned char Preprocessing = 0;
/* Management data for #if */ /* Management data for #if */
#define IFCOND_NONE 0x00U #define IFCOND_NONE 0x00U
#define IFCOND_SKIP 0x01U #define IFCOND_SKIP 0x01U
@ -79,8 +76,15 @@ static unsigned char Preprocessing = 0;
/* Current PP if stack */ /* Current PP if stack */
static PPIfStack* PPStack; static PPIfStack* PPStack;
/* Buffer for macro expansion */ /* Intermediate input buffers */
static StrBuf* MLine; static StrBuf* PLine; /* Buffer for macro expansion */
static StrBuf* MLine; /* Buffer for macro expansion in #pragma */
static StrBuf* OLine; /* Buffer for #pragma output */
/* Newlines to be added to preprocessed text */
static int PendingNewLines;
static int FileChanged;
static int LeadingWhitespace;
/* Structure used when expanding macros */ /* Structure used when expanding macros */
typedef struct MacroExp MacroExp; typedef struct MacroExp MacroExp;
@ -103,12 +107,12 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target);
** non-newline whitespace sequences. ** non-newline whitespace sequences.
*/ */
static unsigned Pass1 (StrBuf* Source, StrBuf* Target); static int ParseDirectives (void);
/* Preprocessor pass 1. Remove whitespace. Handle old and new style comments /* Handle directives. Return 1 if there are directives parsed, -1 if new lines
** and the "defined" operator. ** are read, otherwise 0.
*/ */
static void MacroReplacement (StrBuf* Source, StrBuf* Target); static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine);
/* Perform macro replacement. */ /* Perform macro replacement. */
@ -256,6 +260,46 @@ static int ME_ArgIsVariadic (const MacroExp* E)
static void AddPreLine (StrBuf* Str)
/* Add newlines to the string buffer */
{
if (!PreprocessOnly) {
PendingNewLines = 0;
return;
}
if (FileChanged || PendingNewLines > 4) {
/* Output #line directives as source info */
StrBuf Comment = AUTO_STRBUF_INITIALIZER;
if (SB_NotEmpty (Str) && SB_LookAtLast (Str) != '\n') {
SB_AppendChar (Str, '\n');
}
SB_Printf (&Comment, "#line %u \"%s\"\n", GetCurrentLine (), GetCurrentFile ());
SB_Append (Str, &Comment);
} else {
/* Output new lines */
while (PendingNewLines > 0) {
SB_AppendChar (Str, '\n');
--PendingNewLines;
}
}
FileChanged = 0;
PendingNewLines = 0;
}
static void AppendIndent (StrBuf* Str, int Count)
/* Add Count of spaces ' ' to the string buffer */
{
while (Count > 0) {
SB_AppendChar (Str, ' ');
--Count;
}
}
static void Stringize (StrBuf* Source, StrBuf* Target) static void Stringize (StrBuf* Source, StrBuf* Target)
/* Stringize the given string: Add double quotes at start and end and preceed /* Stringize the given string: Add double quotes at start and end and preceed
** each occurance of " and \ by a backslash. ** each occurance of " and \ by a backslash.
@ -341,12 +385,15 @@ static void NewStyleComment (void)
static int SkipWhitespace (int SkipLines) static int SkipWhitespace (int SkipLines)
/* Skip white space and comments in the input stream. Do also skip newlines if /* Skip white space and comments in the input stream. If skipLines is true,
** SkipLines is true. Return zero if nothing was skipped, otherwise return a ** also skip newlines and add that count to global PendingNewLines. Return 1
** value != zero. ** if the last skipped character was a white space other than a newline '\n',
** otherwise return -1 if there were any newline characters skipped, otherwise
** return 0 if nothing was skipped.
*/ */
{ {
int Skipped = 0; int Skipped = 0;
int NewLine = 0;
while (1) { while (1) {
if (IsSpace (CurC)) { if (IsSpace (CurC)) {
NextChar (); NextChar ();
@ -360,7 +407,9 @@ static int SkipWhitespace (int SkipLines)
} else if (CurC == '\0' && SkipLines) { } else if (CurC == '\0' && SkipLines) {
/* End of line, read next */ /* End of line, read next */
if (NextLine () != 0) { if (NextLine () != 0) {
Skipped = 1; ++PendingNewLines;
NewLine = 1;
Skipped = 0;
} else { } else {
/* End of input */ /* End of input */
break; break;
@ -370,7 +419,36 @@ static int SkipWhitespace (int SkipLines)
break; break;
} }
} }
return Skipped; return Skipped != 0 ? Skipped : -(NewLine != 0);
}
static void CopyHeaderNameToken (StrBuf* Target)
/* Copy a header name from the input to Target. */
{
/* Remember the quote character, copy it to the target buffer and skip it */
char Quote = CurC == '"' ? '"' : '>';
SB_AppendChar (Target, CurC);
NextChar ();
/* Copy the characters inside the string */
while (CurC != '\0' && CurC != Quote) {
/* Keep an escaped char */
if (CurC == '\\') {
SB_AppendChar (Target, CurC);
NextChar ();
}
/* Copy the character */
SB_AppendChar (Target, CurC);
NextChar ();
}
/* If we had a terminating quote, copy it */
if (CurC != '\0') {
SB_AppendChar (Target, CurC);
NextChar ();
}
} }
@ -447,7 +525,7 @@ static int MacName (char* Ident)
static void ReadMacroArgs (MacroExp* E) static void ReadMacroArgs (MacroExp* E, int MultiLine)
/* Identify the arguments to a macro call as-is */ /* Identify the arguments to a macro call as-is */
{ {
int MissingParen = 0; int MissingParen = 0;
@ -460,6 +538,30 @@ static void ReadMacroArgs (MacroExp* E)
/* Read the actual macro arguments */ /* Read the actual macro arguments */
Parens = 0; Parens = 0;
while (1) { while (1) {
/* Squeeze runs of blanks within an arg */
int OldPendingNewLines = PendingNewLines;
int Skipped = SkipWhitespace (MultiLine);
if (MultiLine && CurC == '#') {
int Newlines = 0;
SB_Cut (OLine, SB_GetLen (OLine) - LeadingWhitespace);
if (OldPendingNewLines == 0 && SB_NotEmpty (Line) && SB_LookAtLast (OLine) != '\n') {
OldPendingNewLines = 1;
}
while (CurC == '#') {
Newlines += PendingNewLines - OldPendingNewLines;
PendingNewLines = OldPendingNewLines;
OldPendingNewLines = 0;
Skipped = ParseDirectives () || Skipped;
Skipped = SkipWhitespace (MultiLine) || Skipped;
}
AppendIndent (OLine, LeadingWhitespace);
LeadingWhitespace = 0;
PendingNewLines += Newlines;
}
if (Skipped && SB_NotEmpty (&Arg)) {
SB_AppendChar (&Arg, ' ');
}
if (CurC == '(') { if (CurC == '(') {
/* Nested parenthesis */ /* Nested parenthesis */
@ -510,11 +612,6 @@ static void ReadMacroArgs (MacroExp* E)
NextChar (); NextChar ();
SB_Clear (&Arg); SB_Clear (&Arg);
} }
} else if (SkipWhitespace (1)) {
/* Squeeze runs of blanks within an arg */
if (SB_NotEmpty (&Arg)) {
SB_AppendChar (&Arg, ' ');
}
} else if (CurC == '\0') { } else if (CurC == '\0') {
/* End of input inside macro argument list */ /* End of input inside macro argument list */
PPError ("Unterminated argument list invoking macro '%s'", E->M->Name); PPError ("Unterminated argument list invoking macro '%s'", E->M->Name);
@ -593,7 +690,7 @@ static void MacroArgSubst (MacroExp* E)
** of the actual. ** of the actual.
*/ */
SB_Reset (Arg); SB_Reset (Arg);
MacroReplacement (Arg, &E->Replacement); MacroReplacement (Arg, &E->Replacement, 0);
/* If we skipped whitespace before, re-add it now */ /* If we skipped whitespace before, re-add it now */
if (HaveSpace) { if (HaveSpace) {
@ -682,60 +779,53 @@ static void MacroArgSubst (MacroExp* E)
static void MacroCall (StrBuf* Target, Macro* M) static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine)
/* Process a function like macro */
{
MacroExp E;
/* Initialize our MacroExp structure */
InitMacroExp (&E, M);
/* Read the actual macro arguments (with the enclosing parentheses) */
ReadMacroArgs (&E);
/* Replace macro arguments handling the # and ## operators */
MacroArgSubst (&E);
/* Do macro replacement on the macro that already has the parameters
** substituted.
*/
M->Expanding = 1;
MacroReplacement (&E.Replacement, Target);
M->Expanding = 0;
/* Free memory allocated for the macro expansion structure */
DoneMacroExp (&E);
}
static void ExpandMacro (StrBuf* Target, Macro* M)
/* Expand a macro into Target */ /* Expand a macro into Target */
{ {
MacroExp E;
#if 0 #if 0
static unsigned V = 0; static unsigned V = 0;
printf ("Expanding %s(%u)\n", M->Name, ++V); printf ("Expanding %s(%u)\n", M->Name, ++V);
#endif #endif
/* Check if this is a function like macro */ /* Initialize our MacroExp structure */
if (M->ArgCount >= 0) { InitMacroExp (&E, M);
int Whitespace = SkipWhitespace (1); /* Check if this is a function like macro */
if (CurC != '(') { if (E.M->ArgCount >= 0) {
/* Function like macro but no parameter list */
SB_AppendStr (Target, M->Name); /* Since the macro could be undefined or redefined during its argument
if (Whitespace) { ** parsing, we make a clone of the current one and stick to it.
SB_AppendChar (Target, ' '); */
} if (MultiLine) {
} else { E.M = CloneMacro (E.M);
/* Function like macro */
MacroCall (Target, M);
} }
} else { /* Read the actual macro arguments (with the enclosing parentheses) */
ReadMacroArgs (&E, MultiLine);
MacroExp E; /* Replace macro arguments handling the # and ## operators */
InitMacroExp (&E, M); MacroArgSubst (&E);
/* Do macro replacement on the macro that already has the parameters
** substituted.
*/
if (MultiLine) {
/* Check if the macro was undefined or redefined */
M = FindMacro (E.M->Name);
if (M == 0 || MacroCmp (E.M, M) != 0) {
/* Use the cloned macro */
M = E.M;
}
}
/* Forbide repeated expansion of the same macro in use */
M->Expanding = 1;
MacroReplacement (&E.Replacement, Target, 0);
M->Expanding = 0;
} else {
/* Handle # and ## operators for object like macros */ /* Handle # and ## operators for object like macros */
MacroArgSubst (&E); MacroArgSubst (&E);
@ -744,16 +834,23 @@ static void ExpandMacro (StrBuf* Target, Macro* M)
** substituted. ** substituted.
*/ */
M->Expanding = 1; M->Expanding = 1;
MacroReplacement (&E.Replacement, Target); MacroReplacement (&E.Replacement, Target, 0);
M->Expanding = 0; M->Expanding = 0;
/* Free memory allocated for the macro expansion structure */
DoneMacroExp (&E);
} }
#if 0 #if 0
printf ("Done with %s(%u)\n", M->Name, V--); printf ("Done with %s(%u)\n", E.M->Name, V--);
#endif #endif
/* Free cloned macro */
if (MultiLine && E.M->ArgCount >= 0) {
FreeMacro (E.M);
E.M = 0;
}
/* Free memory allocated for the macro expansion structure */
DoneMacroExp (&E);
} }
@ -935,20 +1032,25 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
static unsigned Pass1 (StrBuf* Source, StrBuf* Target) static void ProcessSingleLine (StrBuf* Source,
/* Preprocessor pass 1. Remove whitespace, old and new style comments. Handle StrBuf* Target,
** the "defined" operator. int HandleDefined,
int HandleHeader)
/* Process a single line. Remove whitespace, old and new style comments.
** Recognize and handle the "defined" operator if HandleDefined is true.
** Recognize and handle header name tokens if HandleHeader is true.
*/ */
{ {
unsigned IdentCount; int OldIndex = SB_GetIndex (Source);
ident Ident; ident Ident;
int HaveParen; int HaveParen;
/* Switch to the new input source */ /* Operate on the new input source */
StrBuf* OldSource = InitLine (Source); StrBuf* OldSource = InitLine (Source);
SkipWhitespace (0);
/* Loop removing ws and comments */ /* Loop removing ws and comments */
IdentCount = 0;
while (CurC != '\0') { while (CurC != '\0') {
if (SkipWhitespace (0)) { if (SkipWhitespace (0)) {
/* Squeeze runs of blanks */ /* Squeeze runs of blanks */
@ -956,7 +1058,7 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
SB_AppendChar (Target, ' '); SB_AppendChar (Target, ' ');
} }
} else if (IsSym (Ident)) { } else if (IsSym (Ident)) {
if (Preprocessing && strcmp (Ident, "defined") == 0) { if (HandleDefined && strcmp (Ident, "defined") == 0) {
/* Handle the "defined" operator */ /* Handle the "defined" operator */
SkipWhitespace (0); SkipWhitespace (0);
HaveParen = 0; HaveParen = 0;
@ -980,9 +1082,32 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
SB_AppendChar (Target, '0'); SB_AppendChar (Target, '0');
} }
} else { } else {
++IdentCount; Macro* M = FindMacro (Ident);
SB_AppendStr (Target, Ident); if (M != 0 && !M->Expanding) {
/* Check if this is a function-like macro */
if (M->ArgCount >= 0) {
int Whitespace = SkipWhitespace (0);
if (CurC != '(') {
/* Function-like macro without an argument list is not replaced */
SB_AppendStr (Target, M->Name);
if (Whitespace) {
SB_AppendChar (Target, ' ');
}
} else {
/* Function-like macro */
ExpandMacro (Target, M, 0);
}
} else {
/* Object-like macro */
ExpandMacro (Target, M, 0);
}
} else {
/* An identifier, keep it */
SB_AppendStr (Target, Ident);
}
} }
} else if (HandleHeader && (CurC == '<' || CurC == '\"')) {
CopyHeaderNameToken (Target);
} else if (IsQuote (CurC)) { } else if (IsQuote (CurC)) {
CopyQuotedString (Target); CopyQuotedString (Target);
} else { } else {
@ -994,13 +1119,13 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
/* Switch back to the old source */ /* Switch back to the old source */
InitLine (OldSource); InitLine (OldSource);
/* Return the number of identifiers found in the line */ /* Restore the source input index */
return IdentCount; SB_SetIndex (Source, OldIndex);
} }
static void MacroReplacement (StrBuf* Source, StrBuf* Target) static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine)
/* Perform macro replacement. */ /* Perform macro replacement. */
{ {
ident Ident; ident Ident;
@ -1015,22 +1140,54 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target)
if (IsSym (Ident)) { if (IsSym (Ident)) {
/* Check if it's a macro */ /* Check if it's a macro */
if ((M = FindMacro (Ident)) != 0 && !M->Expanding) { if ((M = FindMacro (Ident)) != 0 && !M->Expanding) {
/* It's a macro, expand it */ /* Check if this is a function-like macro */
ExpandMacro (Target, M); if (M->ArgCount >= 0) {
int Whitespace = SkipWhitespace (MultiLine);
if (CurC != '(') {
/* Function-like macro without an argument list is not replaced */
SB_AppendStr (Target, M->Name);
if (Whitespace > 0) {
SB_AppendChar (Target, ' ');
}
if (CurC == '#') {
if (OLine == 0) {
OLine = Target;
ParseDirectives ();
OLine = 0;
} else {
ParseDirectives ();
}
}
/* Add the source info to preprocessor output if needed */
AddPreLine (Target);
} else {
/* Function-like macro */
if (OLine == 0) {
OLine = Target;
ExpandMacro (Target, M, MultiLine);
OLine = 0;
} else {
ExpandMacro (Target, M, MultiLine);
}
}
} else {
/* Object-like macro */
ExpandMacro (Target, M, 0);
}
} else { } else {
/* An identifier, keep it */ /* An identifier, keep it */
SB_AppendStr (Target, Ident); SB_AppendStr (Target, Ident);
} }
} else if (IsQuote (CurC)) { } else if (IsQuote (CurC)) {
CopyQuotedString (Target); CopyQuotedString (Target);
} else if (IsSpace (CurC)) {
if (!IsSpace (SB_LookAtLast (Target))) {
SB_AppendChar (Target, CurC);
}
NextChar ();
} else { } else {
SB_AppendChar (Target, CurC); int Whitespace = SkipWhitespace (0);
NextChar (); if (Whitespace) {
SB_AppendChar (Target, ' ');
} else {
SB_AppendChar (Target, CurC);
NextChar ();
}
} }
} }
@ -1040,27 +1197,6 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target)
static void PreprocessLine (void)
/* Translate one line with defined macros replaced */
{
/* Trim whitespace and remove comments. The function returns the number of
** identifiers found. If there were any, we will have to check for macros.
*/
SB_Clear (MLine);
if (Pass1 (Line, MLine) > 0) {
MLine = InitLine (MLine);
SB_Reset (Line);
SB_Clear (MLine);
MacroReplacement (Line, MLine);
}
/* Read from the new line */
SB_Reset (MLine);
MLine = InitLine (MLine);
}
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 */
{ {
@ -1108,10 +1244,11 @@ static int DoIf (int Skip)
PPExpr Expr = AUTO_PPEXPR_INITIALIZER; PPExpr Expr = AUTO_PPEXPR_INITIALIZER;
if (!Skip) { if (!Skip) {
/* We're about to use a dedicated expression parser to evaluate the #if /* We're about to use a dedicated expression parser to evaluate the #if
** expression. Save the current tokens to come back here later. ** expression. Save the current tokens to come back here later.
*/ */
Token SavedCurTok = CurTok; Token SavedCurTok = CurTok;
Token SavedNextTok = NextTok; Token SavedNextTok = NextTok;
/* Make sure the line infos for the tokens won't get removed */ /* Make sure the line infos for the tokens won't get removed */
@ -1122,11 +1259,13 @@ static int DoIf (int Skip)
UseLineInfo (SavedNextTok.LI); UseLineInfo (SavedNextTok.LI);
} }
/* Switch into special preprocessing mode */ /* Macro-replace a single line with support for the "defined" operator */
Preprocessing = 1; SB_Clear (MLine);
ProcessSingleLine (Line, MLine, 1, 0);
/* Expand macros in this line */ /* Read from the processed line */
PreprocessLine (); SB_Reset (MLine);
MLine = InitLine (MLine);
/* Add two semicolons as sentinels to the line, so the following /* Add two semicolons as sentinels to the line, so the following
** expression evaluation will eat these two tokens but nothing from ** expression evaluation will eat these two tokens but nothing from
@ -1142,8 +1281,8 @@ static int DoIf (int Skip)
/* Call the expression parser */ /* Call the expression parser */
ParsePPExpr (&Expr); ParsePPExpr (&Expr);
/* End preprocessing mode */ /* Restore input source */
Preprocessing = 0; MLine = InitLine (MLine);
/* Reset the old tokens */ /* Reset the old tokens */
CurTok = SavedCurTok; CurTok = SavedCurTok;
@ -1182,14 +1321,15 @@ static void DoInclude (void)
{ {
char RTerm; char RTerm;
InputType IT; InputType IT;
StrBuf Filename = STATIC_STRBUF_INITIALIZER; StrBuf Filename = AUTO_STRBUF_INITIALIZER;
/* Macro-replace a single line with special support for <filename> */
SB_Clear (MLine);
ProcessSingleLine (Line, MLine, 0, 1);
/* Preprocess the remainder of the line */ /* Read from the processed line */
PreprocessLine (); SB_Reset (MLine);
MLine = InitLine (MLine);
/* Skip blanks */
SkipWhitespace (0);
/* Get the next char and check for a valid file name terminator. Setup /* Get the next char and check for a valid file name terminator. Setup
** the include directory spec (SYS/USR) by looking at the terminator. ** the include directory spec (SYS/USR) by looking at the terminator.
@ -1236,6 +1376,9 @@ Done:
/* Free the allocated filename data */ /* Free the allocated filename data */
SB_Done (&Filename); SB_Done (&Filename);
/* Restore input source */
MLine = InitLine (MLine);
/* Clear the remaining line so the next input will come from the new /* Clear the remaining line so the next input will come from the new
** file (if open) ** file (if open)
*/ */
@ -1249,19 +1392,30 @@ static void DoPragma (void)
** the _Pragma() compiler operator. ** the _Pragma() compiler operator.
*/ */
{ {
/* Copy the remainder of the line into MLine removing comments and ws */ StrBuf* PragmaLine = OLine;
/* Macro-replace a single line */
SB_Clear (MLine); SB_Clear (MLine);
Pass1 (Line, MLine); ProcessSingleLine (Line, MLine, 0, 0);
/* Convert the directive into the operator */ /* Convert the directive into the operator */
SB_CopyStr (Line, "_Pragma ("); if (OLine == 0) {
SB_Reset (MLine); SB_Clear (Line);
Stringize (MLine, Line); PragmaLine = Line;
SB_AppendChar (Line, ')'); }
/* Initialize reading from line */ /* Add the source info to preprocessor output if needed */
SB_Reset (Line); AddPreLine (PragmaLine);
InitLine (Line);
/* Convert #pragma to _Pragma () */
SB_AppendStr (PragmaLine, "_Pragma (");
SB_Reset (MLine);
Stringize (MLine, PragmaLine);
SB_AppendChar (PragmaLine, ')');
SB_AppendChar (PragmaLine, '\n');
/* End this line */
SB_SetIndex (PragmaLine, SB_GetLen (PragmaLine));
} }
@ -1300,17 +1454,13 @@ static void DoWarning (void)
void Preprocess (void) static int ParseDirectives (void)
/* Preprocess a line */ /* Handle directives. Return howmany newlines are parsed. */
{ {
int NewLines = 0;
int Skip; int Skip;
ident Directive; ident Directive;
/* Create the output buffer if we don't already have one */
if (MLine == 0) {
MLine = NewStrBuf ();
}
/* Skip white space at the beginning of the line */ /* Skip white space at the beginning of the line */
SkipWhitespace (0); SkipWhitespace (0);
@ -1435,7 +1585,7 @@ void Preprocess (void)
case PP_PRAGMA: case PP_PRAGMA:
if (!Skip) { if (!Skip) {
DoPragma (); DoPragma ();
goto Done; --NewLines;
} }
break; break;
@ -1469,14 +1619,48 @@ void Preprocess (void)
} }
if (NextLine () == 0) { if (NextLine () == 0) {
return; break;
} }
++NewLines;
SkipWhitespace (0); SkipWhitespace (0);
} }
PreprocessLine (); PendingNewLines += NewLines;
return NewLines;
}
void Preprocess (void)
/* Preprocess lines count of which is affected by directives */
{
SB_Clear (PLine);
/* Add the source info to preprocessor output if needed */
AddPreLine (PLine);
/* Parse any directives */
OLine = PLine;
ParseDirectives ();
OLine = 0;
/* Add the source info to preprocessor output if needed */
AddPreLine (PLine);
/* Add leading whitespace to prettify preprocessor output */
LeadingWhitespace = SB_GetIndex (Line);
AppendIndent (PLine, LeadingWhitespace);
/* Expand macros if any */
MacroReplacement (Line, PLine, 1);
/* Add the source info to preprocessor output if needed */
AddPreLine (PLine);
/* Read from the new line */
SB_Reset (PLine);
PLine = InitLine (PLine);
Done:
if (Verbosity > 1 && SB_NotEmpty (Line)) { if (Verbosity > 1 && SB_NotEmpty (Line)) {
printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (), printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (),
(int) SB_GetLen (Line), SB_GetConstBuf (Line)); (int) SB_GetLen (Line), SB_GetConstBuf (Line));
@ -1485,6 +1669,26 @@ Done:
void InitPreprocess (void)
/* Init preprocessor */
{
/* Create the output buffers */
MLine = NewStrBuf ();
PLine = NewStrBuf ();
}
void DonePreprocess (void)
/* Done with preprocessor */
{
/* Done with the output buffers */
SB_Done (MLine);
SB_Done (PLine);
}
void SetPPIfStack (PPIfStack* Stack) void SetPPIfStack (PPIfStack* Stack)
/* Specify which PP #if stack to use */ /* Specify which PP #if stack to use */
{ {
@ -1498,6 +1702,9 @@ void PreprocessBegin (void)
{ {
/* Reset #if depth */ /* Reset #if depth */
PPStack->Index = -1; PPStack->Index = -1;
/* Remember to update source file location in preprocess-only mode */
FileChanged = 1;
} }
@ -1512,4 +1719,7 @@ void PreprocessEnd (void)
} }
--PPStack->Index; --PPStack->Index;
} }
/* Remember to update source file location in preprocess-only mode */
FileChanged = 1;
} }

View File

@ -74,6 +74,12 @@ void PreprocessBegin (void);
void PreprocessEnd (void); void PreprocessEnd (void);
/* Preprocessor done with current file */ /* Preprocessor done with current file */
void InitPreprocess (void);
/* Init preprocessor */
void DonePreprocess (void);
/* Done with preprocessor */
/* End of preproc.h */ /* End of preproc.h */

12
test/val/bug1643.c Normal file
View File

@ -0,0 +1,12 @@
/* bug #1643, macro expansion in #include */
#define MKSTR(a) MKSTR_IMPL(a)
#define MKSTR_IMPL(a) #a
#define BUG1643_H bug1643.h
#include MKSTR(BUG1643_H)
int main(void)
{
return BUG1643_RESULT;
}

13
test/val/bug1643.h Normal file
View File

@ -0,0 +1,13 @@
/* bug #1643, macro expansion in #include */
#define STDIO_H <stdio.h>
#include STDIO_H
#ifdef string
#undef string
#endif
#define string 0!%^&*/_=
#include <string.h>
#define BUG1643_RESULT 0