SQLite Forum

lemon - optional namespace support
Login
Hi Richard,

As promised, the second followup. 

The main issue that I've tried to solve was the use of global function names. Even if I use the `%name` directive to mangle them, there is still the potential of accidentally stepping on the names from other parser, which means that we need to have `some_long_maybe_unique_` prefix. Beyond that, these Lemon routines should never be touched directly by a user once embedded in one or more libraries (in this case paranoid, not pedantic). I also really wanted to avoid exposing more of the Lemon interface than necessary, for fear of entering one of those header interdependencies like flex/bison/flex etc.

In the C++ world, these problems are usually solved with namespaces. If we solve the problem confined to a C domain (notwithstanding the `-e` option), we arrive at a simple solution that works equally well for me and should be good for you in terms of cost/benefit, and benefit others wanting to wrap lemon parsers into large libraries.

If we drop all of my fancy handling of begin/end namespace with anonymous or nesting and simply allow specification of the linkage type, the patched version of `lempar.c` becomes quite small.

```
--- lempar.c.orig       2020-07-07 15:27:12.506352634 +0200
+++ lempar.c    2020-07-07 15:37:58.957932854 +0200
@@ -88,6 +88,10 @@
 #ifndef INTERFACE
 # define INTERFACE 1
 #endif
+/* Default is global linkage. Alternative is 'static' */
+#ifndef LEMON_LINKAGE
+# define LEMON_LINKAGE
+#endif
 /************* Begin control #defines *****************************************/
 %%
 /************* End control #defines *******************************************/
@@ -251,6 +255,7 @@
 ** Outputs:
 ** None.
 */
+LEMON_LINKAGE
 void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
   yyTraceFILE = TraceFILE;
   yyTracePrompt = zTracePrompt;
@@ -320,6 +325,7 @@
 
 /* Initialize a new parser that has already been allocated.
 */
+LEMON_LINKAGE
 void ParseInit(void *yypRawParser ParseCTX_PDECL){
   yyParser *yypParser = (yyParser*)yypRawParser;
   ParseCTX_STORE
@@ -359,6 +365,7 @@
 ** A pointer to a parser.  This pointer is used in subsequent calls
 ** to Parse and ParseFree.
 */
+LEMON_LINKAGE
 void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){
   yyParser *yypParser;
   yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
@@ -427,6 +434,7 @@
 /*
 ** Clear all secondary memory allocations from the parser
 */
+LEMON_LINKAGE
 void ParseFinalize(void *p){
   yyParser *pParser = (yyParser*)p;
   while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
@@ -444,6 +452,7 @@
 ** is defined in a %include section of the input grammar) then it is
 ** assumed that the input pointer is never NULL.
 */
+LEMON_LINKAGE
 void ParseFree(
   void *p,                    /* The parser to be deleted */
   void (*freeProc)(void*)     /* Function used to reclaim memory */
@@ -460,6 +469,7 @@
 ** Return the peak depth of the stack for a parser.
 */
 #ifdef YYTRACKMAXSTACKDEPTH
+LEMON_LINKAGE
 int ParseStackPeak(void *p){
   yyParser *pParser = (yyParser*)p;
   return pParser->yyhwm;
@@ -484,6 +494,7 @@
 ** Return the number of missed state/lookahead combinations.
 */
 #if defined(YYCOVERAGE)
+LEMON_LINKAGE
 int ParseCoverage(FILE *out){
   int stateno, iLookAhead, i;
   int nMissed = 0;
@@ -891,6 +902,7 @@
 ** Outputs:
 ** None.
 */
+LEMON_LINKAGE
 void Parse(
   void *yyp,                   /* The parser */
   int yymajor,                 /* The major token code number */
@@ -1065,6 +1077,7 @@
 ** Return the fallback token corresponding to canonical token iToken, or
 ** 0 if iToken has no fallback.
 */
+LEMON_LINKAGE
 int ParseFallback(int iToken){
 #ifdef YYFALLBACK
   assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
```

If this seems reasonable, then the only nice thing to change afterwards could be a Lemon directive (eg, `%static`?) to emit `#define LEMON_LINKAGE static` from `lemon.c` to restrict the type of things that people could write and reduce the number of pre-processor macros to document or remember.

For the C++ people, I think this is also a pretty good solution. In the end, I have only ever used an anonymous namespace for localising the lemon functions and that is very much what this is. _Except_ that it works for C++ **and** C and it doesn't carve as deeply into lemon (even with an additional directive).