From 0063f73f8a4a80df6e271aaadd9fc2204e0c900a Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 23:19:05 +0800 Subject: [PATCH 01/15] Fixed __FILE__ and __LINE__ macros for preprocessor. --- src/cc65/compile.c | 4 ++++ src/cc65/macrotab.c | 5 +++++ src/cc65/preproc.c | 18 ++++++++++++++++++ src/cc65/preproc.h | 13 +++++++++++++ src/cc65/scanner.c | 11 +---------- 5 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/cc65/compile.c b/src/cc65/compile.c index 75250da0a..d6069e914 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -396,6 +396,10 @@ void Compile (const char* FileName) DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1); } + /* Placeholders for __FILE__ and __LINE__ macros */ + DefineTextMacro ("__FILE__", ""); + DefineTextMacro ("__LINE__", ""); + /* __TIME__ and __DATE__ macros */ Time = time (0); TM = localtime (&Time); diff --git a/src/cc65/macrotab.c b/src/cc65/macrotab.c index 37b52351f..0e80cd638 100644 --- a/src/cc65/macrotab.c +++ b/src/cc65/macrotab.c @@ -42,6 +42,7 @@ /* cc65 */ #include "error.h" +#include "preproc.h" #include "macrotab.h" @@ -246,6 +247,10 @@ Macro* FindMacro (const char* Name) Macro* M = MacroTab[Hash]; while (M) { if (strcmp (M->Name, Name) == 0) { + /* Check for some special macro names */ + if (Name[0] == '_') { + HandleSpecialMacro (M, Name); + } /* Found it */ return M; } diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index f1328c4d0..6dcbeea70 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1533,6 +1533,24 @@ static int ParseDirectives (unsigned ModeFlags) +void HandleSpecialMacro (Macro* M, const char* Name) +/* Handle special mandatory macros */ +{ + if (strcmp (Name, "__LINE__") == 0) { + /* Replace __LINE__ with the current line number */ + SB_Printf (&M->Replacement, "%u", GetCurrentLine ()); + } else if (strcmp (Name, "__FILE__") == 0) { + /* Replace __FILE__ with the current filename */ + StrBuf B = AUTO_STRBUF_INITIALIZER; + SB_InitFromString (&B, GetCurrentFile ()); + SB_Clear (&M->Replacement); + Stringize (&B, &M->Replacement); + SB_Done (&B); + } +} + + + /*****************************************************************************/ /* Preprocessing */ /*****************************************************************************/ diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h index f543b05b5..2143dde98 100644 --- a/src/cc65/preproc.h +++ b/src/cc65/preproc.h @@ -38,6 +38,16 @@ +/*****************************************************************************/ +/* Forwards */ +/*****************************************************************************/ + + + +typedef struct Macro Macro; + + + /*****************************************************************************/ /* Data */ /*****************************************************************************/ @@ -80,6 +90,9 @@ void InitPreprocess (void); void DonePreprocess (void); /* Done with preprocessor */ +void HandleSpecialMacro (Macro* M, const char* Name); +/* Handle special mandatory macros */ + /* End of preproc.h */ diff --git a/src/cc65/scanner.c b/src/cc65/scanner.c index ebdcdb33e..09dd8fef8 100644 --- a/src/cc65/scanner.c +++ b/src/cc65/scanner.c @@ -835,16 +835,7 @@ void NextToken (void) /* No reserved word, check for special symbols */ if (token[0] == '_' && token[1] == '_') { /* Special symbols */ - if (strcmp (token+2, "FILE__") == 0) { - NextTok.SVal = AddLiteral (GetCurrentFile()); - NextTok.Tok = TOK_SCONST; - return; - } else if (strcmp (token+2, "LINE__") == 0) { - NextTok.Tok = TOK_ICONST; - NextTok.IVal = GetCurrentLine(); - NextTok.Type = type_int; - return; - } else if (strcmp (token+2, "func__") == 0) { + if (strcmp (token+2, "func__") == 0) { /* __func__ is only defined in functions */ if (CurrentFunc) { NextTok.SVal = AddLiteral (F_GetFuncName (CurrentFunc)); From 36123c9c8fce00e03938d8d3a585a1548b1c79f4 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 23:19:05 +0800 Subject: [PATCH 02/15] Improved naming for stuff related to preprocessing directives. --- src/cc65/preproc.c | 170 ++++++++++++++++++++++++--------------------- 1 file changed, 91 insertions(+), 79 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 4b1966437..35a9119c7 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -121,67 +121,67 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine); -/* Types of preprocessor tokens */ +/* Types of preprocessor directives */ typedef enum { - PP_ILLEGAL = -1, - PP_DEFINE, - PP_ELIF, - PP_ELSE, - PP_ENDIF, - PP_ERROR, - PP_IF, - PP_IFDEF, - PP_IFNDEF, - PP_INCLUDE, - PP_LINE, - PP_PRAGMA, - PP_UNDEF, - PP_WARNING, -} pptoken_t; + PPD_ILLEGAL = -1, + PPD_DEFINE, + PPD_ELIF, + PPD_ELSE, + PPD_ENDIF, + PPD_ERROR, + PPD_IF, + PPD_IFDEF, + PPD_IFNDEF, + PPD_INCLUDE, + PPD_LINE, + PPD_PRAGMA, + PPD_UNDEF, + PPD_WARNING, +} ppdirective_t; -/* Preprocessor keyword to token mapping table */ -static const struct PPToken { - const char* Key; /* Keyword */ - pptoken_t Tok; /* Token */ -} PPTokens[] = { - { "define", PP_DEFINE }, - { "elif", PP_ELIF }, - { "else", PP_ELSE }, - { "endif", PP_ENDIF }, - { "error", PP_ERROR }, - { "if", PP_IF }, - { "ifdef", PP_IFDEF }, - { "ifndef", PP_IFNDEF }, - { "include", PP_INCLUDE }, - { "line", PP_LINE }, - { "pragma", PP_PRAGMA }, - { "undef", PP_UNDEF }, - { "warning", PP_WARNING }, +/* Preprocessor directive tokens mapping table */ +static const struct PPDType { + const char* Tok; /* Token */ + ppdirective_t Type; /* Type */ +} PPDTypes[] = { + { "define", PPD_DEFINE }, + { "elif", PPD_ELIF }, + { "else", PPD_ELSE }, + { "endif", PPD_ENDIF }, + { "error", PPD_ERROR }, + { "if", PPD_IF }, + { "ifdef", PPD_IFDEF }, + { "ifndef", PPD_IFNDEF }, + { "include", PPD_INCLUDE }, + { "line", PPD_LINE }, + { "pragma", PPD_PRAGMA }, + { "undef", PPD_UNDEF }, + { "warning", PPD_WARNING }, }; -/* Number of preprocessor tokens */ -#define PPTOKEN_COUNT (sizeof(PPTokens) / sizeof(PPTokens[0])) +/* Number of preprocessor directive types */ +#define PPDTOKEN_COUNT (sizeof(PPDTypes) / sizeof(PPDTypes[0])) static int CmpToken (const void* Key, const void* Elem) /* Compare function for bsearch */ { - return strcmp ((const char*) Key, ((const struct PPToken*) Elem)->Key); + return strcmp ((const char*) Key, ((const struct PPDType*) Elem)->Tok); } -static pptoken_t FindPPToken (const char* Ident) -/* Find a preprocessor token and return it. Return PP_ILLEGAL if the identifier -** is not a valid preprocessor token. +static ppdirective_t FindPPDirectiveType (const char* Ident) +/* Find a preprocessor directive type and return it. Return PPD_ILLEGAL if the +** identifier is not a valid preprocessor directive token. */ { - struct PPToken* P; - P = bsearch (Ident, PPTokens, PPTOKEN_COUNT, sizeof (PPTokens[0]), CmpToken); - return P? P->Tok : PP_ILLEGAL; + struct PPDType* P; + P = bsearch (Ident, PPDTypes, PPDTOKEN_COUNT, sizeof (PPDTypes[0]), CmpToken); + return P? P->Type : PPD_ILLEGAL; } @@ -257,6 +257,26 @@ static int ME_ArgIsVariadic (const MacroExp* E, const Macro* M) +static int MacName (char* Ident) +/* Get a macro symbol name into Ident. If we have an error, print a +** diagnostic message and clear the line. +*/ +{ + if (IsSym (Ident) == 0) { + if (CurC != '\0') { + PPError ("Macro name must be an identifier"); + } else { + PPError ("Missing macro name"); + } + ClearLine (); + return 0; + } else { + return 1; + } +} + + + static void AddPreLine (StrBuf* Str) /* Add newlines to the string buffer */ { @@ -502,26 +522,6 @@ static int CheckExtraTokens (const char* Name) -static int MacName (char* Ident) -/* Get a macro symbol name into Ident. If we have an error, print a -** diagnostic message and clear the line. -*/ -{ - if (IsSym (Ident) == 0) { - if (CurC != '\0') { - PPError ("Macro name must be an identifier"); - } else { - PPError ("Missing macro name"); - } - ClearLine (); - return 0; - } else { - return 1; - } -} - - - static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) /* Identify the arguments to a macro call as-is */ { @@ -637,7 +637,7 @@ static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) -static void MacroArgSubst (MacroExp* E, Macro* M) +static void SubstMacroArgs (MacroExp* E, Macro* M) /* Argument substitution according to ISO/IEC 9899:1999 (E), 6.10.3.1ff */ { ident Ident; @@ -792,7 +792,7 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine) } /* Replace macro arguments handling the # and ## operators */ - MacroArgSubst (&E, M); + SubstMacroArgs (&E, M); /* Forbide repeated expansion of the same macro in use */ M->Expanding = 1; @@ -1036,6 +1036,12 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine) +/*****************************************************************************/ +/* Directives */ +/*****************************************************************************/ + + + static void DoDefine (void) /* Process #define directive */ { @@ -1468,15 +1474,15 @@ static int ParseDirectives (int InArgList) } ClearLine (); } else { - switch (FindPPToken (Directive)) { + switch (FindPPDirectiveType (Directive)) { - case PP_DEFINE: + case PPD_DEFINE: if (!PPSkip) { DoDefine (); } break; - case PP_ELIF: + case PPD_ELIF: if (PPStack->Index >= 0) { if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) { /* Handle as #else/#if combination */ @@ -1496,7 +1502,7 @@ static int ParseDirectives (int InArgList) } break; - case PP_ELSE: + case PPD_ELSE: if (PPStack->Index >= 0) { if ((PPStack->Stack[PPStack->Index] & IFCOND_ELSE) == 0) { if ((PPStack->Stack[PPStack->Index] & IFCOND_SKIP) == 0) { @@ -1514,7 +1520,7 @@ static int ParseDirectives (int InArgList) } break; - case PP_ENDIF: + case PPD_ENDIF: if (PPStack->Index >= 0) { /* Remove any clauses on top of stack that do not ** need a terminating #endif. @@ -1537,38 +1543,38 @@ static int ParseDirectives (int InArgList) } break; - case PP_ERROR: + case PPD_ERROR: if (!PPSkip) { DoError (); } break; - case PP_IF: + case PPD_IF: PPSkip = DoIf (PPSkip); break; - case PP_IFDEF: + case PPD_IFDEF: PPSkip = DoIfDef (PPSkip, 1); break; - case PP_IFNDEF: + case PPD_IFNDEF: PPSkip = DoIfDef (PPSkip, 0); break; - case PP_INCLUDE: + case PPD_INCLUDE: if (!PPSkip) { DoInclude (); } break; - case PP_LINE: + case PPD_LINE: /* Should do something in C99 at least, but we ignore it */ if (!PPSkip) { ClearLine (); } break; - case PP_PRAGMA: + case PPD_PRAGMA: if (!PPSkip) { if (!InArgList) { DoPragma (); @@ -1578,13 +1584,13 @@ static int ParseDirectives (int InArgList) } break; - case PP_UNDEF: + case PPD_UNDEF: if (!PPSkip) { DoUndef (); } break; - case PP_WARNING: + case PPD_WARNING: /* #warning is a non standard extension */ if (IS_Get (&Standard) > STD_C99) { if (!PPSkip) { @@ -1619,6 +1625,12 @@ static int ParseDirectives (int InArgList) +/*****************************************************************************/ +/* Preprocessor */ +/*****************************************************************************/ + + + void Preprocess (void) /* Preprocess lines count of which is affected by directives */ { From bb9c98f4c9ce005b5becc7d47f5b38ccc9500e91 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 23:19:05 +0800 Subject: [PATCH 03/15] 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; From 43d2fd2a960c1fb40c740eb057a34329f8d54075 Mon Sep 17 00:00:00 2001 From: acqn Date: Sun, 24 Jul 2022 23:19:05 +0800 Subject: [PATCH 04/15] Added support for the popular __COUNTER__ macro. --- src/cc65/compile.c | 3 ++- src/cc65/input.c | 14 +++++++++++ src/cc65/input.h | 3 +++ src/cc65/preproc.c | 10 ++++++-- src/cc65/preproc.h | 2 +- test/val/counter.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++ test/val/counter.h | 4 ++++ 7 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 test/val/counter.c create mode 100644 test/val/counter.h diff --git a/src/cc65/compile.c b/src/cc65/compile.c index d6069e914..11dcbced0 100644 --- a/src/cc65/compile.c +++ b/src/cc65/compile.c @@ -396,9 +396,10 @@ void Compile (const char* FileName) DefineNumericMacro ("__EAGERLY_INLINE_FUNCS__", 1); } - /* Placeholders for __FILE__ and __LINE__ macros */ + /* Placeholders for __FILE__, __LINE__ and __COUNTER__ macros */ DefineTextMacro ("__FILE__", ""); DefineTextMacro ("__LINE__", ""); + DefineTextMacro ("__COUNTER__", ""); /* __TIME__ and __DATE__ macros */ Time = time (0); diff --git a/src/cc65/input.c b/src/cc65/input.c index c6037091f..0e8fc3276 100644 --- a/src/cc65/input.c +++ b/src/cc65/input.c @@ -106,6 +106,9 @@ static Collection AFiles = STATIC_COLLECTION_INITIALIZER; /* Input stack used when preprocessing. */ static Collection InputStack = STATIC_COLLECTION_INITIALIZER; +/* Counter for the __COUNTER__ macro */ +static unsigned MainFileCounter; + /*****************************************************************************/ @@ -280,6 +283,9 @@ void OpenMainFile (const char* Name) ** the main file before the first line is read. */ UpdateLineInfo (MainFile->Input, MainFile->Line, Line); + + /* Initialize the __COUNTER__ counter */ + MainFileCounter = 0; } @@ -658,6 +664,14 @@ void SetCurrentFilename (const char* Name) +unsigned GetCurrentCounter (void) +/* Return the counter number in the current input file */ +{ + return MainFileCounter++; +} + + + 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 cf529e169..fb24bbaa8 100644 --- a/src/cc65/input.h +++ b/src/cc65/input.h @@ -128,6 +128,9 @@ void SetCurrentLine (unsigned LineNum); void SetCurrentFilename (const char* Name); /* Set the presumed name of the current input file */ +unsigned GetCurrentCounter (void); +/* Return the counter number in 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 91aa503fc..020df011a 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1630,9 +1630,15 @@ static int ParseDirectives (unsigned ModeFlags) void HandleSpecialMacro (Macro* M, const char* Name) -/* Handle special mandatory macros */ +/* Handle special "magic" macros that may change */ { - if (strcmp (Name, "__LINE__") == 0) { + if (strcmp (Name, "__COUNTER__") == 0) { + /* Replace __COUNTER__ with the current counter number */ + if (IS_Get (&Standard) < STD_CC65) { + PPWarning ("__COUNTER__ is a cc65 extension"); + } + SB_Printf (&M->Replacement, "%u", GetCurrentCounter ()); + } else if (strcmp (Name, "__LINE__") == 0) { /* Replace __LINE__ with the current line number */ SB_Printf (&M->Replacement, "%u", GetCurrentLine ()); } else if (strcmp (Name, "__FILE__") == 0) { diff --git a/src/cc65/preproc.h b/src/cc65/preproc.h index 2143dde98..a4619e545 100644 --- a/src/cc65/preproc.h +++ b/src/cc65/preproc.h @@ -91,7 +91,7 @@ void DonePreprocess (void); /* Done with preprocessor */ void HandleSpecialMacro (Macro* M, const char* Name); -/* Handle special mandatory macros */ +/* Handle special "magic" macros that may change */ diff --git a/test/val/counter.c b/test/val/counter.c new file mode 100644 index 000000000..4efa18359 --- /dev/null +++ b/test/val/counter.c @@ -0,0 +1,60 @@ +/* Tests for predefined macro __COUNTER__ */ + +#include + +static int failures = 0; + +#if __COUNTER__ /* 0 */ +# error __COUNTER__ should begin at 0! +#elif __COUNTER__ == 1 /* 1 */ +# define CONCAT(a,b) CONCAT_impl_(a,b) +# define CONCAT_impl_(a,b) a##b +#endif + +#line 42 "What is the answer?" +int CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}, CONCAT(ident,__COUNTER__)[0+__LINE__] = {__LINE__}; /* 2,3 */ + +#if __COUNTER__ == 4 ? 1 || __COUNTER__ : 0 && __COUNTER__ /* 4,5,6 */ +_Static_assert(__COUNTER__ == 7, "__COUNTER__ should be 7 here!"); /* 7 */ +# define GET_COUNTER() __COUNTER__ +# define GET_LINE() __LINE__ +# warning __COUNTER__ in #warning is just output as text and will never increase! +#else +# if __COUNTER__ + __COUNTER__ + __COUNTER__ /* Skipped as a whole and not incrementing */ +# endif +# error __COUNTER__ is skipped along with the whole #error line and will never increase anyways! */ +#endif + +#include "counter.h" +#include "counter.h" + +_Static_assert(GET_COUNTER() == 10, "__COUNTER__ should be 10 here!"); /* 10 */ + +int main(void) +{ + if (ident2[0] != 42) { + printf("Expected ident2[0]: %s, got: %s\n", 42, ident2[0]); + ++failures; + } + + if (ident3[0] != 42) { + printf("Expected ident3[0]: %s, got: %s\n", 42, ident3[0]); + ++failures; + } + + if (ident8 != 8) { + printf("Expected ident8: %s, got: %s\n", 8, ident8); + ++failures; + } + + if (ident9 != 9) { + printf("Expected ident9: %s, got: %s\n", 9, ident9); + ++failures; + } + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + + return failures; +} diff --git a/test/val/counter.h b/test/val/counter.h new file mode 100644 index 000000000..b6b5a98e2 --- /dev/null +++ b/test/val/counter.h @@ -0,0 +1,4 @@ +/* Tests for predefined macro __COUNTER__ */ + +#line GET_COUNTER() /* 1st: 8; 2nd: 9 */ +int CONCAT(ident,GET_LINE()) = GET_LINE(); From 79f97e77149467ec28792b0c28b77fad06f07342 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 22 Aug 2022 00:24:28 +0800 Subject: [PATCH 05/15] Reused code more for macros in preprocessing directives. --- src/cc65/preproc.c | 330 ++++++++++++++++++++------------------------- 1 file changed, 149 insertions(+), 181 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 35a9119c7..855d59844 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -67,6 +67,17 @@ +/* Macro scanner mode flags */ +#define MSM_NONE 0x00U /* Default */ +#define MSM_MULTILINE 0x01U /* Read from multiple lines */ +#define MSM_IN_DIRECTIVE 0x02U /* In PP directives scan */ +#define MSM_IN_ARG_LIST 0x04U /* In macro argument scan */ +#define MSM_IN_ARG_EXPANSION 0x08U /* In expansion on arguments */ +#define MSM_OP_DEFINED 0x10U /* Handle the defined operator */ +#define MSM_OP_HAS_INCLUDE 0x20U /* Handle the __has_include operator */ +#define MSM_OP_HAS_C_ATTRIBUTE 0x40U /* Handle the __has_c_attribute operator */ +#define MSM_TOK_HEADER 0x80U /* Support header tokens */ + /* Management data for #if */ #define IFCOND_NONE 0x00U #define IFCOND_SKIP 0x01U @@ -105,13 +116,16 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target); ** non-newline whitespace sequences. */ -static int ParseDirectives (int InArgList); -/* Handle directives. Return 1 if there are directives parsed, -1 if new lines -** are read, otherwise 0. +static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); +/* Preprocess a single line. Handle specified tokens and operators, remove +** whitespace and comments, then do macro replacement. */ -static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine); -/* Perform macro replacement. */ +static int ParseDirectives (unsigned ModeFlags); +/* Handle directives. Return 1 if any whitespace or newlines are parsed. */ + +static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags); +/* Scan for and perform macro replacement */ @@ -545,7 +559,7 @@ static void ReadMacroArgs (MacroExp* E, const Macro* M, int MultiLine) Newlines += PendingNewLines - OldPendingNewLines; PendingNewLines = OldPendingNewLines; OldPendingNewLines = 0; - Skipped = ParseDirectives (1) || Skipped; + Skipped = ParseDirectives (MSM_IN_ARG_LIST) || Skipped; Skipped = SkipWhitespace (MultiLine) || Skipped; } PendingNewLines += Newlines; @@ -809,122 +823,89 @@ static void ExpandMacro (StrBuf* Target, Macro* M, int MultiLine) -/*****************************************************************************/ -/* Preprocessing */ -/*****************************************************************************/ - - - -static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) -/* Mimic Translation Phase 3. Handle old and new style comments. Collapse -** non-newline whitespace sequences. -*/ +static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags) +/* Scan for and perform macro replacement */ { - /* Switch to the new input source */ - StrBuf* OldSource = InitLine (Source); - - /* Loop removing ws and comments */ - while (CurC != '\0') { - int HasWhiteSpace = 0; - while (1) { - /* Squeeze runs of blanks */ - if (IsSpace (CurC)) { - NextChar (); - HasWhiteSpace = 1; - } else if (CurC == '/' && NextC == '*') { - OldStyleComment (); - HasWhiteSpace = 1; - } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { - NewStyleComment (); - HasWhiteSpace = 1; - } else { - /* No more white space */ - break; - } - } - if (HasWhiteSpace) { - SB_AppendChar (Target, ' '); - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); - } else { - SB_AppendChar (Target, CurC); - NextChar (); - } - } - - /* Terminate the new input line */ - SB_Terminate (Target); - - /* Switch back to the old source */ - InitLine (OldSource); -} - - - -static void ProcessSingleLine (StrBuf* Source, - StrBuf* Target, - int HandleDefined, - int HandleHeader) -/* Process a single line. Remove whitespace, old and new style comments. -** Recognize and handle the "defined" operator if HandleDefined is true. -** Recognize and handle header name tokens if HandleHeader is true. -*/ -{ - int OldIndex = SB_GetIndex (Source); ident Ident; - int HaveParen; - /* Operate on the new input source */ + /* Remember the current input and switch to Source */ StrBuf* OldSource = InitLine (Source); - SkipWhitespace (0); - - /* Loop removing ws and comments */ + /* Loop substituting macros */ while (CurC != '\0') { - if (SkipWhitespace (0)) { - /* Squeeze runs of blanks */ - if (!IsSpace (SB_LookAtLast (Target))) { - SB_AppendChar (Target, ' '); - } - } else if (IsSym (Ident)) { - if (HandleDefined && strcmp (Ident, "defined") == 0) { + /* If we have an identifier, check if it's a macro */ + if (IsSym (Ident)) { + if ((ModeFlags & MSM_OP_DEFINED) != 0 && strcmp (Ident, "defined") == 0) { /* Handle the "defined" operator */ + int HaveParen = 0; + SkipWhitespace (0); - HaveParen = 0; if (CurC == '(') { HaveParen = 1; NextChar (); SkipWhitespace (0); } if (IsSym (Ident)) { - SB_AppendChar (Target, IsMacro (Ident)? '1' : '0'); + /* Eat the identifier */ + SB_AppendChar (Target, IsMacro (Ident) ? '1' : '0'); if (HaveParen) { SkipWhitespace (0); if (CurC != ')') { PPError ("')' expected"); + ClearLine (); } else { NextChar (); } } } else { - PPError ("Identifier expected"); + PPError ("Macro name must be an identifier"); + ClearLine (); SB_AppendChar (Target, '0'); } } else { + /* Check if it's an expandable macro */ Macro* M = FindMacro (Ident); if (M != 0 && !M->Expanding) { /* Check if this is a function-like macro */ if (M->ArgCount >= 0) { - int Whitespace = SkipWhitespace (0); + int MultiLine = (ModeFlags & MSM_MULTILINE) != 0; + int Whitespace = SkipWhitespace (MultiLine); if (CurC != '(') { /* Function-like macro without an argument list is not replaced */ SB_AppendStr (Target, M->Name); - if (Whitespace) { + if (Whitespace > 0) { SB_AppendChar (Target, ' '); } + + /* Directives can only be found in an argument list + ** that spans multiple lines. + */ + if (MultiLine) { + if (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); + } } else { /* Function-like macro */ - ExpandMacro (Target, M, 0); + if (OLine == 0) { + OLine = Target; + ExpandMacro (Target, M, MultiLine); + OLine = 0; + } else { + ExpandMacro (Target, M, MultiLine); + } } } else { /* Object-like macro */ @@ -935,97 +916,19 @@ static void ProcessSingleLine (StrBuf* Source, SB_AppendStr (Target, Ident); } } - } else if (HandleHeader && (CurC == '<' || CurC == '\"')) { - CopyHeaderNameToken (Target); - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); } else { - SB_AppendChar (Target, CurC); - NextChar (); - } - } - - /* Switch back to the old source */ - InitLine (OldSource); - - /* Restore the source input index */ - SB_SetIndex (Source, OldIndex); -} - - - -static void MacroReplacement (StrBuf* Source, StrBuf* Target, int MultiLine) -/* Perform macro replacement. */ -{ - ident Ident; - Macro* M; - - /* Remember the current input and switch to Source */ - StrBuf* OldSource = InitLine (Source); - - /* Loop substituting macros */ - while (CurC != '\0') { - /* If we have an identifier, check if it's a macro */ - if (IsSym (Ident)) { - /* Check if it's a macro */ - if ((M = FindMacro (Ident)) != 0 && !M->Expanding) { - /* Check if this is a function-like macro */ - if (M->ArgCount >= 0) { - int Whitespace = SkipWhitespace (MultiLine); - if (CurC != '(') { - /* Function-like macro without an argument list is not replaced */ - SB_AppendStr (Target, M->Name); - if (Whitespace > 0) { - SB_AppendChar (Target, ' '); - } - - /* Directives can only be found in an argument list - ** that spans multiple lines. - */ - if (MultiLine) { - if (CurC == '#') { - /* If we were going to support #pragma in - ** macro argument list, it would be output - ** to OLine. - */ - if (OLine == 0) { - OLine = Target; - ParseDirectives (0); - OLine = 0; - } else { - ParseDirectives (0); - } - } - /* Add the source info to preprocessor output if needed */ - AddPreLine (Target); - } - } else { - /* Function-like macro */ - if (OLine == 0) { - OLine = Target; - ExpandMacro (Target, M, MultiLine); - OLine = 0; - } else { - ExpandMacro (Target, M, MultiLine); - } - } + if ((ModeFlags & MSM_TOK_HEADER) != 0 && (CurC == '<' || CurC == '\"')) { + CopyHeaderNameToken (Target); + } else if (IsQuote (CurC)) { + CopyQuotedString (Target); + } else { + int Whitespace = SkipWhitespace (0); + if (Whitespace) { + SB_AppendChar (Target, ' '); } else { - /* Object-like macro */ - ExpandMacro (Target, M, 0); + SB_AppendChar (Target, CurC); + NextChar (); } - } else { - /* An identifier, keep it */ - SB_AppendStr (Target, Ident); - } - } else if (IsQuote (CurC)) { - CopyQuotedString (Target); - } else { - int Whitespace = SkipWhitespace (0); - if (Whitespace) { - SB_AppendChar (Target, ' '); - } else { - SB_AppendChar (Target, CurC); - NextChar (); } } } @@ -1260,7 +1163,7 @@ static int DoIf (int Skip) /* Macro-replace a single line with support for the "defined" operator */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 1, 0); + PreprocessDirective (Line, MLine, MSM_OP_DEFINED); /* Read from the processed line */ SB_Reset (MLine); @@ -1324,7 +1227,7 @@ static void DoInclude (void) /* Macro-replace a single line with special support for */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 0, 1); + PreprocessDirective (Line, MLine, MSM_TOK_HEADER); /* Read from the processed line */ SB_Reset (MLine); @@ -1400,7 +1303,7 @@ static void DoPragma (void) /* Macro-replace a single line */ SB_Clear (MLine); - ProcessSingleLine (Line, MLine, 0, 0); + PreprocessDirective (Line, MLine, MSM_NONE); /* Convert #pragma to _Pragma () */ SB_AppendStr (PragmaLine, "_Pragma ("); @@ -1448,7 +1351,7 @@ static void DoWarning (void) -static int ParseDirectives (int InArgList) +static int ParseDirectives (unsigned ModeFlags) /* Handle directives. Return 1 if any whitespace or newlines are parsed. */ { int PPSkip = 0; @@ -1576,7 +1479,7 @@ static int ParseDirectives (int InArgList) case PPD_PRAGMA: if (!PPSkip) { - if (!InArgList) { + if ((ModeFlags & MSM_IN_ARG_LIST) == 0) { DoPragma (); } else { PPError ("Embedded #pragma directive within macro arguments is unsupported"); @@ -1626,11 +1529,76 @@ static int ParseDirectives (int InArgList) /*****************************************************************************/ -/* Preprocessor */ +/* Preprocessing */ /*****************************************************************************/ +static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) +/* Mimic Translation Phase 3. Handle old and new style comments. Collapse +** non-newline whitespace sequences. +*/ +{ + /* Switch to the new input source */ + StrBuf* OldSource = InitLine (Source); + + /* Loop removing ws and comments */ + while (CurC != '\0') { + int HasWhiteSpace = 0; + while (1) { + /* Squeeze runs of blanks */ + if (IsSpace (CurC)) { + NextChar (); + HasWhiteSpace = 1; + } else if (CurC == '/' && NextC == '*') { + OldStyleComment (); + HasWhiteSpace = 1; + } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { + NewStyleComment (); + HasWhiteSpace = 1; + } else { + /* No more white space */ + break; + } + } + if (HasWhiteSpace) { + SB_AppendChar (Target, ' '); + } else if (IsQuote (CurC)) { + CopyQuotedString (Target); + } else { + SB_AppendChar (Target, CurC); + NextChar (); + } + } + + /* Terminate the new input line */ + SB_Terminate (Target); + + /* Switch back to the old source */ + InitLine (OldSource); +} + + + +static void PreprocessDirective (StrBuf* Source, StrBuf* Target, unsigned ModeFlags) +/* Preprocess a single line. Handle specified tokens and operators, remove +** whitespace and comments, then do macro replacement. +*/ +{ + int OldIndex = SB_GetIndex (Source); + MacroExp E; + + SkipWhitespace (0); + InitMacroExp (&E); + MacroReplacement (Source, Target, ModeFlags | MSM_IN_DIRECTIVE); + DoneMacroExp (&E); + + /* Restore the source input index */ + SB_SetIndex (Source, OldIndex); +} + + + void Preprocess (void) /* Preprocess lines count of which is affected by directives */ { @@ -1641,7 +1609,7 @@ void Preprocess (void) /* Parse any directives */ OLine = PLine; - ParseDirectives (0); + ParseDirectives (MSM_MULTILINE); OLine = 0; /* Add the source info to preprocessor output if needed */ @@ -1651,7 +1619,7 @@ void Preprocess (void) AppendIndent (PLine, SB_GetIndex (Line)); /* Expand macros if any */ - MacroReplacement (Line, PLine, 1); + MacroReplacement (Line, PLine, MSM_MULTILINE); /* Add the source info to preprocessor output if needed */ AddPreLine (PLine); From 5d5bd472c637d8ec5304e1b152e2930abd8e3399 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 22 Aug 2022 00:27:21 +0800 Subject: [PATCH 06/15] Removed extra whitespace at line ends in preprocess-only output (-E). Increased threshold from 5 to 7 for skipped newlines with #line directives in preprocess-only output (-E). --- src/cc65/preproc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 855d59844..76a625f53 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -299,7 +299,7 @@ static void AddPreLine (StrBuf* Str) return; } - if (FileChanged || PendingNewLines > 4) { + if (FileChanged || PendingNewLines > 6) { /* Output #line directives as source info */ StrBuf Comment = AUTO_STRBUF_INITIALIZER; if (SB_NotEmpty (Str) && SB_LookAtLast (Str) != '\n') { @@ -933,6 +933,11 @@ static void MacroReplacement (StrBuf* Source, StrBuf* Target, unsigned ModeFlags } } + /* Drop whitespace at the end */ + if (IsBlank (SB_LookAtLast (Target))) { + SB_Drop (Target, 1); + } + /* Switch back the input */ InitLine (OldSource); } From 9565f41381285d06814c993c75148d8f49381750 Mon Sep 17 00:00:00 2001 From: acqn Date: Fri, 19 Aug 2022 13:27:56 +0800 Subject: [PATCH 07/15] Improved Diagnostic with #include. --- src/cc65/preproc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index 76a625f53..f1328c4d0 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1254,7 +1254,7 @@ static void DoInclude (void) break; default: - PPError ("'\"' or '<' expected"); + PPError ("#include expects \"FILENAME\" or "); goto Done; } NextChar (); @@ -1274,7 +1274,7 @@ static void DoInclude (void) CheckExtraTokens ("include"); /* Open the include file */ OpenIncludeFile (SB_GetConstBuf (&Filename), IT); - } else if (CurC == '\0') { + } else { /* No terminator found */ PPError ("#include expects \"FILENAME\" or "); } From fd7f32ecd3c3bcb331612a17b79e25a8f1ee8b99 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 22 Aug 2022 14:31:51 +0800 Subject: [PATCH 08/15] Improved error handling and diagnostics with failed macro definitions. --- src/cc65/preproc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index f1328c4d0..ffae5baa6 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -1004,6 +1004,7 @@ static void DoDefine (void) if (CurC != '.' || NextC != '.') { PPError ("'...' expected"); ClearLine (); + FreeMacro (M); return; } NextChar (); @@ -1043,8 +1044,9 @@ static void DoDefine (void) /* Check for a right paren and eat it if we find one */ if (CurC != ')') { - PPError ("')' expected"); + PPError ("')' expected for macro definition"); ClearLine (); + FreeMacro (M); return; } NextChar (); From 57ad7c87661f2bf313321e71476f5b75ecaaf548 Mon Sep 17 00:00:00 2001 From: acqn Date: Mon, 22 Aug 2022 14:31:53 +0800 Subject: [PATCH 09/15] Improved diagnostics about C++ style comments for c89. --- src/cc65/preproc.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/cc65/preproc.c b/src/cc65/preproc.c index ffae5baa6..a49fade20 100644 --- a/src/cc65/preproc.c +++ b/src/cc65/preproc.c @@ -400,6 +400,11 @@ static void OldStyleComment (void) static void NewStyleComment (void) /* Remove a new style C comment from line. */ { + /* Diagnose if this is unsupported */ + if (IS_Get (&Standard) < STD_C99) { + PPError ("C++ style comments are not allowed in C89"); + } + /* Beware: Because line continuation chars are handled when reading ** lines, we may only skip until the end of the source line, which ** may not be the same as the end of the input line. The end of the @@ -432,7 +437,7 @@ static int SkipWhitespace (int SkipLines) } else if (CurC == '/' && NextC == '*') { OldStyleComment (); Skipped = 1; - } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { + } else if (CurC == '/' && NextC == '/') { NewStyleComment (); Skipped = 1; } else if (CurC == '\0' && SkipLines) { @@ -1560,7 +1565,7 @@ static void TranslationPhase3 (StrBuf* Source, StrBuf* Target) } else if (CurC == '/' && NextC == '*') { OldStyleComment (); HasWhiteSpace = 1; - } else if (IS_Get (&Standard) >= STD_C99 && CurC == '/' && NextC == '/') { + } else if (CurC == '/' && NextC == '/') { NewStyleComment (); HasWhiteSpace = 1; } else { From 22ea30c75f02b4c130d42b3c18fe908a66851ef7 Mon Sep 17 00:00:00 2001 From: Bob Andrews Date: Tue, 23 Aug 2022 11:56:05 +0200 Subject: [PATCH 10/15] "cat" result to console on failure (only on *nix right now) --- test/val/Makefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/val/Makefile b/test/val/Makefile index acac670cb..a3722f7bf 100644 --- a/test/val/Makefile +++ b/test/val/Makefile @@ -9,11 +9,13 @@ ifdef CMD_EXE NULLDEV = nul: MKDIR = mkdir $(subst /,\,$1) RMDIR = -rmdir /s /q $(subst /,\,$1) + CATRES = else S = / NULLDEV = /dev/null MKDIR = mkdir -p $1 RMDIR = $(RM) -r $1 + CATRES = || (cat $(WORKDIR)/$$@.out && false) endif ifdef QUIET @@ -51,7 +53,7 @@ $(WORKDIR)/%.$1.$2.prg: %.c | $(WORKDIR) $(CC65) -t sim$2 $$(CC65FLAGS) --add-source -$1 -o $$(@:.prg=.s) $$< $(NULLERR) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) - $(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$@.out + $(SIM65) $(SIM65FLAGS) $$@ > $(WORKDIR)/$$@.out $(CATRES) endef # PRG_template From 26945c32ac91d30797f0529fc6d567af030db631 Mon Sep 17 00:00:00 2001 From: acqn Date: Wed, 24 Aug 2022 15:30:52 +0800 Subject: [PATCH 11/15] Fixed function parameters declared as function types rather than function pointers. --- src/cc65/expr.c | 8 ++++---- test/val/bug1838.c | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) create mode 100644 test/val/bug1838.c diff --git a/src/cc65/expr.c b/src/cc65/expr.c index f3003507a..afb5e1960 100644 --- a/src/cc65/expr.c +++ b/src/cc65/expr.c @@ -1133,10 +1133,6 @@ static void Primary (ExprDesc* E) /* Enum or some other numeric constant */ E->Flags = E_LOC_NONE | E_RTYPE_RVAL; E->IVal = Sym->V.ConstVal; - } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { - /* Function */ - E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; - E->Name = (uintptr_t) Sym->Name; } else if ((Sym->Flags & SC_AUTO) == SC_AUTO) { /* Local variable. If this is a parameter for a variadic ** function, we have to add some address calculations, and the @@ -1151,6 +1147,10 @@ static void Primary (ExprDesc* E) E->Flags = E_LOC_STACK | E_RTYPE_LVAL; E->IVal = Sym->V.Offs; } + } else if ((Sym->Flags & SC_FUNC) == SC_FUNC) { + /* Function */ + E->Flags = E_LOC_GLOBAL | E_RTYPE_LVAL; + E->Name = (uintptr_t) Sym->Name; } else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) { /* Register variable, zero page based */ E->Flags = E_LOC_REGISTER | E_RTYPE_LVAL; diff --git a/test/val/bug1838.c b/test/val/bug1838.c new file mode 100644 index 000000000..ba3c1164f --- /dev/null +++ b/test/val/bug1838.c @@ -0,0 +1,35 @@ +/* Bug 1838 - function parameters declared as function types rather than function pointers */ + +#include + +static int failures = 0; + +typedef int fn_t(int); + +int main(void) +{ + void foo(fn_t*); + fn_t bar; + + foo(bar); + return 0; +} + +void foo(int func(int)) +{ + int n = func(42); + + if (n != 12) { + printf("n = %d, expected: 12\n", n); + ++failures; + } +} + +int bar(int a) +{ + if (a != 42) { + printf("a = %d, expected: 42\n", a); + ++failures; + } + return 12; +} From 1dbc5cb325c487d50242051029f508b266771602 Mon Sep 17 00:00:00 2001 From: acqn Date: Wed, 24 Aug 2022 16:39:44 +0800 Subject: [PATCH 12/15] Simple testcase for __LINE__, __FILE__ as well as #line. --- test/val/bug1573.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ test/val/bug1573.h | 14 ++++++++ 2 files changed, 95 insertions(+) create mode 100644 test/val/bug1573.c create mode 100644 test/val/bug1573.h diff --git a/test/val/bug1573.c b/test/val/bug1573.c new file mode 100644 index 000000000..47172c398 --- /dev/null +++ b/test/val/bug1573.c @@ -0,0 +1,81 @@ +/* Tests for predefined macros __LINE__ and __FILE__ as well as #line control */ + +#include +#include + +static int failures = 0; + +#if !defined __LINE__ +#error __LINE__ is not predefined! +#endif + +#if !defined __FILE__ +#error __FILE__ is not predefined! +#endif + +#define CONCAT(a,b) CONCAT_impl_(a,b) +#define CONCAT_impl_(a,b) a##b +#define MKSTR(a) MKSTR_impl_(a) +#define MKSTR_impl_(a) #a +char CONCAT(ident,__LINE__)[0+__LINE__]; +char CONCAT(ident,__LINE__)[0+__LINE__]; + +#define GET_FILE() __FILE__ +#define THIS_FILENAME_1 "bug1573.c" +#define THIS_FILENAME_2 "<>" +#define INC_FILENAME_1 "bug1573.h" +#define INC_FILENAME_2 "<>" + +#line __LINE__ THIS_FILENAME_1 /* Note: #line sets the line number of the NEXT line */ +void foo(void) +{ + if (strcmp (GET_FILE(), THIS_FILENAME_1) != 0) { + printf("Expected: %s, got: %s\n", THIS_FILENAME_1, GET_FILE()); + ++failures; + } +} + +#line __LINE__ THIS_FILENAME_2 /* Note: #line sets the line number of the NEXT line */ +#include INC_FILENAME_1 +long line2 = __LINE__; + +int main(void) +{ + if (strcmp (filename1, INC_FILENAME_1) != 0) { + printf("Expected filename1: %s, got: %s\n", INC_FILENAME_1, filename1); + ++failures; + } + + if (strcmp (filename2, INC_FILENAME_2) != 0) { + printf("Expected filename2: %s, got: %s\n", INC_FILENAME_2, filename2); + ++failures; + } + + foo(); + +#line 65535 + if (strcmp (GET_FILE(), THIS_FILENAME_2) != 0) { + printf("Expected: %s, got: %s\n", THIS_FILENAME_2, GET_FILE()); + ++failures; + } + + if (line1 != 5L) { + printf("Expected line1: %ld, got: %ld\n", 5L, line1); + ++failures; + } + + if (line2 != 38L) { + printf("Expected line2: %ld, got: %ld\n", 38L, line2); + ++failures; + } + + if (strcmp (ans1, ans2) != 0 || strcmp (ans1, "42") != 0) { + ++failures; + printf("Expected: 42, ans1: %s, ans2: %s\n", ans1, ans2); + } + + if (failures != 0) { + printf("Failures: %d\n", failures); + } + return failures; +} diff --git a/test/val/bug1573.h b/test/val/bug1573.h new file mode 100644 index 000000000..4e64b5ca2 --- /dev/null +++ b/test/val/bug1573.h @@ -0,0 +1,14 @@ +/* Tests for predefined macros __LINE__ and __FILE__ as well as #line control */ + +#line __LINE__ INC_FILENAME_1 +#define GET_LINE() __LINE__ +char filename1[] = GET_FILE(); +long line1 = GET_LINE(); + +#line 42 +const char ans1[] = MKSTR(GET_LINE()); + +#line 40 INC_FILENAME_2 +char filename2[] = GET_FILE(); +const char ans2[] = \ +MKSTR(GET_LINE()); From 90b9438b48647f573464aede78e7b6e40263cb1d Mon Sep 17 00:00:00 2001 From: mrdudz Date: Sat, 27 Aug 2022 01:15:06 +0200 Subject: [PATCH 13/15] added testcase related to issue #1768 --- test/misc/Makefile | 6 ++++++ test/misc/bug1768.c | 14 ++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 test/misc/bug1768.c diff --git a/test/misc/Makefile b/test/misc/Makefile index e6c58c5a4..e77d37b29 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -58,6 +58,12 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR) define PRG_template +# should compile, but gives an error +$(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR) + @echo "FIXME: " $$@ "currently does not compile." + $(if $(QUIET),echo misc/bug1768.$1.$2.prg) + $(NOT) $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) + # should compile, but gives an error $(WORKDIR)/bug760.$1.$2.prg: bug760.c | $(WORKDIR) @echo "FIXME: " $$@ "currently does not compile." diff --git a/test/misc/bug1768.c b/test/misc/bug1768.c new file mode 100644 index 000000000..916aa64bc --- /dev/null +++ b/test/misc/bug1768.c @@ -0,0 +1,14 @@ + +#include + +int a = 1 || (8 / 0); +int b = 0 && (8 % 0); +int c = 1 ? 42 : (0 % 0); +int d = 1 || a / 0; +int e = 0 && b % 0; +int f = 1 ? 42 : (a %= 0, b /= 0); + +int main(void) +{ + return EXIT_SUCCESS; +} From 41b29d5c81f26879b79d2093295e2764387951d5 Mon Sep 17 00:00:00 2001 From: mrdudz Date: Sat, 27 Aug 2022 02:10:02 +0200 Subject: [PATCH 14/15] add testcase related to issue #1252 --- test/misc/Makefile | 8 ++++++++ test/misc/bug1252.c | 19 +++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 test/misc/bug1252.c diff --git a/test/misc/Makefile b/test/misc/Makefile index e77d37b29..e761b1e3e 100644 --- a/test/misc/Makefile +++ b/test/misc/Makefile @@ -58,6 +58,14 @@ $(ISEQUAL): ../isequal.c | $(WORKDIR) define PRG_template +# should compile, but gives an error +$(WORKDIR)/bug1252.$1.$2.prg: bug1252.c | $(WORKDIR) + @echo "FIXME: " $$@ "currently does not compile." + $(if $(QUIET),echo misc/bug1252.$1.$2.prg) + $(CC65) -t sim$2 -$1 -o $$@ $$< $(NULLERR) + $(NOT) $(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR) +# $(NOT) $(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR) + # should compile, but gives an error $(WORKDIR)/bug1768.$1.$2.prg: bug1768.c | $(WORKDIR) @echo "FIXME: " $$@ "currently does not compile." diff --git a/test/misc/bug1252.c b/test/misc/bug1252.c new file mode 100644 index 000000000..c94508d7d --- /dev/null +++ b/test/misc/bug1252.c @@ -0,0 +1,19 @@ + +#include + +int main(void) +{ +// this works +c_label: + asm("inx\n" + "bne %g\n", + c_label); + +// this does not work +c_label2: + asm("inx\n" + "bne %g \n", + c_label2); + + return EXIT_SUCCESS; +} From 168f42bb836ba940ec7aedaf76356d3facf7d595 Mon Sep 17 00:00:00 2001 From: mrdudz Date: Sat, 27 Aug 2022 02:14:52 +0200 Subject: [PATCH 15/15] fix whitespace --- test/misc/bug1252.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/misc/bug1252.c b/test/misc/bug1252.c index c94508d7d..599aa064b 100644 --- a/test/misc/bug1252.c +++ b/test/misc/bug1252.c @@ -7,13 +7,13 @@ int main(void) c_label: asm("inx\n" "bne %g\n", - c_label); + c_label); // this does not work c_label2: asm("inx\n" "bne %g \n", - c_label2); + c_label2); return EXIT_SUCCESS; }