From 7381a2c4201fcd7edc07d3fbc499d11bc28ec2f4 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 19:07:16 +0800 Subject: [PATCH 01/11] Added check for extra tokens at the end of directives. Improved diagnostics on missing/illegal macro names. --- src/cc65/preproc.c | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 96bb0bf1c..016abf11e 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -404,6 +404,21 @@ static void CopyQuotedString (StrBuf* Target) +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 +431,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 { @@ -1144,6 +1163,8 @@ static int DoIfDef (int skip, int flag) SkipWhitespace (0); if (MacName (Ident)) { Value = IsMacro (Ident); + /* Check for extra tokens */ + CheckExtraTokens (flag ? "ifdef" : "ifndef"); } } @@ -1196,6 +1217,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') { @@ -1246,6 +1271,8 @@ static void DoUndef (void) if (MacName (Ident)) { UndefineMacro (Ident); } + /* Check for extra tokens */ + CheckExtraTokens ("undef"); } @@ -1312,7 +1339,6 @@ void Preprocess (void) case PP_ELIF: if (IfIndex >= 0) { if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) { - /* Handle as #else/#if combination */ if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) { Skip = !Skip; @@ -1337,6 +1363,9 @@ void Preprocess (void) Skip = !Skip; } IfStack[IfIndex] |= IFCOND_ELSE; + + /* Check for extra tokens */ + CheckExtraTokens ("else"); } else { PPError ("Duplicate #else"); } @@ -1359,6 +1388,9 @@ void Preprocess (void) /* Remove the clause that needs a terminator */ Skip = (IfStack[IfIndex--] & IFCOND_SKIP) != 0; + + /* Check for extra tokens */ + CheckExtraTokens ("endif"); } else { PPError ("Unexpected '#endif'"); } From 60c12904686cda5ad4552514d72584545168527a Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:10:26 +0800 Subject: [PATCH 02/11] Fixed the bug that preprocessor could run past the end of included files. Fixed the wrong filename and 0 line number in disgnostics when a preprocessor error occurred at the end of a file. Fixed diagnostics for missing #endif. --- src/cc65/compile.c | 21 +++++---- src/cc65/input.c | 115 +++++++++++++++++++++++++++++++++------------ src/cc65/input.h | 16 ++++++- src/cc65/preproc.c | 77 ++++++++++++++++++++---------- src/cc65/preproc.h | 29 +++++++++++- src/cc65/scanner.c | 3 +- 6 files changed, 193 insertions(+), 68 deletions(-) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index d1f78098d..f4fb16c37 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 */ @@ -336,6 +339,9 @@ static void Parse (void) } } + + /* Done with deferred operations */ + DoneDeferredOps (); } @@ -401,8 +407,6 @@ void Compile (const char* FileName) /* DefineNumericMacro ("__STDC__", 1); <- not now */ DefineNumericMacro ("__STDC_HOSTED__", 1); - InitDeferredOps (); - /* Create the base lexical level */ EnterGlobalLevel (); @@ -431,10 +435,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 (); @@ -492,9 +494,8 @@ void Compile (const char* FileName) } } } - } - DoneDeferredOps (); + } 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/preproc.c b/src/cc65/preproc.c index 016abf11e..7b33d4b0f 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -71,13 +71,13 @@ 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; + +/* Current PP if stack */ +static PPIfStack* PPStack; /* Buffer for macro expansion */ static StrBuf* MLine; @@ -1061,18 +1061,18 @@ 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); } } @@ -1337,17 +1337,17 @@ void Preprocess (void) 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) { + if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) { Skip = !Skip; } - IfStack[IfIndex] |= IFCOND_ELSE; + PPStack->Stack[PPStack->Index] |= IFCOND_ELSE; Skip = DoIf (Skip); /* #elif doesn't need a terminator */ - IfStack[IfIndex] &= ~IFCOND_NEEDTERM; + PPStack->Stack[PPStack->Index] &= ~IFCOND_NEEDTERM; } else { PPError ("Duplicate #else/#elif"); } @@ -1357,12 +1357,12 @@ void Preprocess (void) break; case PP_ELSE: - if (IfIndex >= 0) { - if ((IfStack[IfIndex] & IFCOND_ELSE) == 0) { - if ((IfStack[IfIndex] & IFCOND_SKIP) == 0) { + if (PPStack->Index >= 0) { + if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) { + if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) { Skip = !Skip; } - IfStack[IfIndex] |= IFCOND_ELSE; + PPStack->Stack[PPStack->Index] |= IFCOND_ELSE; /* Check for extra tokens */ CheckExtraTokens ("else"); @@ -1375,19 +1375,20 @@ 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; + Skip = (PPStack->Stack[PPStack->Index--] & IFCOND_SKIP) != 0; /* Check for extra tokens */ CheckExtraTokens ("endif"); @@ -1464,9 +1465,6 @@ void Preprocess (void) } if (NextLine () == 0) { - if (IfIndex >= 0) { - PPError ("'#endif' expected"); - } return; } SkipWhitespace (0); @@ -1480,3 +1478,34 @@ Done: (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } } + + + +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; +} + + + +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; + } +} diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h index 34f62c114..67b371252 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,15 @@ 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 */ + /* End of preproc.h */ diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 70203d027..98e9e1c06 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -188,10 +188,9 @@ static int SkipWhite (void) { while (1) { while (CurC == '\0') { - if (NextLine () == 0) { + if (PreprocessNextLine () == 0) { return 0; } - Preprocess (); } if (IsSpace (CurC)) { NextChar (); From 2c9c8ee19615fbae1463d9db3ccf0ce0972e76af Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:10:31 +0800 Subject: [PATCH 03/11] Fixed extra "Macro argument count mismatch" message when a macro argument list is unterminated. --- src/cc65/preproc.c | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 7b33d4b0f..6de50d0b5 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -446,10 +446,14 @@ static int MacName (char* Ident) static void ReadMacroArgs (MacroExp* E) -/* Identify the arguments to a macro call */ +/* 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; @@ -512,7 +516,7 @@ static void ReadMacroArgs (MacroExp* E) } else if (CurC == '\0') { /* End of input inside macro argument list */ PPError ("Unterminated argument list invoking macro '%s'", E->M->Name); - + MissingParen = 1; ClearLine (); break; } else { @@ -522,6 +526,21 @@ static void ReadMacroArgs (MacroExp* E) } } + /* Compare formal and actual argument count */ + if (CollCount (&E->ActualArgs) != (unsigned) E->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) E->M->ArgCount) { + ME_AppendActual (E, &Arg); + } + } + /* Deallocate string buf resources */ SB_Done (&Arg); } @@ -666,29 +685,12 @@ static void MacroCall (StrBuf* Target, Macro* M) { MacroExp E; - /* Eat the left paren */ - NextChar (); - /* Initialize our MacroExp structure */ InitMacroExp (&E, M); - /* Read the actual macro arguments */ + /* Read the actual macro arguments (with the enclosing parentheses) */ 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); From 80fc8cd11ef913f8e51f16dc7526ac1ac4188fe3 Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:10:36 +0800 Subject: [PATCH 04/11] Added preprocessor warning on missing terminating characters of character/string literals. --- src/cc65/preproc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 6de50d0b5..4af37a4b5 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -399,6 +399,8 @@ static void CopyQuotedString (StrBuf* Target) if (CurC != '\0') { SB_AppendChar (Target, CurC); NextChar (); + } else { + PPWarning ("Missing terminating %c character", Quote); } } From 2f357ba9b24bee49b09e8c2dc9ae9adb363ac34b Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:10:38 +0800 Subject: [PATCH 05/11] 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. --- src/cc65/compile.c | 6 + src/cc65/macrotab.c | 23 ++ src/cc65/macrotab.h | 6 + src/cc65/preproc.c | 498 +++++++++++++++++++++++++---------- src/cc65/preproc.h | 6 + test/{misc => val}/bug1357.c | 0 test/val/bug1643.c | 12 + test/val/bug1643.h | 13 + test/{misc => val}/bug760.c | 0 9 files changed, 420 insertions(+), 144 deletions(-) rename test/{misc => val}/bug1357.c (100%) create mode 100644 test/val/bug1643.c create mode 100644 test/val/bug1643.h rename test/{misc => val}/bug760.c (100%) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index f4fb16c37..4b3584147 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -425,6 +425,9 @@ void Compile (const char* FileName) /* Generate the code generator preamble */ g_preamble (); + /* Init preprocessor */ + InitPreprocess (); + /* Open the input file */ OpenMainFile (FileName); @@ -497,6 +500,9 @@ void Compile (const char* FileName) } + /* Done with preprocessor */ + DonePreprocess (); + if (Debug) { PrintMacroStats (stdout); } diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c index c04024dc8..d835b7708 100644 --- a/src/cc65/macrotab.c +++ b/src/cc65/macrotab.c @@ -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) /* Define a macro for a numeric constant */ { diff --git a/src/cc65/macrotab.h b/src/cc65/macrotab.h index c3ff20ceb..0f9bff01a 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 */ diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 4af37a4b5..c06545e77 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -67,9 +67,6 @@ -/* Set when the preprocessor calls expr() recursively */ -static unsigned char Preprocessing = 0; - /* Management data for #if */ #define IFCOND_NONE 0x00U #define IFCOND_SKIP 0x01U @@ -79,8 +76,15 @@ static unsigned char Preprocessing = 0; /* Current PP if stack */ static PPIfStack* PPStack; -/* Buffer for macro expansion */ -static StrBuf* MLine; +/* 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; +static int LeadingWhitespace; /* Structure used when expanding macros */ typedef struct MacroExp MacroExp; @@ -103,12 +107,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 (void); +/* 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. */ @@ -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) /* Stringize the given string: Add double quotes at start and end and preceed ** each occurance of " and \ by a backslash. @@ -341,12 +385,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 +407,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 +419,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 (); + } } @@ -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 */ { int MissingParen = 0; @@ -460,6 +538,30 @@ static void ReadMacroArgs (MacroExp* E) /* 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; + + 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 == '(') { /* Nested parenthesis */ @@ -510,11 +612,6 @@ 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); @@ -593,7 +690,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) { @@ -682,60 +779,53 @@ static void MacroArgSubst (MacroExp* E) -static void MacroCall (StrBuf* Target, Macro* M) -/* 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) +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 - /* Check if this is a function like macro */ - if (M->ArgCount >= 0) { + /* Initialize our MacroExp structure */ + InitMacroExp (&E, M); - 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); + /* Check if this is a function like macro */ + if (E.M->ArgCount >= 0) { + + /* Since the macro could be undefined or redefined during its argument + ** parsing, we make a clone of the current one and stick to it. + */ + if (MultiLine) { + E.M = CloneMacro (E.M); } - } else { + /* Read the actual macro arguments (with the enclosing parentheses) */ + ReadMacroArgs (&E, MultiLine); - MacroExp E; - InitMacroExp (&E, M); + /* Replace macro arguments handling the # and ## operators */ + 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 */ MacroArgSubst (&E); @@ -744,16 +834,23 @@ static void ExpandMacro (StrBuf* Target, Macro* M) ** substituted. */ M->Expanding = 1; - MacroReplacement (&E.Replacement, Target); + MacroReplacement (&E.Replacement, Target, 0); M->Expanding = 0; - /* Free memory allocated for the macro expansion structure */ - DoneMacroExp (&E); - } + #if 0 - printf ("Done with %s(%u)\n", M->Name, V--); + printf ("Done with %s(%u)\n", E.M->Name, V--); #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) -/* 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 */ @@ -956,7 +1058,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; @@ -980,9 +1082,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 { @@ -994,13 +1119,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; @@ -1015,22 +1140,54 @@ 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, ' '); + } + 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 { /* 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 (); + } } } @@ -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) /* Push a new if level onto the if stack */ { @@ -1108,10 +1244,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 */ @@ -1122,11 +1259,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 @@ -1142,8 +1281,8 @@ static int DoIf (int Skip) /* Call the expression parser */ ParsePPExpr (&Expr); - /* End preprocessing mode */ - Preprocessing = 0; + /* Restore input source */ + MLine = InitLine (MLine); /* Reset the old tokens */ CurTok = SavedCurTok; @@ -1182,14 +1321,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. @@ -1236,6 +1376,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) */ @@ -1249,19 +1392,30 @@ static void DoPragma (void) ** 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); - Pass1 (Line, MLine); + ProcessSingleLine (Line, MLine, 0, 0); /* Convert the directive into the operator */ - SB_CopyStr (Line, "_Pragma ("); - SB_Reset (MLine); - Stringize (MLine, Line); - SB_AppendChar (Line, ')'); + if (OLine == 0) { + SB_Clear (Line); + PragmaLine = Line; + } - /* Initialize reading from line */ - SB_Reset (Line); - InitLine (Line); + /* Add the source info to preprocessor output if needed */ + AddPreLine (PragmaLine); + + /* 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) -/* Preprocess a line */ +static int ParseDirectives (void) +/* Handle directives. Return howmany newlines are parsed. */ { + int NewLines = 0; int Skip; 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); @@ -1435,7 +1585,7 @@ void Preprocess (void) case PP_PRAGMA: if (!Skip) { DoPragma (); - goto Done; + --NewLines; } break; @@ -1469,14 +1619,48 @@ void Preprocess (void) } if (NextLine () == 0) { - return; + break; } + ++NewLines; 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)) { printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (), (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) /* Specify which PP #if stack to use */ { @@ -1498,6 +1702,9 @@ void PreprocessBegin (void) { /* Reset #if depth */ PPStack->Index = -1; + + /* Remember to update source file location in preprocess-only mode */ + FileChanged = 1; } @@ -1512,4 +1719,7 @@ void PreprocessEnd (void) } --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 67b371252..f543b05b5 100644 --- a/src/cc65/preproc.h +++ b/src/cc65/preproc.h @@ -74,6 +74,12 @@ void PreprocessBegin (void); 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/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 From f8d08b1e1a13bdbdd96e667ab5c5650b03c97a6f Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:40:19 +0800 Subject: [PATCH 06/11] More post-C99 predefined macros. --- src/cc65/compile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 4b3584147..78d0817e3 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -407,6 +407,14 @@ void Compile (const char* FileName) /* DefineNumericMacro ("__STDC__", 1); <- not now */ DefineNumericMacro ("__STDC_HOSTED__", 1); + /* 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 (); From 251e984ba88ca9afe62a2b22d789a453d2e6f2cf Mon Sep 17 00:00:00 2001 From: acqn Date: Fri, 5 Aug 2022 14:03:51 +0800 Subject: [PATCH 07/11] Fixed error recovery with preprocessing directives failures. --- src/cc65/ppexpr.c | 40 +++++++++++++++++++++++++++++++++------- src/cc65/ppexpr.h | 2 +- src/cc65/preproc.c | 2 +- src/cc65/scanner.c | 4 +++- src/cc65/scanner.h | 1 + 5 files changed, 39 insertions(+), 10 deletions(-) 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 c06545e77..4cbef33f3 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1279,7 +1279,7 @@ static int DoIf (int Skip) NextToken (); /* Call the expression parser */ - ParsePPExpr (&Expr); + ParsePPExprInLine (&Expr); /* Restore input source */ MLine = InitLine (MLine); diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index 98e9e1c06..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,7 +189,8 @@ static int SkipWhite (void) { while (1) { while (CurC == '\0') { - if (PreprocessNextLine () == 0) { + /* If reading next line fails or is forbidden, bail out */ + if (NextLineDisabled || PreprocessNextLine () == 0) { return 0; } } 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 */ From 0a051a4deebe70ec92d50ffa1553a09ae49f3512 Mon Sep 17 00:00:00 2001 From: acqn Date: Sat, 6 Aug 2022 16:56:28 +0800 Subject: [PATCH 08/11] Unsupported #pragma within argument lists of function-like macro invocation. --- src/cc65/preproc.c | 97 ++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 55 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 4cbef33f3..d33bef34c 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -84,7 +84,6 @@ 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 */ typedef struct MacroExp MacroExp; @@ -107,7 +106,7 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target); ** non-newline whitespace sequences. */ -static int ParseDirectives (void); +static int ParseDirectives (int InArgList); /* Handle directives. Return 1 if there are directives parsed, -1 if new lines ** are read, otherwise 0. */ @@ -544,19 +543,13 @@ static void ReadMacroArgs (MacroExp* E, int 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 = ParseDirectives (1) || Skipped; Skipped = SkipWhitespace (MultiLine) || Skipped; } - AppendIndent (OLine, LeadingWhitespace); - LeadingWhitespace = 0; PendingNewLines += Newlines; } if (Skipped && SB_NotEmpty (&Arg)) { @@ -1152,10 +1145,10 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine) if (CurC == '#') { if (OLine == 0) { OLine = Target; - ParseDirectives (); + ParseDirectives (0); OLine = 0; } else { - ParseDirectives (); + ParseDirectives (0); } } /* Add the source info to preprocessor output if needed */ @@ -1394,25 +1387,20 @@ static void DoPragma (void) { StrBuf* PragmaLine = OLine; - /* Macro-replace a single line */ - SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 0, 0); - - /* Convert the directive into the operator */ - if (OLine == 0) { - SB_Clear (Line); - PragmaLine = Line; - } + PRECONDITION (PragmaLine != 0); /* Add the source info to preprocessor output if needed */ AddPreLine (PragmaLine); + /* Macro-replace a single line */ + SB_Clear (MLine); + ProcessSingleLine (Line, MLine, 0, 0); + /* 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)); @@ -1454,19 +1442,17 @@ static void DoWarning (void) -static int ParseDirectives (void) -/* Handle directives. Return howmany newlines are parsed. */ +static int ParseDirectives (int InArgList) +/* Handle directives. Return 1 if any whitespace or newlines are parsed. */ { - int NewLines = 0; - int Skip; + int PPSkip = 0; ident Directive; - /* 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 == '#') { @@ -1477,7 +1463,7 @@ static int ParseDirectives (void) continue; } if (!IsSym (Directive)) { - if (!Skip) { + if (!PPSkip) { PPError ("Preprocessor directive expected"); } ClearLine (); @@ -1485,7 +1471,7 @@ static int ParseDirectives (void) switch (FindPPToken (Directive)) { case PP_DEFINE: - if (!Skip) { + if (!PPSkip) { DefineMacro (); } break; @@ -1495,10 +1481,10 @@ static int ParseDirectives (void) if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) { /* Handle as #else/#if combination */ if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) { - Skip = !Skip; + PPSkip = !PPSkip; } PPStack->Stack[PPStack->Index] |= IFCOND_ELSE; - Skip = DoIf (Skip); + PPSkip = DoIf (PPSkip); /* #elif doesn't need a terminator */ PPStack->Stack[PPStack->Index] &= ~IFCOND_NEEDTERM; @@ -1514,7 +1500,7 @@ static int ParseDirectives (void) if (PPStack->Index >= 0) { if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) { if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) { - Skip = !Skip; + PPSkip = !PPSkip; } PPStack->Stack[PPStack->Index] |= IFCOND_ELSE; @@ -1542,7 +1528,7 @@ static int ParseDirectives (void) CHECK (PPStack->Index >= 0); /* Remove the clause that needs a terminator */ - Skip = (PPStack->Stack[PPStack->Index--] & IFCOND_SKIP) != 0; + PPSkip = (PPStack->Stack[PPStack->Index--] & IFCOND_SKIP) != 0; /* Check for extra tokens */ CheckExtraTokens ("endif"); @@ -1552,45 +1538,48 @@ static int ParseDirectives (void) 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 (); - --NewLines; + 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; @@ -1598,11 +1587,11 @@ static int ParseDirectives (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 (); @@ -1610,7 +1599,7 @@ static int ParseDirectives (void) break; default: - if (!Skip) { + if (!PPSkip) { PPError ("Preprocessor directive expected"); } ClearLine (); @@ -1621,12 +1610,11 @@ static int ParseDirectives (void) if (NextLine () == 0) { break; } - ++NewLines; - SkipWhitespace (0); + ++PendingNewLines; + Whitespace = SkipWhitespace (0) || Whitespace; } - PendingNewLines += NewLines; - return NewLines; + return Whitespace != 0; } @@ -1641,15 +1629,14 @@ void Preprocess (void) /* Parse any directives */ OLine = PLine; - ParseDirectives (); + ParseDirectives (0); 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); + AppendIndent (PLine, SB_GetIndex (Line)); /* Expand macros if any */ MacroReplacement (Line, PLine, 1); From 7971eec3ccf05719fb497ee026c0ecc610819865 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 7 Aug 2022 12:45:48 +0800 Subject: [PATCH 09/11] Fixed parentheses handling when a function-like macro name itself is used as an macro argument. --- src/cc65/preproc.c | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index d33bef34c..3fd994e80 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1142,17 +1142,27 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine) if (Whitespace > 0) { SB_AppendChar (Target, ' '); } - if (CurC == '#') { - if (OLine == 0) { - OLine = Target; - ParseDirectives (0); - OLine = 0; - } else { - ParseDirectives (0); + + /* 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); } - /* Add the source info to preprocessor output if needed */ - AddPreLine (Target); } else { /* Function-like macro */ if (OLine == 0) { From 47d5e74a6e3cd2b2483d8b640e0f97a3a7faa214 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 18 Aug 2022 22:51:23 +0800 Subject: [PATCH 10/11] Modified way to keep undefined macro handling more consistent. --- src/cc65/macrotab.c | 36 +++++++++++++--- src/cc65/macrotab.h | 12 ++++-- src/cc65/preproc.c | 102 ++++++++++++++------------------------------ 3 files changed, 70 insertions(+), 80 deletions(-) diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c index d835b7708..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; + /*****************************************************************************/ @@ -173,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 */ @@ -196,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 */ @@ -214,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 0f9bff01a..6a09d7281 100644 --- a/src/cc65/macrotab.h +++ b/src/cc65/macrotab.h @@ -97,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/preproc.c b/src/cc65/preproc.c index 3fd994e80..c545bf889 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -90,7 +90,6 @@ typedef struct MacroExp MacroExp; struct MacroExp { Collection ActualArgs; /* Actual arguments */ StrBuf Replacement; /* Replacement with arguments substituted */ - Macro* M; /* The macro we're handling */ }; @@ -193,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; } @@ -244,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); } @@ -524,7 +522,7 @@ static int MacName (char* Ident) -static void ReadMacroArgs (MacroExp* E, int MultiLine) +static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) /* Identify the arguments to a macro call as-is */ { int MissingParen = 0; @@ -576,7 +574,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) } 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. */ @@ -591,7 +589,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) /* 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); } @@ -607,7 +605,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) } } 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; @@ -619,7 +617,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) } /* Compare formal and actual argument count */ - if (CollCount (&E->ActualArgs) != (unsigned) E->M->ArgCount) { + if (CollCount (&E->ActualArgs) != (unsigned) M->ArgCount) { if (!MissingParen) { /* Argument count mismatch */ @@ -628,7 +626,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) /* Be sure to make enough empty arguments available */ SB_Clear (&Arg); - while (CollCount (&E->ActualArgs) < (unsigned) E->M->ArgCount) { + while (CollCount (&E->ActualArgs) < (unsigned) M->ArgCount) { ME_AppendActual (E, &Arg); } } @@ -639,7 +637,7 @@ static void ReadMacroArgs (MacroExp* E, int MultiLine) -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; @@ -650,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') { @@ -661,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); @@ -720,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)); @@ -733,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 @@ -741,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 */ @@ -767,7 +765,7 @@ static void MacroArgSubst (MacroExp* E) /* Switch back the input */ InitLine (OldSource); - SB_SetIndex (&E->M->Replacement, OldIndex); + SB_SetIndex (&M->Replacement, OldIndex); } @@ -783,65 +781,28 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine) #endif /* Initialize our MacroExp structure */ - InitMacroExp (&E, M); + InitMacroExp (&E); /* Check if this is a function like macro */ - if (E.M->ArgCount >= 0) { - - /* Since the macro could be undefined or redefined during its argument - ** parsing, we make a clone of the current one and stick to it. - */ - if (MultiLine) { - E.M = CloneMacro (E.M); - } + if (M->ArgCount >= 0) { /* Read the actual macro arguments (with the enclosing parentheses) */ - ReadMacroArgs (&E, MultiLine); - - /* Replace macro arguments handling the # and ## operators */ - 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 */ - MacroArgSubst (&E); - - /* Do macro replacement on the macro that already has the parameters - ** substituted. - */ - M->Expanding = 1; - MacroReplacement (&E.Replacement, Target, 0); - M->Expanding = 0; + 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", E.M->Name, V--); #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); } @@ -1662,6 +1623,9 @@ void Preprocess (void) printf ("%s:%u: %.*s\n", GetCurrentFile (), GetCurrentLine (), (int) SB_GetLen (Line), SB_GetConstBuf (Line)); } + + /* Free all undefined macros */ + FreeUndefinedMacros (); } From b93f9fbba43693e549dd2c5935a4f7622e5979be Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 18 Aug 2022 22:51:23 +0800 Subject: [PATCH 11/11] Updated documents about the predefined macros. --- doc/cc65.sgml | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) 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).