<p>There can be multiple <tt>%code</tt> directives. The arguments of
all <tt>%code</tt> directives are concatenated.</p>
+<p>If the argument to <tt>%code</tt> is a filename within <tt><...></tt>
+then the content of the named file is inserted instead of the text of the
+argument itself.
+
<a id='default_destructor'></a>
<h4>4.4.2 The <tt>%default_destructor</tt> directive</h4>
<p>This might be needed, for example, if some of the C actions in the
grammar call functions that are prototyped in unistd.h.</p>
+<p>If the argument to <tt>%include</tt> is a filename within
+<tt><...></tt> then the content of that file is inserted instead
+of the text of the argument itself.
+
+
<p>Use the <tt><a href="#pcode">%code</a></tt> directive to add code to
the end of the generated parser.</p>
-C Fix\spointless\scomparison\sof\san\sunsigned\sinteger\sto\sless\sthan\szero\sin\sLemon.
-D 2025-03-04T17:06:38.231
+C Update\sLemon\sso\sthat\sit\saccepts\sfilename\sarguments\sto\sdirectives\slike\n"%include".\s\sEx:\s\s"<tt>%include\s<./subdir/file-to-include.txt></tt>".\nThis\swas\scapability\sneeded\sby\spikchr\sand\sbackported\shere\sfor\ssafe\skeeping.\nSQLite\sdoes\snot\sneed\sthis\scapability,\sthough\sit\sdoesn't\shurt\sto\shave\sit\sin\stree.
+D 2025-03-05T13:39:33.597
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
F LICENSE.md e108e1e69ae8e8a59e93c455654b8ac9356a11720d3345df2a4743e9590fb20d
F doc/compile-for-windows.md 5141661e783c9ca9e3fd30e813345898712f5c311d71316f183db87038fa28a6
F doc/json-enhancements.md e356fc834781f1f1aa22ee300027a270b2c960122468499bf347bb123ce1ea4f
F doc/jsonb.md ede3238186e3a90bb79d20b2a6a06d0f9429a38e069e9da0efbad0f2ed48b924
-F doc/lemon.html 7504a6dc9b56dd376a046833ea9cc8b08def93f19bfad6eab9f1a365a4b5f49a
+F doc/lemon.html 6aa6b6a75890bc71a6ad2b94e0723c273818b8b5e43b591eb483a6db0838441f
F doc/pager-invariants.txt 83aa3a4724b2d7970cc3f3461f0295c46d4fc19a835a5781cbb35cb52feb0577
F doc/shared_schema.md 759fc374709fccf4e5d2d0cbd05f8fedd38fb022bdd8a6c5b5f492684c7023b9
F doc/tcl-extension-testing.md 864875c3b672db79e7d42348dd726f9a4fbd852b1d8e5efcf09fe3d1ff6bf2a2
F tool/getlock.c f4c39b651370156cae979501a7b156bdba50e7ce
F tool/index_usage.c f62a0c701b2c7ff2f3e21d206f093c123f222dbf07136a10ffd1ca15a5c706c5
F tool/kvtest-speed.sh 4761a9c4b3530907562314d7757995787f7aef8f
-F tool/lemon.c 7bcb2260da613323718746469e314025b46f33ccb8c6753dbc39eb76bed756c8
+F tool/lemon.c 5f999ac3801e8b585149a5fd5c7c2bbdde3baca98985ebe68e1a41b8e19d19a4
F tool/lempar.c bdffd3b233a4e4e78056c9c01fadd2bb3fe902435abde3bce3d769fdf0d5cca2
F tool/libvers.c caafc3b689638a1d88d44bc5f526c2278760d9b9
F tool/loadfts.c c3c64e4d5e90e8ba41159232c2189dba4be7b862
F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee87c1b31a7
F tool/warnings.sh 49a486c5069de041aedcbde4de178293e0463ae9918ecad7539eedf0ec77a139
F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P b51690e180cfb6034c772899f068453da8484a830283f7c152cfb6fa4330c31e
-R 3a658530666f2614542125c8c0123731
+P 559560da45d0e22ccc6f47dd9eb5ba16851ea444da7e4e951f07b8aa6f6b3753
+R 07ddd929d7c988ac87c481e6c4cfbbbc
U drh
-Z a3c8a6bfe570a8e9f50de3de3edd3fe5
+Z c7f5ed8a6a37ec5d454f01999c7e18cd
# Remove this line to create a well-formed Fossil manifest.
}
}
/*********************** From the file "parse.c" ****************************/
+
+
/*
** Input file parser for the LEMON parser generator.
*/
struct rule *lastrule; /* Pointer to the most recently parsed rule */
};
+/*
+** input x[] is a filename enclosed in <...>. This routine strives
+** to load the complete text of the named file into memory obtained
+** from lemon_malloc() and return that text. The complete filename
+** (without the enclosing <...>) is also written into memory obtained
+** from lemon_malloc() and written back into *pzFN.
+**
+** Except, if any error occurs, the error message is set on psp and
+** no memory is allocated and a NULL is returned.
+*/
+static char *load_file_content(
+ struct pstate *psp, /* Parsing context */
+ const char *x, /* Filename enclosed in <....> */
+ char **pzFN /* Write true filename here */
+){
+ char *zContent;
+ char *zFN;
+ int nFN;
+ FILE *in;
+ int nAlloc;
+ int nContent;
+
+ *pzFN = 0;
+ nFN = lemonStrlen(x);
+ zFN = lemon_malloc( nFN );
+ memcpy(zFN, x+1, nFN-1);
+ zFN[nFN-1] = 0;
+ in = fopen(zFN, "rb");
+ if( in==0 ){
+ ErrorMsg(psp->filename,psp->tokenlineno,
+ "Cannot read file \"%s\"", zFN);
+ psp->errorcnt++;
+ lemon_free(zFN);
+ return 0;
+ }
+ *pzFN = zFN;
+ nAlloc = 2000;
+ zContent = lemon_malloc( nAlloc );
+ nContent = 0;
+ while( nContent<nAlloc-1 ){
+ long got = fread(&zContent[nContent], 1, nAlloc-nContent-1, in);
+ if( got<=0 ) break;
+ nContent += got;
+ if( nContent>=nAlloc-1 ){
+ nAlloc *= 2;
+ zContent = lemon_realloc(zContent, nAlloc);
+ }
+ }
+ zContent[nContent] = 0;
+ fclose(in);
+ return zContent;
+}
+
+
/* Parse a single token */
static void parseonetoken(struct pstate *psp)
{
}
break;
case WAITING_FOR_DECL_ARG:
- if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0]) ){
+ if( x[0]=='{' || x[0]=='\"' || ISALNUM(x[0])
+ || (x[0]=='<' && psp->insertLineMacro)
+ ){
const char *zOld, *zNew;
- char *zBuf, *z;
+ char *zBuf;
+ const char *z;
int nOld, n, nLine = 0, nNew, nBack;
int addLineMacro;
char zLine[50];
- zNew = x;
- if( zNew[0]=='"' || zNew[0]=='{' ) zNew++;
+ char *zToFreeTxt = 0;
+ char *zToFreeFN = 0;
+ const char *zFN = psp->filename;
+ int ln = psp->tokenlineno;
+
+ if( x[0]=='<' ){
+ zToFreeTxt = load_file_content(psp,x,&zToFreeFN);
+ if( psp->errorcnt ) break;
+ zNew = zToFreeTxt;
+ zFN = zToFreeFN;
+ ln = 1;
+ }else{
+ zNew = x;
+ if( zNew[0]=='"' || zNew[0]=='{' ) zNew++;
+ }
nNew = lemonStrlen(zNew);
if( *psp->declargslot ){
zOld = *psp->declargslot;
&& psp->insertLineMacro
&& psp->tokenlineno>1
&& (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
- if( addLineMacro ){
- for(z=psp->filename, nBack=0; *z; z++){
+ if( addLineMacro || x[0]=='<' ){
+ addLineMacro = 1;
+ for(z=zFN, nBack=0; *z; z++){
if( *z=='\\' ) nBack++;
}
- lemon_sprintf(zLine, "#line %d ", psp->tokenlineno);
+ lemon_sprintf(zLine, "#line %d ", ln);
nLine = lemonStrlen(zLine);
- n += nLine + lemonStrlen(psp->filename) + nBack;
+ n += nLine + lemonStrlen(zFN) + nBack;
}
*psp->declargslot = (char *) lemon_realloc(*psp->declargslot, n);
zBuf = *psp->declargslot + nOld;
memcpy(zBuf, zLine, nLine);
zBuf += nLine;
*(zBuf++) = '"';
- for(z=psp->filename; *z; z++){
+ for(z=zFN; *z; z++){
if( *z=='\\' ){
*(zBuf++) = '\\';
}
zBuf += nNew;
*zBuf = 0;
psp->state = WAITING_FOR_DECL_OR_RULE;
+ lemon_free(zToFreeTxt);
+ lemon_free(zToFreeFN);
}else{
ErrorMsg(psp->filename,psp->tokenlineno,
"Illegal argument to %%%s: %s",psp->declkeyword,x);
}else{
nextcp = cp+1;
}
+ }else if( c=='<' ){ /* Pathname in <...> */
+ cp++;
+ while( (c= *cp)!=0 && c!='>' && (c&0xfc)!=0 ){ cp++; }
+ if( (c&0xfc)==0 ){
+ ErrorMsg(ps.filename,startline,
+ c==0 ? "Unterminated filename"
+ : "Control-character in filename");
+ ps.errorcnt++;
+ nextcp = cp;
+ }else{
+ nextcp = cp+1;
+ }
}else if( c=='{' ){ /* A block of C code */
int level;
cp++;