Enhance Lemon to generate more compact and efficient code for yy_reduce().

Update the main SQL grammar to take advantage of the new capabilities.

FossilOrigin-Name: 53fd040c98d9647ea135d43c493777bf8da4aebd
This commit is contained in:
drh 2016-02-17 13:24:12 +00:00
commit b7997fe3a9
7 changed files with 412 additions and 284 deletions

View File

@ -161,8 +161,9 @@ such as ``identifier'' or ``number'' and the third argument will
be the name of the identifier or the value of the number.</p> be the name of the identifier or the value of the number.</p>
<p>The Parse() function may have either three or four arguments, <p>The Parse() function may have either three or four arguments,
depending on the grammar. If the grammar specification file request depending on the grammar. If the grammar specification file requests
it, the Parse() function will have a fourth parameter that can be it (via the <a href='#extraarg'><tt>extra_argument</tt> directive</a>),
the Parse() function will have a fourth parameter that can be
of any type chosen by the programmer. The parser doesn't do anything of any type chosen by the programmer. The parser doesn't do anything
with this argument except to pass it through to action routines. with this argument except to pass it through to action routines.
This is a convenient mechanism for passing state information down This is a convenient mechanism for passing state information down
@ -263,6 +264,12 @@ with prior yacc and bison experience.
But after years of experience using Lemon, I firmly But after years of experience using Lemon, I firmly
believe that the Lemon way of doing things is better.</p> believe that the Lemon way of doing things is better.</p>
<p><i>Updated as of 2016-02-16:</i>
The text above was written in the 1990s.
We are told that Bison has lately been enhanced to support the
tokenizer-calls-parser paradigm used by Lemon, and to obviate the
need for global variables.</p>
<h2>Input File Syntax</h2> <h2>Input File Syntax</h2>
<p>The main purpose of the grammar specification file for Lemon is <p>The main purpose of the grammar specification file for Lemon is
@ -617,6 +624,7 @@ build a parser using Lemon that can be used within a long-running
program, such as a GUI, that will not leak memory or other resources. program, such as a GUI, that will not leak memory or other resources.
To do the same using yacc or bison is much more difficult.</p> To do the same using yacc or bison is much more difficult.</p>
<a name="extraarg"></a>
<h4>The <tt>%extra_argument</tt> directive</h4> <h4>The <tt>%extra_argument</tt> directive</h4>
The %extra_argument directive instructs Lemon to add a 4th parameter The %extra_argument directive instructs Lemon to add a 4th parameter

View File

@ -34,7 +34,6 @@
); );
} }
%stack_overflow { %stack_overflow {
UNUSED_PARAM(yypMinor); /* Silence a compiler warning */
sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow"); sqlite3Fts5ParseError(pParse, "fts5: parser stack overflow");
} }

View File

@ -1,5 +1,5 @@
C Documentation\stypo\son\ssqlite3_wal_hook().\s\sNo\schanges\sto\scode. C Enhance\sLemon\sto\sgenerate\smore\scompact\sand\sefficient\scode\sfor\syy_reduce().\nUpdate\sthe\smain\sSQL\sgrammar\sto\stake\sadvantage\sof\sthe\snew\scapabilities.
D 2016-02-17T11:13:20.401 D 2016-02-17T13:24:12.055
F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142 F Makefile.in 4e90dc1521879022aa9479268a4cd141d1771142
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc 30f075dc4f27a07abb76088946b2944178d85347 F Makefile.msc 30f075dc4f27a07abb76088946b2944178d85347
@ -33,7 +33,7 @@ F config.sub 9ebe4c3b3dab6431ece34f16828b594fb420da55
F configure 12d96e3798e612e0ffa53a7a8c4d7fb1090df80e x F configure 12d96e3798e612e0ffa53a7a8c4d7fb1090df80e x
F configure.ac a2224b1162f79848982d3618ac1deffcd94e88ec F configure.ac a2224b1162f79848982d3618ac1deffcd94e88ec
F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad F contrib/sqlitecon.tcl 210a913ad63f9f991070821e599d600bd913e0ad
F doc/lemon.html 334dbf6621b8fb8790297ec1abf3cfa4621709d1 F doc/lemon.html c30255bea0fd87a81f082d17a72c9dffbc3f6dd9
F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710 F doc/pager-invariants.txt 27fed9a70ddad2088750c4a2b493b63853da2710
F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a F doc/vfs-shm.txt e101f27ea02a8387ce46a05be2b1a902a021d37a
F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1 F ext/README.txt 913a7bd3f4837ab14d7e063304181787658b14e1
@ -114,7 +114,7 @@ F ext/fts5/fts5_tokenize.c 2ce7b44183538ec46b7907726262ee43ffdd39a8
F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf F ext/fts5/fts5_unicode2.c b450b209b157d598f7b9df9f837afb75a14c24bf
F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738 F ext/fts5/fts5_varint.c a5aceacda04dafcbae725413d7a16818ecd65738
F ext/fts5/fts5_vocab.c dba72ca393d71c2588548b51380387f6b44c77a8 F ext/fts5/fts5_vocab.c dba72ca393d71c2588548b51380387f6b44c77a8
F ext/fts5/fts5parse.y 59432ea369f1aa65511bad465f55d31a22f9f223 F ext/fts5/fts5parse.y 86fe6ba094a47e02fe8be2571539e6833d197764
F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba F ext/fts5/mkportersteps.tcl 5acf962d2e0074f701620bb5308155fa1e4a63ba
F ext/fts5/test/fts5_common.tcl 61ff0d1a29d98a91c4553b20b3f410d858834ee9 F ext/fts5/test/fts5_common.tcl 61ff0d1a29d98a91c4553b20b3f410d858834ee9
F ext/fts5/test/fts5aa.test 7e814df4a0e6c22a6fe2d84f210fdc0b5068a084 F ext/fts5/test/fts5aa.test 7e814df4a0e6c22a6fe2d84f210fdc0b5068a084
@ -337,7 +337,7 @@ F src/os_win.c f0d7aa603eb6262143d7169a222aea07c4fca91d
F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca F src/os_win.h eb7a47aa17b26b77eb97e4823f20a00b8bda12ca
F src/pager.c 6812f3803951774b56abded396171e1c12b0b003 F src/pager.c 6812f3803951774b56abded396171e1c12b0b003
F src/pager.h f3eb324a3ff2408b28bab7e81c1c55c13720f865 F src/pager.h f3eb324a3ff2408b28bab7e81c1c55c13720f865
F src/parse.y d7bff41d460f2df96fb890f36700e85cb0fc5634 F src/parse.y c3ce2c4a7cbf0b699239be6b2a945c5cb51875e2
F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df F src/pcache.c 647bb53a86b7bbcf55ad88089b3ea5a9170b90df
F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545 F src/pcache.h 4d0ccaad264d360981ec5e6a2b596d6e85242545
F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051 F src/pcache1.c 72f644dc9e1468c72922eff5904048427b817051
@ -1378,8 +1378,8 @@ F tool/fuzzershell.c 94019b185caceffc9f7c7b678a6489e42bc2aefa
F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4 F tool/genfkey.README cf68fddd4643bbe3ff8e31b8b6d8b0a1b85e20f4
F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5 F tool/genfkey.test 4196a8928b78f51d54ef58e99e99401ab2f0a7e5
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/lemon.c 799e73e19a33b8dd7767a7fa34618ed2a9c2397d F tool/lemon.c 251f5c3f21b553240cbdd42dd187a51bb2372cd3
F tool/lempar.c ff7763747f93c9d7eac6df1e802a200b3f0e2cc0 F tool/lempar.c 5f626c741e034da827b4224d0c68eaf6d8fcc72c
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862 F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6 F tool/logest.c eef612f8adf4d0993dafed0416064cf50d5d33c6
F tool/mkautoconfamal.sh c78caa3214f25dc28ea157b5a82abb311f209906 F tool/mkautoconfamal.sh c78caa3214f25dc28ea157b5a82abb311f209906
@ -1427,7 +1427,8 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh a98af506df552f3b3c0d904f94e4cdc4e1a6d598 F tool/warnings.sh a98af506df552f3b3c0d904f94e4cdc4e1a6d598
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
P 9570b6b43df3bc5ce314cded20bca8be9e968efe P fc2043ebaa3f106529500164936bb82f9b921b1c 417e777701bbf4bd67626d4ca3bc2c5d847f6cd0
R fa7ad000641c654ec7b23cbb3e1a9847 R 2ca4dc2ba891e3629351ceac13b91136
T +closed 417e777701bbf4bd67626d4ca3bc2c5d847f6cd0
U drh U drh
Z 6e5104d61f82ea485c4100026aadb443 Z 146115d4bedb6d62469919152a1417e4

View File

@ -1 +1 @@
fc2043ebaa3f106529500164936bb82f9b921b1c 53fd040c98d9647ea135d43c493777bf8da4aebd

View File

@ -35,7 +35,6 @@
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN); sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &TOKEN);
} }
%stack_overflow { %stack_overflow {
UNUSED_PARAMETER(yypMinor); /* Silence some compiler warnings */
sqlite3ErrorMsg(pParse, "parser stack overflow"); sqlite3ErrorMsg(pParse, "parser stack overflow");
} }
@ -139,9 +138,9 @@ trans_opt ::= TRANSACTION.
trans_opt ::= TRANSACTION nm. trans_opt ::= TRANSACTION nm.
%type transtype {int} %type transtype {int}
transtype(A) ::= . {A = TK_DEFERRED;} transtype(A) ::= . {A = TK_DEFERRED;}
transtype(A) ::= DEFERRED(X). {A = @X;} transtype(A) ::= DEFERRED(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= IMMEDIATE(X). {A = @X;} transtype(A) ::= IMMEDIATE(X). {A = @X; /*A-overwrites-X*/}
transtype(A) ::= EXCLUSIVE(X). {A = @X;} transtype(A) ::= EXCLUSIVE(X). {A = @X; /*A-overwrites-X*/}
cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= COMMIT trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);} cmd ::= END trans_opt. {sqlite3CommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);} cmd ::= ROLLBACK trans_opt. {sqlite3RollbackTransaction(pParse);}
@ -164,10 +163,8 @@ cmd ::= create_table create_table_args.
create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). { create_table ::= createkw temp(T) TABLE ifnotexists(E) nm(Y) dbnm(Z). {
sqlite3StartTable(pParse,&Y,&Z,T,0,0,E); sqlite3StartTable(pParse,&Y,&Z,T,0,0,E);
} }
createkw(A) ::= CREATE(X). { createkw(A) ::= CREATE(A). {disableLookaside(pParse);}
disableLookaside(pParse);
A = X;
}
%type ifnotexists {int} %type ifnotexists {int}
ifnotexists(A) ::= . {A = 0;} ifnotexists(A) ::= . {A = 0;}
ifnotexists(A) ::= IF NOT EXISTS. {A = 1;} ifnotexists(A) ::= IF NOT EXISTS. {A = 1;}
@ -201,13 +198,11 @@ columnlist ::= column.
// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES, // datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
// NOT NULL and so forth. // NOT NULL and so forth.
// //
column(A) ::= columnid(X) type carglist. { column(A) ::= columnid(A) type carglist. {
A.z = X.z; A.n = (int)(pParse->sLastToken.z-A.z) + pParse->sLastToken.n;
A.n = (int)(pParse->sLastToken.z-X.z) + pParse->sLastToken.n;
} }
columnid(A) ::= nm(X). { columnid(A) ::= nm(A). {
sqlite3AddColumn(pParse,&X); sqlite3AddColumn(pParse,&A);
A = X;
pParse->constraintName.n = 0; pParse->constraintName.n = 0;
} }
@ -265,9 +260,9 @@ columnid(A) ::= nm(X). {
// The name of a column or table can be any of the following: // The name of a column or table can be any of the following:
// //
%type nm {Token} %type nm {Token}
nm(A) ::= id(X). {A = X;} nm(A) ::= id(A).
nm(A) ::= STRING(X). {A = X;} nm(A) ::= STRING(A).
nm(A) ::= JOIN_KW(X). {A = X;} nm(A) ::= JOIN_KW(A).
// A typetoken is really one or more tokens that form a type name such // A typetoken is really one or more tokens that form a type name such
// as can be found after the column name in a CREATE TABLE statement. // as can be found after the column name in a CREATE TABLE statement.
@ -276,18 +271,16 @@ nm(A) ::= JOIN_KW(X). {A = X;}
%type typetoken {Token} %type typetoken {Token}
type ::= . type ::= .
type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);} type ::= typetoken(X). {sqlite3AddColumnType(pParse,&X);}
typetoken(A) ::= typename(X). {A = X;} typetoken(A) ::= typename(A).
typetoken(A) ::= typename(X) LP signed RP(Y). { typetoken(A) ::= typename(A) LP signed RP(Y). {
A.z = X.z; A.n = (int)(&Y.z[Y.n] - A.z);
A.n = (int)(&Y.z[Y.n] - X.z);
} }
typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). { typetoken(A) ::= typename(A) LP signed COMMA signed RP(Y). {
A.z = X.z; A.n = (int)(&Y.z[Y.n] - A.z);
A.n = (int)(&Y.z[Y.n] - X.z);
} }
%type typename {Token} %type typename {Token}
typename(A) ::= ids(X). {A = X;} typename(A) ::= ids(A).
typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(int)(Y.z-X.z);} typename(A) ::= typename(A) ids(Y). {A.n=Y.n+(int)(Y.z-A.z);}
signed ::= plus_num. signed ::= plus_num.
signed ::= minus_num. signed ::= minus_num.
@ -309,7 +302,7 @@ ccons ::= DEFAULT MINUS(A) term(X). {
} }
ccons ::= DEFAULT id(X). { ccons ::= DEFAULT id(X). {
ExprSpan v; ExprSpan v;
spanExpr(&v, pParse, TK_STRING, &X); spanExpr(&v, pParse, TK_STRING, X);
sqlite3AddDefaultValue(pParse,&v); sqlite3AddDefaultValue(pParse,&v);
} }
@ -339,7 +332,7 @@ autoinc(X) ::= AUTOINCR. {X = 1;}
// //
%type refargs {int} %type refargs {int}
refargs(A) ::= . { A = OE_None*0x0101; /* EV: R-19803-45884 */} refargs(A) ::= . { A = OE_None*0x0101; /* EV: R-19803-45884 */}
refargs(A) ::= refargs(X) refarg(Y). { A = (X & ~Y.mask) | Y.value; } refargs(A) ::= refargs(A) refarg(Y). { A = (A & ~Y.mask) | Y.value; }
%type refarg {struct {int value; int mask;}} %type refarg {struct {int value; int mask;}}
refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; } refarg(A) ::= MATCH nm. { A.value = 0; A.mask = 0x000000; }
refarg(A) ::= ON INSERT refact. { A.value = 0; A.mask = 0x000000; } refarg(A) ::= ON INSERT refact. { A.value = 0; A.mask = 0x000000; }
@ -360,7 +353,7 @@ init_deferred_pred_opt(A) ::= INITIALLY DEFERRED. {A = 1;}
init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;} init_deferred_pred_opt(A) ::= INITIALLY IMMEDIATE. {A = 0;}
conslist_opt(A) ::= . {A.n = 0; A.z = 0;} conslist_opt(A) ::= . {A.n = 0; A.z = 0;}
conslist_opt(A) ::= COMMA(X) conslist. {A = X;} conslist_opt(A) ::= COMMA(A) conslist.
conslist ::= conslist tconscomma tcons. conslist ::= conslist tconscomma tcons.
conslist ::= tcons. conslist ::= tcons.
tconscomma ::= COMMA. {pParse->constraintName.n = 0;} tconscomma ::= COMMA. {pParse->constraintName.n = 0;}
@ -379,7 +372,7 @@ tcons ::= FOREIGN KEY LP eidlist(FA) RP
} }
%type defer_subclause_opt {int} %type defer_subclause_opt {int}
defer_subclause_opt(A) ::= . {A = 0;} defer_subclause_opt(A) ::= . {A = 0;}
defer_subclause_opt(A) ::= defer_subclause(X). {A = X;} defer_subclause_opt(A) ::= defer_subclause(A).
// The following is a non-standard extension that allows us to declare the // The following is a non-standard extension that allows us to declare the
// default behavior when there is a constraint conflict. // default behavior when there is a constraint conflict.
@ -391,7 +384,7 @@ onconf(A) ::= . {A = OE_Default;}
onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;} onconf(A) ::= ON CONFLICT resolvetype(X). {A = X;}
orconf(A) ::= . {A = OE_Default;} orconf(A) ::= . {A = OE_Default;}
orconf(A) ::= OR resolvetype(X). {A = X;} orconf(A) ::= OR resolvetype(X). {A = X;}
resolvetype(A) ::= raisetype(X). {A = X;} resolvetype(A) ::= raisetype(A).
resolvetype(A) ::= IGNORE. {A = OE_Ignore;} resolvetype(A) ::= IGNORE. {A = OE_Ignore;}
resolvetype(A) ::= REPLACE. {A = OE_Replace;} resolvetype(A) ::= REPLACE. {A = OE_Replace;}
@ -463,14 +456,14 @@ select(A) ::= with(W) selectnowith(X). {
}else{ }else{
sqlite3WithDelete(pParse->db, W); sqlite3WithDelete(pParse->db, W);
} }
A = p; A = p; /*A-overwrites-W*/
} }
selectnowith(A) ::= oneselect(X). {A = X;} selectnowith(A) ::= oneselect(A).
%ifndef SQLITE_OMIT_COMPOUND_SELECT %ifndef SQLITE_OMIT_COMPOUND_SELECT
selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). { selectnowith(A) ::= selectnowith(A) multiselect_op(Y) oneselect(Z). {
Select *pRhs = Z; Select *pRhs = Z;
Select *pLhs = X; Select *pLhs = A;
if( pRhs && pRhs->pPrior ){ if( pRhs && pRhs->pPrior ){
SrcList *pFrom; SrcList *pFrom;
Token x; Token x;
@ -491,12 +484,15 @@ selectnowith(A) ::= selectnowith(X) multiselect_op(Y) oneselect(Z). {
A = pRhs; A = pRhs;
} }
%type multiselect_op {int} %type multiselect_op {int}
multiselect_op(A) ::= UNION(OP). {A = @OP;} multiselect_op(A) ::= UNION(OP). {A = @OP; /*A-overwrites-OP*/}
multiselect_op(A) ::= UNION ALL. {A = TK_ALL;} multiselect_op(A) ::= UNION ALL. {A = TK_ALL;}
multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP;} multiselect_op(A) ::= EXCEPT|INTERSECT(OP). {A = @OP; /*A-overwrites-OP*/}
%endif SQLITE_OMIT_COMPOUND_SELECT %endif SQLITE_OMIT_COMPOUND_SELECT
oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y) oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). { groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
#if SELECTTRACE_ENABLED
Token s = S; /*A-overwrites-S*/
#endif
A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset); A = sqlite3SelectNew(pParse,W,X,Y,P,Q,Z,D,L.pLimit,L.pOffset);
#if SELECTTRACE_ENABLED #if SELECTTRACE_ENABLED
/* Populate the Select.zSelName[] string that is used to help with /* Populate the Select.zSelName[] string that is used to help with
@ -509,7 +505,7 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
** is an integer that is incremented with each SELECT statement seen. ** is an integer that is incremented with each SELECT statement seen.
*/ */
if( A!=0 ){ if( A!=0 ){
const char *z = S.z+6; const char *z = s.z+6;
int i; int i;
sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d", sqlite3_snprintf(sizeof(A->zSelName), A->zSelName, "#%d",
++pParse->nSelect); ++pParse->nSelect);
@ -523,20 +519,19 @@ oneselect(A) ::= SELECT(S) distinct(D) selcollist(W) from(X) where_opt(Y)
} }
#endif /* SELECTRACE_ENABLED */ #endif /* SELECTRACE_ENABLED */
} }
oneselect(A) ::= values(X). {A = X;} oneselect(A) ::= values(A).
%type values {Select*} %type values {Select*}
%destructor values {sqlite3SelectDelete(pParse->db, $$);} %destructor values {sqlite3SelectDelete(pParse->db, $$);}
values(A) ::= VALUES LP nexprlist(X) RP. { values(A) ::= VALUES LP nexprlist(X) RP. {
A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0); A = sqlite3SelectNew(pParse,X,0,0,0,0,0,SF_Values,0,0);
} }
values(A) ::= values(X) COMMA LP exprlist(Y) RP. { values(A) ::= values(A) COMMA LP exprlist(Y) RP. {
Select *pRight, *pLeft = X; Select *pRight, *pLeft = A;
pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0); pRight = sqlite3SelectNew(pParse,Y,0,0,0,0,0,SF_Values|SF_MultiValue,0,0);
if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue; if( ALWAYS(pLeft) ) pLeft->selFlags &= ~SF_MultiValue;
if( pRight ){ if( pRight ){
pRight->op = TK_ALL; pRight->op = TK_ALL;
pLeft = X;
pRight->pPrior = pLeft; pRight->pPrior = pLeft;
A = pRight; A = pRight;
}else{ }else{
@ -561,22 +556,22 @@ distinct(A) ::= . {A = 0;}
%destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);} %destructor selcollist {sqlite3ExprListDelete(pParse->db, $$);}
%type sclp {ExprList*} %type sclp {ExprList*}
%destructor sclp {sqlite3ExprListDelete(pParse->db, $$);} %destructor sclp {sqlite3ExprListDelete(pParse->db, $$);}
sclp(A) ::= selcollist(X) COMMA. {A = X;} sclp(A) ::= selcollist(A) COMMA.
sclp(A) ::= . {A = 0;} sclp(A) ::= . {A = 0;}
selcollist(A) ::= sclp(P) expr(X) as(Y). { selcollist(A) ::= sclp(A) expr(X) as(Y). {
A = sqlite3ExprListAppend(pParse, P, X.pExpr); A = sqlite3ExprListAppend(pParse, A, X.pExpr);
if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1); if( Y.n>0 ) sqlite3ExprListSetName(pParse, A, &Y, 1);
sqlite3ExprListSetSpan(pParse,A,&X); sqlite3ExprListSetSpan(pParse,A,&X);
} }
selcollist(A) ::= sclp(P) STAR. { selcollist(A) ::= sclp(A) STAR. {
Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0); Expr *p = sqlite3Expr(pParse->db, TK_ASTERISK, 0);
A = sqlite3ExprListAppend(pParse, P, p); A = sqlite3ExprListAppend(pParse, A, p);
} }
selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). { selcollist(A) ::= sclp(A) nm(X) DOT STAR(Y). {
Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &Y); Expr *pRight = sqlite3PExpr(pParse, TK_ASTERISK, 0, 0, &Y);
Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X); Expr *pLeft = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0); Expr *pDot = sqlite3PExpr(pParse, TK_DOT, pLeft, pRight, 0);
A = sqlite3ExprListAppend(pParse,P, pDot); A = sqlite3ExprListAppend(pParse,A, pDot);
} }
// An option "AS <id>" phrase that can follow one of the expressions that // An option "AS <id>" phrase that can follow one of the expressions that
@ -584,7 +579,7 @@ selcollist(A) ::= sclp(P) nm(X) DOT STAR(Y). {
// //
%type as {Token} %type as {Token}
as(X) ::= AS nm(Y). {X = Y;} as(X) ::= AS nm(Y). {X = Y;}
as(X) ::= ids(Y). {X = Y;} as(X) ::= ids(X).
as(X) ::= . {X.n = 0;} as(X) ::= . {X.n = 0;}
@ -606,32 +601,31 @@ from(A) ::= FROM seltablist(X). {
// "seltablist" is a "Select Table List" - the content of the FROM clause // "seltablist" is a "Select Table List" - the content of the FROM clause
// in a SELECT statement. "stl_prefix" is a prefix of this list. // in a SELECT statement. "stl_prefix" is a prefix of this list.
// //
stl_prefix(A) ::= seltablist(X) joinop(Y). { stl_prefix(A) ::= seltablist(A) joinop(Y). {
A = X;
if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y; if( ALWAYS(A && A->nSrc>0) ) A->a[A->nSrc-1].fg.jointype = (u8)Y;
} }
stl_prefix(A) ::= . {A = 0;} stl_prefix(A) ::= . {A = 0;}
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) as(Z) indexed_opt(I) seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) as(Z) indexed_opt(I)
on_opt(N) using_opt(U). { on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
sqlite3SrcListIndexedBy(pParse, A, &I); sqlite3SrcListIndexedBy(pParse, A, &I);
} }
seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) LP exprlist(E) RP as(Z) seltablist(A) ::= stl_prefix(A) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
on_opt(N) using_opt(U). { on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,&Y,&D,&Z,0,N,U); A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U);
sqlite3SrcListFuncArgs(pParse, A, E); sqlite3SrcListFuncArgs(pParse, A, E);
} }
%ifndef SQLITE_OMIT_SUBQUERY %ifndef SQLITE_OMIT_SUBQUERY
seltablist(A) ::= stl_prefix(X) LP select(S) RP seltablist(A) ::= stl_prefix(A) LP select(S) RP
as(Z) on_opt(N) using_opt(U). { as(Z) on_opt(N) using_opt(U). {
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,S,N,U); A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U);
} }
seltablist(A) ::= stl_prefix(X) LP seltablist(F) RP seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP
as(Z) on_opt(N) using_opt(U). { as(Z) on_opt(N) using_opt(U). {
if( X==0 && Z.n==0 && N==0 && U==0 ){ if( A==0 && Z.n==0 && N==0 && U==0 ){
A = F; A = F;
}else if( F->nSrc==1 ){ }else if( F->nSrc==1 ){
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,0,N,U); A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U);
if( A ){ if( A ){
struct SrcList_item *pNew = &A->a[A->nSrc-1]; struct SrcList_item *pNew = &A->a[A->nSrc-1];
struct SrcList_item *pOld = F->a; struct SrcList_item *pOld = F->a;
@ -646,7 +640,7 @@ seltablist(A) ::= stl_prefix(X) nm(Y) dbnm(D) LP exprlist(E) RP as(Z)
Select *pSubquery; Select *pSubquery;
sqlite3SrcListShiftJoinType(F); sqlite3SrcListShiftJoinType(F);
pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0,0);
A = sqlite3SrcListAppendFromTerm(pParse,X,0,0,&Z,pSubquery,N,U); A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U);
} }
} }
%endif SQLITE_OMIT_SUBQUERY %endif SQLITE_OMIT_SUBQUERY
@ -657,14 +651,17 @@ dbnm(A) ::= DOT nm(X). {A = X;}
%type fullname {SrcList*} %type fullname {SrcList*}
%destructor fullname {sqlite3SrcListDelete(pParse->db, $$);} %destructor fullname {sqlite3SrcListDelete(pParse->db, $$);}
fullname(A) ::= nm(X) dbnm(Y). {A = sqlite3SrcListAppend(pParse->db,0,&X,&Y);} fullname(A) ::= nm(X) dbnm(Y).
{A = sqlite3SrcListAppend(pParse->db,0,&X,&Y); /*A-overwrites-X*/}
%type joinop {int} %type joinop {int}
joinop(X) ::= COMMA|JOIN. { X = JT_INNER; } joinop(X) ::= COMMA|JOIN. { X = JT_INNER; }
joinop(X) ::= JOIN_KW(A) JOIN. { X = sqlite3JoinType(pParse,&A,0,0); } joinop(X) ::= JOIN_KW(A) JOIN.
joinop(X) ::= JOIN_KW(A) nm(B) JOIN. { X = sqlite3JoinType(pParse,&A,&B,0); } {X = sqlite3JoinType(pParse,&A,0,0); /*X-overwrites-A*/}
joinop(X) ::= JOIN_KW(A) nm(B) JOIN.
{X = sqlite3JoinType(pParse,&A,&B,0); /*X-overwrites-A*/}
joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN. joinop(X) ::= JOIN_KW(A) nm(B) nm(C) JOIN.
{ X = sqlite3JoinType(pParse,&A,&B,&C); } {X = sqlite3JoinType(pParse,&A,&B,&C);/*X-overwrites-A*/}
%type on_opt {Expr*} %type on_opt {Expr*}
%destructor on_opt {sqlite3ExprDelete(pParse->db, $$);} %destructor on_opt {sqlite3ExprDelete(pParse->db, $$);}
@ -704,12 +701,12 @@ using_opt(U) ::= . {U = 0;}
orderby_opt(A) ::= . {A = 0;} orderby_opt(A) ::= . {A = 0;}
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;} orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). { sortlist(A) ::= sortlist(A) COMMA expr(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,X,Y.pExpr); A = sqlite3ExprListAppend(pParse,A,Y.pExpr);
sqlite3ExprListSetSortOrder(A,Z); sqlite3ExprListSetSortOrder(A,Z);
} }
sortlist(A) ::= expr(Y) sortorder(Z). { sortlist(A) ::= expr(Y) sortorder(Z). {
A = sqlite3ExprListAppend(pParse,0,Y.pExpr); A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/
sqlite3ExprListSetSortOrder(A,Z); sqlite3ExprListSetSortOrder(A,Z);
} }
@ -799,8 +796,8 @@ cmd ::= with(C) UPDATE orconf(R) fullname(X) indexed_opt(I) SET setlist(Y)
%type setlist {ExprList*} %type setlist {ExprList*}
%destructor setlist {sqlite3ExprListDelete(pParse->db, $$);} %destructor setlist {sqlite3ExprListDelete(pParse->db, $$);}
setlist(A) ::= setlist(Z) COMMA nm(X) EQ expr(Y). { setlist(A) ::= setlist(A) COMMA nm(X) EQ expr(Y). {
A = sqlite3ExprListAppend(pParse, Z, Y.pExpr); A = sqlite3ExprListAppend(pParse, A, Y.pExpr);
sqlite3ExprListSetName(pParse, A, &X, 1); sqlite3ExprListSetName(pParse, A, &X, 1);
} }
setlist(A) ::= nm(X) EQ expr(Y). { setlist(A) ::= nm(X) EQ expr(Y). {
@ -831,10 +828,10 @@ insert_cmd(A) ::= REPLACE. {A = OE_Replace;}
idlist_opt(A) ::= . {A = 0;} idlist_opt(A) ::= . {A = 0;}
idlist_opt(A) ::= LP idlist(X) RP. {A = X;} idlist_opt(A) ::= LP idlist(X) RP. {A = X;}
idlist(A) ::= idlist(X) COMMA nm(Y). idlist(A) ::= idlist(A) COMMA nm(Y).
{A = sqlite3IdListAppend(pParse->db,X,&Y);} {A = sqlite3IdListAppend(pParse->db,A,&Y);}
idlist(A) ::= nm(Y). idlist(A) ::= nm(Y).
{A = sqlite3IdListAppend(pParse->db,0,&Y);} {A = sqlite3IdListAppend(pParse->db,0,&Y); /*A-overwrites-Y*/}
/////////////////////////// Expression Processing ///////////////////////////// /////////////////////////// Expression Processing /////////////////////////////
// //
@ -858,61 +855,62 @@ idlist(A) ::= nm(Y).
** new Expr to populate pOut. Set the span of pOut to be the identifier ** new Expr to populate pOut. Set the span of pOut to be the identifier
** that created the expression. ** that created the expression.
*/ */
static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token *pValue){ static void spanExpr(ExprSpan *pOut, Parse *pParse, int op, Token t){
pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, pValue); pOut->pExpr = sqlite3PExpr(pParse, op, 0, 0, &t);
pOut->zStart = pValue->z; pOut->zStart = t.z;
pOut->zEnd = &pValue->z[pValue->n]; pOut->zEnd = &t.z[t.n];
} }
} }
expr(A) ::= term(X). {A = X;} expr(A) ::= term(A).
expr(A) ::= LP(B) expr(X) RP(E). {A.pExpr = X.pExpr; spanSet(&A,&B,&E);} expr(A) ::= LP(B) expr(X) RP(E).
term(A) ::= NULL(X). {spanExpr(&A, pParse, @X, &X);} {spanSet(&A,&B,&E); /*A-overwrites-B*/ A.pExpr = X.pExpr;}
expr(A) ::= id(X). {spanExpr(&A, pParse, TK_ID, &X);} term(A) ::= NULL(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
expr(A) ::= JOIN_KW(X). {spanExpr(&A, pParse, TK_ID, &X);} expr(A) ::= id(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
expr(A) ::= JOIN_KW(X). {spanExpr(&A,pParse,TK_ID,X); /*A-overwrites-X*/}
expr(A) ::= nm(X) DOT nm(Y). { expr(A) ::= nm(X) DOT nm(Y). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X); Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y); Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
spanSet(&A,&X,&Y); /*A-overwrites-X*/
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0); A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp2, 0);
spanSet(&A,&X,&Y);
} }
expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). { expr(A) ::= nm(X) DOT nm(Y) DOT nm(Z). {
Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X); Expr *temp1 = sqlite3PExpr(pParse, TK_ID, 0, 0, &X);
Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y); Expr *temp2 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Y);
Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z); Expr *temp3 = sqlite3PExpr(pParse, TK_ID, 0, 0, &Z);
Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0); Expr *temp4 = sqlite3PExpr(pParse, TK_DOT, temp2, temp3, 0);
spanSet(&A,&X,&Z); /*A-overwrites-X*/
A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0); A.pExpr = sqlite3PExpr(pParse, TK_DOT, temp1, temp4, 0);
spanSet(&A,&X,&Z);
} }
term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A, pParse, @X, &X);} term(A) ::= INTEGER|FLOAT|BLOB(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
term(A) ::= STRING(X). {spanExpr(&A, pParse, @X, &X);} term(A) ::= STRING(X). {spanExpr(&A,pParse,@X,X);/*A-overwrites-X*/}
expr(A) ::= VARIABLE(X). { expr(A) ::= VARIABLE(X). {
if( X.n>=2 && X.z[0]=='#' && sqlite3Isdigit(X.z[1]) ){ Token t = X; /*A-overwrites-X*/
if( t.n>=2 && t.z[0]=='#' && sqlite3Isdigit(t.z[1]) ){
/* When doing a nested parse, one can include terms in an expression /* When doing a nested parse, one can include terms in an expression
** that look like this: #1 #2 ... These terms refer to registers ** that look like this: #1 #2 ... These terms refer to registers
** in the virtual machine. #N is the N-th register. */ ** in the virtual machine. #N is the N-th register. */
spanSet(&A, &t, &t);
if( pParse->nested==0 ){ if( pParse->nested==0 ){
sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &X); sqlite3ErrorMsg(pParse, "near \"%T\": syntax error", &t);
A.pExpr = 0; A.pExpr = 0;
}else{ }else{
A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &X); A.pExpr = sqlite3PExpr(pParse, TK_REGISTER, 0, 0, &t);
if( A.pExpr ) sqlite3GetInt32(&X.z[1], &A.pExpr->iTable); if( A.pExpr ) sqlite3GetInt32(&t.z[1], &A.pExpr->iTable);
} }
}else{ }else{
spanExpr(&A, pParse, TK_VARIABLE, &X); spanExpr(&A, pParse, TK_VARIABLE, t);
sqlite3ExprAssignVarNumber(pParse, A.pExpr); sqlite3ExprAssignVarNumber(pParse, A.pExpr);
} }
spanSet(&A, &X, &X);
} }
expr(A) ::= expr(E) COLLATE ids(C). { expr(A) ::= expr(A) COLLATE ids(C). {
A.pExpr = sqlite3ExprAddCollateToken(pParse, E.pExpr, &C, 1); A.pExpr = sqlite3ExprAddCollateToken(pParse, A.pExpr, &C, 1);
A.zStart = E.zStart;
A.zEnd = &C.z[C.n]; A.zEnd = &C.z[C.n];
} }
%ifndef SQLITE_OMIT_CAST %ifndef SQLITE_OMIT_CAST
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). { expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
spanSet(&A,&X,&Y); /*A-overwrites-X*/
A.pExpr = sqlite3PExpr(pParse, TK_CAST, E.pExpr, 0, &T); A.pExpr = sqlite3PExpr(pParse, TK_CAST, E.pExpr, 0, &T);
spanSet(&A,&X,&Y);
} }
%endif SQLITE_OMIT_CAST %endif SQLITE_OMIT_CAST
expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). { expr(A) ::= id(X) LP distinct(D) exprlist(Y) RP(E). {
@ -939,58 +937,56 @@ term(A) ::= CTIME_KW(OP). {
** objects and uses the result to populate a new ExprSpan object. ** objects and uses the result to populate a new ExprSpan object.
*/ */
static void spanBinaryExpr( static void spanBinaryExpr(
ExprSpan *pOut, /* Write the result here */
Parse *pParse, /* The parsing context. Errors accumulate here */ Parse *pParse, /* The parsing context. Errors accumulate here */
int op, /* The binary operation */ int op, /* The binary operation */
ExprSpan *pLeft, /* The left operand */ ExprSpan *pLeft, /* The left operand, and output */
ExprSpan *pRight /* The right operand */ ExprSpan *pRight /* The right operand */
){ ){
pOut->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0); pLeft->pExpr = sqlite3PExpr(pParse, op, pLeft->pExpr, pRight->pExpr, 0);
pOut->zStart = pLeft->zStart; pLeft->zEnd = pRight->zEnd;
pOut->zEnd = pRight->zEnd;
} }
/* If doNot is true, then add a TK_NOT Expr-node wrapper around the /* If doNot is true, then add a TK_NOT Expr-node wrapper around the
** outside of *ppExpr. ** outside of *ppExpr.
*/ */
static void exprNot(Parse *pParse, int doNot, Expr **ppExpr){ static void exprNot(Parse *pParse, int doNot, ExprSpan *pSpan){
if( doNot ) *ppExpr = sqlite3PExpr(pParse, TK_NOT, *ppExpr, 0, 0); if( doNot ){
pSpan->pExpr = sqlite3PExpr(pParse, TK_NOT, pSpan->pExpr, 0, 0);
}
} }
} }
expr(A) ::= expr(X) AND(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} expr(A) ::= expr(A) AND(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) OR(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} expr(A) ::= expr(A) OR(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) LT|GT|GE|LE(OP) expr(Y). expr(A) ::= expr(A) LT|GT|GE|LE(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);} {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) EQ|NE(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} expr(A) ::= expr(A) EQ|NE(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y). expr(A) ::= expr(A) BITAND|BITOR|LSHIFT|RSHIFT(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);} {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) PLUS|MINUS(OP) expr(Y). expr(A) ::= expr(A) PLUS|MINUS(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);} {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) STAR|SLASH|REM(OP) expr(Y). expr(A) ::= expr(A) STAR|SLASH|REM(OP) expr(Y).
{spanBinaryExpr(&A,pParse,@OP,&X,&Y);} {spanBinaryExpr(pParse,@OP,&A,&Y);}
expr(A) ::= expr(X) CONCAT(OP) expr(Y). {spanBinaryExpr(&A,pParse,@OP,&X,&Y);} expr(A) ::= expr(A) CONCAT(OP) expr(Y). {spanBinaryExpr(pParse,@OP,&A,&Y);}
%type likeop {struct LikeOp} %type likeop {struct LikeOp}
likeop(A) ::= LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 0;} likeop(A) ::= LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 0;/*A-overwrites-X*/}
likeop(A) ::= NOT LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 1;} likeop(A) ::= NOT LIKE_KW|MATCH(X). {A.eOperator = X; A.bNot = 1;}
expr(A) ::= expr(X) likeop(OP) expr(Y). [LIKE_KW] { expr(A) ::= expr(A) likeop(OP) expr(Y). [LIKE_KW] {
ExprList *pList; ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr); pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr); pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator); A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
exprNot(pParse, OP.bNot, &A.pExpr); exprNot(pParse, OP.bNot, &A);
A.zStart = X.zStart;
A.zEnd = Y.zEnd; A.zEnd = Y.zEnd;
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc; if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
} }
expr(A) ::= expr(X) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] { expr(A) ::= expr(A) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
ExprList *pList; ExprList *pList;
pList = sqlite3ExprListAppend(pParse,0, Y.pExpr); pList = sqlite3ExprListAppend(pParse,0, Y.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, X.pExpr); pList = sqlite3ExprListAppend(pParse,pList, A.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, E.pExpr); pList = sqlite3ExprListAppend(pParse,pList, E.pExpr);
A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator); A.pExpr = sqlite3ExprFunction(pParse, pList, &OP.eOperator);
exprNot(pParse, OP.bNot, &A.pExpr); exprNot(pParse, OP.bNot, &A);
A.zStart = X.zStart;
A.zEnd = E.zEnd; A.zEnd = E.zEnd;
if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc; if( A.pExpr ) A.pExpr->flags |= EP_InfixFunc;
} }
@ -999,20 +995,18 @@ expr(A) ::= expr(X) likeop(OP) expr(Y) ESCAPE expr(E). [LIKE_KW] {
/* Construct an expression node for a unary postfix operator /* Construct an expression node for a unary postfix operator
*/ */
static void spanUnaryPostfix( static void spanUnaryPostfix(
ExprSpan *pOut, /* Write the new expression node here */
Parse *pParse, /* Parsing context to record errors */ Parse *pParse, /* Parsing context to record errors */
int op, /* The operator */ int op, /* The operator */
ExprSpan *pOperand, /* The operand */ ExprSpan *pOperand, /* The operand, and output */
Token *pPostOp /* The operand token for setting the span */ Token *pPostOp /* The operand token for setting the span */
){ ){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0); pOperand->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pOperand->zStart; pOperand->zEnd = &pPostOp->z[pPostOp->n];
pOut->zEnd = &pPostOp->z[pPostOp->n];
} }
} }
expr(A) ::= expr(X) ISNULL|NOTNULL(E). {spanUnaryPostfix(&A,pParse,@E,&X,&E);} expr(A) ::= expr(A) ISNULL|NOTNULL(E). {spanUnaryPostfix(pParse,@E,&A,&E);}
expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);} expr(A) ::= expr(A) NOT NULL(E). {spanUnaryPostfix(pParse,TK_NOTNULL,&A,&E);}
%include { %include {
/* A routine to convert a binary TK_IS or TK_ISNOT expression into a /* A routine to convert a binary TK_IS or TK_ISNOT expression into a
@ -1033,12 +1027,12 @@ expr(A) ::= expr(X) NOT NULL(E). {spanUnaryPostfix(&A,pParse,TK_NOTNULL,&X,&E);}
// If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2 // If expr2 is NULL then code as TK_ISNULL or TK_NOTNULL. If expr2
// is any other expression, code as TK_IS or TK_ISNOT. // is any other expression, code as TK_IS or TK_ISNOT.
// //
expr(A) ::= expr(X) IS expr(Y). { expr(A) ::= expr(A) IS expr(Y). {
spanBinaryExpr(&A,pParse,TK_IS,&X,&Y); spanBinaryExpr(pParse,TK_IS,&A,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL); binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_ISNULL);
} }
expr(A) ::= expr(X) IS NOT expr(Y). { expr(A) ::= expr(A) IS NOT expr(Y). {
spanBinaryExpr(&A,pParse,TK_ISNOT,&X,&Y); spanBinaryExpr(pParse,TK_ISNOT,&A,&Y);
binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL); binaryToUnaryIfNull(pParse, Y.pExpr, A.pExpr, TK_NOTNULL);
} }
@ -1052,42 +1046,43 @@ expr(A) ::= expr(X) IS NOT expr(Y). {
ExprSpan *pOperand, /* The operand */ ExprSpan *pOperand, /* The operand */
Token *pPreOp /* The operand token for setting the span */ Token *pPreOp /* The operand token for setting the span */
){ ){
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zStart = pPreOp->z; pOut->zStart = pPreOp->z;
pOut->pExpr = sqlite3PExpr(pParse, op, pOperand->pExpr, 0, 0);
pOut->zEnd = pOperand->zEnd; pOut->zEnd = pOperand->zEnd;
} }
} }
expr(A) ::= NOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} expr(A) ::= NOT(B) expr(X).
expr(A) ::= BITNOT(B) expr(X). {spanUnaryPrefix(&A,pParse,@B,&X,&B);} {spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
expr(A) ::= BITNOT(B) expr(X).
{spanUnaryPrefix(&A,pParse,@B,&X,&B);/*A-overwrites-B*/}
expr(A) ::= MINUS(B) expr(X). [BITNOT] expr(A) ::= MINUS(B) expr(X). [BITNOT]
{spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);} {spanUnaryPrefix(&A,pParse,TK_UMINUS,&X,&B);/*A-overwrites-B*/}
expr(A) ::= PLUS(B) expr(X). [BITNOT] expr(A) ::= PLUS(B) expr(X). [BITNOT]
{spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);} {spanUnaryPrefix(&A,pParse,TK_UPLUS,&X,&B);/*A-overwrites-B*/}
%type between_op {int} %type between_op {int}
between_op(A) ::= BETWEEN. {A = 0;} between_op(A) ::= BETWEEN. {A = 0;}
between_op(A) ::= NOT BETWEEN. {A = 1;} between_op(A) ::= NOT BETWEEN. {A = 1;}
expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] { expr(A) ::= expr(A) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr); ExprList *pList = sqlite3ExprListAppend(pParse,0, X.pExpr);
pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr); pList = sqlite3ExprListAppend(pParse,pList, Y.pExpr);
A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, W.pExpr, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_BETWEEN, A.pExpr, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pList = pList; A.pExpr->x.pList = pList;
}else{ }else{
sqlite3ExprListDelete(pParse->db, pList); sqlite3ExprListDelete(pParse->db, pList);
} }
exprNot(pParse, N, &A.pExpr); exprNot(pParse, N, &A);
A.zStart = W.zStart;
A.zEnd = Y.zEnd; A.zEnd = Y.zEnd;
} }
%ifndef SQLITE_OMIT_SUBQUERY %ifndef SQLITE_OMIT_SUBQUERY
%type in_op {int} %type in_op {int}
in_op(A) ::= IN. {A = 0;} in_op(A) ::= IN. {A = 0;}
in_op(A) ::= NOT IN. {A = 1;} in_op(A) ::= NOT IN. {A = 1;}
expr(A) ::= expr(X) in_op(N) LP exprlist(Y) RP(E). [IN] { expr(A) ::= expr(A) in_op(N) LP exprlist(Y) RP(E). [IN] {
if( Y==0 ){ if( Y==0 ){
/* Expressions of the form /* Expressions of the form
** **
@ -1097,8 +1092,8 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
** simplify to constants 0 (false) and 1 (true), respectively, ** simplify to constants 0 (false) and 1 (true), respectively,
** regardless of the value of expr1. ** regardless of the value of expr1.
*/ */
sqlite3ExprDelete(pParse->db, A.pExpr);
A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]); A.pExpr = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &sqlite3IntTokens[N]);
sqlite3ExprDelete(pParse->db, X.pExpr);
}else if( Y->nExpr==1 ){ }else if( Y->nExpr==1 ){
/* Expressions of the form: /* Expressions of the form:
** **
@ -1125,21 +1120,21 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
pRHS->flags &= ~EP_Collate; pRHS->flags &= ~EP_Collate;
pRHS->flags |= EP_Generic; pRHS->flags |= EP_Generic;
} }
A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, X.pExpr, pRHS, 0); A.pExpr = sqlite3PExpr(pParse, N ? TK_NE : TK_EQ, A.pExpr, pRHS, 0);
}else{ }else{
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pList = Y; A.pExpr->x.pList = Y;
sqlite3ExprSetHeightAndFlags(pParse, A.pExpr); sqlite3ExprSetHeightAndFlags(pParse, A.pExpr);
}else{ }else{
sqlite3ExprListDelete(pParse->db, Y); sqlite3ExprListDelete(pParse->db, Y);
} }
exprNot(pParse, N, &A.pExpr); exprNot(pParse, N, &A);
} }
A.zStart = X.zStart;
A.zEnd = &E.z[E.n]; A.zEnd = &E.z[E.n];
} }
expr(A) ::= LP(B) select(X) RP(E). { expr(A) ::= LP(B) select(X) RP(E). {
spanSet(&A,&B,&E); /*A-overwrites-B*/
A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_SELECT, 0, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pSelect = X; A.pExpr->x.pSelect = X;
@ -1148,11 +1143,9 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
}else{ }else{
sqlite3SelectDelete(pParse->db, X); sqlite3SelectDelete(pParse->db, X);
} }
A.zStart = B.z;
A.zEnd = &E.z[E.n];
} }
expr(A) ::= expr(X) in_op(N) LP select(Y) RP(E). [IN] { expr(A) ::= expr(A) in_op(N) LP select(Y) RP(E). [IN] {
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pSelect = Y; A.pExpr->x.pSelect = Y;
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery); ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
@ -1160,13 +1153,12 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
}else{ }else{
sqlite3SelectDelete(pParse->db, Y); sqlite3SelectDelete(pParse->db, Y);
} }
exprNot(pParse, N, &A.pExpr); exprNot(pParse, N, &A);
A.zStart = X.zStart;
A.zEnd = &E.z[E.n]; A.zEnd = &E.z[E.n];
} }
expr(A) ::= expr(X) in_op(N) nm(Y) dbnm(Z). [IN] { expr(A) ::= expr(A) in_op(N) nm(Y) dbnm(Z). [IN] {
SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z); SrcList *pSrc = sqlite3SrcListAppend(pParse->db, 0,&Y,&Z);
A.pExpr = sqlite3PExpr(pParse, TK_IN, X.pExpr, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_IN, A.pExpr, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0); A.pExpr->x.pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0,0);
ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery); ExprSetProperty(A.pExpr, EP_xIsSelect|EP_Subquery);
@ -1174,12 +1166,13 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
}else{ }else{
sqlite3SrcListDelete(pParse->db, pSrc); sqlite3SrcListDelete(pParse->db, pSrc);
} }
exprNot(pParse, N, &A.pExpr); exprNot(pParse, N, &A);
A.zStart = X.zStart;
A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n]; A.zEnd = Z.z ? &Z.z[Z.n] : &Y.z[Y.n];
} }
expr(A) ::= EXISTS(B) LP select(Y) RP(E). { expr(A) ::= EXISTS(B) LP select(Y) RP(E). {
Expr *p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0); Expr *p;
spanSet(&A,&B,&E); /*A-overwrites-B*/
p = A.pExpr = sqlite3PExpr(pParse, TK_EXISTS, 0, 0, 0);
if( p ){ if( p ){
p->x.pSelect = Y; p->x.pSelect = Y;
ExprSetProperty(p, EP_xIsSelect|EP_Subquery); ExprSetProperty(p, EP_xIsSelect|EP_Subquery);
@ -1187,13 +1180,12 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
}else{ }else{
sqlite3SelectDelete(pParse->db, Y); sqlite3SelectDelete(pParse->db, Y);
} }
A.zStart = B.z;
A.zEnd = &E.z[E.n];
} }
%endif SQLITE_OMIT_SUBQUERY %endif SQLITE_OMIT_SUBQUERY
/* CASE expressions */ /* CASE expressions */
expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). { expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
spanSet(&A,&C,&E); /*A-overwrites-C*/
A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_CASE, X, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y; A.pExpr->x.pList = Z ? sqlite3ExprListAppend(pParse,Y,Z) : Y;
@ -1202,13 +1194,11 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
sqlite3ExprListDelete(pParse->db, Y); sqlite3ExprListDelete(pParse->db, Y);
sqlite3ExprDelete(pParse->db, Z); sqlite3ExprDelete(pParse->db, Z);
} }
A.zStart = C.z;
A.zEnd = &E.z[E.n];
} }
%type case_exprlist {ExprList*} %type case_exprlist {ExprList*}
%destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);} %destructor case_exprlist {sqlite3ExprListDelete(pParse->db, $$);}
case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). { case_exprlist(A) ::= case_exprlist(A) WHEN expr(Y) THEN expr(Z). {
A = sqlite3ExprListAppend(pParse,X, Y.pExpr); A = sqlite3ExprListAppend(pParse,A, Y.pExpr);
A = sqlite3ExprListAppend(pParse,A, Z.pExpr); A = sqlite3ExprListAppend(pParse,A, Z.pExpr);
} }
case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). { case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
@ -1221,7 +1211,7 @@ case_else(A) ::= ELSE expr(X). {A = X.pExpr;}
case_else(A) ::= . {A = 0;} case_else(A) ::= . {A = 0;}
%type case_operand {Expr*} %type case_operand {Expr*}
%destructor case_operand {sqlite3ExprDelete(pParse->db, $$);} %destructor case_operand {sqlite3ExprDelete(pParse->db, $$);}
case_operand(A) ::= expr(X). {A = X.pExpr;} case_operand(A) ::= expr(X). {A = X.pExpr; /*A-overwrites-X*/}
case_operand(A) ::= . {A = 0;} case_operand(A) ::= . {A = 0;}
%type exprlist {ExprList*} %type exprlist {ExprList*}
@ -1229,12 +1219,12 @@ case_operand(A) ::= . {A = 0;}
%type nexprlist {ExprList*} %type nexprlist {ExprList*}
%destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);} %destructor nexprlist {sqlite3ExprListDelete(pParse->db, $$);}
exprlist(A) ::= nexprlist(X). {A = X;} exprlist(A) ::= nexprlist(A).
exprlist(A) ::= . {A = 0;} exprlist(A) ::= . {A = 0;}
nexprlist(A) ::= nexprlist(X) COMMA expr(Y). nexprlist(A) ::= nexprlist(A) COMMA expr(Y).
{A = sqlite3ExprListAppend(pParse,X,Y.pExpr);} {A = sqlite3ExprListAppend(pParse,A,Y.pExpr);}
nexprlist(A) ::= expr(Y). nexprlist(A) ::= expr(Y).
{A = sqlite3ExprListAppend(pParse,0,Y.pExpr);} {A = sqlite3ExprListAppend(pParse,0,Y.pExpr); /*A-overwrites-Y*/}
///////////////////////////// The CREATE INDEX command /////////////////////// ///////////////////////////// The CREATE INDEX command ///////////////////////
@ -1298,11 +1288,11 @@ uniqueflag(A) ::= . {A = OE_None;}
eidlist_opt(A) ::= . {A = 0;} eidlist_opt(A) ::= . {A = 0;}
eidlist_opt(A) ::= LP eidlist(X) RP. {A = X;} eidlist_opt(A) ::= LP eidlist(X) RP. {A = X;}
eidlist(A) ::= eidlist(X) COMMA nm(Y) collate(C) sortorder(Z). { eidlist(A) ::= eidlist(A) COMMA nm(Y) collate(C) sortorder(Z). {
A = parserAddExprIdListTerm(pParse, X, &Y, C, Z); A = parserAddExprIdListTerm(pParse, A, &Y, C, Z);
} }
eidlist(A) ::= nm(Y) collate(C) sortorder(Z). { eidlist(A) ::= nm(Y) collate(C) sortorder(Z). {
A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z); A = parserAddExprIdListTerm(pParse, 0, &Y, C, Z); /*A-overwrites-Y*/
} }
%type collate {int} %type collate {int}
@ -1334,15 +1324,15 @@ cmd ::= PRAGMA nm(X) dbnm(Z) EQ minus_num(Y).
cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP. cmd ::= PRAGMA nm(X) dbnm(Z) LP minus_num(Y) RP.
{sqlite3Pragma(pParse,&X,&Z,&Y,1);} {sqlite3Pragma(pParse,&X,&Z,&Y,1);}
nmnum(A) ::= plus_num(X). {A = X;} nmnum(A) ::= plus_num(A).
nmnum(A) ::= nm(X). {A = X;} nmnum(A) ::= nm(A).
nmnum(A) ::= ON(X). {A = X;} nmnum(A) ::= ON(A).
nmnum(A) ::= DELETE(X). {A = X;} nmnum(A) ::= DELETE(A).
nmnum(A) ::= DEFAULT(X). {A = X;} nmnum(A) ::= DEFAULT(A).
%endif SQLITE_OMIT_PRAGMA %endif SQLITE_OMIT_PRAGMA
%token_class number INTEGER|FLOAT. %token_class number INTEGER|FLOAT.
plus_num(A) ::= PLUS number(X). {A = X;} plus_num(A) ::= PLUS number(X). {A = X;}
plus_num(A) ::= number(X). {A = X;} plus_num(A) ::= number(A).
minus_num(A) ::= MINUS number(X). {A = X;} minus_num(A) ::= MINUS number(X). {A = X;}
//////////////////////////// The CREATE TRIGGER command ///////////////////// //////////////////////////// The CREATE TRIGGER command /////////////////////
@ -1359,7 +1349,7 @@ trigger_decl(A) ::= temp(T) TRIGGER ifnotexists(NOERR) nm(B) dbnm(Z)
trigger_time(C) trigger_event(D) trigger_time(C) trigger_event(D)
ON fullname(E) foreach_clause when_clause(G). { ON fullname(E) foreach_clause when_clause(G). {
sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR); sqlite3BeginTrigger(pParse, &B, &Z, C, D.a, D.b, E, G, T, NOERR);
A = (Z.n==0?B:Z); A = (Z.n==0?B:Z); /*A-overwrites-T*/
} }
%type trigger_time {int} %type trigger_time {int}
@ -1370,8 +1360,8 @@ trigger_time(A) ::= . { A = TK_BEFORE; }
%type trigger_event {struct TrigEvent} %type trigger_event {struct TrigEvent}
%destructor trigger_event {sqlite3IdListDelete(pParse->db, $$.b);} %destructor trigger_event {sqlite3IdListDelete(pParse->db, $$.b);}
trigger_event(A) ::= DELETE|INSERT(OP). {A.a = @OP; A.b = 0;} trigger_event(A) ::= DELETE|INSERT(X). {A.a = @X; /*A-overwrites-X*/ A.b = 0;}
trigger_event(A) ::= UPDATE(OP). {A.a = @OP; A.b = 0;} trigger_event(A) ::= UPDATE(X). {A.a = @X; /*A-overwrites-X*/ A.b = 0;}
trigger_event(A) ::= UPDATE OF idlist(X).{A.a = TK_UPDATE; A.b = X;} trigger_event(A) ::= UPDATE OF idlist(X).{A.a = TK_UPDATE; A.b = X;}
foreach_clause ::= . foreach_clause ::= .
@ -1384,16 +1374,14 @@ when_clause(A) ::= WHEN expr(X). { A = X.pExpr; }
%type trigger_cmd_list {TriggerStep*} %type trigger_cmd_list {TriggerStep*}
%destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);} %destructor trigger_cmd_list {sqlite3DeleteTriggerStep(pParse->db, $$);}
trigger_cmd_list(A) ::= trigger_cmd_list(Y) trigger_cmd(X) SEMI. { trigger_cmd_list(A) ::= trigger_cmd_list(A) trigger_cmd(X) SEMI. {
assert( Y!=0 ); assert( A!=0 );
Y->pLast->pNext = X; A->pLast->pNext = X;
Y->pLast = X; A->pLast = X;
A = Y;
} }
trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. { trigger_cmd_list(A) ::= trigger_cmd(A) SEMI. {
assert( X!=0 ); assert( A!=0 );
X->pLast = X; A->pLast = A;
A = X;
} }
// Disallow qualified table names on INSERT, UPDATE, and DELETE statements // Disallow qualified table names on INSERT, UPDATE, and DELETE statements
@ -1401,7 +1389,7 @@ trigger_cmd_list(A) ::= trigger_cmd(X) SEMI. {
// the same database as the table that the trigger fires on. // the same database as the table that the trigger fires on.
// //
%type trnm {Token} %type trnm {Token}
trnm(A) ::= nm(X). {A = X;} trnm(A) ::= nm(A).
trnm(A) ::= nm DOT nm(X). { trnm(A) ::= nm DOT nm(X). {
A = X; A = X;
sqlite3ErrorMsg(pParse, sqlite3ErrorMsg(pParse,
@ -1436,31 +1424,30 @@ trigger_cmd(A) ::=
// INSERT // INSERT
trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S). trigger_cmd(A) ::= insert_cmd(R) INTO trnm(X) idlist_opt(F) select(S).
{A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);} {A = sqlite3TriggerInsertStep(pParse->db, &X, F, S, R);/*A-overwrites-R*/}
// DELETE // DELETE
trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y). trigger_cmd(A) ::= DELETE FROM trnm(X) tridxby where_opt(Y).
{A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);} {A = sqlite3TriggerDeleteStep(pParse->db, &X, Y);}
// SELECT // SELECT
trigger_cmd(A) ::= select(X). {A = sqlite3TriggerSelectStep(pParse->db, X); } trigger_cmd(A) ::= select(X).
{A = sqlite3TriggerSelectStep(pParse->db, X); /*A-overwrites-X*/}
// The special RAISE expression that may occur in trigger programs // The special RAISE expression that may occur in trigger programs
expr(A) ::= RAISE(X) LP IGNORE RP(Y). { expr(A) ::= RAISE(X) LP IGNORE RP(Y). {
spanSet(&A,&X,&Y); /*A-overwrites-X*/
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0); A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, 0);
if( A.pExpr ){ if( A.pExpr ){
A.pExpr->affinity = OE_Ignore; A.pExpr->affinity = OE_Ignore;
} }
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
} }
expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). { expr(A) ::= RAISE(X) LP raisetype(T) COMMA nm(Z) RP(Y). {
spanSet(&A,&X,&Y); /*A-overwrites-X*/
A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z); A.pExpr = sqlite3PExpr(pParse, TK_RAISE, 0, 0, &Z);
if( A.pExpr ) { if( A.pExpr ) {
A.pExpr->affinity = (char)T; A.pExpr->affinity = (char)T;
} }
A.zStart = X.z;
A.zEnd = &Y.z[Y.n];
} }
%endif !SQLITE_OMIT_TRIGGER %endif !SQLITE_OMIT_TRIGGER
@ -1556,9 +1543,9 @@ with(A) ::= WITH wqlist(W). { A = W; }
with(A) ::= WITH RECURSIVE wqlist(W). { A = W; } with(A) ::= WITH RECURSIVE wqlist(W). { A = W; }
wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. { wqlist(A) ::= nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, 0, &X, Y, Z); A = sqlite3WithAdd(pParse, 0, &X, Y, Z); /*A-overwrites-X*/
} }
wqlist(A) ::= wqlist(W) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. { wqlist(A) ::= wqlist(A) COMMA nm(X) eidlist_opt(Y) AS LP select(Z) RP. {
A = sqlite3WithAdd(pParse, W, &X, Y, Z); A = sqlite3WithAdd(pParse, A, &X, Y, Z);
} }
%endif SQLITE_OMIT_CTE %endif SQLITE_OMIT_CTE

View File

@ -286,6 +286,8 @@ struct rule {
const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */ const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */
int line; /* Line number at which code begins */ int line; /* Line number at which code begins */
const char *code; /* The code executed when this rule is reduced */ const char *code; /* The code executed when this rule is reduced */
const char *codePrefix; /* Setup code before code[] above */
const char *codeSuffix; /* Breakdown code after code[] above */
struct symbol *precsym; /* Precedence symbol for this rule */ struct symbol *precsym; /* Precedence symbol for this rule */
int index; /* An index number for this rule */ int index; /* An index number for this rule */
Boolean canReduce; /* True if this rule is ever reduced */ Boolean canReduce; /* True if this rule is ever reduced */
@ -3430,6 +3432,7 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2){
int c; int c;
char zInt[40]; char zInt[40];
if( zText==0 ){ if( zText==0 ){
if( used==0 && z!=0 ) z[0] = 0;
used = 0; used = 0;
return z; return z;
} }
@ -3466,12 +3469,21 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2){
** zCode is a string that is the action associated with a rule. Expand ** zCode is a string that is the action associated with a rule. Expand
** the symbols in this string so that the refer to elements of the parser ** the symbols in this string so that the refer to elements of the parser
** stack. ** stack.
**
** Return 1 if the expanded code requires that "yylhsminor" local variable
** to be defined.
*/ */
PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
char *cp, *xp; char *cp, *xp;
int i; int i;
int rc = 0; /* True if yylhsminor is used */
int dontUseRhs0 = 0; /* If true, use of left-most RHS label is illegal */
const char *zSkip = 0; /* The zOvwrt comment within rp->code, or NULL */
char lhsused = 0; /* True if the LHS element has been used */ char lhsused = 0; /* True if the LHS element has been used */
char lhsdirect; /* True if LHS writes directly into stack */
char used[MAXRHS]; /* True for each RHS element which is used */ char used[MAXRHS]; /* True for each RHS element which is used */
char zLhs[50]; /* Convert the LHS symbol into this string */
char zOvwrt[900]; /* Comment that to allow LHS to overwrite RHS */
for(i=0; i<rp->nrhs; i++) used[i] = 0; for(i=0; i<rp->nrhs; i++) used[i] = 0;
lhsused = 0; lhsused = 0;
@ -3482,23 +3494,83 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
rp->line = rp->ruleline; rp->line = rp->ruleline;
} }
if( rp->lhsalias==0 ){
/* There is no LHS value symbol. */
lhsdirect = 1;
}else if( rp->nrhs==0 ){
/* If there are no RHS symbols, then writing directly to the LHS is ok */
lhsdirect = 1;
}else if( rp->rhsalias[0]==0 ){
/* The left-most RHS symbol has not value. LHS direct is ok. But
** we have to call the distructor on the RHS symbol first. */
lhsdirect = 1;
if( has_destructor(rp->rhs[0],lemp) ){
append_str(0,0,0,0);
append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
rp->rhs[0]->index,1-rp->nrhs);
rp->codePrefix = Strsafe(append_str(0,0,0,0));
}
}else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){
/* The LHS symbol and the left-most RHS symbol are the same, so
** direct writing is allowed */
lhsdirect = 1;
lhsused = 1;
used[0] = 1;
if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){
ErrorMsg(lemp->filename,rp->ruleline,
"%s(%s) and %s(%s) share the same label but have "
"different datatypes.",
rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]);
lemp->errorcnt++;
}
}else{
lemon_sprintf(zOvwrt, "/*%s-overwrites-%s*/",
rp->lhsalias, rp->rhsalias[0]);
zSkip = strstr(rp->code, zOvwrt);
if( zSkip!=0 ){
/* The code contains a special comment that indicates that it is safe
** for the LHS label to overwrite left-most RHS label. */
lhsdirect = 1;
}else{
lhsdirect = 0;
}
}
if( lhsdirect ){
sprintf(zLhs, "yymsp[%d].minor.yy%d",1-rp->nrhs,rp->lhs->dtnum);
}else{
rc = 1;
sprintf(zLhs, "yylhsminor.yy%d",rp->lhs->dtnum);
}
append_str(0,0,0,0); append_str(0,0,0,0);
/* This const cast is wrong but harmless, if we're careful. */ /* This const cast is wrong but harmless, if we're careful. */
for(cp=(char *)rp->code; *cp; cp++){ for(cp=(char *)rp->code; *cp; cp++){
if( cp==zSkip ){
append_str(zOvwrt,0,0,0);
cp += lemonStrlen(zOvwrt)-1;
dontUseRhs0 = 1;
continue;
}
if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){ if( ISALPHA(*cp) && (cp==rp->code || (!ISALNUM(cp[-1]) && cp[-1]!='_')) ){
char saved; char saved;
for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++); for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++);
saved = *xp; saved = *xp;
*xp = 0; *xp = 0;
if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){
append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0); append_str(zLhs,0,0,0);
cp = xp; cp = xp;
lhsused = 1; lhsused = 1;
}else{ }else{
for(i=0; i<rp->nrhs; i++){ for(i=0; i<rp->nrhs; i++){
if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){ if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
if( cp!=rp->code && cp[-1]=='@' ){ if( i==0 && dontUseRhs0 ){
ErrorMsg(lemp->filename,rp->ruleline,
"Label %s used after '%s'.",
rp->rhsalias[0], zOvwrt);
lemp->errorcnt++;
}else if( cp!=rp->code && cp[-1]=='@' ){
/* If the argument is of the form @X then substituted /* If the argument is of the form @X then substituted
** the token number of X, not the value of X */ ** the token number of X, not the value of X */
append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0); append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
@ -3523,6 +3595,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
append_str(cp, 1, 0, 0); append_str(cp, 1, 0, 0);
} /* End loop */ } /* End loop */
/* Main code generation completed */
cp = append_str(0,0,0,0);
if( cp && cp[0] ) rp->code = Strsafe(cp);
append_str(0,0,0,0);
/* Check to make sure the LHS has been used */ /* Check to make sure the LHS has been used */
if( rp->lhsalias && !lhsused ){ if( rp->lhsalias && !lhsused ){
ErrorMsg(lemp->filename,rp->ruleline, ErrorMsg(lemp->filename,rp->ruleline,
@ -3531,27 +3608,55 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
lemp->errorcnt++; lemp->errorcnt++;
} }
/* Generate destructor code for RHS symbols which are not used in the /* Generate destructor code for RHS minor values which are not referenced.
** reduce code */ ** Generate error messages for unused labels and duplicate labels.
*/
for(i=0; i<rp->nrhs; i++){ for(i=0; i<rp->nrhs; i++){
if( rp->rhsalias[i] && !used[i] ){ if( rp->rhsalias[i] ){
if( i>0 ){
int j;
if( rp->lhsalias && strcmp(rp->lhsalias,rp->rhsalias[i])==0 ){
ErrorMsg(lemp->filename,rp->ruleline,
"%s(%s) has the same label as the LHS but is not the left-most "
"symbol on the RHS.",
rp->rhs[i]->name, rp->rhsalias);
lemp->errorcnt++;
}
for(j=0; j<i; j++){
if( rp->rhsalias[j] && strcmp(rp->rhsalias[j],rp->rhsalias[i])==0 ){
ErrorMsg(lemp->filename,rp->ruleline,
"Label %s used for multiple symbols on the RHS of a rule.",
rp->rhsalias[i]);
lemp->errorcnt++;
break;
}
}
}
if( !used[i] ){
ErrorMsg(lemp->filename,rp->ruleline, ErrorMsg(lemp->filename,rp->ruleline,
"Label %s for \"%s(%s)\" is never used.", "Label %s for \"%s(%s)\" is never used.",
rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]); rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
lemp->errorcnt++; lemp->errorcnt++;
}else if( rp->rhsalias[i]==0 ){ }
if( has_destructor(rp->rhs[i],lemp) ){ }else if( i>0 && has_destructor(rp->rhs[i],lemp) ){
append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
rp->rhs[i]->index,i-rp->nrhs+1); rp->rhs[i]->index,i-rp->nrhs+1);
}else{
/* No destructor defined for this term */
} }
} }
/* If unable to write LHS values directly into the stack, write the
** saved LHS value now. */
if( lhsdirect==0 ){
append_str(" yymsp[%d].minor.yy%d = ", 0, 1-rp->nrhs, rp->lhs->dtnum);
append_str(zLhs, 0, 0, 0);
append_str(";\n", 0, 0, 0);
} }
if( rp->code ){
/* Suffix code generation complete */
cp = append_str(0,0,0,0); cp = append_str(0,0,0,0);
rp->code = Strsafe(cp?cp:""); if( cp ) rp->codeSuffix = Strsafe(cp);
}
return rc;
} }
/* /*
@ -3566,6 +3671,12 @@ PRIVATE void emit_code(
){ ){
const char *cp; const char *cp;
/* Setup code prior to the #line directive */
if( rp->codePrefix && rp->codePrefix[0] ){
fprintf(out, "{%s", rp->codePrefix);
for(cp=rp->codePrefix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
}
/* Generate code to do the reduce action */ /* Generate code to do the reduce action */
if( rp->code ){ if( rp->code ){
if( !lemp->nolinenosflag ){ if( !lemp->nolinenosflag ){
@ -3573,15 +3684,23 @@ PRIVATE void emit_code(
tplt_linedir(out,rp->line,lemp->filename); tplt_linedir(out,rp->line,lemp->filename);
} }
fprintf(out,"{%s",rp->code); fprintf(out,"{%s",rp->code);
for(cp=rp->code; *cp; cp++){ for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
if( *cp=='\n' ) (*lineno)++;
} /* End loop */
fprintf(out,"}\n"); (*lineno)++; fprintf(out,"}\n"); (*lineno)++;
if( !lemp->nolinenosflag ){ if( !lemp->nolinenosflag ){
(*lineno)++; (*lineno)++;
tplt_linedir(out,*lineno,lemp->outname); tplt_linedir(out,*lineno,lemp->outname);
} }
} /* End if( rp->code ) */ }
/* Generate breakdown code that occurs after the #line directive */
if( rp->codeSuffix && rp->codeSuffix[0] ){
fprintf(out, "%s", rp->codeSuffix);
for(cp=rp->codeSuffix; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
}
if( rp->codePrefix ){
fprintf(out, "}\n"); (*lineno)++;
}
return; return;
} }
@ -4206,8 +4325,12 @@ void ReportTable(
tplt_xfer(lemp->name,in,out,&lineno); tplt_xfer(lemp->name,in,out,&lineno);
/* Generate code which execution during each REDUCE action */ /* Generate code which execution during each REDUCE action */
i = 0;
for(rp=lemp->rule; rp; rp=rp->next){ for(rp=lemp->rule; rp; rp=rp->next){
translate_code(lemp, rp); i += translate_code(lemp, rp);
}
if( i ){
fprintf(out," YYMINORTYPE yylhsminor;\n"); lineno++;
} }
/* First output rules other than the default: rule */ /* First output rules other than the default: rule */
for(rp=lemp->rule; rp; rp=rp->next){ for(rp=lemp->rule; rp; rp=rp->next){

View File

@ -518,7 +518,7 @@ static int yy_find_reduce_action(
/* /*
** The following routine is called if the stack overflows. ** The following routine is called if the stack overflows.
*/ */
static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ static void yyStackOverflow(yyParser *yypParser){
ParseARG_FETCH; ParseARG_FETCH;
yypParser->yyidx--; yypParser->yyidx--;
#ifndef NDEBUG #ifndef NDEBUG
@ -562,7 +562,7 @@ static void yy_shift(
yyParser *yypParser, /* The parser to be shifted */ yyParser *yypParser, /* The parser to be shifted */
int yyNewState, /* The new state to shift in */ int yyNewState, /* The new state to shift in */
int yyMajor, /* The major token to shift in */ int yyMajor, /* The major token to shift in */
YYMINORTYPE *yypMinor /* Pointer to the minor token to shift in */ ParseTOKENTYPE yyMinor /* The minor token to shift in */
){ ){
yyStackEntry *yytos; yyStackEntry *yytos;
yypParser->yyidx++; yypParser->yyidx++;
@ -573,14 +573,14 @@ static void yy_shift(
#endif #endif
#if YYSTACKDEPTH>0 #if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH ){ if( yypParser->yyidx>=YYSTACKDEPTH ){
yyStackOverflow(yypParser, yypMinor); yyStackOverflow(yypParser);
return; return;
} }
#else #else
if( yypParser->yyidx>=yypParser->yystksz ){ if( yypParser->yyidx>=yypParser->yystksz ){
yyGrowStack(yypParser); yyGrowStack(yypParser);
if( yypParser->yyidx>=yypParser->yystksz ){ if( yypParser->yyidx>=yypParser->yystksz ){
yyStackOverflow(yypParser, yypMinor); yyStackOverflow(yypParser);
return; return;
} }
} }
@ -588,7 +588,7 @@ static void yy_shift(
yytos = &yypParser->yystack[yypParser->yyidx]; yytos = &yypParser->yystack[yypParser->yyidx];
yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->stateno = (YYACTIONTYPE)yyNewState;
yytos->major = (YYCODETYPE)yyMajor; yytos->major = (YYCODETYPE)yyMajor;
yytos->minor = *yypMinor; yytos->minor.yy0 = yyMinor;
yyTraceShift(yypParser, yyNewState); yyTraceShift(yypParser, yyNewState);
} }
@ -614,7 +614,6 @@ static void yy_reduce(
){ ){
int yygoto; /* The next state */ int yygoto; /* The next state */
int yyact; /* The next action */ int yyact; /* The next action */
YYMINORTYPE yygotominor; /* The LHS of the rule reduced */
yyStackEntry *yymsp; /* The top of the parser's stack */ yyStackEntry *yymsp; /* The top of the parser's stack */
int yysize; /* Amount to pop the stack */ int yysize; /* Amount to pop the stack */
ParseARG_FETCH; ParseARG_FETCH;
@ -627,7 +626,31 @@ static void yy_reduce(
yyRuleName[yyruleno], yymsp[-yysize].stateno); yyRuleName[yyruleno], yymsp[-yysize].stateno);
} }
#endif /* NDEBUG */ #endif /* NDEBUG */
yygotominor = yyzerominor;
/* Check that the stack is large enough to grow by a single entry
** if the RHS of the rule is empty. This ensures that there is room
** enough on the stack to push the LHS value */
if( yyRuleInfo[yyruleno].nrhs==0 ){
#ifdef YYTRACKMAXSTACKDEPTH
if( yypParser->yyidx>yypParser->yyidxMax ){
yypParser->yyidxMax = yypParser->yyidx;
}
#endif
#if YYSTACKDEPTH>0
if( yypParser->yyidx>=YYSTACKDEPTH-1 ){
yyStackOverflow(yypParser);
return;
}
#else
if( yypParser->yyidx>=yypParser->yystksz-1 ){
yyGrowStack(yypParser);
if( yypParser->yyidx>=yypParser->yystksz-1 ){
yyStackOverflow(yypParser);
return;
}
}
#endif
}
switch( yyruleno ){ switch( yyruleno ){
/* Beginning here are the reduction cases. A typical example /* Beginning here are the reduction cases. A typical example
@ -645,26 +668,17 @@ static void yy_reduce(
assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
yygoto = yyRuleInfo[yyruleno].lhs; yygoto = yyRuleInfo[yyruleno].lhs;
yysize = yyRuleInfo[yyruleno].nrhs; yysize = yyRuleInfo[yyruleno].nrhs;
yypParser->yyidx -= yysize;
yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto);
if( yyact <= YY_MAX_SHIFTREDUCE ){ if( yyact <= YY_MAX_SHIFTREDUCE ){
if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
/* If the reduce action popped at least yypParser->yyidx -= yysize - 1;
** one element off the stack, then we can push the new element back
** onto the stack here, and skip the stack overflow test in yy_shift().
** That gives a significant speed improvement. */
if( yysize ){
yypParser->yyidx++;
yymsp -= yysize-1; yymsp -= yysize-1;
yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->stateno = (YYACTIONTYPE)yyact;
yymsp->major = (YYCODETYPE)yygoto; yymsp->major = (YYCODETYPE)yygoto;
yymsp->minor = yygotominor;
yyTraceShift(yypParser, yyact); yyTraceShift(yypParser, yyact);
}else{
yy_shift(yypParser,yyact,yygoto,&yygotominor);
}
}else{ }else{
assert( yyact == YY_ACCEPT_ACTION ); assert( yyact == YY_ACCEPT_ACTION );
yypParser->yyidx -= yysize;
yy_accept(yypParser); yy_accept(yypParser);
} }
} }
@ -698,10 +712,10 @@ static void yy_parse_failed(
static void yy_syntax_error( static void yy_syntax_error(
yyParser *yypParser, /* The parser */ yyParser *yypParser, /* The parser */
int yymajor, /* The major type of the error token */ int yymajor, /* The major type of the error token */
YYMINORTYPE yyminor /* The minor type of the error token */ ParseTOKENTYPE yyminor /* The minor type of the error token */
){ ){
ParseARG_FETCH; ParseARG_FETCH;
#define TOKEN (yyminor.yy0) #define TOKEN yyminor
/************ Begin %syntax_error code ****************************************/ /************ Begin %syntax_error code ****************************************/
%% %%
/************ End %syntax_error code ******************************************/ /************ End %syntax_error code ******************************************/
@ -769,9 +783,7 @@ void Parse(
if( yypParser->yyidx<0 ){ if( yypParser->yyidx<0 ){
#if YYSTACKDEPTH<=0 #if YYSTACKDEPTH<=0
if( yypParser->yystksz <=0 ){ if( yypParser->yystksz <=0 ){
/*memset(&yyminorunion, 0, sizeof(yyminorunion));*/ yyStackOverflow(yypParser);
yyminorunion = yyzerominor;
yyStackOverflow(yypParser, &yyminorunion);
return; return;
} }
#endif #endif
@ -788,7 +800,6 @@ void Parse(
} }
#endif #endif
} }
yyminorunion.yy0 = yyminor;
#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY)
yyendofinput = (yymajor==0); yyendofinput = (yymajor==0);
#endif #endif
@ -804,7 +815,7 @@ void Parse(
yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor);
if( yyact <= YY_MAX_SHIFTREDUCE ){ if( yyact <= YY_MAX_SHIFTREDUCE ){
if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE;
yy_shift(yypParser,yyact,yymajor,&yyminorunion); yy_shift(yypParser,yyact,yymajor,yyminor);
#ifndef YYNOERRORRECOVERY #ifndef YYNOERRORRECOVERY
yypParser->yyerrcnt--; yypParser->yyerrcnt--;
#endif #endif
@ -813,6 +824,7 @@ void Parse(
yy_reduce(yypParser,yyact-YY_MIN_REDUCE); yy_reduce(yypParser,yyact-YY_MIN_REDUCE);
}else{ }else{
assert( yyact == YY_ERROR_ACTION ); assert( yyact == YY_ERROR_ACTION );
yyminorunion.yy0 = yyminor;
#ifdef YYERRORSYMBOL #ifdef YYERRORSYMBOL
int yymx; int yymx;
#endif #endif
@ -842,7 +854,7 @@ void Parse(
** **
*/ */
if( yypParser->yyerrcnt<0 ){ if( yypParser->yyerrcnt<0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion); yy_syntax_error(yypParser,yymajor,yyminor);
} }
yymx = yypParser->yystack[yypParser->yyidx].major; yymx = yypParser->yystack[yypParser->yyidx].major;
if( yymx==YYERRORSYMBOL || yyerrorhit ){ if( yymx==YYERRORSYMBOL || yyerrorhit ){
@ -869,9 +881,7 @@ void Parse(
yy_parse_failed(yypParser); yy_parse_failed(yypParser);
yymajor = YYNOCODE; yymajor = YYNOCODE;
}else if( yymx!=YYERRORSYMBOL ){ }else if( yymx!=YYERRORSYMBOL ){
YYMINORTYPE u2; yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor);
u2.YYERRSYMDT = 0;
yy_shift(yypParser,yyact,YYERRORSYMBOL,&u2);
} }
} }
yypParser->yyerrcnt = 3; yypParser->yyerrcnt = 3;
@ -884,7 +894,7 @@ void Parse(
** Applications can set this macro (for example inside %include) if ** Applications can set this macro (for example inside %include) if
** they intend to abandon the parse upon the first syntax error seen. ** they intend to abandon the parse upon the first syntax error seen.
*/ */
yy_syntax_error(yypParser,yymajor,yyminorunion); yy_syntax_error(yypParser,yymajor, yyminor);
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);
yymajor = YYNOCODE; yymajor = YYNOCODE;
@ -899,7 +909,7 @@ void Parse(
** three input tokens have been successfully shifted. ** three input tokens have been successfully shifted.
*/ */
if( yypParser->yyerrcnt<=0 ){ if( yypParser->yyerrcnt<=0 ){
yy_syntax_error(yypParser,yymajor,yyminorunion); yy_syntax_error(yypParser,yymajor, yyminor);
} }
yypParser->yyerrcnt = 3; yypParser->yyerrcnt = 3;
yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion);