mirror of
https://github.com/cc65/cc65.git
synced 2025-01-10 19:29:45 +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:
parent
7381a2c420
commit
60c1290468
@ -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);
|
||||
|
115
src/cc65/input.c
115
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)";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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 ();
|
||||
|
Loading…
x
Reference in New Issue
Block a user