X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=src%2Fcc65%2Finput.c;h=0f254f4921bb6034ad7ec79a62425aae5c46fae6;hb=aef8789873bd008d42aa50330ca98488fad91b31;hp=4bd910e61a84203574d91669801862ed3d390262;hpb=c31008c78a3d299f14f6c59e99e235a68a20b62b;p=cc65 diff --git a/src/cc65/input.c b/src/cc65/input.c index 4bd910e61..0f254f492 100644 --- a/src/cc65/input.c +++ b/src/cc65/input.c @@ -36,20 +36,27 @@ #include #include #include +#include +#include -#include "../common/xmalloc.h" +/* common */ +#include "check.h" +#include "coll.h" +#include "print.h" +#include "xmalloc.h" +/* cc65 */ #include "asmcode.h" -#include "check.h" +#include "codegen.h" #include "error.h" -#include "global.h" #include "incpath.h" +#include "lineinfo.h" #include "input.h" /*****************************************************************************/ -/* Data */ +/* Data */ /*****************************************************************************/ @@ -57,57 +64,55 @@ /* Input line stuff */ static char LineBuf [LINESIZE]; char* line = LineBuf; -char* lptr = LineBuf; +const char* lptr = LineBuf; + +/* Current and next input character */ +char CurC = '\0'; +char NextC = '\0'; /* Maximum count of nested includes */ #define MAX_INC_NESTING 16 -/* Struct that describes an input file */ -typedef struct IFile IFile; -struct IFile { - IFile* Next; /* Next file in single linked list */ - IFile* Active; /* Next file in list of active includes */ - unsigned Index; /* File index */ - unsigned Line; /* Line number for this file */ - FILE* F; /* Input file stream */ - char Name[1]; /* Name of file (dynamically allocated) */ +/* Struct that describes an active input file */ +typedef struct AFile AFile; +struct AFile { + unsigned Line; /* Line number for this file */ + FILE* F; /* Input file stream */ + IFile* Input; /* Points to corresponding IFile */ }; -/* List of input files */ -static unsigned IFileTotal = 0; /* Total number of files */ -static IFile* IFileList = 0; /* Single linked list of all files */ -static unsigned IFileCount = 0; /* Number of active input files */ -static IFile* Input = 0; /* Single linked list of active files */ +/* List of all input files */ +static Collection IFiles = STATIC_COLLECTION_INITIALIZER; + +/* List of all active files */ +static Collection AFiles = STATIC_COLLECTION_INITIALIZER; /*****************************************************************************/ -/* struct IFile */ +/* struct IFile */ /*****************************************************************************/ -static IFile* NewIFile (const char* Name, FILE* F) +static IFile* NewIFile (const char* Name) /* Create and return a new IFile */ { /* Get the length of the name */ unsigned Len = strlen (Name); /* Allocate a IFile structure */ - IFile* IF = xmalloc (sizeof (IFile) + Len); + IFile* IF = (IFile*) xmalloc (sizeof (IFile) + Len); /* Initialize the fields */ - IF->Index = ++IFileTotal; - IF->Line = 0; - IF->F = F; + IF->Index = CollCount (&IFiles) + 1; + IF->Usage = 0; + IF->Size = 0; + IF->MTime = 0; memcpy (IF->Name, Name, Len+1); - /* Insert the structure into both lists */ - IF->Next = IFileList; - IFileList = IF; - IF->Active = Input; - Input = IF; - ++IFileCount; + /* Insert the new structure into the IFile collection */ + CollAppend (&IFiles, IF); /* Return the new struct */ return IF; @@ -115,24 +120,103 @@ static IFile* NewIFile (const char* Name, FILE* F) +/*****************************************************************************/ +/* struct AFile */ +/*****************************************************************************/ + + + +static AFile* NewAFile (IFile* IF, FILE* F) +/* Create and return a new AFile */ +{ + /* Allocate a AFile structure */ + AFile* AF = (AFile*) xmalloc (sizeof (AFile)); + + /* Initialize the fields */ + AF->Line = 0; + AF->F = F; + AF->Input = IF; + + /* Increment the usage counter of the corresponding IFile. If this + * is the first use, set the file data and output debug info if + * requested. + */ + if (IF->Usage++ == 0) { + + /* Get file size and modification time */ + struct stat Buf; + if (fstat (fileno (F), &Buf) != 0) { + /* Error */ + Fatal ("Cannot stat `%s': %s", IF->Name, strerror (errno)); + } + IF->Size = (unsigned long) Buf.st_size; + IF->MTime = (unsigned long) Buf.st_mtime; + + /* Set the debug data */ + g_fileinfo (IF->Name, IF->Size, IF->MTime); + } + + /* Insert the new structure into the AFile collection */ + CollAppend (&AFiles, AF); + + /* Return the new struct */ + return AF; +} + + + +static void FreeAFile (AFile* AF) +/* Free an AFile structure */ +{ + xfree (AF); +} + + + /*****************************************************************************/ /* Code */ /*****************************************************************************/ +static IFile* FindFile (const char* Name) +/* Find the file with the given name in the list of all files. Since the list + * is not large (usually less than 10), I don't care about using hashes or + * similar things and do a linear search. + */ +{ + unsigned I; + for (I = 0; I < CollCount (&IFiles); ++I) { + /* Get the file struct */ + IFile* IF = (IFile*) CollAt (&IFiles, I); + /* Check the name */ + if (strcmp (Name, IF->Name) == 0) { + /* Found, return the struct */ + return IF; + } + } + + /* Not found */ + return 0; +} + + + void OpenMainFile (const char* Name) /* Open the main file. Will call Fatal() in case of failures. */ { + /* Setup a new IFile structure for the main file */ + IFile* IF = NewIFile (Name); + /* Open the file for reading */ FILE* F = fopen (Name, "r"); if (F == 0) { - /* Cannot open */ - Fatal (FAT_CANNOT_OPEN_INPUT, strerror (errno)); + /* Cannot open */ + Fatal ("Cannot open input file `%s': %s", Name, strerror (errno)); } - /* Setup a new IFile structure */ - NewIFile (Name, F); + /* Allocate a new AFile structure for the file */ + (void) NewAFile (IF, F); } @@ -140,36 +224,47 @@ void OpenMainFile (const char* Name) void OpenIncludeFile (const char* Name, unsigned DirSpec) /* Open an include file and insert it into the tables. */ { - char* N; - FILE* F; + char* N; + FILE* F; + IFile* IF; /* Check for the maximum include nesting */ - if (IFileCount > MAX_INC_NESTING) { - PPError (ERR_INCLUDE_NESTING); + if (CollCount (&AFiles) > MAX_INC_NESTING) { + PPError ("Include nesting too deep"); return; } /* Search for the file */ N = FindInclude (Name, DirSpec); if (N == 0) { - PPError (ERR_INCLUDE_NOT_FOUND, Name); + PPError ("Include file `%s' not found", Name); return; } + /* Search the list of all input files for this file. If we don't find + * it, create a new IFile object. + */ + IF = FindFile (N); + if (IF == 0) { + IF = NewIFile (N); + } + + /* We don't need N any longer, since we may now use IF->Name */ + xfree (N); + /* Open the file */ - F = fopen (N, "r"); + F = fopen (IF->Name, "r"); if (F == 0) { /* Error opening the file */ - PPError (ERR_INCLUDE_OPEN_FAILURE, N, strerror (errno)); - xfree (N); + PPError ("Cannot open include file `%s': %s", IF->Name, strerror (errno)); return; } - /* Allocate a new IFile structure */ - NewIFile (N, F); + /* Debugging output */ + Print (stdout, 1, "Opened include file `%s'\n", IF->Name); - /* We don't need the full name any longer */ - xfree (N); + /* Allocate a new AFile structure */ + (void) NewAFile (IF, F); } @@ -179,14 +274,71 @@ static void CloseIncludeFile (void) * NULL if this was the main file. */ { + AFile* Input; + + /* Get the number of active input files */ + unsigned AFileCount = CollCount (&AFiles); + /* Must have an input file when called */ - PRECONDITION (Input != 0); + PRECONDITION (AFileCount > 0); + + /* Get the current active input file */ + Input = (AFile*) CollLast (&AFiles); /* Close the current input file (we're just reading so no error check) */ fclose (Input->F); - /* Make this file inactive and the last one active again */ - Input = Input->Active; + /* Delete the last active file from the active file collection */ + CollDelete (&AFiles, AFileCount-1); + + /* Delete the active file structure */ + FreeAFile (Input); +} + + + +void ClearLine (void) +/* Clear the current input line */ +{ + line[0] = '\0'; + lptr = line; + CurC = '\0'; + NextC = '\0'; +} + + + +void InitLine (const char* Buf) +/* Initialize lptr from Buf and read CurC and NextC from the new input line */ +{ + lptr = Buf; + CurC = lptr[0]; + if (CurC != '\0') { + NextC = lptr[1]; + } else { + NextC = '\0'; + } +} + + + +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 + * are read by this function. + */ +{ + if (lptr[0] != '\0') { + ++lptr; + CurC = lptr[0]; + if (CurC != '\0') { + NextC = lptr[1]; + } else { + NextC = '\0'; + } + } else { + CurC = NextC = '\0'; + } } @@ -194,6 +346,7 @@ static void CloseIncludeFile (void) int NextLine (void) /* Get a line from the current input. Returns 0 on end of file. */ { + AFile* Input; unsigned Len; unsigned Part; unsigned Start; @@ -202,10 +355,11 @@ int NextLine (void) /* Setup the line */ ClearLine (); - /* If there is no file open, bail out */ - if (Input == 0) { + /* If there is no file open, bail out, otherwise get the current input file */ + if (CollCount (&AFiles) == 0) { return 0; } + Input = (AFile*) CollLast (&AFiles); /* Read lines until we get one with real contents */ Len = 0; @@ -220,31 +374,31 @@ int NextLine (void) /* Leave the current file */ CloseIncludeFile (); - /* If this was the last file, bail out */ - if (Input == 0) { - return 0; + /* If there is no file open, bail out, otherwise get the + * current input file + */ + if (CollCount (&AFiles) == 0) { + return 0; } + Input = (AFile*) CollLast (&AFiles); + } /* We got a new line */ ++Input->Line; - /* Remove the trailing newline if we have one */ + /* Remove the trailing cr/lf if we have one. We will ignore both, cr + * and lf on all systems since this enables us to compile DOS/Windows + * stuff also on unix systems (where fgets does not remove the cr). + */ Part = strlen (line + Len); Start = Len; Len += Part; - while (Len > 0 && line [Len-1] == '\n') { + while (Len > 0 && (line[Len-1] == '\n' || line[Len-1] == '\r')) { --Len; } line [Len] = '\0'; - /* Output the source line in the generated assembler file - * if requested. - */ - if (AddSource && line[Start] != '\0') { - AddCodeLine ("; %s", line+Start); - } - /* Check if we have a line continuation character at the end. If not, * we're done. */ @@ -255,17 +409,14 @@ int NextLine (void) } } - /* Got a line */ - return 1; -} - + /* Got a line. Initialize the current and next characters. */ + InitLine (line); + /* Create line information for this line */ + UpdateLineInfo (Input->Input, Input->Line, line); -void ClearLine (void) -/* Clear the current input line */ -{ - line [0] = '\0'; - lptr = line; + /* Done */ + return 1; } @@ -273,10 +424,19 @@ void ClearLine (void) const char* GetCurrentFile (void) /* Return the name of the current input file */ { - if (Input == 0) { - return "(outside file scope)"; + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); + return AF->Input->Name; } else { - return Input->Name; + /* 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)"; + } } } @@ -285,43 +445,41 @@ const char* GetCurrentFile (void) unsigned GetCurrentLine (void) /* Return the line number in the current input file */ { - return Input? Input->Line : 0; -} - - - -int nch (void) -/* Get the next char in input stream (the one behind the current one) */ -{ - if (*lptr == '\0') { - return 0; + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); + return AF->Line; } else { - return lptr[1] & 0xFF; + /* No open file */ + return 0; } } -int cgch (void) -/* Get the current character in the input stream and advance line - * pointer (unless already at end of line). - */ +void WriteDependencies (FILE* F, const char* OutputFile) +/* Write a makefile dependency list to the given file */ { - if (*lptr == '\0') { - return (0); - } else { - return (*lptr++ & 0xFF); + unsigned I; + + /* Get the number of input files */ + unsigned IFileCount = CollCount (&IFiles); + + /* Print the output file followed by a tab char */ + fprintf (F, "%s:\t", OutputFile); + + /* Loop over all files */ + for (I = 0; I < IFileCount; ++I) { + /* Get the next input file */ + const IFile* IF = (const IFile*) CollAt (&IFiles, I); + /* If this is not the first file, add a space */ + const char* Format = (I == 0)? "%s" : " %s"; + /* Print the dependency */ + fprintf (F, Format, IF->Name); } -} - - -int gch (void) -/* Get the current character in the input stream and advance line - * pointer (no end of line check is performed). - */ -{ - return (*lptr++ & 0xFF); + /* End the line */ + fprintf (F, "\n\n"); }