From 60c12904686cda5ad4552514d72584545168527a Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 26 Jul 2022 21:10:26 +0800 Subject: [PATCH] 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 ();