Repository: cc65/cc65 (C)

Issue:
[cc65] Extension: predefined macro __COUNTER__
`__COUNTER__` is a commonly supported predefined macro in many major C compilers (eg. [GCC](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html)), which has well-established and understood behavior (except when involved with precompiled headers, maybe) and been used in practice.

For those who might be unfamiliar with it: `__COUNTER__` is a "magical" macro that evaluates to an integer literal whose value is starting from 0 and increased by one every time it is found in a source code text. It is a convenient way to provide a unqinue identifier in conjunctions with the `##` operator.

Is this feature desired for cc65?


Discussion:
Yes, I use WDMs with unique signature bytes at the beginning of each proc I am debugging to tell them apart.  It would be nice if the signature bytes could be generated automatically at assemble-time and some kind of map back to proc names were generated.

On second thought, having a `__LINE__` predefined macros would probably be easier to work with.  Two adjacent WDMs would be enough for small projects.
we HAVE __LINE__, no?
It looks like cc65 has `__LINE__` but ca65 does not.
> we HAVE **LINE**, no?

Actually, I came up with this topic when I was working on a fix for #1573. `__COUNTER__` allows to get multiple unique identifiers on the same line more easily than `__LINE__` does.
feel free to implement this :) and please add a test - this sounds like something that could be easily screwed up in a non trivial situation.



Patch:
diff --git a/src/cc65/compile.c b/src/cc65/compile.c
index d6069e9143..11dcbced0b 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 c6037091f6..0e8fc32764 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 cf529e169e..fb24bbaa8d 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 91aa503fcc..020df011a3 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 2143dde98b..a4619e545e 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 */
 
 
 


Test patch:
diff --git a/test/val/counter.c b/test/val/counter.c
new file mode 100644
index 0000000000..4efa18359e
--- /dev/null
+++ b/test/val/counter.c
@@ -0,0 +1,60 @@
+/* Tests for predefined macro __COUNTER__ */
+
+#include <stdio.h>
+
+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 0000000000..b6b5a98e2c
--- /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();