Commit 6365bab8 authored by Mark Olesen's avatar Mark Olesen
Browse files

ENH: update lemon version and linkage directive (#1768)

- replace `%namespace` directive with simpler `%static` directive.

  We always encapsulate Lemon parser routines in an anonymous
  namespace, so a simpler static linkage directive suffices.

  This reduces the size of the Lemon patch (program and template).
parent a088bda4
......@@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -120,7 +120,8 @@ tmp_management()
// ------------------------------------------------------------------------- //
%namespace {}
// File-scope visibility for exposed Lemon parser routines
%static
// Use extra argument for the return value
%extra_context { Foam::expressions::fieldExpr::parseDriver* driver }
......
......@@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -66,7 +66,8 @@ tmp_management()
// ------------------------------------------------------------------------- //
%namespace {}
// File-scope visibility for exposed Lemon parser routines
%static
// Use extra argument for the return value
%extra_context { Foam::expressions::patchExpr::parseDriver* driver }
......
......@@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
......@@ -99,7 +99,8 @@ dnl
// ------------------------------------------------------------------------- //
%namespace {}
// File-scope visibility for exposed Lemon parser routines
%static
// Use extra argument for the return value
%extra_context { Foam::expressions::volumeExpr::parseDriver* driver }
......
......@@ -93,6 +93,12 @@
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
/* Default linkage for exposed parser routines is global
*/
#ifndef YYFUNCAPI
# define YYFUNCAPI
#endif
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
......@@ -251,14 +257,13 @@ static char *yyTracePrompt = 0;
** Outputs:
** None.
*/
%namespace_begin
YYFUNCAPI
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
%namespace_end
#endif /* NDEBUG */
#if defined(YYCOVERAGE) || !defined(NDEBUG)
......@@ -322,7 +327,7 @@ static int yyGrowStack(yyParser *p){
/* Initialize a new parser that has already been allocated.
*/
%namespace_begin
YYFUNCAPI
void ParseInit(void *yypRawParser ParseCTX_PDECL){
yyParser *yypParser = (yyParser*)yypRawParser;
ParseCTX_STORE
......@@ -348,7 +353,6 @@ void ParseInit(void *yypRawParser ParseCTX_PDECL){
yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#endif
}
%namespace_end
#ifndef Parse_ENGINEALWAYSONSTACK
/*
......@@ -363,7 +367,7 @@ void ParseInit(void *yypRawParser ParseCTX_PDECL){
** A pointer to a parser. This pointer is used in subsequent calls
** to Parse and ParseFree.
*/
%namespace_begin
YYFUNCAPI
void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){
yyParser *yypParser;
yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
......@@ -373,7 +377,6 @@ void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){
}
return (void*)yypParser;
}
%namespace_end
#endif /* Parse_ENGINEALWAYSONSTACK */
......@@ -433,7 +436,7 @@ static void yy_pop_parser_stack(yyParser *pParser){
/*
** Clear all secondary memory allocations from the parser
*/
%namespace_begin
YYFUNCAPI
void ParseFinalize(void *p){
yyParser *pParser = (yyParser*)p;
while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
......@@ -441,7 +444,6 @@ void ParseFinalize(void *p){
if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
#endif
}
%namespace_end
#ifndef Parse_ENGINEALWAYSONSTACK
/*
......@@ -452,7 +454,7 @@ void ParseFinalize(void *p){
** is defined in a %include section of the input grammar) then it is
** assumed that the input pointer is never NULL.
*/
%namespace_begin
YYFUNCAPI
void ParseFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
......@@ -463,19 +465,17 @@ void ParseFree(
ParseFinalize(p);
(*freeProc)(p);
}
%namespace_end
#endif /* Parse_ENGINEALWAYSONSTACK */
/*
** Return the peak depth of the stack for a parser.
*/
#ifdef YYTRACKMAXSTACKDEPTH
%namespace_begin
YYFUNCAPI
int ParseStackPeak(void *p){
yyParser *pParser = (yyParser*)p;
return pParser->yyhwm;
}
%namespace_end
#endif
/* This array of booleans keeps track of the parser statement
......@@ -496,7 +496,7 @@ static unsigned char yycoverage[YYNSTATE][YYNTOKEN];
** Return the number of missed state/lookahead combinations.
*/
#if defined(YYCOVERAGE)
%namespace_begin
YYFUNCAPI
int ParseCoverage(FILE *out){
int stateno, iLookAhead, i;
int nMissed = 0;
......@@ -514,7 +514,6 @@ int ParseCoverage(FILE *out){
}
return nMissed;
}
%namespace_end
#endif
/*
......@@ -905,7 +904,7 @@ static void yy_accept(
** Outputs:
** None.
*/
%namespace_begin
YYFUNCAPI
void Parse(
void *yyp, /* The parser */
int yymajor, /* The major token code number */
......@@ -1075,13 +1074,12 @@ void Parse(
#endif
return;
}
%namespace_end
/*
** Return the fallback token corresponding to canonical token iToken, or
** 0 if iToken has no fallback.
*/
%namespace_begin
YYFUNCAPI
int ParseFallback(int iToken){
#ifdef YYFALLBACK
assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
......@@ -1091,4 +1089,3 @@ int ParseFallback(int iToken){
return 0;
#endif
}
%namespace_end
--- lempar.c.orig 2020-01-10 14:08:55.225662130 +0100
+++ lempar.c 2020-01-10 14:31:25.891656998 +0100
@@ -251,12 +251,14 @@
--- lempar.c.orig 2020-07-09 14:55:42.000000000 +0200
+++ lempar.c 2020-07-10 11:04:51.991472607 +0200
@@ -93,6 +93,12 @@
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
+/* Default linkage for exposed parser routines is global
+*/
+#ifndef YYFUNCAPI
+# define YYFUNCAPI
+#endif
+
/* Define the yytestcase() macro to be a no-op if is not already defined
** otherwise.
**
@@ -251,6 +257,7 @@
** Outputs:
** None.
*/
+%namespace_begin
+YYFUNCAPI
void ParseTrace(FILE *TraceFILE, char *zTracePrompt){
yyTraceFILE = TraceFILE;
yyTracePrompt = zTracePrompt;
if( yyTraceFILE==0 ) yyTracePrompt = 0;
else if( yyTracePrompt==0 ) yyTraceFILE = 0;
}
+%namespace_end
#endif /* NDEBUG */
#if defined(YYCOVERAGE) || !defined(NDEBUG)
@@ -320,6 +322,7 @@
@@ -320,6 +327,7 @@
/* Initialize a new parser that has already been allocated.
*/
+%namespace_begin
+YYFUNCAPI
void ParseInit(void *yypRawParser ParseCTX_PDECL){
yyParser *yypParser = (yyParser*)yypRawParser;
ParseCTX_STORE
@@ -345,6 +348,7 @@
yypParser->yystackEnd = &yypParser->yystack[YYSTACKDEPTH-1];
#endif
}
+%namespace_end
#ifndef Parse_ENGINEALWAYSONSTACK
/*
@@ -359,6 +363,7 @@
@@ -359,6 +367,7 @@
** A pointer to a parser. This pointer is used in subsequent calls
** to Parse and ParseFree.
*/
+%namespace_begin
+YYFUNCAPI
void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE) ParseCTX_PDECL){
yyParser *yypParser;
yypParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) );
@@ -368,6 +373,7 @@
}
return (void*)yypParser;
}
+%namespace_end
#endif /* Parse_ENGINEALWAYSONSTACK */
@@ -427,6 +433,7 @@
@@ -427,6 +436,7 @@
/*
** Clear all secondary memory allocations from the parser
*/
+%namespace_begin
+YYFUNCAPI
void ParseFinalize(void *p){
yyParser *pParser = (yyParser*)p;
while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser);
@@ -434,6 +441,7 @@
if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack);
#endif
}
+%namespace_end
#ifndef Parse_ENGINEALWAYSONSTACK
/*
@@ -444,6 +452,7 @@
@@ -444,6 +454,7 @@
** is defined in a %include section of the input grammar) then it is
** assumed that the input pointer is never NULL.
*/
+%namespace_begin
+YYFUNCAPI
void ParseFree(
void *p, /* The parser to be deleted */
void (*freeProc)(void*) /* Function used to reclaim memory */
@@ -454,16 +463,19 @@
ParseFinalize(p);
(*freeProc)(p);
}
+%namespace_end
#endif /* Parse_ENGINEALWAYSONSTACK */
/*
@@ -460,6 +471,7 @@
** Return the peak depth of the stack for a parser.
*/
#ifdef YYTRACKMAXSTACKDEPTH
+%namespace_begin
+YYFUNCAPI
int ParseStackPeak(void *p){
yyParser *pParser = (yyParser*)p;
return pParser->yyhwm;
}
+%namespace_end
#endif
/* This array of booleans keeps track of the parser statement
@@ -484,6 +496,7 @@
** Return the number of missed state/lookahead combinations.
*/
#if defined(YYCOVERAGE)
+%namespace_begin
+YYFUNCAPI
int ParseCoverage(FILE *out){
int stateno, iLookAhead, i;
int nMissed = 0;
@@ -501,6 +514,7 @@
}
return nMissed;
}
+%namespace_end
#endif
/*
@@ -891,6 +905,7 @@
@@ -891,6 +904,7 @@
** Outputs:
** None.
*/
+%namespace_begin
+YYFUNCAPI
void Parse(
void *yyp, /* The parser */
int yymajor, /* The major token code number */
@@ -1060,11 +1075,13 @@
#endif
return;
}
+%namespace_end
/*
@@ -1065,6 +1079,7 @@
** Return the fallback token corresponding to canonical token iToken, or
** 0 if iToken has no fallback.
*/
+%namespace_begin
+YYFUNCAPI
int ParseFallback(int iToken){
#ifdef YYFALLBACK
assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
@@ -1074,3 +1091,4 @@
return 0;
#endif
}
+%namespace_end
Minimal changes to lemon for C++ integration.
- New '-e' command line option to define the code extension.
- Additional '-e' command line option to define the code extension.
By default this is 'c', but with this option can define something
like -ecxx etc for using a C++ compiler.
like '-ecxx' etc for using a C++ compiler.
- New '%namespace' directive. This can be used to embed the 'Parse*'
routines into a C++ namespace. The namespace can be anonymous or
contain multiple nested namespaces. For example,
- Additional '%static' Lemon directive, which is boolean-like:
%namespace {}
%namespace {ns1::ns2::ns3}
%static
One simple means to encapsulate code is to use an anonymous
namespace for the Lemon code and place all C++ interface code with
the %code block in the same translation unit.
This adds a 'static' qualifier to all of the 'Parse*' routines that
would otherwise have global linkage, thus making them only visible
in the same file-scope.
Can subsequently place all of the C++ interface code within a %code
block in the same translation unit.
This allows good encapsulation without fundamentally changing how
Lemon works.
--
2019-09-27
2020-07-10
/*
* Part of check-in [https://www.sqlite.org/src/info/fccfb8a9ed3c1df9]
* artifact:
* https://www.sqlite.org/src/raw/tool/lemon.c?name=a361b85fa230560b783006ac002a6a8bad214c3b9d7fa48980aecc2b691ddcad
/* https://sqlite.org/src/artifact/600a58b9
* Artifact 600a58b9d1b8ec5419373982428e927ca208826edacb91ca42ab94514d006039:
* File tool/lemon.c part of check-in [951d22b7] at 2020-07-03
*/
/*
** This file contains all sources (including headers) to the LEMON
......@@ -406,7 +405,6 @@ struct lemon {
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 */
......@@ -429,8 +427,10 @@ struct lemon {
int nlookaheadtab; /* Number of entries in yy_lookahead[] */
int tablesize; /* Total table size of all tables in bytes */
int basisflag; /* Print only basis configurations */
int printPreprocessed; /* Show preprocessor output on stdout */
int has_fallback; /* True if any %fallback is seen in the grammar */
int nolinenosflag; /* True if #line statements should not be printed */
int linkage; /* 1 if %static provided (use static linkage) */
char *argv0; /* Name of the program */
};
......@@ -1561,8 +1561,9 @@ static void handle_d_option(char *z){
}
/* Remember the name of the code extension (automatically prefix '.')
** default is "c" extension
*/
static char *code_ext = NULL;
static char *code_ext = ".c";
static void handle_e_option(char *z){
code_ext = (char *) malloc( lemonStrlen(z)+2 );
if( code_ext==0 ){
......@@ -1659,6 +1660,7 @@ int main(int argc, char **argv)
static int nolinenosflag = 0;
static int noResort = 0;
static int sqlFlag = 0;
static int printPP = 0;
static struct s_options options[] = {
{OPT_FLAG, "b", (char*)&basisflag, "Print only the basis in report."},
......@@ -1666,6 +1668,7 @@ int main(int argc, char **argv)
{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_FLAG, "E", (char*)&printPP, "Print input file after preprocessing."},
{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.)"},
......@@ -1710,11 +1713,12 @@ int main(int argc, char **argv)
lem.filename = OptArg(0);
lem.basisflag = basisflag;
lem.nolinenosflag = nolinenosflag;
lem.printPreprocessed = printPP;
Symbol_new("$");
/* Parse the input file */
Parse(&lem);
if( lem.errorcnt ) exit(lem.errorcnt);
if( lem.printPreprocessed || lem.errorcnt ) exit(lem.errorcnt);
if( lem.nrule==0 ){
fprintf(stderr,"Empty grammar.\n");
exit(1);
......@@ -2286,6 +2290,7 @@ static void parseonetoken(struct pstate *psp)
psp->preccounter = 0;
psp->firstrule = psp->lastrule = 0;
psp->gp->nrule = 0;
psp->gp->linkage = 0;
/* Fall thru to next case */
case WAITING_FOR_DECL_OR_RULE:
if( x[0]=='%' ){
......@@ -2509,9 +2514,6 @@ static void parseonetoken(struct pstate *psp)
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 ){
......@@ -2574,6 +2576,11 @@ static void parseonetoken(struct pstate *psp)
psp->state = WAITING_FOR_WILDCARD_ID;
}else if( strcmp(x,"token_class")==0 ){
psp->state = WAITING_FOR_CLASS_ID;
}else if( strcmp(x,"static")==0 ){
/* %static is boolean-like */
psp->gp->linkage = 1; /* 1 = static (True) */
psp->insertLineMacro = 0;
psp->state = WAITING_FOR_DECL_OR_RULE;
}else{
ErrorMsg(psp->filename,psp->tokenlineno,
"Unknown declaration keyword: \"%%%s\".",x);
......@@ -2806,13 +2813,108 @@ static void parseonetoken(struct pstate *psp)
}
}
/* The text in the input is part of the argument to an %ifdef or %ifndef.
** Evaluate the text as a boolean expression. Return true or false.
*/
static int eval_preprocessor_boolean(char *z, int lineno){
int neg = 0;
int res = 0;
int okTerm = 1;
int i;
for(i=0; z[i]!=0; i++){
if( ISSPACE(z[i]) ) continue;
if( z[i]=='!' ){
if( !okTerm ) goto pp_syntax_error;
neg = !neg;
continue;
}
if( z[i]=='|' && z[i+1]=='|' ){
if( okTerm ) goto pp_syntax_error;
if( res ) return 1;
i++;
okTerm = 1;
continue;
}
if( z[i]=='&' && z[i+1]=='&' ){
if( okTerm ) goto pp_syntax_error;
if( !res ) return 0;
i++;
okTerm = 1;
continue;
}
if( z[i]=='(' ){
int k;
int n = 1;
if( !okTerm ) goto pp_syntax_error;
for(k=i+1; z[k]; k++){
if( z[k]==')' ){
n--;
if( n==0 ){
z[k] = 0;
res = eval_preprocessor_boolean(&z[i+1], -1);
z[k] = ')';
if( res<0 ){
i = i-res;
goto pp_syntax_error;
}
i = k;
break;
}
}else if( z[k]=='(' ){
n++;
}else if( z[k]==0 ){
i = k;
goto pp_syntax_error;
}
}
if( neg ){
res = !res;
neg = 0;
}
okTerm = 0;
continue;
}
if( ISALPHA(z[i]) ){
int j, k, n;
if( !okTerm ) goto pp_syntax_error;
for(k=i+1; ISALNUM(z[k]) || z[k]=='_'; k++){}
n = k - i;
res = 0;
for(j=0; j<nDefine; j++){
if( strncmp(azDefine[j],&z[i],n)==0 && azDefine[j][n]==0 ){
res = 1;
break;
}
}
i = k-1;
if( neg ){
res = !res;
neg = 0;
}
okTerm = 0;
continue;
}
goto pp_syntax_error;
}
return res;
pp_syntax_error:
if( lineno>0 ){
fprintf(stderr, "%%if syntax error on line %d.\n", lineno);
fprintf(stderr, " %.*s <-- syntax error here\n", i+1, z);
exit(1);
}else{
return -(i+1);
}
}
/* Run the preprocessor over the input file text. The global variables
** azDefine[0] through azDefine[nDefine-1] contains the names of all defined
** macros. This routine looks for "%ifdef" and "%ifndef" and "%endif" and
** comments them out. Text in between is also commented out as appropriate.
*/
static void preprocess_input(char *z){
int i, j, k, n;
int i, j, k;
int exclude = 0;
int start = 0;
int lineno = 1;
......@@ -2828,21 +2930,33 @@ static void preprocess_input(char *z){
}
}
for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
}else if( (strncmp(&z[i],"%ifdef",6)==0 && ISSPACE(z[i+6]))
|| (strncmp(&z[i],"%ifndef",7)==0 && ISSPACE(z[i+7])) ){
}else if( strncmp(&z[i],"%else",5)==0 && ISSPACE(z[i+5]) ){
if( exclude==1){
exclude = 0;
for(j=start; j<i; j++) if( z[j]!='\n' ) z[j] = ' ';
}else if( exclude==0 ){
exclude = 1;
start = i;
start_lineno = lineno;
}
for(j=i; z[j] && z[j]!='\n'; j++) z[j] = ' ';
}else if( strncmp(&z[i],"%ifdef ",7)==0
|| strncmp(&z[i],"%if ",4)==0
|| strncmp(&z[i],"%ifndef ",8)==0 ){
if( exclude ){
exclude++;
}else{
for(j=i+7; ISSPACE(z[j]); j++){}
for(n=0; z[j+n] && !ISSPACE(z[j+n]); n++){}