From bb9c98f4c9ce005b5becc7d47f5b38ccc9500e91 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 23:19:05 +0800 Subject: [PATCH] Added support for the #line directive. --- src/cc65/input.c | 40 ++++++++++++++++++-- src/cc65/input.h | 6 +++ src/cc65/preproc.c | 93 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 5 deletions(-) diff --git a/src/cc65/input.c b/src/cc65/input.c index 18441f5c8..c6037091f 100644 --- a/src/cc65/input.c +++ b/src/cc65/input.c @@ -92,6 +92,7 @@ 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 */ + char* PName; /* Presumed name of the file */ PPIfStack IfStack; /* PP #if stack */ int MissingNL; /* Last input line was missing a newline */ }; @@ -159,6 +160,7 @@ static AFile* NewAFile (IFile* IF, FILE* F) AF->Line = 0; AF->F = F; AF->Input = IF; + AF->PName = 0; AF->IfStack.Index = -1; AF->MissingNL = 0; @@ -209,6 +211,9 @@ static AFile* NewAFile (IFile* IF, FILE* F) static void FreeAFile (AFile* AF) /* Free an AFile structure */ { + if (AF->PName != 0) { + xfree (AF->PName); + } xfree (AF); } @@ -599,8 +604,8 @@ const char* GetCurrentFile (void) { unsigned AFileCount = CollCount (&AFiles); if (AFileCount > 0) { - const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); - return AF->Input->Name; + const AFile* AF = CollLast (&AFiles); + return AF->PName == 0 ? AF->Input->Name : AF->PName; } else { /* No open file */ return "(outside file scope)"; @@ -614,7 +619,7 @@ unsigned GetCurrentLine (void) { unsigned AFileCount = CollCount (&AFiles); if (AFileCount > 0) { - const AFile* AF = (const AFile*) CollAt (&AFiles, AFileCount-1); + const AFile* AF = CollLast (&AFiles); return AF->Line; } else { /* No open file */ @@ -624,6 +629,35 @@ unsigned GetCurrentLine (void) +void SetCurrentLine (unsigned LineNum) +/* Set the line number in the current input file */ +{ + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + AFile* AF = CollLast (&AFiles); + AF->Line = LineNum; + } +} + + + +void SetCurrentFilename (const char* Name) +/* Set the presumed name of the current input file */ +{ + unsigned AFileCount = CollCount (&AFiles); + if (AFileCount > 0) { + size_t Len = strlen (Name); + AFile* AF = CollLast (&AFiles); + if (AF->PName != 0) { + xfree (AF->PName); + } + AF->PName = xmalloc (Len + 1); + memcpy (AF->PName, Name, Len + 1); + } +} + + + static void WriteEscaped (FILE* F, const char* Name) /* Write a file name to a dependency file escaping spaces */ { diff --git a/src/cc65/input.h b/src/cc65/input.h index 779217b9b..cf529e169 100644 --- a/src/cc65/input.h +++ b/src/cc65/input.h @@ -122,6 +122,12 @@ const char* GetCurrentFile (void); unsigned GetCurrentLine (void); /* Return the line number in the current input file */ +void SetCurrentLine (unsigned LineNum); +/* Set the line number in the current input file */ + +void SetCurrentFilename (const char* Name); +/* Set the presumed name of the current input file */ + void CreateDependencies (void); /* Create dependency files requested by the user */ diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 6dcbeea70..3b73ee493 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -57,6 +57,7 @@ #include "ppexpr.h" #include "preproc.h" #include "scanner.h" +#include "scanstrbuf.h" #include "standard.h" @@ -1294,6 +1295,95 @@ Done: +static unsigned GetLineDirectiveNum (void) +/* Get a decimal digit-sequence from the input. Return 0 on errors. */ +{ + unsigned long Num = 0; + StrBuf Buf = AUTO_STRBUF_INITIALIZER; + + /* The only non-decimal-numeric character allowed in the digit-sequence is + ** the digit separator '\'' as of C23, but we haven't supported it yet. + */ + SkipWhitespace (0); + while (IsDigit (CurC)) + { + SB_AppendChar (&Buf, CurC); + NextChar (); + } + + /* Ensure the buffer is terminated with a '\0' */ + SB_Terminate (&Buf); + if (SkipWhitespace (0) != 0 || CurC == '\0') { + const char* Str = SB_GetConstBuf (&Buf); + if (Str[0] == '\0') { + PPWarning ("#line directive interprets number as decimal, not octal"); + } else { + Num = strtoul (Str, 0, 10); + if (Num > 2147483647) { + PPError ("#line directive requires an integer argument not greater than 2147483647"); + ClearLine (); + Num = 0; + } else if (Num == 0) { + PPError ("#line directive requires a positive integer argument"); + ClearLine (); + } + } + } else { + PPError ("#line directive requires a simple decimal digit sequence"); + ClearLine (); + } + + /* Done with the buffer */ + SB_Done (&Buf); + + return (unsigned)Num; +} + + + +static void DoLine (void) +/* Process #line directive */ +{ + unsigned LineNum; + + /* Macro-replace a single line with support for the "defined" operator */ + SB_Clear (MLine); + PreprocessDirective (Line, MLine, MSM_NONE); + + /* Read from the processed line */ + SB_Reset (MLine); + MLine = InitLine (MLine); + + /* Parse and check the specified line number */ + LineNum = GetLineDirectiveNum (); + if (LineNum != 0) { + /* Parse and check the optional filename argument */ + if (SB_GetIndex (Line) < SB_GetLen (Line)) { + StrBuf Filename = AUTO_STRBUF_INITIALIZER; + if (SB_GetString (Line, &Filename)) { + SB_Terminate (&Filename); + SetCurrentFilename (SB_GetConstBuf (&Filename)); + } else { + PPError ("Invalid filename for #line directive"); + LineNum = 0; + } + SB_Done (&Filename); + } + + /* #line actually sets the line number of the next line */ + if (LineNum > 0) { + SetCurrentLine (LineNum - 1); + /* Check for extra tokens at the end */ + CheckExtraTokens ("line"); + } + } + + /* Restore input source */ + MLine = InitLine (MLine); +} + + + static void DoPragma (void) /* Handle a #pragma line by converting the #pragma preprocessor directive into ** the _Pragma() compiler operator. @@ -1476,9 +1566,8 @@ static int ParseDirectives (unsigned ModeFlags) break; case PPD_LINE: - /* Should do something in C99 at least, but we ignore it */ if (!PPSkip) { - ClearLine (); + DoLine (); } break;