diff --git a/doc/cc65.sgml b/doc/cc65.sgml
index 43039f713..683249bda 100644
--- a/doc/cc65.sgml
+++ b/doc/cc65.sgml
@@ -1202,17 +1202,34 @@ The compiler defines several macros at startup:
This macro is defined if the target is the Commodore Plus/4 (-t plus4).
- __STDC_HOSTED__
-
- This macro is expands to the integer constant 1.
-
__SIM6502__
This macro is defined if the target is sim65 in 6502 mode (-t sim6502).
__SIM65C02__
+
This macro is defined if the target is sim65 in 65C02 mode (-t sim65c02).
+ __STDC_HOSTED__
+
+ This macro expands to the integer constant 1.
+
+ __STDC_NO_ATOMICS__
+
+ This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
+
+ __STDC_NO_COMPLEX__
+
+ This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
+
+ __STDC_NO_THREADS__
+
+ This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
+
+ __STDC_NO_VLA__
+
+ This macro expands to the integer constant 1 if the language standard is cc65 (--standard cc65).
+
__SUPERVISION__
This macro is defined if the target is the Supervision (-t supervision).
diff --git a/src/cc65/compile.c b/src/cc65/compile.c
index 7f2cd8ba0..75250da0a 100644
--- a/src/cc65/compile.c
+++ b/src/cc65/compile.c
@@ -82,8 +82,11 @@ static void Parse (void)
SymEntry* Entry;
FuncDesc* FuncDef = 0;
- /* Go... */
- NextToken ();
+ /* Initialization for deferred operations */
+ InitDeferredOps ();
+
+ /* Fill up the next token with a bogus semicolon and start the tokenizer */
+ NextTok.Tok = TOK_SEMI;
NextToken ();
/* Parse until end of input */
@@ -338,6 +341,9 @@ static void Parse (void)
}
}
+
+ /* Done with deferred operations */
+ DoneDeferredOps ();
}
@@ -403,7 +409,13 @@ void Compile (const char* FileName)
/* DefineNumericMacro ("__STDC__", 1); <- not now */
DefineNumericMacro ("__STDC_HOSTED__", 1);
- InitDeferredOps ();
+ /* Stuff unsupported */
+ if (IS_Get (&Standard) > STD_C99) {
+ DefineNumericMacro ("__STDC_NO_ATOMICS__", 1);
+ DefineNumericMacro ("__STDC_NO_COMPLEX__", 1);
+ DefineNumericMacro ("__STDC_NO_THREADS__", 1);
+ DefineNumericMacro ("__STDC_NO_VLA__", 1);
+ }
/* Create the base lexical level */
EnterGlobalLevel ();
@@ -423,6 +435,9 @@ void Compile (const char* FileName)
/* Generate the code generator preamble */
g_preamble ();
+ /* Init preprocessor */
+ InitPreprocess ();
+
/* Open the input file */
OpenMainFile (FileName);
@@ -433,10 +448,8 @@ void Compile (const char* FileName)
OpenOutputFile ();
/* Preprocess each line and write it to the output file */
- while (NextLine ()) {
- Preprocess ();
- WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
- }
+ while (PreprocessNextLine ())
+ { /* Nothing */ }
/* Close the output file */
CloseOutputFile ();
@@ -494,9 +507,11 @@ void Compile (const char* FileName)
}
}
}
+
}
- DoneDeferredOps ();
+ /* Done with preprocessor */
+ DonePreprocess ();
if (Debug) {
PrintMacroStats (stdout);
diff --git a/src/cc65/input.c b/src/cc65/input.c
index 22a66e1f7..18441f5c8 100644
--- a/src/cc65/input.c
+++ b/src/cc65/input.c
@@ -54,6 +54,7 @@
#include "input.h"
#include "lineinfo.h"
#include "output.h"
+#include "preproc.h"
@@ -91,6 +92,8 @@ struct AFile {
FILE* F; /* Input file stream */
IFile* Input; /* Points to corresponding IFile */
int SearchPath; /* True if we've added a path for this file */
+ PPIfStack IfStack; /* PP #if stack */
+ int MissingNL; /* Last input line was missing a newline */
};
/* List of all input files */
@@ -156,6 +159,8 @@ static AFile* NewAFile (IFile* IF, FILE* F)
AF->Line = 0;
AF->F = F;
AF->Input = IF;
+ AF->IfStack.Index = -1;
+ AF->MissingNL = 0;
/* Increment the usage counter of the corresponding IFile. If this
** is the first use, set the file data and output debug info if
@@ -257,6 +262,12 @@ void OpenMainFile (const char* Name)
/* Allocate a new AFile structure for the file */
MainFile = NewAFile (IF, F);
+ /* Use this file with PP */
+ SetPPIfStack (&MainFile->IfStack);
+
+ /* Begin PP for this file */
+ PreprocessBegin ();
+
/* Allocate the input line buffer */
Line = NewStrBuf ();
@@ -274,6 +285,7 @@ void OpenIncludeFile (const char* Name, InputType IT)
char* N;
FILE* F;
IFile* IF;
+ AFile* AF;
/* Check for the maximum include nesting */
if (CollCount (&AFiles) > MAX_INC_NESTING) {
@@ -311,12 +323,18 @@ void OpenIncludeFile (const char* Name, InputType IT)
Print (stdout, 1, "Opened include file '%s'\n", IF->Name);
/* Allocate a new AFile structure */
- (void) NewAFile (IF, F);
+ AF = NewAFile (IF, F);
+
+ /* Use this file with PP */
+ SetPPIfStack (&AF->IfStack);
+
+ /* Begin PP for this file */
+ PreprocessBegin ();
}
-static void CloseIncludeFile (void)
+void CloseIncludeFile (void)
/* Close an include file and switch to the higher level file. Set Input to
** NULL if this was the main file.
*/
@@ -329,14 +347,18 @@ static void CloseIncludeFile (void)
/* Must have an input file when called */
PRECONDITION (AFileCount > 0);
+ /* End preprocessor in this file */
+ PreprocessEnd ();
+
/* Get the current active input file */
- Input = (AFile*) CollLast (&AFiles);
+ Input = CollLast (&AFiles);
/* Close the current input file (we're just reading so no error check) */
fclose (Input->F);
/* Delete the last active file from the active file collection */
- CollDelete (&AFiles, AFileCount-1);
+ --AFileCount;
+ CollDelete (&AFiles, AFileCount);
/* If we had added an extra search path for this AFile, remove it */
if (Input->SearchPath) {
@@ -345,6 +367,12 @@ static void CloseIncludeFile (void)
/* Delete the active file structure */
FreeAFile (Input);
+
+ /* Use previous file with PP if it is not the main file */
+ if (AFileCount > 0) {
+ Input = CollLast (&AFiles);
+ SetPPIfStack (&Input->IfStack);
+ }
}
@@ -436,47 +464,49 @@ StrBuf* InitLine (StrBuf* Buf)
int NextLine (void)
-/* Get a line from the current input. Returns 0 on end of file. */
+/* Get a line from the current input. Returns 0 on end of file with no new
+** input bytes.
+*/
{
+ int C;
AFile* Input;
/* Clear the current line */
ClearLine ();
+ SB_Clear (Line);
- /* If there is no file open, bail out, otherwise get the current input file */
- if (CollCount (&AFiles) == 0) {
+ /* Must have an input file when called */
+ if (CollCount(&AFiles) == 0) {
return 0;
}
+
+ /* Get the current input file */
Input = CollLast (&AFiles);
/* Read characters until we have one complete line */
while (1) {
/* Read the next character */
- int C = fgetc (Input->F);
+ C = fgetc (Input->F);
/* Check for EOF */
if (C == EOF) {
- /* Accept files without a newline at the end */
- if (SB_NotEmpty (Line)) {
+ if (!Input->MissingNL || SB_NotEmpty (Line)) {
+
+ /* Accept files without a newline at the end */
++Input->Line;
- break;
- }
- /* Leave the current file */
- CloseIncludeFile ();
+ /* Assume no new line */
+ Input->MissingNL = 1;
- /* If there is no file open, bail out, otherwise get the
- ** previous input file and start over.
- */
- if (CollCount (&AFiles) == 0) {
- return 0;
}
- Input = CollLast (&AFiles);
- continue;
+ break;
}
+ /* Assume no new line */
+ Input->MissingNL = 1;
+
/* Check for end of line */
if (C == '\n') {
@@ -497,6 +527,7 @@ int NextLine (void)
if (SB_LookAtLast (Line) == '\\') {
Line->Buf[Line->Len-1] = '\n';
} else {
+ Input->MissingNL = 0;
break;
}
@@ -517,6 +548,38 @@ int NextLine (void)
/* Create line information for this line */
UpdateLineInfo (Input->Input, Input->Line, Line);
+ /* Done */
+ return C != EOF || SB_NotEmpty (Line);
+}
+
+
+
+int PreprocessNextLine (void)
+/* Get a line from opened input files and do preprocess. Returns 0 on end of
+** main file.
+*/
+{
+ while (NextLine() == 0) {
+
+ /* If there is no input file open, bail out. Otherwise get the previous
+ ** input file and start over.
+ */
+ if (CollCount (&AFiles) == 0) {
+ return 0;
+ }
+
+ /* Leave the current file */
+ CloseIncludeFile ();
+ }
+
+ /* Do preprocess anyways */
+ Preprocess ();
+
+ /* Write it to the output file if in preprocess-only mode */
+ if (PreprocessOnly) {
+ WriteOutput ("%.*s\n", (int) SB_GetLen (Line), SB_GetConstBuf (Line));
+ }
+
/* Done */
return 1;
}
@@ -539,14 +602,8 @@ const char* GetCurrentFile (void)
const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1);
return AF->Input->Name;
} else {
- /* No open file. Use the main file if we have one. */
- unsigned IFileCount = CollCount (&IFiles);
- if (IFileCount > 0) {
- const IFile* IF = (const IFile*) CollAt (&IFiles, 0);
- return IF->Name;
- } else {
- return "(outside file scope)";
- }
+ /* No open file */
+ return "(outside file scope)";
}
}
diff --git a/src/cc65/input.h b/src/cc65/input.h
index a643800ba..779217b9b 100644
--- a/src/cc65/input.h
+++ b/src/cc65/input.h
@@ -46,7 +46,7 @@
/*****************************************************************************/
-/* data */
+/* Data */
/*****************************************************************************/
@@ -84,6 +84,11 @@ void OpenMainFile (const char* Name);
void OpenIncludeFile (const char* Name, InputType IT);
/* Open an include file and insert it into the tables. */
+void CloseIncludeFile (void);
+/* Close an include file and switch to the higher level file. Set Input to
+** NULL if this was the main file.
+*/
+
void NextChar (void);
/* Read the next character from the input stream and make CurC and NextC
** valid. If end of line is reached, both are set to NUL, no more lines
@@ -99,7 +104,14 @@ StrBuf* InitLine (StrBuf* Buf);
*/
int NextLine (void);
-/* Get a line from the current input. Returns 0 on end of file. */
+/* Get a line from the current input. Returns 0 on end of file with no new
+** input bytes.
+*/
+
+int PreprocessNextLine (void);
+/* Get a line from opened input files and do preprocess. Returns 0 on end of
+** main file.
+*/
const char* GetInputFile (const struct IFile* IF);
/* Return a filename from an IFile struct */
diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c
index c04024dc8..37b52351f 100644
--- a/src/cc65/macrotab.c
+++ b/src/cc65/macrotab.c
@@ -56,6 +56,9 @@
#define MACRO_TAB_SIZE 211
static Macro* MacroTab[MACRO_TAB_SIZE];
+/* The undefined macros list head */
+static Macro* UndefinedMacrosListHead;
+
/*****************************************************************************/
@@ -108,6 +111,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)
/* Define a macro for a numeric constant */
{
@@ -150,10 +176,11 @@ void InsertMacro (Macro* M)
-int UndefineMacro (const char* Name)
-/* Search for the macro with the given name and remove it from the macro
-** table if it exists. Return 1 if a macro was found and deleted, return
-** 0 otherwise.
+Macro* UndefineMacro (const char* Name)
+/* Search for the macro with the given name, if it exists, remove it from
+** the defined macro table and insert it to a list for pending deletion.
+** Return the macro if it was found and removed, return 0 otherwise.
+** To safely free the removed macro, use FreeUndefinedMacros().
*/
{
/* Get the hash value of the macro name */
@@ -173,11 +200,12 @@ int UndefineMacro (const char* Name)
L->Next = M->Next;
}
- /* Delete the macro */
- FreeMacro (M);
+ /* Add this macro to pending deletion list */
+ M->Next = UndefinedMacrosListHead;
+ UndefinedMacrosListHead = M;
/* Done */
- return 1;
+ return M;
}
/* Next macro */
@@ -191,6 +219,23 @@ int UndefineMacro (const char* Name)
+void FreeUndefinedMacros (void)
+/* Free all undefined macros */
+{
+ Macro* Next;
+
+ while (UndefinedMacrosListHead != 0) {
+ Next = UndefinedMacrosListHead->Next;
+
+ /* Delete the macro */
+ FreeMacro (UndefinedMacrosListHead);
+
+ UndefinedMacrosListHead = Next;
+ }
+}
+
+
+
Macro* FindMacro (const char* Name)
/* Find a macro with the given name. Return the macro definition or NULL */
{
diff --git a/src/cc65/macrotab.h b/src/cc65/macrotab.h
index c3ff20ceb..6a09d7281 100644
--- a/src/cc65/macrotab.h
+++ b/src/cc65/macrotab.h
@@ -82,6 +82,12 @@ void FreeMacro (Macro* M);
** 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);
/* Define a macro for a numeric constant */
@@ -91,12 +97,16 @@ void DefineTextMacro (const char* Name, const char* Val);
void InsertMacro (Macro* M);
/* Insert the given macro into the macro table. */
-int UndefineMacro (const char* Name);
-/* Search for the macro with the given name and remove it from the macro
-** table if it exists. Return 1 if a macro was found and deleted, return
-** 0 otherwise.
+Macro* UndefineMacro (const char* Name);
+/* Search for the macro with the given name, if it exists, remove it from
+** the defined macro table and insert it to a list for pending deletion.
+** Return the macro if it was found and removed, return 0 otherwise.
+** To safely free the removed macro, use FreeUndefinedMacros().
*/
+void FreeUndefinedMacros (void);
+/* Free all undefined macros */
+
Macro* FindMacro (const char* Name);
/* Find a macro with the given name. Return the macro definition or NULL */
diff --git a/src/cc65/ppexpr.c b/src/cc65/ppexpr.c
index da25e12f1..af2c1de3b 100644
--- a/src/cc65/ppexpr.c
+++ b/src/cc65/ppexpr.c
@@ -90,12 +90,14 @@ static void PPExprInit (PPExpr* Expr)
static void PPErrorSkipLine (void)
-/* Skip the remain tokens till the end of the line and set the expression
-** parser error flag.
+/* Set the expression parser error flag, skip the remain tokens till the end
+** of the line, clear the current and the next tokens.
*/
{
- SkipTokens (0, 0);
PPEvaluationFailed = 1;
+ SkipTokens (0, 0);
+ CurTok.Tok = TOK_CEOF;
+ NextTok.Tok = TOK_CEOF;
}
@@ -148,6 +150,10 @@ static void PPhiePrimary (PPExpr* Expr)
Expr->IVal = 0;
break;
+ case TOK_CEOF:
+ /* Error recovery */
+ break;
+
default:
/* Illegal expression in PP mode */
PPError ("Preprocessor expression expected");
@@ -252,6 +258,10 @@ void PPhie10 (PPExpr* Expr)
Expr->IVal = !Expr->IVal;
break;
+ case TOK_CEOF:
+ /* Error recovery */
+ break;
+
case TOK_STAR:
case TOK_AND:
case TOK_SIZEOF:
@@ -286,7 +296,7 @@ static void PPhie_internal (const token_t* Ops, /* List of generators */
/* Get the right hand side */
hienext (&Rhs);
- if (PPEvaluationEnabled) {
+ if (PPEvaluationEnabled && !PPEvaluationFailed) {
/* If either side is unsigned, the result is unsigned */
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
@@ -407,7 +417,7 @@ static void PPhie_compare (const token_t* Ops, /* List of generators */
/* Get the right hand side */
hienext (&Rhs);
- if (PPEvaluationEnabled) {
+ if (PPEvaluationEnabled && !PPEvaluationFailed) {
/* If either side is unsigned, the comparison is unsigned */
Expr->Flags |= Rhs.Flags & PPEXPR_UNSIGNED;
@@ -501,7 +511,7 @@ static void PPhie7 (PPExpr* Expr)
PPhie8 (&Rhs);
/* Evaluate */
- if (PPEvaluationEnabled) {
+ if (PPEvaluationEnabled && !PPEvaluationFailed) {
/* To shift by a negative value is equivalent to shift to the
** opposite direction.
*/
@@ -761,46 +771,57 @@ static void PPhie1 (PPExpr* Expr)
case TOK_ASSIGN:
PPError ("Token \"=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_PLUS_ASSIGN:
PPError ("Token \"+=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_MINUS_ASSIGN:
PPError ("Token \"-=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_MUL_ASSIGN:
PPError ("Token \"*=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_DIV_ASSIGN:
PPError ("Token \"/=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_MOD_ASSIGN:
PPError ("Token \"%%=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_SHL_ASSIGN:
PPError ("Token \"<<=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_SHR_ASSIGN:
PPError ("Token \">>=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_AND_ASSIGN:
PPError ("Token \"&=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_OR_ASSIGN:
PPError ("Token \"|=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
case TOK_XOR_ASSIGN:
PPError ("Token \"^=\" is not valid in preprocessor expressions");
+ PPErrorSkipLine ();
break;
default:
@@ -827,12 +848,13 @@ static void PPhie0 (PPExpr* Expr)
-void ParsePPExpr (PPExpr* Expr)
+void ParsePPExprInLine (PPExpr* Expr)
/* Parse a line for PP expression */
{
/* Initialize the parser status */
PPEvaluationFailed = 0;
PPEvaluationEnabled = 1;
+ NextLineDisabled = 1;
/* Parse */
PPExprInit (Expr);
@@ -841,5 +863,9 @@ void ParsePPExpr (PPExpr* Expr)
/* If the evaluation fails, the result is always zero */
if (PPEvaluationFailed) {
Expr->IVal = 0;
+ PPEvaluationFailed = 0;
}
+
+ /* Restore parser status */
+ NextLineDisabled = 0;
}
diff --git a/src/cc65/ppexpr.h b/src/cc65/ppexpr.h
index 683c6c49d..5e9968a2b 100644
--- a/src/cc65/ppexpr.h
+++ b/src/cc65/ppexpr.h
@@ -66,7 +66,7 @@ struct PPExpr
-void ParsePPExpr (PPExpr* Expr);
+void ParsePPExprInLine (PPExpr* Expr);
/* Parse a line for PP expression */
diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c
index 96bb0bf1c..c545bf889 100644
--- a/src/cc65/preproc.c
+++ b/src/cc65/preproc.c
@@ -67,27 +67,29 @@
-/* Set when the preprocessor calls expr() recursively */
-static unsigned char Preprocessing = 0;
-
/* Management data for #if */
-#define MAX_IFS 256
#define IFCOND_NONE 0x00U
#define IFCOND_SKIP 0x01U
#define IFCOND_ELSE 0x02U
#define IFCOND_NEEDTERM 0x04U
-static unsigned char IfStack[MAX_IFS];
-static int IfIndex = -1;
-/* Buffer for macro expansion */
-static StrBuf* MLine;
+/* Current PP if stack */
+static PPIfStack* PPStack;
+
+/* Intermediate input buffers */
+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;
/* Structure used when expanding macros */
typedef struct MacroExp MacroExp;
struct MacroExp {
Collection ActualArgs; /* Actual arguments */
StrBuf Replacement; /* Replacement with arguments substituted */
- Macro* M; /* The macro we're handling */
};
@@ -103,12 +105,12 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target);
** non-newline whitespace sequences.
*/
-static unsigned Pass1 (StrBuf* Source, StrBuf* Target);
-/* Preprocessor pass 1. Remove whitespace. Handle old and new style comments
-** and the "defined" operator.
+static int ParseDirectives (int InArgList);
+/* Handle directives. Return 1 if there are directives parsed, -1 if new lines
+** are read, otherwise 0.
*/
-static void MacroReplacement (StrBuf* Source, StrBuf* Target);
+static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine);
/* Perform macro replacement. */
@@ -190,12 +192,11 @@ static pptoken_t FindPPToken (const char* Ident)
-static MacroExp* InitMacroExp (MacroExp* E, Macro* M)
+static MacroExp* InitMacroExp (MacroExp* E)
/* Initialize a MacroExp structure */
{
InitCollection (&E->ActualArgs);
SB_Init (&E->Replacement);
- E->M = M;
return E;
}
@@ -241,11 +242,11 @@ static StrBuf* ME_GetActual (MacroExp* E, unsigned Index)
-static int ME_ArgIsVariadic (const MacroExp* E)
+static int ME_ArgIsVariadic (const MacroExp* E, const Macro* M)
/* Return true if the next actual argument we will add is a variadic one */
{
- return (E->M->Variadic &&
- E->M->ArgCount == (int) CollCount (&E->ActualArgs) + 1);
+ return (M->Variadic &&
+ M->ArgCount == (int) CollCount (&E->ActualArgs) + 1);
}
@@ -256,6 +257,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)
/* Stringize the given string: Add double quotes at start and end and preceed
** each occurance of " and \ by a backslash.
@@ -341,12 +382,15 @@ static void NewStyleComment (void)
static int SkipWhitespace (int SkipLines)
-/* Skip white space and comments in the input stream. Do also skip newlines if
-** SkipLines is true. Return zero if nothing was skipped, otherwise return a
-** value != zero.
+/* Skip white space and comments in the input stream. If skipLines is true,
+** also skip newlines and add that count to global PendingNewLines. Return 1
+** 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 NewLine = 0;
while (1) {
if (IsSpace (CurC)) {
NextChar ();
@@ -360,7 +404,9 @@ static int SkipWhitespace (int SkipLines)
} else if (CurC == '\0' && SkipLines) {
/* End of line, read next */
if (NextLine () != 0) {
- Skipped = 1;
+ ++PendingNewLines;
+ NewLine = 1;
+ Skipped = 0;
} else {
/* End of input */
break;
@@ -370,7 +416,36 @@ static int SkipWhitespace (int SkipLines)
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 ();
+ }
}
@@ -399,11 +474,28 @@ static void CopyQuotedString (StrBuf* Target)
if (CurC != '\0') {
SB_AppendChar (Target, CurC);
NextChar ();
+ } else {
+ PPWarning ("Missing terminating %c character", Quote);
}
}
+static int CheckExtraTokens (const char* Name)
+/* Check for extra tokens at the end of the directive. Return 1 if there are
+** extra tokens, otherwise 0.
+*/
+{
+ SkipWhitespace (0);
+ if (SB_GetIndex (Line) != SB_GetLen (Line)) {
+ PPWarning ("Extra tokens at end of #%s directive", Name);
+ return 1;
+ }
+ return 0;
+}
+
+
+
/*****************************************************************************/
/* Macro stuff */
/*****************************************************************************/
@@ -416,7 +508,11 @@ static int MacName (char* Ident)
*/
{
if (IsSym (Ident) == 0) {
- PPError ("Identifier expected");
+ if (CurC != '\0') {
+ PPError ("Macro name must be an identifier");
+ } else {
+ PPError ("Missing macro name");
+ }
ClearLine ();
return 0;
} else {
@@ -426,15 +522,37 @@ static int MacName (char* Ident)
-static void ReadMacroArgs (MacroExp* E)
-/* Identify the arguments to a macro call */
+static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine)
+/* Identify the arguments to a macro call as-is */
{
+ int MissingParen = 0;
unsigned Parens; /* Number of open parenthesis */
- StrBuf Arg = STATIC_STRBUF_INITIALIZER;
+ StrBuf Arg = AUTO_STRBUF_INITIALIZER;
+
+ /* Eat the left paren */
+ NextChar ();
/* Read the actual macro arguments */
Parens = 0;
while (1) {
+ /* Squeeze runs of blanks within an arg */
+ int OldPendingNewLines = PendingNewLines;
+ int Skipped = SkipWhitespace (MultiLine);
+ if (MultiLine && CurC == '#') {
+ int Newlines = 0;
+
+ while (CurC == '#') {
+ Newlines += PendingNewLines - OldPendingNewLines;
+ PendingNewLines = OldPendingNewLines;
+ OldPendingNewLines = 0;
+ Skipped = ParseDirectives (1) || Skipped;
+ Skipped = SkipWhitespace (MultiLine) || Skipped;
+ }
+ PendingNewLines += Newlines;
+ }
+ if (Skipped && SB_NotEmpty (&Arg)) {
+ SB_AppendChar (&Arg, ' ');
+ }
if (CurC == '(') {
/* Nested parenthesis */
@@ -456,7 +574,7 @@ static void ReadMacroArgs (MacroExp* E)
}
SB_AppendChar (&Arg, CurC);
NextChar ();
- } else if (CurC == ',' && ME_ArgIsVariadic (E)) {
+ } else if (CurC == ',' && ME_ArgIsVariadic (E, M)) {
/* It's a comma, but we're inside a variadic macro argument, so
** just copy it and proceed.
*/
@@ -471,7 +589,7 @@ static void ReadMacroArgs (MacroExp* E)
/* If this is not the single empty argument for a macro with
** an empty argument list, remember it.
*/
- if (CurC != ')' || SB_NotEmpty (&Arg) || E->M->ArgCount > 0) {
+ if (CurC != ')' || SB_NotEmpty (&Arg) || M->ArgCount > 0) {
ME_AppendActual (E, &Arg);
}
@@ -485,15 +603,10 @@ static void ReadMacroArgs (MacroExp* E)
NextChar ();
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') {
/* End of input inside macro argument list */
- PPError ("Unterminated argument list invoking macro '%s'", E->M->Name);
-
+ PPError ("Unterminated argument list invoking macro '%s'", M->Name);
+ MissingParen = 1;
ClearLine ();
break;
} else {
@@ -503,13 +616,28 @@ static void ReadMacroArgs (MacroExp* E)
}
}
+ /* Compare formal and actual argument count */
+ if (CollCount (&E->ActualArgs) != (unsigned) M->ArgCount) {
+
+ if (!MissingParen) {
+ /* Argument count mismatch */
+ PPError ("Macro argument count mismatch");
+ }
+
+ /* Be sure to make enough empty arguments available */
+ SB_Clear (&Arg);
+ while (CollCount (&E->ActualArgs) < (unsigned) M->ArgCount) {
+ ME_AppendActual (E, &Arg);
+ }
+ }
+
/* Deallocate string buf resources */
SB_Done (&Arg);
}
-static void MacroArgSubst (MacroExp* E)
+static void MacroArgSubst (MacroExp* E, Macro* M)
/* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */
{
ident Ident;
@@ -520,9 +648,9 @@ static void MacroArgSubst (MacroExp* E)
/* Remember the current input and switch to the macro replacement. */
- int OldIndex = SB_GetIndex (&E->M->Replacement);
- SB_Reset (&E->M->Replacement);
- OldSource = InitLine (&E->M->Replacement);
+ int OldIndex = SB_GetIndex (&M->Replacement);
+ SB_Reset (&M->Replacement);
+ OldSource = InitLine (&M->Replacement);
/* Argument handling loop */
while (CurC != '\0') {
@@ -531,7 +659,7 @@ static void MacroArgSubst (MacroExp* E)
if (IsSym (Ident)) {
/* Check if it's a macro argument */
- if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
+ if ((ArgIdx = FindMacroArg (M, Ident)) >= 0) {
/* A macro argument. Get the corresponding actual argument. */
Arg = ME_GetActual (E, ArgIdx);
@@ -553,7 +681,7 @@ static void MacroArgSubst (MacroExp* E)
** of the actual.
*/
SB_Reset (Arg);
- MacroReplacement (Arg, &E->Replacement);
+ MacroReplacement (Arg, &E->Replacement, 0);
/* If we skipped whitespace before, re-add it now */
if (HaveSpace) {
@@ -590,7 +718,7 @@ static void MacroArgSubst (MacroExp* E)
if (IsSym (Ident)) {
/* Check if it's a macro argument */
- if ((ArgIdx = FindMacroArg (E->M, Ident)) >= 0) {
+ if ((ArgIdx = FindMacroArg (M, Ident)) >= 0) {
/* Get the corresponding actual argument and add it. */
SB_Append (&E->Replacement, ME_GetActual (E, ArgIdx));
@@ -603,7 +731,7 @@ static void MacroArgSubst (MacroExp* E)
}
}
- } else if (CurC == '#' && E->M->ArgCount >= 0) {
+ } else if (CurC == '#' && M->ArgCount >= 0) {
/* A # operator within a macro expansion of a function like
** macro. Read the following identifier and check if it's a
@@ -611,7 +739,7 @@ static void MacroArgSubst (MacroExp* E)
*/
NextChar ();
SkipWhitespace (0);
- if (!IsSym (Ident) || (ArgIdx = FindMacroArg (E->M, Ident)) < 0) {
+ if (!IsSym (Ident) || (ArgIdx = FindMacroArg (M, Ident)) < 0) {
PPError ("'#' is not followed by a macro parameter");
} else {
/* Make a valid string from Replacement */
@@ -637,100 +765,46 @@ static void MacroArgSubst (MacroExp* E)
/* Switch back the input */
InitLine (OldSource);
- SB_SetIndex (&E->M->Replacement, OldIndex);
+ SB_SetIndex (&M->Replacement, OldIndex);
}
-static void MacroCall (StrBuf* Target, Macro* M)
-/* Process a function like macro */
-{
- MacroExp E;
-
- /* Eat the left paren */
- NextChar ();
-
- /* Initialize our MacroExp structure */
- InitMacroExp (&E, M);
-
- /* Read the actual macro arguments */
- ReadMacroArgs (&E);
-
- /* Compare formal and actual argument count */
- if (CollCount (&E.ActualArgs) != (unsigned) M->ArgCount) {
-
- StrBuf Arg = STATIC_STRBUF_INITIALIZER;
-
- /* Argument count mismatch */
- PPError ("Macro argument count mismatch");
-
- /* Be sure to make enough empty arguments available */
- while (CollCount (&E.ActualArgs) < (unsigned) M->ArgCount) {
- ME_AppendActual (&E, &Arg);
- }
- }
-
- /* 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)
+static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine)
/* Expand a macro into Target */
{
+ MacroExp E;
+
#if 0
static unsigned V = 0;
printf ("Expanding %s(%u)\n", M->Name, ++V);
#endif
+ /* Initialize our MacroExp structure */
+ InitMacroExp (&E);
+
/* Check if this is a function like macro */
if (M->ArgCount >= 0) {
- int Whitespace = SkipWhitespace (1);
- if (CurC != '(') {
- /* Function like macro but no parameter list */
- SB_AppendStr (Target, M->Name);
- if (Whitespace) {
- SB_AppendChar (Target, ' ');
- }
- } else {
- /* Function like macro */
- MacroCall (Target, M);
- }
-
- } else {
-
- MacroExp E;
- InitMacroExp (&E, M);
-
- /* Handle # and ## operators for object like macros */
- 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);
+ /* Read the actual macro arguments (with the enclosing parentheses) */
+ ReadMacroArgs (&E, M, MultiLine);
}
+
+ /* Replace macro arguments handling the # and ## operators */
+ MacroArgSubst (&E, M);
+
+ /* Forbide repeated expansion of the same macro in use */
+ M->Expanding = 1;
+ MacroReplacement (&E.Replacement, Target, 0);
+ M->Expanding = 0;
+
#if 0
- printf ("Done with %s(%u)\n", M->Name, V--);
+ printf ("Done with %s(%u)\n", E.M->Name, V--);
#endif
+
+ /* Free memory allocated for the macro expansion structure */
+ DoneMacroExp (&E);
}
@@ -912,20 +986,25 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target)
-static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
-/* Preprocessor pass 1. Remove whitespace, old and new style comments. Handle
-** the "defined" operator.
+static void ProcessSingleLine (StrBuf* Source,
+ StrBuf* Target,
+ 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;
int HaveParen;
- /* Switch to the new input source */
+ /* Operate on the new input source */
StrBuf* OldSource = InitLine (Source);
+ SkipWhitespace (0);
+
/* Loop removing ws and comments */
- IdentCount = 0;
while (CurC != '\0') {
if (SkipWhitespace (0)) {
/* Squeeze runs of blanks */
@@ -933,7 +1012,7 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
SB_AppendChar (Target, ' ');
}
} else if (IsSym (Ident)) {
- if (Preprocessing && strcmp (Ident, "defined") == 0) {
+ if (HandleDefined && strcmp (Ident, "defined") == 0) {
/* Handle the "defined" operator */
SkipWhitespace (0);
HaveParen = 0;
@@ -957,9 +1036,32 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
SB_AppendChar (Target, '0');
}
} else {
- ++IdentCount;
- SB_AppendStr (Target, Ident);
+ Macro* M = FindMacro (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)) {
CopyQuotedString (Target);
} else {
@@ -971,13 +1073,13 @@ static unsigned Pass1 (StrBuf* Source, StrBuf* Target)
/* Switch back to the old source */
InitLine (OldSource);
- /* Return the number of identifiers found in the line */
- return IdentCount;
+ /* Restore the source input index */
+ SB_SetIndex (Source, OldIndex);
}
-static void MacroReplacement (StrBuf* Source, StrBuf* Target)
+static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine)
/* Perform macro replacement. */
{
ident Ident;
@@ -992,22 +1094,64 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target)
if (IsSym (Ident)) {
/* Check if it's a macro */
if ((M = FindMacro (Ident)) != 0 && !M->Expanding) {
- /* It's a macro, expand it */
- ExpandMacro (Target, M);
+ /* Check if this is a function-like macro */
+ 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, ' ');
+ }
+
+ /* Directives can only be found in an argument list
+ ** that spans multiple lines.
+ */
+ if (MultiLine) {
+ if (CurC == '#') {
+ /* If we were going to support #pragma in
+ ** macro argument list, it would be output
+ ** to OLine.
+ */
+ if (OLine == 0) {
+ OLine = Target;
+ ParseDirectives (0);
+ OLine = 0;
+ } else {
+ ParseDirectives (0);
+ }
+ }
+ /* 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 {
/* An identifier, keep it */
SB_AppendStr (Target, Ident);
}
} else if (IsQuote (CurC)) {
CopyQuotedString (Target);
- } else if (IsSpace (CurC)) {
- if (!IsSpace (SB_LookAtLast (Target))) {
- SB_AppendChar (Target, CurC);
- }
- NextChar ();
} else {
- SB_AppendChar (Target, CurC);
- NextChar ();
+ int Whitespace = SkipWhitespace (0);
+ if (Whitespace) {
+ SB_AppendChar (Target, ' ');
+ } else {
+ SB_AppendChar (Target, CurC);
+ NextChar ();
+ }
}
}
@@ -1017,43 +1161,22 @@ 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)
/* Push a new if level onto the if stack */
{
/* Check for an overflow of the if stack */
- if (IfIndex >= MAX_IFS-1) {
+ if (PPStack->Index >= MAX_PP_IFS-1) {
PPError ("Too many nested #if clauses");
return 1;
}
/* Push the #if condition */
- ++IfIndex;
+ ++PPStack->Index;
if (Skip) {
- IfStack[IfIndex] = IFCOND_SKIP | IFCOND_NEEDTERM;
+ PPStack->Stack[PPStack->Index] = IFCOND_SKIP | IFCOND_NEEDTERM;
return 1;
} else {
- IfStack[IfIndex] = IFCOND_NONE | IFCOND_NEEDTERM;
+ PPStack->Stack[PPStack->Index] = IFCOND_NONE | IFCOND_NEEDTERM;
return (Invert ^ Cond);
}
}
@@ -1085,10 +1208,11 @@ static int DoIf (int Skip)
PPExpr Expr = AUTO_PPEXPR_INITIALIZER;
if (!Skip) {
+
/* We're about to use a dedicated expression parser to evaluate the #if
** expression. Save the current tokens to come back here later.
*/
- Token SavedCurTok = CurTok;
+ Token SavedCurTok = CurTok;
Token SavedNextTok = NextTok;
/* Make sure the line infos for the tokens won't get removed */
@@ -1099,11 +1223,13 @@ static int DoIf (int Skip)
UseLineInfo (SavedNextTok.LI);
}
- /* Switch into special preprocessing mode */
- Preprocessing = 1;
+ /* Macro-replace a single line with support for the "defined" operator */
+ SB_Clear (MLine);
+ ProcessSingleLine (Line, MLine, 1, 0);
- /* Expand macros in this line */
- PreprocessLine ();
+ /* Read from the processed line */
+ SB_Reset (MLine);
+ MLine = InitLine (MLine);
/* Add two semicolons as sentinels to the line, so the following
** expression evaluation will eat these two tokens but nothing from
@@ -1117,10 +1243,10 @@ static int DoIf (int Skip)
NextToken ();
/* Call the expression parser */
- ParsePPExpr (&Expr);
+ ParsePPExprInLine (&Expr);
- /* End preprocessing mode */
- Preprocessing = 0;
+ /* Restore input source */
+ MLine = InitLine (MLine);
/* Reset the old tokens */
CurTok = SavedCurTok;
@@ -1144,6 +1270,8 @@ static int DoIfDef (int skip, int flag)
SkipWhitespace (0);
if (MacName (Ident)) {
Value = IsMacro (Ident);
+ /* Check for extra tokens */
+ CheckExtraTokens (flag ? "ifdef" : "ifndef");
}
}
@@ -1157,14 +1285,15 @@ static void DoInclude (void)
{
char RTerm;
InputType IT;
- StrBuf Filename = STATIC_STRBUF_INITIALIZER;
+ StrBuf Filename = AUTO_STRBUF_INITIALIZER;
+ /* Macro-replace a single line with special support for */
+ SB_Clear (MLine);
+ ProcessSingleLine (Line, MLine, 0, 1);
- /* Preprocess the remainder of the line */
- PreprocessLine ();
-
- /* Skip blanks */
- SkipWhitespace (0);
+ /* Read from the processed line */
+ SB_Reset (MLine);
+ MLine = InitLine (MLine);
/* Get the next char and check for a valid file name terminator. Setup
** the include directory spec (SYS/USR) by looking at the terminator.
@@ -1196,6 +1325,10 @@ static void DoInclude (void)
/* Check if we got a terminator */
if (CurC == RTerm) {
+ /* Skip the terminator */
+ NextChar ();
+ /* Check for extra tokens following the filename */
+ CheckExtraTokens ("include");
/* Open the include file */
OpenIncludeFile (SB_GetConstBuf (&Filename), IT);
} else if (CurC == '\0') {
@@ -1207,6 +1340,9 @@ Done:
/* Free the allocated filename data */
SB_Done (&Filename);
+ /* Restore input source */
+ MLine = InitLine (MLine);
+
/* Clear the remaining line so the next input will come from the new
** file (if open)
*/
@@ -1220,19 +1356,25 @@ static void DoPragma (void)
** the _Pragma() compiler operator.
*/
{
- /* Copy the remainder of the line into MLine removing comments and ws */
+ StrBuf* PragmaLine = OLine;
+
+ PRECONDITION (PragmaLine != 0);
+
+ /* Add the source info to preprocessor output if needed */
+ AddPreLine (PragmaLine);
+
+ /* Macro-replace a single line */
SB_Clear (MLine);
- Pass1 (Line, MLine);
+ ProcessSingleLine (Line, MLine, 0, 0);
- /* Convert the directive into the operator */
- SB_CopyStr (Line, "_Pragma (");
+ /* Convert #pragma to _Pragma () */
+ SB_AppendStr (PragmaLine, "_Pragma (");
SB_Reset (MLine);
- Stringize (MLine, Line);
- SB_AppendChar (Line, ')');
+ Stringize (MLine, PragmaLine);
+ SB_AppendChar (PragmaLine, ')');
- /* Initialize reading from line */
- SB_Reset (Line);
- InitLine (Line);
+ /* End this line */
+ SB_SetIndex (PragmaLine, SB_GetLen (PragmaLine));
}
@@ -1246,6 +1388,8 @@ static void DoUndef (void)
if (MacName (Ident)) {
UndefineMacro (Ident);
}
+ /* Check for extra tokens */
+ CheckExtraTokens ("undef");
}
@@ -1269,23 +1413,17 @@ static void DoWarning (void)
-void Preprocess (void)
-/* Preprocess a line */
+static int ParseDirectives (int InArgList)
+/* Handle directives. Return 1 if any whitespace or newlines are parsed. */
{
- int Skip;
+ int PPSkip = 0;
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 */
- SkipWhitespace (0);
+ /* Skip white space at the beginning of the first line */
+ int Whitespace = SkipWhitespace (0);
/* Check for stuff to skip */
- Skip = 0;
- while (CurC == '\0' || CurC == '#' || Skip) {
+ while (CurC == '\0' || CurC == '#' || PPSkip) {
/* Check for preprocessor lines lines */
if (CurC == '#') {
@@ -1296,7 +1434,7 @@ void Preprocess (void)
continue;
}
if (!IsSym (Directive)) {
- if (!Skip) {
+ if (!PPSkip) {
PPError ("Preprocessor directive expected");
}
ClearLine ();
@@ -1304,24 +1442,23 @@ void Preprocess (void)
switch (FindPPToken (Directive)) {
case PP_DEFINE:
- if (!Skip) {
+ if (!PPSkip) {
DefineMacro ();
}
break;
case PP_ELIF:
- if (IfIndex >= 0) {
- if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
-
+ if (PPStack->Index >= 0) {
+ if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) {
/* Handle as #else/#if combination */
- if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
- Skip = !Skip;
+ if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) {
+ PPSkip = !PPSkip;
}
- IfStack[IfIndex] |= IFCOND_ELSE;
- Skip = DoIf (Skip);
+ PPStack->Stack[PPStack->Index] |= IFCOND_ELSE;
+ PPSkip = DoIf (PPSkip);
/* #elif doesn't need a terminator */
- IfStack[IfIndex] &= ~IFCOND_NEEDTERM;
+ PPStack->Stack[PPStack->Index] &= ~IFCOND_NEEDTERM;
} else {
PPError ("Duplicate #else/#elif");
}
@@ -1331,12 +1468,15 @@ void Preprocess (void)
break;
case PP_ELSE:
- if (IfIndex >= 0) {
- if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) {
- if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) {
- Skip = !Skip;
+ if (PPStack->Index >= 0) {
+ if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) {
+ if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) {
+ PPSkip = !PPSkip;
}
- IfStack[IfIndex] |= IFCOND_ELSE;
+ PPStack->Stack[PPStack->Index] |= IFCOND_ELSE;
+
+ /* Check for extra tokens */
+ CheckExtraTokens ("else");
} else {
PPError ("Duplicate #else");
}
@@ -1346,64 +1486,71 @@ void Preprocess (void)
break;
case PP_ENDIF:
- if (IfIndex >= 0) {
+ if (PPStack->Index >= 0) {
/* Remove any clauses on top of stack that do not
** need a terminating #endif.
*/
- while (IfIndex >= 0 && (IfStack[IfIndex] & IFCOND_NEEDTERM) == 0) {
- --IfIndex;
+ while (PPStack->Index >= 0 &&
+ (PPStack->Stack[PPStack->Index] & IFCOND_NEEDTERM) == 0) {
+ --PPStack->Index;
}
/* Stack may not be empty here or something is wrong */
- CHECK (IfIndex >= 0);
+ CHECK (PPStack->Index >= 0);
/* Remove the clause that needs a terminator */
- Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0;
+ PPSkip = (PPStack->Stack[PPStack->Index--] & IFCOND_SKIP) != 0;
+
+ /* Check for extra tokens */
+ CheckExtraTokens ("endif");
} else {
PPError ("Unexpected '#endif'");
}
break;
case PP_ERROR:
- if (!Skip) {
+ if (!PPSkip) {
DoError ();
}
break;
case PP_IF:
- Skip = DoIf (Skip);
+ PPSkip = DoIf (PPSkip);
break;
case PP_IFDEF:
- Skip = DoIfDef (Skip, 1);
+ PPSkip = DoIfDef (PPSkip, 1);
break;
case PP_IFNDEF:
- Skip = DoIfDef (Skip, 0);
+ PPSkip = DoIfDef (PPSkip, 0);
break;
case PP_INCLUDE:
- if (!Skip) {
+ if (!PPSkip) {
DoInclude ();
}
break;
case PP_LINE:
/* Should do something in C99 at least, but we ignore it */
- if (!Skip) {
+ if (!PPSkip) {
ClearLine ();
}
break;
case PP_PRAGMA:
- if (!Skip) {
- DoPragma ();
- goto Done;
+ if (!PPSkip) {
+ if (!InArgList) {
+ DoPragma ();
+ } else {
+ PPError ("Embedded #pragma directive within macro arguments is unsupported");
+ }
}
break;
case PP_UNDEF:
- if (!Skip) {
+ if (!PPSkip) {
DoUndef ();
}
break;
@@ -1411,11 +1558,11 @@ void Preprocess (void)
case PP_WARNING:
/* #warning is a non standard extension */
if (IS_Get (&Standard) > STD_C99) {
- if (!Skip) {
+ if (!PPSkip) {
DoWarning ();
}
} else {
- if (!Skip) {
+ if (!PPSkip) {
PPError ("Preprocessor directive expected");
}
ClearLine ();
@@ -1423,7 +1570,7 @@ void Preprocess (void)
break;
default:
- if (!Skip) {
+ if (!PPSkip) {
PPError ("Preprocessor directive expected");
}
ClearLine ();
@@ -1432,19 +1579,108 @@ void Preprocess (void)
}
if (NextLine () == 0) {
- if (IfIndex >= 0) {
- PPError ("'#endif' expected");
- }
- return;
+ break;
}
- SkipWhitespace (0);
+ ++PendingNewLines;
+ Whitespace = SkipWhitespace (0) || Whitespace;
}
- PreprocessLine ();
+ return Whitespace != 0;
+}
+
+
+
+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 (0);
+ OLine = 0;
+
+ /* Add the source info to preprocessor output if needed */
+ AddPreLine (PLine);
+
+ /* Add leading whitespace to prettify preprocessor output */
+ AppendIndent (PLine, SB_GetIndex (Line));
+
+ /* 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)) {
printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (),
(int) SB_GetLen (Line), SB_GetConstBuf (Line));
}
+
+ /* Free all undefined macros */
+ FreeUndefinedMacros ();
+}
+
+
+
+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)
+/* Specify which PP #if stack to use */
+{
+ PPStack = Stack;
+}
+
+
+
+void PreprocessBegin (void)
+/* Initialize preprocessor with current file */
+{
+ /* Reset #if depth */
+ PPStack->Index = -1;
+
+ /* Remember to update source file location in preprocess-only mode */
+ FileChanged = 1;
+}
+
+
+
+void PreprocessEnd (void)
+/* Preprocessor done with current file */
+{
+ /* Check for missing #endif */
+ while (PPStack->Index >= 0) {
+ if ((PPStack->Stack[PPStack->Index] & IFCOND_NEEDTERM) != 0) {
+ PPError ("#endif expected");
+ }
+ --PPStack->Index;
+ }
+
+ /* Remember to update source file location in preprocess-only mode */
+ FileChanged = 1;
}
diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h
index 34f62c114..f543b05b5 100644
--- a/src/cc65/preproc.h
+++ b/src/cc65/preproc.h
@@ -39,7 +39,25 @@
/*****************************************************************************/
-/* code */
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Maximum #if depth per file */
+#define MAX_PP_IFS 256
+
+/* Data struct used for per-file-directive handling */
+typedef struct PPIfStack PPIfStack;
+struct PPIfStack {
+ unsigned char Stack[MAX_PP_IFS];
+ int Index;
+};
+
+
+
+/*****************************************************************************/
+/* Code */
/*****************************************************************************/
@@ -47,6 +65,21 @@
void Preprocess (void);
/* Preprocess a line */
+void SetPPIfStack (PPIfStack* Stack);
+/* Specify which PP #if stack to use */
+
+void PreprocessBegin (void);
+/* Initialize preprocessor with current file */
+
+void PreprocessEnd (void);
+/* Preprocessor done with current file */
+
+void InitPreprocess (void);
+/* Init preprocessor */
+
+void DonePreprocess (void);
+/* Done with preprocessor */
+
/* End of preproc.h */
diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c
index 70203d027..c7e9bb6c2 100644
--- a/src/cc65/scanner.c
+++ b/src/cc65/scanner.c
@@ -69,6 +69,7 @@
Token CurTok; /* The current token */
Token NextTok; /* The next token */
+int NextLineDisabled; /* Disabled to read next line */
@@ -188,10 +189,10 @@ static int SkipWhite (void)
{
while (1) {
while (CurC == '\0') {
- if (NextLine () == 0) {
+ /* If reading next line fails or is forbidden, bail out */
+ if (NextLineDisabled || PreprocessNextLine () == 0) {
return 0;
}
- Preprocess ();
}
if (IsSpace (CurC)) {
NextChar ();
diff --git a/src/cc65/scanner.h b/src/cc65/scanner.h
index e6a362bf3..cd34cbbe8 100644
--- a/src/cc65/scanner.h
+++ b/src/cc65/scanner.h
@@ -210,6 +210,7 @@ struct Token {
extern Token CurTok; /* The current token */
extern Token NextTok; /* The next token */
+extern int NextLineDisabled; /* Disabled to read next line */
diff --git a/test/misc/bug1357.c b/test/val/bug1357.c
similarity index 100%
rename from test/misc/bug1357.c
rename to test/val/bug1357.c
diff --git a/test/val/bug1643.c b/test/val/bug1643.c
new file mode 100644
index 000000000..eba733511
--- /dev/null
+++ b/test/val/bug1643.c
@@ -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;
+}
diff --git a/test/val/bug1643.h b/test/val/bug1643.h
new file mode 100644
index 000000000..fe0423688
--- /dev/null
+++ b/test/val/bug1643.h
@@ -0,0 +1,13 @@
+/* bug #1643, macro expansion in #include */
+
+#define STDIO_H
+#include STDIO_H
+
+#ifdef string
+#undef string
+#endif
+
+#define string 0!%^&*/_=
+#include
+
+#define BUG1643_RESULT 0
diff --git a/test/misc/bug760.c b/test/val/bug760.c
similarity index 100%
rename from test/misc/bug760.c
rename to test/val/bug760.c