--- lemon.c.orig 2020-01-10 14:08:19.181711107 +0100 +++ lemon.c 2020-01-10 14:12:00.621402133 +0100 @@ -406,6 +406,7 @@ struct symbol *errsym; /* The error symbol */ struct symbol *wildcard; /* Token that matches anything */ char *name; /* Name of the generated parser */ + char *namesp; /* Surrounding namespace for generated parser */ char *arg; /* Declaration of the 3th argument to parser */ char *ctx; /* Declaration of 2nd argument to constructor */ char *tokentype; /* Type of terminal symbols in the parser stack */ @@ -1559,6 +1560,23 @@ lemon_strcpy(outputDir, z); } +/* Remember the name of the code extension (automatically prefix '.') +*/ +static char *code_ext = NULL; +static void handle_e_option(char *z){ + code_ext = (char *) malloc( lemonStrlen(z)+2 ); + if( code_ext==0 ){ + fprintf(stderr,"out of memory\n"); + exit(1); + } + if(*z == '.'){ + lemon_strcpy(code_ext, z); + } else { + code_ext[0] = '.'; + lemon_strcpy(&(code_ext[1]), z); + } +} + static char *user_templatename = NULL; static void handle_T_option(char *z){ user_templatename = (char *) malloc( lemonStrlen(z)+1 ); @@ -1647,6 +1665,7 @@ {OPT_FLAG, "c", (char*)&compress, "Don't compress the action table."}, {OPT_FSTR, "d", (char*)&handle_d_option, "Output directory. Default '.'"}, {OPT_FSTR, "D", (char*)handle_D_option, "Define an %ifdef macro."}, + {OPT_FSTR, "e", (char*)&handle_e_option, "Output code extension. Default 'c'"}, {OPT_FSTR, "f", 0, "Ignored. (Placeholder for -f compiler options.)"}, {OPT_FLAG, "g", (char*)&rpflag, "Print grammar without actions."}, {OPT_FSTR, "I", 0, "Ignored. (Placeholder for '-I' compiler options.)"}, @@ -2490,6 +2509,9 @@ if( strcmp(x,"name")==0 ){ psp->declargslot = &(psp->gp->name); psp->insertLineMacro = 0; + }else if( strcmp(x,"namespace")==0 ){ + psp->declargslot = &(psp->gp->namesp); + psp->insertLineMacro = 0; }else if( strcmp(x,"include")==0 ){ psp->declargslot = &(psp->gp->include); }else if( strcmp(x,"code")==0 ){ @@ -3477,20 +3499,83 @@ #define LINESIZE 1000 /* The next cluster of routines are for reading the template file ** and writing the results to the generated parser */ + +/* Helper function to emit begin of namespace when namesp!=0 +** Converts "ns1::ns2" to "namespace ns1 { namespace ns2 {" +*/ +PRIVATE void tplt_namespace_begin(char *namesp, FILE *out) +{ + if(!namesp) return; + while (ISSPACE(*namesp)) ++namesp; + + char *cp = namesp; + do { + fprintf(out,"namespace "); + cp = strchr(namesp, ':'); + if (cp) { + while (namesp != cp) { + fputc(*namesp,out); + ++namesp; + } + while(*namesp == ':') ++namesp; + } + else { + while (*namesp && !ISSPACE(*namesp)) { + fputc(*namesp,out); + ++namesp; + } + } + fprintf(out, " {"); + } while (cp); + fputc('\n',out); +} + +/* Helper function to emit end of namespace when namesp!=0 +** Converts "ns1::ns2" to "}} // End namespace" +*/ +PRIVATE void tplt_namespace_end(char *namesp, FILE *out) +{ + if(!namesp) return; + while (ISSPACE(*namesp)) ++namesp; + + char *cp = namesp; + do { + cp = strchr(cp, ':'); + if (cp) { + while(*cp == ':') ++cp; + } + fputc('}',out); + } while (cp); + + fprintf(out," // End namespace %s\n", namesp); +} + /* The first function transfers data from "in" to "out" until ** a line is seen which begins with "%%". The line number is ** tracked. ** ** if name!=0, then any word that begin with "Parse" is changed to ** begin with *name instead. +** +** if namesp!=0, then replace %namespace_begin / %namespace_end */ -PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno) +PRIVATE void tplt_xfer(char *name, char *namesp, FILE *in, FILE *out, int *lineno) { int i, iStart; char line[LINESIZE]; while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){ (*lineno)++; iStart = 0; + if(line[0]=='%' && line[1]=='n'){ + if(strncmp(&line[1],"namespace_begin",15)==0){ + tplt_namespace_begin(namesp, out); + continue; + }else if(strncmp(&line[1],"namespace_end",13)==0){ + tplt_namespace_end(namesp, out); + continue; + } + } + if( name ){ for(i=0; line[i]; i++){ if( line[i]=='P' && strncmp(&line[i],"Parse",5)==0 @@ -4187,7 +4272,8 @@ in = tplt_open(lemp); if( in==0 ) return; - out = file_open(lemp,".c","wb"); + if(code_ext) out = file_open(lemp,code_ext,"wb"); + else out = file_open(lemp,".c","wb"); if( out==0 ){ fclose(in); return; @@ -4265,7 +4351,7 @@ fprintf(sql, "COMMIT;\n"); } lineno = 1; - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate the include code, if any */ tplt_print(out,lemp,lemp->include,&lineno); @@ -4274,7 +4360,7 @@ fprintf(out,"#include \"%s\"\n", incName); lineno++; free(incName); } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate #defines for all tokens */ if( mhflag ){ @@ -4288,7 +4374,7 @@ } fprintf(out,"#endif\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate the defines */ fprintf(out,"#define YYCODETYPE %s\n", @@ -4453,7 +4539,7 @@ fprintf(out,"#define YY_MIN_REDUCE %d\n", lemp->minReduce); lineno++; i = lemp->minReduce + lemp->nrule; fprintf(out,"#define YY_MAX_REDUCE %d\n", i-1); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Now output the action table and its associates: ** @@ -4591,7 +4677,7 @@ } } fprintf(out, "};\n"); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate the table of fallback tokens. */ @@ -4612,7 +4698,7 @@ lineno++; } } - tplt_xfer(lemp->name, in, out, &lineno); + tplt_xfer(lemp->name,lemp->namesp, in, out, &lineno); /* Generate a table containing the symbolic name of every symbol */ @@ -4620,7 +4706,7 @@ lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name); fprintf(out," /* %4d */ \"%s\",\n",i, lemp->symbols[i]->name); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate a table containing a text string that describes every ** rule in the rule set of the grammar. This information is used @@ -4632,7 +4718,7 @@ writeRuleText(out, rp); fprintf(out,"\",\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which executes every time a symbol is popped from ** the stack while processing errors or while destroying the parser. @@ -4695,11 +4781,11 @@ emit_destructor_code(out,lemp->symbols[i],lemp,&lineno); fprintf(out," break;\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which executes whenever the parser stack overflows */ tplt_print(out,lemp,lemp->overflow,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate the tables of rule information. yyRuleInfoLhs[] and ** yyRuleInfoNRhs[]. @@ -4712,13 +4798,13 @@ rule_print(out, rp); fprintf(out," */\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){ fprintf(out," %3d, /* (%d) ", -rp->nrhs, i); rule_print(out, rp); fprintf(out," */\n"); lineno++; } - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which execution during each REDUCE action */ i = 0; @@ -4771,19 +4857,19 @@ } } fprintf(out," break;\n"); lineno++; - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which executes if a parse fails */ tplt_print(out,lemp,lemp->failure,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which executes when a syntax error occurs */ tplt_print(out,lemp,lemp->error,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Generate code which executes when the parser accepts its input */ tplt_print(out,lemp,lemp->accept,&lineno); - tplt_xfer(lemp->name,in,out,&lineno); + tplt_xfer(lemp->name,lemp->namesp,in,out,&lineno); /* Append any addition code the user desires */ tplt_print(out,lemp,lemp->extracode,&lineno);