<li><tt><a href='#pright'>%right</a></tt>
<li><tt><a href='#reallc'>%realloc</a></tt>
<li><tt><a href='#stack_overflow'>%stack_overflow</a></tt>
+<li><tt><a href='#reallc'>%stack_resizer</a></tt>
<li><tt><a href='#stack_size'>%stack_size</a></tt>
<li><tt><a href='#start_symbol'>%start_symbol</a></tt>
<li><tt><a href='#syntax_error'>%syntax_error</a></tt>
The wildcard token is only matched if there are no alternatives.</p>
<a id='reallc'></a>
-<h4>4.4.26 The <tt>%realloc</tt> and <tt>%free</tt> directives</h4>
+<h4>4.4.26 The <tt>%realloc</tt>, <tt>%free</tt>, and
+<tt>%stack_resizer</tt> directives</h4>
<p>The <tt>%realloc</tt> and <tt>%free</tt> directives defines function
that allocate and free heap memory. The signatures of these functions
is specified by either <tt>%stack_size</tt> or the
-DYYSTACKDEPTH compile-time flag.
+<p>The <tt>%stack_resizer</tt> directive defines a function that computes
+the new size of the stack whenever it needs resizing. The function takes
+two arguments: The old stack size, and the %extra_context value. The
+function returns an integer which is the new stack size. If %stack_resizer
+is not defined, then the stack size roughly doubles with each new allocation.
+The %stack_resizer function is entirely optional. The parser works fine
+without it. The %stack_resizer function merely gives the application more
+control over the stack size, and offers an opportunity to raise warnings or
+errors if the parser stack grows too large.
+
+<p>If the %stack_resizer function returns an integer that is less than or
+equal to its first parameter, then %stack_overflow is invoked and parsing
+stops.
+
+<p>The %stack_resizer function only works if %extra_context is also defined.
+
<a id='errors'></a>
<h2>5.0 Error Processing</h2>
-C Fix\sincorrect\s"#line"\sgeneration\sin\sLemon.
-D 2025-11-18T10:38:41.356
+C Yet\sanother\sattempt\sat\scontrolling\sthe\sparser\sstack\ssize.
+D 2025-11-18T13:03:08.837
F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F doc/compile-for-windows.md f9e74d74da88f384edd5809f825035e071608f00f7f39c0e448df7b3982f979c
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md acd77fc3a709f51242655ad7803510c886aa8304202fa9cf2abc5f5c4e9d7ae5
-F doc/lemon.html 89ea833a6f71773ab1a9063fbb7fb9b32147bc0b1057b53ecab94a3b30c0aef5
+F doc/lemon.html 60b3836301ac8555622523569fc5cd3bae5b7a8cd1abab545b6ec14800c90aec
F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577
F doc/tcl-extension-testing.md b88861804fc1eaf83249f8e206334189b61e150c360e1b80d0dcf91af82354f5
F doc/testrunner.md 5ee928637e03f136a25fef852c5ed975932e31927bd9b05a574424ae18c31019
F src/os_win.h 4c247cdb6d407c75186c94a1e84d5a22cbae4adcec93fcae8d2bc1f956fd1f19
F src/pager.c a81461de271ac4886ad75b7ca2cca8157a48635820c4646cd2714acdc2c17e5f
F src/pager.h 6137149346e6c8a3ddc1eeb40aee46381e9bc8b0fcc6dda8a1efde993c2275b8
-F src/parse.y 619c3e92a54686c5e47923688c4b9bf7ec534a4690db5677acc28b299c403250
+F src/parse.y f54dff6d07f337f9cea8cb3e28144e47877fd2f211fc3a5c5e238e456d51cc8a
F src/pcache.c 588cc3c5ccaaadde689ed35ce5c5c891a1f7b1f4d1f56f6cf0143b74d8ee6484
F src/pcache.h 1497ce1b823cf00094bb0cf3bac37b345937e6f910890c626b16512316d3abf5
F src/pcache1.c 131ca0daf4e66b4608d2945ae76d6ed90de3f60539afbd5ef9ec65667a5f2fcd
F tool/genfkey.test b6afd7b825d797a1e1274f519ab5695373552ecad5cd373530c63533638a5a4f
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
-F tool/lemon.c 861099d4d328251c85a35cfe3da81e00e35a0708be5aab0e1c7feb157b9735e8
-F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2
+F tool/lemon.c acb9b4e4d6a9826d40163b1da71e049859c7230217c39a6a63dc81ed8d28c906
+F tool/lempar.c ff3c9b32cf36152616dd2bb78ea0fdd3ec6c0f2e76ec55f0d2b50dcb35122b46
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c 63412f9790e5e8538fbde0b4f6db154aaaf80f7a10a01e3c94d14b773a8dd5a6
F tool/logest.c c34e5944318415de513d29a6098df247a9618c96d83c38d4abd88641fe46e669
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh d924598cf2f55a4ecbc2aeb055c10bd5f48114793e7ba25f9585435da29e7e98
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P ea48567ac54e4949a8b68977a58a5de7946e074ae8737133071d02f40ac97f34
-R 956e0d8d894da87712e963f1d74f3842
+P 5c0214df2c0a7470ac2edca0c483a3edd3c39ef0739688ab9a06e23882200360
+R 77442b17c4e08c97334e79ed87f9944e
+T *branch * parser-stack-size
+T *sym-parser-stack-size *
+T -sym-trunk *
U drh
-Z 160fdfae770c78987ceedbc701266298
+Z df6b29f678f7d3bd6a12aec2b921e4cb
# Remove this line to create a well-formed Fossil manifest.
-branch trunk
-tag trunk
+branch parser-stack-size
+tag parser-stack-size
-5c0214df2c0a7470ac2edca0c483a3edd3c39ef0739688ab9a06e23882200360
+cb19986dc6bc483df21e082e54a14cb6d7540b1734259e6d326d676908ac0172
}
// Function used to enlarge the parser stack, if needed
-%realloc parserStackRealloc
-%free sqlite3_free
+%stack_resizer parserStackResize
+%realloc parserStackRealloc
+%free sqlite3_free
// All token codes are small integers with #defines that begin with "TK_"
%token_prefix TK_
}
}
%stack_overflow {
- sqlite3OomFault(pParse->db);
+ if( pParse->nErr==0 ) sqlite3OomFault(pParse->db);
}
// The name of the generated procedure that implements the parser
static void *parserStackRealloc(void *pOld, sqlite3_uint64 newSize){
return sqlite3FaultSim(700) ? 0 : sqlite3_realloc(pOld, newSize);
}
+
+ /* Determine how big to make the stack */
+ static int parserStackResize(int oldSize, Parse *pParse){
+ int newSize;
+ int limit;
+ limit = pParse->db->aLimit[SQLITE_LIMIT_EXPR_DEPTH];
+ if( limit ) limit = limit*4 +100;
+ newSize = oldSize*2 + 100;
+ if( newSize>limit ) newSize = limit;
+ if( newSize<=oldSize ) sqlite3ErrorMsg(pParse, "Recursion limit");
+ return newSize;
+ }
}
%ifndef SQLITE_OMIT_CTE
char *filename; /* Name of the input file */
char *outname; /* Name of the current output file */
char *tokenprefix; /* A prefix added to token names in the .h file */
+ char *resizeFunc; /* Function to compute new stack size */
char *reallocFunc; /* Function to use to allocate stack space */
char *freeFunc; /* Function to use to free stack space */
int nconflict; /* Number of parsing conflicts */
}else if( strcmp(x,"default_type")==0 ){
psp->declargslot = &(psp->gp->vartype);
psp->insertLineMacro = 0;
+ }else if( strcmp(x,"stack_resizer")==0 ){
+ psp->declargslot = &(psp->gp->resizeFunc);
+ psp->insertLineMacro = 0;
}else if( strcmp(x,"realloc")==0 ){
psp->declargslot = &(psp->gp->reallocFunc);
psp->insertLineMacro = 0;
}
}
+/*
+** Return true if the string is not NULL and not empty.
+*/
+static int notnull(const char *z){
+ return z && z[0];
+}
+
/* Generate C source code for the parser */
void ReportTable(
fprintf(out,"#define %sARG_FETCH\n",name); lineno++;
fprintf(out,"#define %sARG_STORE\n",name); lineno++;
}
+ fprintf(out, "#undef YYREALLOC\n"); lineno++;
if( lemp->reallocFunc ){
fprintf(out,"#define YYREALLOC %s\n", lemp->reallocFunc); lineno++;
}else{
fprintf(out,"#define YYREALLOC realloc\n"); lineno++;
}
+ fprintf(out, "#undef YYFREE\n"); lineno++;
if( lemp->freeFunc ){
fprintf(out,"#define YYFREE %s\n", lemp->freeFunc); lineno++;
}else{
fprintf(out,"#define YYFREE free\n"); lineno++;
}
+ fprintf(out, "#undef YYDYNSTACK\n"); lineno++;
if( lemp->reallocFunc && lemp->freeFunc ){
fprintf(out,"#define YYDYNSTACK 1\n"); lineno++;
}else{
fprintf(out,"#define YYDYNSTACK 0\n"); lineno++;
}
- if( lemp->ctx && lemp->ctx[0] ){
+ fprintf(out, "#undef YYRESIZE\n"); lineno++;
+ if( notnull(lemp->ctx) ){
i = lemonStrlen(lemp->ctx);
while( i>=1 && ISSPACE(lemp->ctx[i-1]) ) i--;
while( i>=1 && (ISALNUM(lemp->ctx[i-1]) || lemp->ctx[i-1]=='_') ) i--;
+ if( notnull(lemp->resizeFunc) ){
+ fprintf(out,"#define YYRESIZE %s\n", lemp->resizeFunc); lineno++;
+ }
+ fprintf(out,"#define %sCTX(P) ((P)->%s)\n",name,&lemp->ctx[i]); lineno++;
fprintf(out,"#define %sCTX_SDECL %s;\n",name,lemp->ctx); lineno++;
fprintf(out,"#define %sCTX_PDECL ,%s\n",name,lemp->ctx); lineno++;
fprintf(out,"#define %sCTX_PARAM ,%s\n",name,&lemp->ctx[i]); lineno++;
if( mhflag ){
fprintf(out,"#endif\n"); lineno++;
}
+ fprintf(out, "#undef YYERRORSYMBOL\n"); lineno++;
+ fprintf(out, "#undef YYERRSYMDT\n"); lineno++;
if( lemp->errsym && lemp->errsym->useCnt ){
fprintf(out,"#define YYERRORSYMBOL %d\n",lemp->errsym->index); lineno++;
fprintf(out,"#define YYERRSYMDT yy%d\n",lemp->errsym->dtnum); lineno++;
}
+ fprintf(out,"#undef YYFALLBACK\n"); lineno++;
if( lemp->has_fallback ){
fprintf(out,"#define YYFALLBACK 1\n"); lineno++;
}
int idx;
yyStackEntry *pNew;
+#ifdef YYRESIZE
+ newSize = YYRESIZE(oldSize, ParseCTX(p));
+ if( newSize<=oldSize ) return 1;
+#else
newSize = oldSize*2 + 100;
+#endif
idx = (int)(p->yytos - p->yystack);
if( p->yystack==p->yystk0 ){
pNew = YYREALLOC(0, newSize*sizeof(pNew[0]));