From 942ee47d05479ab8077ed9397ade66ff1037df7c Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:58:52 +0800 Subject: [PATCH 1/6] Changed supposed usage of the original line input stack. It is now used for reusing input lines. --- src/cc65/input.c | 94 +++++++++++++++++++++++++++--------------------- src/cc65/input.h | 3 ++ 2 files changed, 57 insertions(+), 40 deletions(-) diff --git a/src/cc65/input.c b/src/cc65/input.c index 5754b1054..8c8007504 100644 --- a/src/cc65/input.c +++ b/src/cc65/input.c @@ -67,6 +67,9 @@ /* The current input line */ StrBuf* Line; +/* The input line to reuse as the next line */ +static StrBuf* CurReusedLine; + /* Current and next input character */ char CurC = '\0'; char NextC = '\0'; @@ -403,24 +406,6 @@ static void GetInputChar (void) /* NextC is '\0' by default */ NextC = '\0'; - /* Drop all pushed fragments that don't have data left */ - if (CurrentInputStack != 0) { - while (SB_GetIndex (Line) >= SB_GetLen (Line)) { - /* Cannot read more from this line, check next line on stack if any */ - if (CollCount (CurrentInputStack) == 0) { - /* This is THE line */ - break; - } - FreeStrBuf (Line); - Line = CollPop (CurrentInputStack); - } - - /* NextC comes from next fragment */ - if (CollCount (CurrentInputStack) > 0) { - NextC = ' '; - } - } - /* Get CurC from the line */ CurC = SB_LookAt (Line, SB_GetIndex (Line)); } @@ -461,13 +446,17 @@ void PushLine (StrBuf* L) /* Save the current input line and use a new one */ { PRECONDITION (CurrentInputStack != 0); - if (SB_GetIndex (L) < SB_GetLen (L)) { - CollAppend (CurrentInputStack, Line); - Line = L; - GetInputChar (); - } else { - FreeStrBuf (L); - } + CollAppend (CurrentInputStack, Line); + Line = L; + GetInputChar (); +} + + + +void ReuseInputLine (void) +/* Save and reuse the current line as the next line */ +{ + CurReusedLine = Line; } @@ -475,16 +464,6 @@ void PushLine (StrBuf* L) void ClearLine (void) /* Clear the current input line */ { - if (CurrentInputStack != 0) { - unsigned I; - - /* Remove all pushed fragments from the input stack */ - for (I = 0; I < CollCount (CurrentInputStack); ++I) { - FreeStrBuf (Line); - Line = CollPop (CurrentInputStack); - } - } - /* Clear the contents of Line */ SB_Clear (Line); CurC = '\0'; @@ -515,12 +494,47 @@ int NextLine (void) int C; AFile* Input; - /* Clear the current line */ - ClearLine (); - SB_Clear (Line); + /* Overwrite the next input line with the pushed line if there is one */ + if (CurReusedLine != 0) { + /* Use data move to resolve the issue that Line may be impersistent */ + if (Line != CurReusedLine) { + SB_Move (Line, CurReusedLine); + } + /* Continue with this Line */ + InitLine (Line); + CurReusedLine = 0; - /* Must have an input file when called */ - if (CollCount(&AFiles) == 0) { + return 1; + } + + /* If there are pushed input lines, read from them */ + if (CurrentInputStack != 0 && CollCount (CurrentInputStack) > 0) { + /* Drop all pushed fragments that have no data left until one can be + ** used as input. + */ + do { + /* Use data move to resolve the issue that Line may be impersistent */ + if (Line != CollLast (CurrentInputStack)) { + SB_Move (Line, CollPop (CurrentInputStack)); + } else { + CollPop (CurrentInputStack); + } + } while (CollCount (CurrentInputStack) > 0 && + SB_GetIndex (Line) >= SB_GetLen (Line)); + + if (SB_GetIndex (Line) < SB_GetLen (Line)) { + InitLine (Line); + + /* Successive */ + return 1; + } + } + + /* Otherwise, clear the current line */ + ClearLine (); + + /* Must have an input file when going on */ + if (CollCount (&AFiles) == 0) { return 0; } diff --git a/src/cc65/input.h b/src/cc65/input.h index f9565229b..cd73c80b6 100644 --- a/src/cc65/input.h +++ b/src/cc65/input.h @@ -105,6 +105,9 @@ Collection* UseInputStack (Collection* InputStack); void PushLine (StrBuf* L); /* Save the current input line and use a new one */ +void ReuseInputLine (void); +/* Save and reuse the current line as the next line */ + void ClearLine (void); /* Clear the current input line */ From 3d1e322519137968c5c1e6bc5881fc7215dfffbd Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:58:52 +0800 Subject: [PATCH 2/6] Fixed keeping spacing in certain rare cases. --- src/cc65/preproc.c | 114 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 91 insertions(+), 23 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 99a8af116..4ae41252b 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -2116,7 +2116,6 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi /* Check if this is a function-like macro */ if (M->ParamCount >= 0) { - int OldPendingNewLines = PendingNewLines; int HaveSpace = SkipWhitespace (MultiLine) > 0; /* A function-like macro name without an immediately @@ -2139,32 +2138,50 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi ME_SetTokLens (E, strlen (M->Name)); } + /* Since we have already got on hold of the next + ** line, we have to reuse it as the next line + ** instead of reading a new line from the source. + */ + if (PendingNewLines > 0 && MultiLine) { + unsigned I = SB_GetIndex (Line); + + /* There is no way a function-like macro call + ** detection could span multiple lines within + ** the range of another just expanded macro. + */ + CHECK (CollCount (&CurRescanStack->Lines) == 1); + + /* Revert one newline */ + --PendingNewLines; + + /* Align indention */ + while (I > 0) { + --I; + if (SB_GetBuf (Line)[I] == '\n') { + ++I; + break; + } + SB_GetBuf (Line)[I] = ' '; + } + + /* Set start index */ + SB_SetIndex (Line, I); + + /* Add newlines */ + AddPreLine (Target); + + /* Reuse this line as the next line */ + ReuseInputLine (); + + /* Quit this loop */ + break; + } + /* Append back the whitespace */ if (HaveSpace) { SB_AppendChar (Target, ' '); } - /* Since we have already got on hold of the next - ** line, we have to go on preprocessing them. - */ - if (MultiLine) { - if (OldPendingNewLines < PendingNewLines && CurC == '#') { - /* If we were going to support #pragma in - ** macro argument list, it would be output - ** to OLine. - */ - if (OLine == 0) { - OLine = Target; - ParseDirectives (ModeFlags); - OLine = 0; - } else { - ParseDirectives (ModeFlags); - } - } - /* Add the source info to preprocessor output if needed */ - AddPreLine (Target); - } - /* Loop */ goto Loop; } @@ -2200,6 +2217,27 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi /* Switch the buffers */ TmpTarget = NewStrBuf (); + } else if (PendingNewLines > 0 && MultiLine) { + /* Cancel remaining check for pp-tokens separation + ** if there is since ther have been newlines that + ** can always separate them. + */ + if (CurRescanStack->PrevTok != 0) { + FreeStrBuf (CurRescanStack->PrevTok); + CurRescanStack->PrevTok = 0; + } + + /* Squeeze whitespace */ + SkipWhitespace (0); + + /* Add indention to preprocessor output if needed */ + if (CurC != '\0' && CollCount (&CurRescanStack->Lines) == 1) { + /* Add newlines */ + AddPreLine (Target); + + /* Align indention */ + AppendIndent (Target, SB_GetIndex (Line)); + } } /* Since we are rescanning, we needn't add the @@ -2239,7 +2277,24 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi } else if (IsQuotedString ()) { CopyQuotedString (Target); } else { - Skipped = SkipWhitespace (0); + /* We want to squeeze whitespace until the end of the current + ** input line, so we have to deal with such cases specially. + */ + if (CollCount (&CurRescanStack->Lines) > 1) { + RescanInputStack* RIS = CurRescanStack; + + /* Temporarily disable input popping */ + CurRescanStack = 0; + Skipped = SkipWhitespace (0); + CurRescanStack = RIS; + + if (CurC == '\0') { + /* Now we are at the end of the input line */ + goto Loop; + } + } else { + Skipped = SkipWhitespace (0); + } /* Punctuators must be checked after whitespace since comments ** introducers may be misinterpreted as division operators. @@ -2282,6 +2337,19 @@ Loop: if (CurC == '\0' && CollCount (&CurRescanStack->Lines) > 1) { /* Check for rescan sequence end and pp-token pasting */ Skipped = SkipWhitespace (0) || Skipped; + + /* Add indention to preprocessor output if needed */ + if (CurC != '\0' && + PendingNewLines > 0 && + (ModeFlags & MSM_MULTILINE) != 0 && + CollCount (&CurRescanStack->Lines) == 1) { + /* Add newlines */ + AddPreLine (Target); + + /* Align indention */ + AppendIndent (Target, SB_GetIndex (Line)); + Skipped = 0; + } } /* Append a space if there hasn't been one */ From 770e529b2033ebe5e0fe26f8d2f41d674080f928 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:58:52 +0800 Subject: [PATCH 3/6] Fixed newline counting inside old C style comments. --- src/cc65/preproc.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 4ae41252b..87d6a7878 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -878,7 +878,7 @@ static void Stringize (StrBuf* Source, StrBuf* Target) static void OldStyleComment (void) -/* Remove an old style C comment from line. */ +/* Remove an old style C comment from line */ { /* Remember the current line number, so we can output better error ** messages if the comment is not terminated in the current file. @@ -897,6 +897,7 @@ static void OldStyleComment (void) StartingLine); return; } + ++PendingNewLines; } else { if (CurC == '/' && NextC == '*') { PPWarning ("'/*' found inside a comment"); @@ -913,7 +914,7 @@ static void OldStyleComment (void) static void NewStyleComment (void) -/* Remove a new style C comment from line. */ +/* Remove a new style C comment from line */ { /* Diagnose if this is unsupported */ if (IS_Get (&Standard) < STD_C99) { From 92f94e4e5b271142caaaa8dabf0d21c1a8db1ae2 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:58:52 +0800 Subject: [PATCH 4/6] A space character will be inserted in front of a leading '#' pp-token as the result of macro expansion. --- src/cc65/preproc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 87d6a7878..833dea9d4 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -2216,6 +2216,13 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi InitLine (TmpTarget); PushRescanLine (CurRescanStack, TmpTarget, LastTokLen); + /* Add a space before a '#' at the beginning of the line */ + if (CurC == '#' && + NextC != '#' && + (SB_IsEmpty (Target) || SB_LookAtLast (Target) == '\n')) { + SB_AppendChar (Target, ' '); + } + /* Switch the buffers */ TmpTarget = NewStrBuf (); } else if (PendingNewLines > 0 && MultiLine) { From 950606d46a45839fe1409e057cc396b5e66e6366 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:59:00 +0800 Subject: [PATCH 5/6] Improved diagnostics on wrong number of arguments in function-like macro calls. --- src/cc65/preproc.c | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 833dea9d4..43c2131d1 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1551,7 +1551,10 @@ static unsigned ReadMacroArgs (unsigned NameIdx, MacroExp* E, const Macro* M, in /* If this is not the single empty argument for a macro with an ** empty argument list, remember it. */ - if (CurC != ')' || SB_NotEmpty (&Arg.Tokens) || M->ParamCount > 0) { + if (CurC != ')' || + CollCount (&E->Args) > 0 || + SB_NotEmpty (&Arg.Tokens) || + M->ParamCount > 0) { MacroExp* A = ME_AppendArg (E, &Arg); unsigned I; @@ -1669,11 +1672,23 @@ static unsigned ReadMacroArgs (unsigned NameIdx, MacroExp* E, const Macro* M, in } /* Compare formal and actual argument count */ - if (CollCount (&E->Args) != (unsigned) M->ParamCount) { - + if (CollCount (&E->Args) < (unsigned) M->ParamCount) { + /* Check further only when the parentheses are paired */ if (Parens == 0) { - /* Argument count mismatch */ - PPError ("Macro argument count mismatch"); + /* Specially casing variable argument */ + if (M->Variadic && + M->ParamCount > 0 && + CollCount (&E->Args) + 1 == (unsigned) M->ParamCount) { + /* The variable argument is left out entirely */ + E->Flags |= MES_NO_VA_COMMA; + if (IS_Get (&Standard) < STD_CC65) { + PPWarning ("ISO C does not permit leaving out the comma before the variable argument"); + } + } else { + /* Too few argument */ + PPError ("Macro \"%s\" passed only %u arguments, but requires %u", + M->Name, CollCount (&E->Args), (unsigned) M->ParamCount); + } } /* Be sure to make enough empty arguments available */ @@ -1683,6 +1698,10 @@ static unsigned ReadMacroArgs (unsigned NameIdx, MacroExp* E, const Macro* M, in while (CollCount (&E->Args) < (unsigned) M->ParamCount) { ME_AppendArg (E, &Arg); } + } else if (Parens == 0 && CollCount (&E->Args) > (unsigned) M->ParamCount) { + /* Too many arguments */ + PPError ("Macro \"%s\" passed %u arguments, but takes just %u", + M->Name, CollCount (&E->Args), (unsigned) M->ParamCount); } /* Deallocate argument resources */ From b4ddd01d78cb20d53fa987cf0cb4d4aad3ee1c77 Mon Sep 17 00:00:00 2001 From: acqn Date: Thu, 1 Sep 2022 12:58:52 +0800 Subject: [PATCH 6/6] Fixed checks on __VA_ARGS__. --- src/cc65/preproc.c | 45 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 43c2131d1..f1a525eae 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -806,6 +806,21 @@ static int MacName (char* Ident) +static void CheckForBadIdent (const char* Ident, int Std, const Macro* M) +/* Check for and warning on problematic identifiers */ +{ + if (Std >= STD_C99 && + (M == 0 || !M->Variadic) && + strcmp (Ident, "__VA_ARGS__") == 0) { + /* __VA_ARGS__ cannot be used as a macro parameter name in post-C89 + ** mode. + */ + PPWarning ("__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); + } +} + + + static void AddPreLine (StrBuf* Str) /* Add newlines to the string buffer */ { @@ -2089,6 +2104,12 @@ static unsigned ReplaceMacros (StrBuf* Source, StrBuf* Target, MacroExp* E, unsi /* If we have an identifier, check if it's a macro */ if (IsSym (Ident)) { + /* Check for bad identifier names */ + if ((ModeFlags & (MSM_MULTILINE | MSM_IN_DIRECTIVE | MSM_IN_ARG_LIST)) != 0 && + (CollCount (&CurRescanStack->Lines) == 1 || CurC == '\0')) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); + } + if ((ModeFlags & MSM_OP_DEFINED) != 0 && strcmp (Ident, "defined") == 0) { /* Handle the "defined" operator */ int HaveParen = 0; @@ -2431,6 +2452,7 @@ static int ParseMacroReplacement (StrBuf* Source, Macro* M) int HasWhiteSpace = 0; unsigned Len; ident Ident; + int Std = IS_Get (&Standard); /* Skip whitespace before the macro replacement */ SkipWhitespace (0); @@ -2448,6 +2470,9 @@ static int ParseMacroReplacement (StrBuf* Source, Macro* M) SB_AppendChar (&M->Replacement, ' '); } else if (IsQuotedString ()) { CopyQuotedString (&M->Replacement); + } else if (IsSym (Ident)) { + CheckForBadIdent (Ident, Std, M); + SB_AppendStr (&M->Replacement, Ident); } else { if (M->ParamCount >= 0 && GetPunc (Ident)) { Len = strlen (Ident); @@ -2516,7 +2541,7 @@ static void DoDefine (void) ident Ident; Macro* M = 0; Macro* Existing; - int C89; + int Std; /* Read the macro name */ SkipWhitespace (0); @@ -2524,8 +2549,8 @@ static void DoDefine (void) goto Error_Handler; } - /* Remember if we're in C89 mode */ - C89 = (IS_Get (&Standard) == STD_C89); + /* Remember the language standard we are in */ + Std = IS_Get (&Standard); /* Check for forbidden macro names */ if (strcmp (Ident, "defined") == 0) { @@ -2533,6 +2558,9 @@ static void DoDefine (void) goto Error_Handler; } + /* Check for and warn on special identifiers */ + CheckForBadIdent (Ident, Std, 0); + /* Create a new macro definition */ M = NewMacro (Ident); @@ -2557,7 +2585,7 @@ static void DoDefine (void) /* The next token must be either an identifier, or - if not in ** C89 mode - the ellipsis. */ - if (!C89 && CurC == '.') { + if (Std >= STD_C99 && CurC == '.') { /* Ellipsis */ NextChar (); if (CurC != '.' || NextC != '.') { @@ -2579,11 +2607,8 @@ static void DoDefine (void) goto Error_Handler; } - /* __VA_ARGS__ is only allowed in post-C89 mode */ - if (!C89 && strcmp (Ident, "__VA_ARGS__") == 0) { - PPWarning ("'__VA_ARGS__' can only appear in the expansion " - "of a C99 variadic macro"); - } + /* Check for and warn on special identifiers */ + CheckForBadIdent (Ident, Std, 0); /* Add the macro parameter */ AddMacroParam (M, Ident); @@ -2758,6 +2783,7 @@ static int DoIfDef (int skip, int flag) SkipWhitespace (0); if (MacName (Ident)) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); Value = IsMacro (Ident); /* Check for extra tokens */ CheckExtraTokens (flag ? "ifdef" : "ifndef"); @@ -2964,6 +2990,7 @@ static void DoUndef (void) SkipWhitespace (0); if (MacName (Ident)) { + CheckForBadIdent (Ident, IS_Get (&Standard), 0); UndefineMacro (Ident); } /* Check for extra tokens */