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

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.
This commit is contained in:
acqn 2022-07-26 21:10:26 +08:00
parent 7381a2c420
commit 60c1290468
6 changed files with 193 additions and 68 deletions

View File

@ -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);

View File

@ -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)";
}
}

View File

@ -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 */

View File

@ -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;
}
}

View File

@ -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 */

View File

@ -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 ();