In lemon, add "%if" and "%else" and allow boolean expressions as the

argument to "%if", "%ifdef", and "%ifndef".

FossilOrigin-Name: 951d22b72f80de9e23df645abcc3d88ca1a275b46ea23b84152ef48716922b37
This commit is contained in:
drh 2020-07-03 15:41:08 +00:00
parent 4b849b0b09
commit 0a34cf551c
3 changed files with 136 additions and 20 deletions

View File

@ -1,6 +1,6 @@
B 7a876209a678a34c198b54ceef9e3c041f128a14dc73357f6a57cadadaa6cf7b
C Fix\sthe\spragma_foreign_key_check\svirtual\stable\sso\sthat\sit\saccepts\sarguments.
D 2020-07-03T12:32:04.573
C In\slemon,\sadd\s"%if"\sand\s"%else"\sand\sallow\sboolean\sexpressions\sas\sthe\nargument\sto\s"%if",\s"%ifdef",\sand\s"%ifndef".
D 2020-07-03T15:41:08.646
F Makefile.in 19374a5db06c3199ec1bab71ab74a103d8abf21053c05e9389255dc58083f806
F Makefile.msc 48f5a3fc32672c09ad73795749f6253e406a31526935fbbffd8f021108d54574
F autoconf/Makefile.am a8d1d24affe52ebf8d7ddcf91aa973fa0316618ab95bb68c87cabf8faf527dc8
@ -34,13 +34,14 @@ F test/fuzzdata8.db 0ae860b36b79fd41cafddc9e6602358b2d5c331cf200283221e659f86e19
F test/gencol1.test b05e6c5edb9b10d48efb634ed07342441bddc89d225043e17095c36e567521a0
F test/ieee754.test b0945d12be7d255f3dfa18e2511b17ca37e0edd2b803231c52d05b86c04ab26e
F test/speedtest1.c a8b5afe72d78ff365012aba48d3f0c579e957facb7630f765f58a6ae4656d20d
F tool/lemon.c 600a58b9d1b8ec5419373982428e927ca208826edacb91ca42ab94514d006039
F tool/mkautoconfamal.sh f62353eb6c06ab264da027fd4507d09914433dbdcab9cb011cdc18016f1ab3b8
F tool/mkpragmatab.tcl ae5585ae76ca26e4d6ccd5ea9cdebaf5efefb318bf989497a0e846cd711d9ab1
F tool/mksqlite3c.tcl f4ef476510eca4124c874a72029f1e01bc54a896b1724e8f9eef0d8bfae0e84c
F tool/mksqlite3h.tcl 1f5e4a1dbbbc43c83cc6e74fe32c6c620502240b66c7c0f33a51378e78fc4edf
F tool/showlocks.c 9cc5e66d4ebbf2d194f39db2527ece92077e86ae627ddd233ee48e16e8142564
F tool/speed-check.sh 615cbdf50f1409ef3bbf9f682e396df80f49d97ed93ed3e61c8e91fae6afde58
P 81bc4b65ae2a68128b0be75a7a3d4f47f05cc588ff130ba56366ab9b16289228
R 959518f214ac8fa04f9479823db88ae3
P 07f849dee3d245ecf80ba3c3ce8dfc630e71ddb1e9c0bcc1f08cee22001fcb07
R ab4092566c985aba1362a3a393cab635
U drh
Z df6c0f239cac29280d3b9659da8bad1e
Z abad44d232bcc4ccdddfa3cd71995651

View File

@ -1 +1 @@
07f849dee3d245ecf80ba3c3ce8dfc630e71ddb1e9c0bcc1f08cee22001fcb07
951d22b72f80de9e23df645abcc3d88ca1a275b46ea23b84152ef48716922b37

View File

@ -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;