diff options
author | drh <drh@noemail.net> | 2020-07-03 15:41:08 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2020-07-03 15:41:08 +0000 |
commit | 0a34cf551cf68dc5778082fa5e7eefc41f9970b6 (patch) | |
tree | 136e88a6fde6f3d500b955aea24d496fdb70c41b /tool/lemon.c | |
parent | 4b849b0b09b1ed472c56effd50ebe09b6e2c4adf (diff) | |
download | sqlite-0a34cf551cf68dc5778082fa5e7eefc41f9970b6.tar.gz sqlite-0a34cf551cf68dc5778082fa5e7eefc41f9970b6.zip |
In lemon, add "%if" and "%else" and allow boolean expressions as the
argument to "%if", "%ifdef", and "%ifndef".
FossilOrigin-Name: 951d22b72f80de9e23df645abcc3d88ca1a275b46ea23b84152ef48716922b37
Diffstat (limited to 'tool/lemon.c')
-rw-r--r-- | tool/lemon.c | 143 |
1 files changed, 129 insertions, 14 deletions
diff --git a/tool/lemon.c b/tool/lemon.c index 8dcf65179..40e4e2894 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -423,6 +423,7 @@ 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 */ char *argv0; /* Name of the program */ @@ -1636,12 +1637,14 @@ 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."}, {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_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.)"}, @@ -1686,11 +1689,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); @@ -2779,13 +2783,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; @@ -2801,21 +2900,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++){} - exclude = 1; - for(k=0; k<nDefine; k++){ - if( strncmp(azDefine[k],&z[j],n)==0 && lemonStrlen(azDefine[k])==n ){ - exclude = 0; - break; - } - } - if( z[i+3]=='n' ) exclude = !exclude; + int isNot; + int iBool; + for(j=i; z[j] && !ISSPACE(z[j]); j++){} + iBool = j; + isNot = (j==i+7); + while( z[j] && z[j]!='\n' ){ j++; } + k = z[j]; + z[j] = 0; + exclude = eval_preprocessor_boolean(&z[iBool], lineno); + z[j] = k; + if( !isNot ) exclude = !exclude; if( exclude ){ start = i; start_lineno = lineno; @@ -2883,6 +2994,10 @@ void Parse(struct lemon *gp) /* Make an initial pass through the file to handle %ifdef and %ifndef */ preprocess_input(filebuf); + if( gp->printPreprocessed ){ + printf("%s\n", filebuf); + return; + } /* Now scan the text of the input file */ lineno = 1; |