forked from osmocom/wireshark
Lemon: import fresh lemon from upstream
- get latest lemon from upstream (SQLite) - update and apply the patches - introduce CC0-1.0 license indication - update documentation
This commit is contained in:
parent
10e9ac701b
commit
27acec97e9
|
@ -7,15 +7,17 @@ Git mirror of the upstream Fossil repository: https://github.com/mackyle/sqlite
|
|||
The lempar.c and lemon.c are taken from sqlite and are modified as little as
|
||||
possible to make it easier to synchronize changes. Last updated at:
|
||||
|
||||
commit 1150d3841d9381555a4b427835fd617d3465040d
|
||||
Date: Sat Sep 8 16:55:18 2018 +0000
|
||||
Add a missing call to free() in Lemon.
|
||||
commit 273ee151217b04c640c1af148e36c518678c89fa
|
||||
Author: mistachkin <mistachkin@noemail.net>
|
||||
Date: Mon Sep 21 20:18:44 2020 +0000
|
||||
|
||||
Fix harmless compiler warning seen with MSVC.
|
||||
|
||||
To check for changes (adjust "previous commit" accordingly):
|
||||
|
||||
git clone --depth=1000 https://github.com/mackyle/sqlite
|
||||
git clone --depth=1000 https://github.com/sqlite/sqlite
|
||||
cd sqlite/tools
|
||||
git log -p 1150d3841d.. lemon.c lempar.c
|
||||
git log -p 273ee15121.. lemon.c lempar.c
|
||||
|
||||
To create a Wireshark version (steps 1-3) and validate the result (steps 4-5):
|
||||
1. Copy the two files.
|
||||
|
@ -39,5 +41,5 @@ A note about the Lemon patches, we have no intention to fork Lemon and maintain
|
|||
it. These patches are written to address static analyzer warnings without
|
||||
actually modifying the functionality. If upstream is willing to accept patches,
|
||||
then that would be great and the intention is to make it as easy as possible.
|
||||
The lemon and lempar patches are dedicated to the public domain. (IANAL, but I
|
||||
hope this is sufficient.)
|
||||
The lemon and lempar patches are dedicated to the public domain, as set forward
|
||||
in Creative Commons Zero v1.0 Universal (IANAL, but I hope this is sufficient).
|
||||
|
|
|
@ -48,6 +48,7 @@ extern int access(const char *path, int mode);
|
|||
#define MAXRHS 1000
|
||||
#endif
|
||||
|
||||
extern void memory_error();
|
||||
static int showPrecedenceConflict = 0;
|
||||
static char *msort(char*,char**,int(*)(const char*,const char*));
|
||||
|
||||
|
@ -217,7 +218,7 @@ void Plink_delete(struct plink *);
|
|||
/********** From the file "report.h" *************************************/
|
||||
void Reprint(struct lemon *);
|
||||
void ReportOutput(struct lemon *);
|
||||
void ReportTable(struct lemon *, int);
|
||||
void ReportTable(struct lemon *, int, int);
|
||||
void ReportHeader(struct lemon *);
|
||||
void CompressTables(struct lemon *);
|
||||
void ResortStates(struct lemon *);
|
||||
|
@ -291,13 +292,15 @@ struct rule {
|
|||
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 */
|
||||
int noCode; /* True if this rule has no associated C code */
|
||||
int codeEmitted; /* True if the code has been emitted already */
|
||||
struct symbol *precsym; /* Precedence symbol for this rule */
|
||||
int index; /* An index number for this rule */
|
||||
int iRule; /* Rule number as used in the generated tables */
|
||||
Boolean noCode; /* True if this rule has no associated C code */
|
||||
Boolean codeEmitted; /* True if the code has been emitted already */
|
||||
Boolean canReduce; /* True if this rule is ever reduced */
|
||||
Boolean doesReduce; /* Reduce actions occur after optimization */
|
||||
Boolean neverReduce; /* Reduce is theoretically possible, but prevented
|
||||
** by actions or other outside implementation */
|
||||
struct rule *nextlhs; /* Next rule with the same LHS */
|
||||
struct rule *next; /* Next rule in the global list */
|
||||
};
|
||||
|
@ -384,6 +387,7 @@ struct lemon {
|
|||
int nstate; /* Number of states */
|
||||
int nxstate; /* nstate with tail degenerate states removed */
|
||||
int nrule; /* Number of rules */
|
||||
int nruleWithAction; /* Number of rules with actions */
|
||||
int nsymbol; /* Number of terminal and nonterminal symbols */
|
||||
int nterminal; /* Number of terminal symbols */
|
||||
int minShiftReduce; /* Minimum shift-reduce action value */
|
||||
|
@ -419,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 */
|
||||
|
@ -483,22 +488,22 @@ void Configtable_clear(int(*)(struct config *));
|
|||
|
||||
/* Allocate a new parser action */
|
||||
static struct action *Action_new(void){
|
||||
static struct action *freelist = 0;
|
||||
static struct action *actionfreelist = 0;
|
||||
struct action *newaction;
|
||||
|
||||
if( freelist==0 ){
|
||||
if( actionfreelist==0 ){
|
||||
int i;
|
||||
int amt = 100;
|
||||
freelist = (struct action *)calloc(amt, sizeof(struct action));
|
||||
if( freelist==0 ){
|
||||
actionfreelist = (struct action *)calloc(amt, sizeof(struct action));
|
||||
if( actionfreelist==0 ){
|
||||
fprintf(stderr,"Unable to allocate memory for a new parser action.");
|
||||
exit(1);
|
||||
}
|
||||
for(i=0; i<amt-1; i++) freelist[i].next = &freelist[i+1];
|
||||
freelist[amt-1].next = 0;
|
||||
for(i=0; i<amt-1; i++) actionfreelist[i].next = &actionfreelist[i+1];
|
||||
actionfreelist[amt-1].next = 0;
|
||||
}
|
||||
newaction = freelist;
|
||||
freelist = freelist->next;
|
||||
newaction = actionfreelist;
|
||||
actionfreelist = actionfreelist->next;
|
||||
return newaction;
|
||||
}
|
||||
|
||||
|
@ -908,9 +913,9 @@ void FindStates(struct lemon *lemp)
|
|||
sp = Symbol_find(lemp->start);
|
||||
if( sp==0 ){
|
||||
ErrorMsg(lemp->filename,0,
|
||||
"The specified start symbol \"%s\" is not \
|
||||
in a nonterminal of the grammar. \"%s\" will be used as the start \
|
||||
symbol instead.",lemp->start,lemp->startRule->lhs->name);
|
||||
"The specified start symbol \"%s\" is not "
|
||||
"in a nonterminal of the grammar. \"%s\" will be used as the start "
|
||||
"symbol instead.",lemp->start,lemp->startRule->lhs->name);
|
||||
lemp->errorcnt++;
|
||||
sp = lemp->startRule->lhs;
|
||||
}
|
||||
|
@ -926,9 +931,9 @@ symbol instead.",lemp->start,lemp->startRule->lhs->name);
|
|||
for(i=0; i<rp->nrhs; i++){
|
||||
if( rp->rhs[i]==sp ){ /* FIX ME: Deal with multiterminals */
|
||||
ErrorMsg(lemp->filename,0,
|
||||
"The start symbol \"%s\" occurs on the \
|
||||
right-hand side of a rule. This will result in a parser which \
|
||||
does not work properly.",sp->name);
|
||||
"The start symbol \"%s\" occurs on the "
|
||||
"right-hand side of a rule. This will result in a parser which "
|
||||
"does not work properly.",sp->name);
|
||||
lemp->errorcnt++;
|
||||
}
|
||||
}
|
||||
|
@ -994,7 +999,9 @@ PRIVATE struct state *getstate(struct lemon *lemp)
|
|||
int ret =
|
||||
#endif
|
||||
State_insert(stp,stp->bp); /* Add to the state table */
|
||||
#ifndef NDEBUG
|
||||
assert(ret == 1); /* CSA hint: stp did not leak, it has escaped. */
|
||||
#endif
|
||||
buildshifts(lemp,stp); /* Recursively compute successor states */
|
||||
}
|
||||
return stp;
|
||||
|
@ -1593,14 +1600,14 @@ static struct rule *Rule_merge(struct rule *pA, struct rule *pB){
|
|||
** Sort a list of rules in order of increasing iRule value
|
||||
*/
|
||||
static struct rule *Rule_sort(struct rule *rp){
|
||||
int i;
|
||||
unsigned int i;
|
||||
struct rule *pNext;
|
||||
struct rule *x[32];
|
||||
memset(x, 0, sizeof(x));
|
||||
while( rp ){
|
||||
pNext = rp->next;
|
||||
rp->next = 0;
|
||||
for(i=0; i<sizeof(x)/sizeof(x[0]) && x[i]; i++){
|
||||
for(i=0; i<sizeof(x)/sizeof(x[0])-1 && x[i]; i++){
|
||||
rp = Rule_merge(x[i], rp);
|
||||
x[i] = 0;
|
||||
}
|
||||
|
@ -1627,8 +1634,7 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
}
|
||||
|
||||
/* The main program. Parse the command line and do it... */
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv){
|
||||
static int version = 0;
|
||||
static int rpflag = 0;
|
||||
static int basisflag = 0;
|
||||
|
@ -1638,14 +1644,15 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
static int mhflag = 0;
|
||||
static int nolinenosflag = 0;
|
||||
static int noResort = 0;
|
||||
|
||||
(void) argc; /* Mark unused, similar to Q_UNUSED */
|
||||
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.)"},
|
||||
|
@ -1658,6 +1665,8 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
{OPT_FLAG, "r", (char*)&noResort, "Do not sort or renumber states"},
|
||||
{OPT_FLAG, "s", (char*)&statistics,
|
||||
"Print parser stats to standard output."},
|
||||
{OPT_FLAG, "S", (char*)&sqlFlag,
|
||||
"Generate the *.sql file describing the parser tables."},
|
||||
{OPT_FLAG, "x", (char*)&version, "Print the version number."},
|
||||
{OPT_FSTR, "T", (char*)handle_T_option, "Specify a template file."},
|
||||
{OPT_FSTR, "W", 0, "Ignored. (Placeholder for '-W' compiler options.)"},
|
||||
|
@ -1668,6 +1677,7 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
struct lemon lem;
|
||||
struct rule *rp;
|
||||
|
||||
(void)argc;
|
||||
OptInit(argv,options,stderr);
|
||||
if( version ){
|
||||
printf("Lemon version 1.0\n");
|
||||
|
@ -1688,11 +1698,12 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
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);
|
||||
assert(lem.rule); /* Hint for CSA (no errors => rule found). */
|
||||
if( lem.nrule==0 ){
|
||||
fprintf(stderr,"Empty grammar.\n");
|
||||
|
@ -1720,6 +1731,7 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
for(i=0, rp=lem.rule; rp; rp=rp->next){
|
||||
rp->iRule = rp->code ? i++ : -1;
|
||||
}
|
||||
lem.nruleWithAction = i;
|
||||
for(rp=lem.rule; rp; rp=rp->next){
|
||||
if( rp->iRule<0 ) rp->iRule = i++;
|
||||
}
|
||||
|
@ -1767,7 +1779,7 @@ static void stats_line(const char *zLabel, int iValue){
|
|||
if( !quiet ) ReportOutput(&lem);
|
||||
|
||||
/* Generate the source code for the parser */
|
||||
ReportTable(&lem, mhflag);
|
||||
ReportTable(&lem, mhflag, sqlFlag);
|
||||
|
||||
/* Produce a header file for use by the scanner. (This step is
|
||||
** omitted if the "-m" option is used because makeheaders will
|
||||
|
@ -1917,7 +1929,7 @@ static char *msort(
|
|||
return ep;
|
||||
}
|
||||
/************************ From the file "option.c" **************************/
|
||||
static char **argv;
|
||||
static char **g_argv;
|
||||
static struct s_options *op;
|
||||
static FILE *errstream;
|
||||
|
||||
|
@ -1930,14 +1942,14 @@ static FILE *errstream;
|
|||
static void errline(int n, int k, FILE *err)
|
||||
{
|
||||
int spcnt, i;
|
||||
if( argv[0] ) fprintf(err,"%s",argv[0]);
|
||||
spcnt = lemonStrlen(argv[0]) + 1;
|
||||
for(i=1; i<n && argv[i]; i++){
|
||||
fprintf(err," %s",argv[i]);
|
||||
spcnt += lemonStrlen(argv[i])+1;
|
||||
if( g_argv[0] ) fprintf(err,"%s",g_argv[0]);
|
||||
spcnt = lemonStrlen(g_argv[0]) + 1;
|
||||
for(i=1; i<n && g_argv[i]; i++){
|
||||
fprintf(err," %s",g_argv[i]);
|
||||
spcnt += lemonStrlen(g_argv[i])+1;
|
||||
}
|
||||
spcnt += k;
|
||||
for(; argv[i]; i++) fprintf(err," %s",argv[i]);
|
||||
for(; g_argv[i]; i++) fprintf(err," %s",g_argv[i]);
|
||||
if( spcnt<20 ){
|
||||
fprintf(err,"\n%*s^-- here\n",spcnt,"");
|
||||
}else{
|
||||
|
@ -1953,13 +1965,13 @@ static int argindex(int n)
|
|||
{
|
||||
int i;
|
||||
int dashdash = 0;
|
||||
if( argv!=0 && *argv!=0 ){
|
||||
for(i=1; argv[i]; i++){
|
||||
if( dashdash || !ISOPT(argv[i]) ){
|
||||
if( g_argv!=0 && *g_argv!=0 ){
|
||||
for(i=1; g_argv[i]; i++){
|
||||
if( dashdash || !ISOPT(g_argv[i]) ){
|
||||
if( n==0 ) return i;
|
||||
n--;
|
||||
}
|
||||
if( strcmp(argv[i],"--")==0 ) dashdash = 1;
|
||||
if( strcmp(g_argv[i],"--")==0 ) dashdash = 1;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
|
@ -1976,9 +1988,9 @@ static int handleflags(int i, FILE *err)
|
|||
int errcnt = 0;
|
||||
int j;
|
||||
for(j=0; op[j].label; j++){
|
||||
if( strncmp(&argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break;
|
||||
if( strncmp(&g_argv[i][1],op[j].label,lemonStrlen(op[j].label))==0 ) break;
|
||||
}
|
||||
v = argv[i][0]=='-' ? 1 : 0;
|
||||
v = g_argv[i][0]=='-' ? 1 : 0;
|
||||
if( op[j].label==0 ){
|
||||
if( err ){
|
||||
fprintf(err,"%sundefined option.\n",emsg);
|
||||
|
@ -1992,7 +2004,7 @@ static int handleflags(int i, FILE *err)
|
|||
}else if( op[j].type==OPT_FFLAG ){
|
||||
(*(void(*)(int))(op[j].arg))(v);
|
||||
}else if( op[j].type==OPT_FSTR ){
|
||||
(*(void(*)(char *))(op[j].arg))(&argv[i][2]);
|
||||
(*(void(*)(char *))(op[j].arg))(&g_argv[i][2]);
|
||||
}else{
|
||||
if( err ){
|
||||
fprintf(err,"%smissing argument on switch.\n",emsg);
|
||||
|
@ -2014,11 +2026,11 @@ static int handleswitch(int i, FILE *err)
|
|||
char *cp;
|
||||
int j;
|
||||
int errcnt = 0;
|
||||
cp = strchr(argv[i],'=');
|
||||
cp = strchr(g_argv[i],'=');
|
||||
assert( cp!=0 );
|
||||
*cp = 0;
|
||||
for(j=0; op[j].label; j++){
|
||||
if( strcmp(argv[i],op[j].label)==0 ) break;
|
||||
if( strcmp(g_argv[i],op[j].label)==0 ) break;
|
||||
}
|
||||
*cp = '=';
|
||||
if( op[j].label==0 ){
|
||||
|
@ -2045,7 +2057,7 @@ static int handleswitch(int i, FILE *err)
|
|||
if( err ){
|
||||
fprintf(err,
|
||||
"%sillegal character in floating-point argument.\n",emsg);
|
||||
errline(i,(int)((char*)end-(char*)argv[i]),err);
|
||||
errline(i,(int)((char*)end-(char*)g_argv[i]),err);
|
||||
}
|
||||
errcnt++;
|
||||
}
|
||||
|
@ -2056,7 +2068,7 @@ static int handleswitch(int i, FILE *err)
|
|||
if( *end ){
|
||||
if( err ){
|
||||
fprintf(err,"%sillegal character in integer argument.\n",emsg);
|
||||
errline(i,(int)((char*)end-(char*)argv[i]),err);
|
||||
errline(i,(int)((char*)end-(char*)g_argv[i]),err);
|
||||
}
|
||||
errcnt++;
|
||||
}
|
||||
|
@ -2096,15 +2108,15 @@ static int handleswitch(int i, FILE *err)
|
|||
int OptInit(char **a, struct s_options *o, FILE *err)
|
||||
{
|
||||
int errcnt = 0;
|
||||
argv = a;
|
||||
g_argv = a;
|
||||
op = o;
|
||||
errstream = err;
|
||||
if( argv && *argv && op ){
|
||||
if( g_argv && *g_argv && op ){
|
||||
int i;
|
||||
for(i=1; argv[i]; i++){
|
||||
if( argv[i][0]=='+' || argv[i][0]=='-' ){
|
||||
for(i=1; g_argv[i]; i++){
|
||||
if( g_argv[i][0]=='+' || g_argv[i][0]=='-' ){
|
||||
errcnt += handleflags(i,err);
|
||||
}else if( strchr(argv[i],'=') ){
|
||||
}else if( strchr(g_argv[i],'=') ){
|
||||
errcnt += handleswitch(i,err);
|
||||
}
|
||||
}
|
||||
|
@ -2121,10 +2133,10 @@ int OptNArgs(void){
|
|||
int cnt = 0;
|
||||
int dashdash = 0;
|
||||
int i;
|
||||
if( argv!=0 && argv[0]!=0 ){
|
||||
for(i=1; argv[i]; i++){
|
||||
if( dashdash || !ISOPT(argv[i]) ) cnt++;
|
||||
if( strcmp(argv[i],"--")==0 ) dashdash = 1;
|
||||
if( g_argv!=0 && g_argv[0]!=0 ){
|
||||
for(i=1; g_argv[i]; i++){
|
||||
if( dashdash || !ISOPT(g_argv[i]) ) cnt++;
|
||||
if( strcmp(g_argv[i],"--")==0 ) dashdash = 1;
|
||||
}
|
||||
}
|
||||
return cnt;
|
||||
|
@ -2134,7 +2146,7 @@ char *OptArg(int n)
|
|||
{
|
||||
int i;
|
||||
i = argindex(n);
|
||||
return i>=0 ? argv[i] : 0;
|
||||
return i>=0 ? g_argv[i] : 0;
|
||||
}
|
||||
|
||||
void OptErr(int n)
|
||||
|
@ -2264,7 +2276,7 @@ static void parseonetoken(struct pstate *psp)
|
|||
psp->preccounter = 0;
|
||||
psp->firstrule = psp->lastrule = 0;
|
||||
psp->gp->nrule = 0;
|
||||
/* Fall thru to next case */
|
||||
/* fall through */
|
||||
case WAITING_FOR_DECL_OR_RULE:
|
||||
if( x[0]=='%' ){
|
||||
psp->state = WAITING_FOR_DECL_KEYWORD;
|
||||
|
@ -2276,14 +2288,16 @@ static void parseonetoken(struct pstate *psp)
|
|||
}else if( x[0]=='{' ){
|
||||
if( psp->prevrule==0 ){
|
||||
ErrorMsg(psp->filename,psp->tokenlineno,
|
||||
"There is no prior rule upon which to attach the code \
|
||||
fragment which begins on this line.");
|
||||
"There is no prior rule upon which to attach the code "
|
||||
"fragment which begins on this line.");
|
||||
psp->errorcnt++;
|
||||
}else if( psp->prevrule->code!=0 ){
|
||||
ErrorMsg(psp->filename,psp->tokenlineno,
|
||||
"Code fragment beginning on this line is not the first \
|
||||
to follow the previous rule.");
|
||||
"Code fragment beginning on this line is not the first "
|
||||
"to follow the previous rule.");
|
||||
psp->errorcnt++;
|
||||
}else if( strcmp(x, "{NEVER-REDUCE")==0 ){
|
||||
psp->prevrule->neverReduce = 1;
|
||||
}else{
|
||||
psp->prevrule->line = psp->tokenlineno;
|
||||
psp->prevrule->code = &x[1];
|
||||
|
@ -2309,8 +2323,8 @@ to follow the previous rule.");
|
|||
psp->errorcnt++;
|
||||
}else if( psp->prevrule->precsym!=0 ){
|
||||
ErrorMsg(psp->filename,psp->tokenlineno,
|
||||
"Precedence mark on this line is not the first \
|
||||
to follow the previous rule.");
|
||||
"Precedence mark on this line is not the first "
|
||||
"to follow the previous rule.");
|
||||
psp->errorcnt++;
|
||||
}else{
|
||||
psp->prevrule->precsym = Symbol_new(x);
|
||||
|
@ -2422,7 +2436,7 @@ to follow the previous rule.");
|
|||
psp->alias[psp->nrhs] = 0;
|
||||
psp->nrhs++;
|
||||
}
|
||||
}else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 ){
|
||||
}else if( (x[0]=='|' || x[0]=='/') && psp->nrhs>0 && ISUPPER(x[1]) ){
|
||||
struct symbol *msp = psp->rhs[psp->nrhs-1];
|
||||
if( msp->type!=MULTITERMINAL ){
|
||||
struct symbol *origsp = msp;
|
||||
|
@ -2634,8 +2648,10 @@ to follow the previous rule.");
|
|||
}
|
||||
nOld = lemonStrlen(zOld);
|
||||
n = nOld + nNew + 20;
|
||||
addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro &&
|
||||
(psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
|
||||
addLineMacro = !psp->gp->nolinenosflag
|
||||
&& psp->insertLineMacro
|
||||
&& psp->tokenlineno>1
|
||||
&& (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
|
||||
if( addLineMacro ){
|
||||
for(z=psp->filename, nBack=0; *z; z++){
|
||||
if( *z=='\\' ) nBack++;
|
||||
|
@ -2738,7 +2754,7 @@ to follow the previous rule.");
|
|||
case WAITING_FOR_CLASS_ID:
|
||||
if( !ISLOWER(x[0]) ){
|
||||
ErrorMsg(psp->filename, psp->tokenlineno,
|
||||
"%%token_class must be followed by an identifier: ", x);
|
||||
"%%token_class must be followed by an identifier: %s", x);
|
||||
psp->errorcnt++;
|
||||
psp->state = RESYNC_AFTER_DECL_ERROR;
|
||||
}else if( Symbol_find(x) ){
|
||||
|
@ -2779,13 +2795,108 @@ to follow the previous rule.");
|
|||
}
|
||||
}
|
||||
|
||||
/* 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 +2912,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 +3006,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;
|
||||
|
@ -2913,7 +3040,8 @@ void Parse(struct lemon *gp)
|
|||
}
|
||||
if( c==0 ){
|
||||
ErrorMsg(ps.filename,startline,
|
||||
"String starting on this line is not terminated before the end of the file.");
|
||||
"String starting on this line is not terminated before "
|
||||
"the end of the file.");
|
||||
ps.errorcnt++;
|
||||
nextcp = cp;
|
||||
}else{
|
||||
|
@ -2952,7 +3080,8 @@ void Parse(struct lemon *gp)
|
|||
}
|
||||
if( c==0 ){
|
||||
ErrorMsg(ps.filename,ps.tokenlineno,
|
||||
"C code starting on this line is not terminated before the end of the file.");
|
||||
"C code starting on this line is not terminated before "
|
||||
"the end of the file.");
|
||||
ps.errorcnt++;
|
||||
nextcp = cp;
|
||||
}else{
|
||||
|
@ -3398,8 +3527,8 @@ void ReportOutput(struct lemon *lemp)
|
|||
PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
|
||||
{
|
||||
const char *pathlist;
|
||||
char *pathbufptr;
|
||||
char *pathbuf;
|
||||
char *pathbufptr = 0;
|
||||
char *pathbuf = 0;
|
||||
char *path,*cp;
|
||||
char c;
|
||||
|
||||
|
@ -3434,8 +3563,8 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
|
|||
else pathbuf = &cp[1];
|
||||
if( access(path,modemask)==0 ) break;
|
||||
}
|
||||
free(pathbufptr);
|
||||
}
|
||||
free(pathbufptr);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
@ -3501,6 +3630,16 @@ PRIVATE void tplt_xfer(char *name, FILE *in, FILE *out, int *lineno)
|
|||
}
|
||||
}
|
||||
|
||||
/* Skip forward past the header of the template file to the first "%%"
|
||||
*/
|
||||
PRIVATE void tplt_skip_header(FILE *in, int *lineno)
|
||||
{
|
||||
char line[LINESIZE];
|
||||
while( fgets(line,LINESIZE,in) && (line[0]!='%' || line[1]!='%') ){
|
||||
(*lineno)++;
|
||||
}
|
||||
}
|
||||
|
||||
/* The next function finds the template file and opens it, returning
|
||||
** a pointer to the opened file. */
|
||||
PRIVATE FILE *tplt_open(struct lemon *lemp)
|
||||
|
@ -3509,11 +3648,9 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
|
|||
char buf[1000];
|
||||
FILE *in;
|
||||
char *tpltname;
|
||||
char *toFree = 0;
|
||||
char *cp;
|
||||
|
||||
/* We always require the -T option, avoid memleak in the other code path. */
|
||||
assert(user_templatename);
|
||||
|
||||
/* first, see if user specified a template filename on the command line. */
|
||||
if (user_templatename != 0) {
|
||||
if( access(user_templatename,004)==-1 ){
|
||||
|
@ -3543,7 +3680,7 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
|
|||
}else if( access(templatename,004)==0 ){
|
||||
tpltname = templatename;
|
||||
}else{
|
||||
tpltname = pathsearch(lemp->argv0,templatename,0);
|
||||
toFree = tpltname = pathsearch(lemp->argv0,templatename,0);
|
||||
}
|
||||
if( tpltname==0 ){
|
||||
fprintf(stderr,"Can't find the parser driver template file \"%s\".\n",
|
||||
|
@ -3553,10 +3690,10 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
|
|||
}
|
||||
in = fopen(tpltname,"rb");
|
||||
if( in==0 ){
|
||||
fprintf(stderr,"Can't open the template file \"%s\".\n",templatename);
|
||||
fprintf(stderr,"Can't open the template file \"%s\".\n",tpltname);
|
||||
lemp->errorcnt++;
|
||||
return 0;
|
||||
}
|
||||
free(toFree);
|
||||
return in;
|
||||
}
|
||||
|
||||
|
@ -3862,7 +3999,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){
|
|||
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);
|
||||
rp->rhs[i]->name, rp->rhsalias[i]);
|
||||
lemp->errorcnt++;
|
||||
}
|
||||
for(j=0; j<i; j++){
|
||||
|
@ -4156,9 +4293,10 @@ static void writeRuleText(FILE *out, struct rule *rp){
|
|||
/* Generate C source code for the parser */
|
||||
void ReportTable(
|
||||
struct lemon *lemp,
|
||||
int mhflag /* Output in makeheaders format if true */
|
||||
int mhflag, /* Output in makeheaders format if true */
|
||||
int sqlFlag /* Generate the *.sql file too */
|
||||
){
|
||||
FILE *out, *in;
|
||||
FILE *out, *in, *sql;
|
||||
char line[LINESIZE];
|
||||
int lineno;
|
||||
struct state *stp;
|
||||
|
@ -4166,12 +4304,14 @@ void ReportTable(
|
|||
struct rule *rp;
|
||||
struct acttab *pActtab;
|
||||
int i, j, n, sz;
|
||||
int nLookAhead;
|
||||
int szActionType; /* sizeof(YYACTIONTYPE) */
|
||||
int szCodeType; /* sizeof(YYCODETYPE) */
|
||||
const char *name;
|
||||
int mnTknOfst, mxTknOfst;
|
||||
int mnNtOfst, mxNtOfst;
|
||||
struct axset *ax;
|
||||
char *prefix;
|
||||
|
||||
lemp->minShiftReduce = lemp->nstate;
|
||||
lemp->errAction = lemp->minShiftReduce + lemp->nrule;
|
||||
|
@ -4187,8 +4327,99 @@ void ReportTable(
|
|||
fclose(in);
|
||||
return;
|
||||
}
|
||||
if( sqlFlag==0 ){
|
||||
sql = 0;
|
||||
}else{
|
||||
sql = file_open(lemp, ".sql", "wb");
|
||||
if( sql==0 ){
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
return;
|
||||
}
|
||||
fprintf(sql,
|
||||
"BEGIN;\n"
|
||||
"CREATE TABLE symbol(\n"
|
||||
" id INTEGER PRIMARY KEY,\n"
|
||||
" name TEXT NOT NULL,\n"
|
||||
" isTerminal BOOLEAN NOT NULL,\n"
|
||||
" fallback INTEGER REFERENCES symbol"
|
||||
" DEFERRABLE INITIALLY DEFERRED\n"
|
||||
");\n"
|
||||
);
|
||||
for(i=0; i<lemp->nsymbol; i++){
|
||||
fprintf(sql,
|
||||
"INSERT INTO symbol(id,name,isTerminal,fallback)"
|
||||
"VALUES(%d,'%s',%s",
|
||||
i, lemp->symbols[i]->name,
|
||||
i<lemp->nterminal ? "TRUE" : "FALSE"
|
||||
);
|
||||
if( lemp->symbols[i]->fallback ){
|
||||
fprintf(sql, ",%d);\n", lemp->symbols[i]->fallback->index);
|
||||
}else{
|
||||
fprintf(sql, ",NULL);\n");
|
||||
}
|
||||
}
|
||||
fprintf(sql,
|
||||
"CREATE TABLE rule(\n"
|
||||
" ruleid INTEGER PRIMARY KEY,\n"
|
||||
" lhs INTEGER REFERENCES symbol(id),\n"
|
||||
" txt TEXT\n"
|
||||
");\n"
|
||||
"CREATE TABLE rulerhs(\n"
|
||||
" ruleid INTEGER REFERENCES rule(ruleid),\n"
|
||||
" pos INTEGER,\n"
|
||||
" sym INTEGER REFERENCES symbol(id)\n"
|
||||
");\n"
|
||||
);
|
||||
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
||||
assert( i==rp->iRule );
|
||||
fprintf(sql,
|
||||
"INSERT INTO rule(ruleid,lhs,txt)VALUES(%d,%d,'",
|
||||
rp->iRule, rp->lhs->index
|
||||
);
|
||||
writeRuleText(sql, rp);
|
||||
fprintf(sql,"');\n");
|
||||
for(j=0; j<rp->nrhs; j++){
|
||||
struct symbol *sp = rp->rhs[j];
|
||||
if( sp->type!=MULTITERMINAL ){
|
||||
fprintf(sql,
|
||||
"INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n",
|
||||
i,j,sp->index
|
||||
);
|
||||
}else{
|
||||
int k;
|
||||
for(k=0; k<sp->nsubsym; k++){
|
||||
fprintf(sql,
|
||||
"INSERT INTO rulerhs(ruleid,pos,sym)VALUES(%d,%d,%d);\n",
|
||||
i,j,sp->subsym[k]->index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(sql, "COMMIT;\n");
|
||||
}
|
||||
lineno = 1;
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
fprintf(out,
|
||||
"/* This file is automatically generated by Lemon from input grammar\n"
|
||||
"** source file \"%s\". */\n", lemp->filename); lineno += 2;
|
||||
|
||||
/* The first %include directive begins with a C-language comment,
|
||||
** then skip over the header comment of the template file
|
||||
*/
|
||||
if( lemp->include==0 ) lemp->include = "";
|
||||
for(i=0; ISSPACE(lemp->include[i]); i++){
|
||||
if( lemp->include[i]=='\n' ){
|
||||
lemp->include += i+1;
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
if( lemp->include[0]=='/' ){
|
||||
tplt_skip_header(in,&lineno);
|
||||
}else{
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
}
|
||||
|
||||
/* Generate the include code, if any */
|
||||
tplt_print(out,lemp,lemp->include,&lineno);
|
||||
|
@ -4200,17 +4431,18 @@ void ReportTable(
|
|||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate #defines for all tokens */
|
||||
if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
|
||||
else prefix = "";
|
||||
if( mhflag ){
|
||||
const char *prefix;
|
||||
fprintf(out,"#if INTERFACE\n"); lineno++;
|
||||
if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
|
||||
else prefix = "";
|
||||
for(i=1; i<lemp->nterminal; i++){
|
||||
fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
|
||||
lineno++;
|
||||
}
|
||||
fprintf(out,"#endif\n"); lineno++;
|
||||
}else{
|
||||
fprintf(out,"#ifndef %s%s\n", prefix, lemp->symbols[1]->name);
|
||||
}
|
||||
for(i=1; i<lemp->nterminal; i++){
|
||||
fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
|
||||
lineno++;
|
||||
}
|
||||
fprintf(out,"#endif\n"); lineno++;
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate the defines */
|
||||
|
@ -4362,6 +4594,8 @@ void ReportTable(
|
|||
** been computed */
|
||||
fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++;
|
||||
fprintf(out,"#define YYNRULE %d\n",lemp->nrule); lineno++;
|
||||
fprintf(out,"#define YYNRULE_WITH_ACTION %d\n",lemp->nruleWithAction);
|
||||
lineno++;
|
||||
fprintf(out,"#define YYNTOKEN %d\n",lemp->nterminal); lineno++;
|
||||
fprintf(out,"#define YY_MAX_SHIFT %d\n",lemp->nxstate-1); lineno++;
|
||||
i = lemp->minShiftReduce;
|
||||
|
@ -4416,15 +4650,30 @@ void ReportTable(
|
|||
if( la<0 ) la = lemp->nsymbol;
|
||||
if( j==0 ) fprintf(out," /* %5d */ ", i);
|
||||
fprintf(out, " %4d,", la);
|
||||
if( j==9 || i==n-1 ){
|
||||
if( j==9 ){
|
||||
fprintf(out, "\n"); lineno++;
|
||||
j = 0;
|
||||
}else{
|
||||
j++;
|
||||
}
|
||||
}
|
||||
/* Add extra entries to the end of the yy_lookahead[] table so that
|
||||
** yy_shift_ofst[]+iToken will always be a valid index into the array,
|
||||
** even for the largest possible value of yy_shift_ofst[] and iToken. */
|
||||
nLookAhead = lemp->nterminal + lemp->nactiontab;
|
||||
while( i<nLookAhead ){
|
||||
if( j==0 ) fprintf(out," /* %5d */ ", i);
|
||||
fprintf(out, " %4d,", lemp->nterminal);
|
||||
if( j==9 ){
|
||||
fprintf(out, "\n"); lineno++;
|
||||
j = 0;
|
||||
}else{
|
||||
j++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if( j>0 ){ fprintf(out, "\n"); lineno++; }
|
||||
fprintf(out, "};\n"); lineno++;
|
||||
acttab_free(pActtab);
|
||||
|
||||
/* Output the yy_shift_ofst[] table */
|
||||
n = lemp->nxstate;
|
||||
|
@ -4503,7 +4752,9 @@ void ReportTable(
|
|||
*/
|
||||
if( lemp->has_fallback ){
|
||||
int mx = lemp->nterminal - 1;
|
||||
while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; }
|
||||
/* 2019-08-28: Generate fallback entries for every token to avoid
|
||||
** having to do a range check on the index */
|
||||
/* while( mx>0 && lemp->symbols[mx]->fallback==0 ){ mx--; } */
|
||||
lemp->tablesize += (mx+1)*szCodeType;
|
||||
for(i=0; i<=mx; i++){
|
||||
struct symbol *p = lemp->symbols[i];
|
||||
|
@ -4605,13 +4856,20 @@ void ReportTable(
|
|||
tplt_print(out,lemp,lemp->overflow,&lineno);
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
|
||||
/* Generate the table of rule information
|
||||
/* Generate the tables of rule information. yyRuleInfoLhs[] and
|
||||
** yyRuleInfoNRhs[].
|
||||
**
|
||||
** Note: This code depends on the fact that rules are number
|
||||
** sequentually beginning with 0.
|
||||
*/
|
||||
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
||||
fprintf(out," { %4d, %4d }, /* (%d) ",rp->lhs->index,-rp->nrhs,i);
|
||||
fprintf(out," %4d, /* (%d) ", rp->lhs->index, i);
|
||||
rule_print(out, rp);
|
||||
fprintf(out," */\n"); lineno++;
|
||||
}
|
||||
tplt_xfer(lemp->name,in,out,&lineno);
|
||||
for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
||||
fprintf(out," %3d, /* (%d) ", -rp->nrhs, i);
|
||||
rule_print(out, rp);
|
||||
fprintf(out," */\n"); lineno++;
|
||||
}
|
||||
|
@ -4657,7 +4915,10 @@ void ReportTable(
|
|||
assert( rp->noCode );
|
||||
fprintf(out," /* (%d) ", rp->iRule);
|
||||
writeRuleText(out, rp);
|
||||
if( rp->doesReduce ){
|
||||
if( rp->neverReduce ){
|
||||
fprintf(out, " (NEVER REDUCES) */ assert(yyruleno!=%d);\n",
|
||||
rp->iRule); lineno++;
|
||||
}else if( rp->doesReduce ){
|
||||
fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;
|
||||
}else{
|
||||
fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n",
|
||||
|
@ -4682,8 +4943,10 @@ void ReportTable(
|
|||
/* Append any addition code the user desires */
|
||||
tplt_print(out,lemp,lemp->extracode,&lineno);
|
||||
|
||||
acttab_free(pActtab);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
if( sql ) fclose(sql);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4926,7 +5189,6 @@ char *SetNew(void){
|
|||
char *s;
|
||||
s = (char*)calloc( size, 1);
|
||||
if( s==0 ){
|
||||
extern void memory_error();
|
||||
memory_error();
|
||||
}
|
||||
return s;
|
||||
|
|
|
@ -22,16 +22,13 @@
|
|||
** The following is the concatenation of all %include directives from the
|
||||
** input grammar file:
|
||||
*/
|
||||
#include <stdio.h>
|
||||
/************ Begin %include sections from the grammar ************************/
|
||||
%%
|
||||
/**************** End of %include directives **********************************/
|
||||
/* These constants specify the various numeric values for terminal symbols
|
||||
** in a format understandable to "makeheaders". This section is blank unless
|
||||
** "lemon" is run with the "-m" command-line option.
|
||||
***************** Begin makeheaders token definitions *************************/
|
||||
/* These constants specify the various numeric values for terminal symbols.
|
||||
***************** Begin token definitions *************************************/
|
||||
%%
|
||||
/**************** End makeheaders token definitions ***************************/
|
||||
/**************** End token definitions ***************************************/
|
||||
|
||||
/* The next sections is a series of control #defines.
|
||||
** various aspects of the generated parser.
|
||||
|
@ -228,6 +225,7 @@ typedef struct yyParser yyParser;
|
|||
|
||||
#ifndef NDEBUG
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
static FILE *yyTraceFILE = 0;
|
||||
static char *yyTracePrompt = 0;
|
||||
#endif /* NDEBUG */
|
||||
|
@ -520,15 +518,18 @@ static YYACTIONTYPE yy_find_shift_action(
|
|||
do{
|
||||
i = yy_shift_ofst[stateno];
|
||||
assert( i>=0 );
|
||||
/* assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD ); */
|
||||
assert( i<=YY_ACTTAB_COUNT );
|
||||
assert( i+YYNTOKEN<=(int)YY_NLOOKAHEAD );
|
||||
assert( iLookAhead!=YYNOCODE );
|
||||
assert( iLookAhead < YYNTOKEN );
|
||||
i += iLookAhead;
|
||||
if( i>=YY_NLOOKAHEAD || yy_lookahead[i]!=iLookAhead ){
|
||||
assert( i<(int)YY_NLOOKAHEAD );
|
||||
if( yy_lookahead[i]!=iLookAhead ){
|
||||
#ifdef YYFALLBACK
|
||||
YYCODETYPE iFallback; /* Fallback token */
|
||||
if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0])
|
||||
&& (iFallback = yyFallback[iLookAhead])!=0 ){
|
||||
assert( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) );
|
||||
iFallback = yyFallback[iLookAhead];
|
||||
if( iFallback!=0 ){
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n",
|
||||
|
@ -543,16 +544,8 @@ static YYACTIONTYPE yy_find_shift_action(
|
|||
#ifdef YYWILDCARD
|
||||
{
|
||||
int j = i - iLookAhead + YYWILDCARD;
|
||||
if(
|
||||
#if YY_SHIFT_MIN+YYWILDCARD<0
|
||||
j>=0 &&
|
||||
#endif
|
||||
#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT
|
||||
j<YY_ACTTAB_COUNT &&
|
||||
#endif
|
||||
j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) &&
|
||||
yy_lookahead[j]==YYWILDCARD && iLookAhead>0
|
||||
){
|
||||
assert( j<(int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])) );
|
||||
if( yy_lookahead[j]==YYWILDCARD && iLookAhead>0 ){
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE ){
|
||||
fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n",
|
||||
|
@ -566,6 +559,7 @@ static YYACTIONTYPE yy_find_shift_action(
|
|||
#endif /* YYWILDCARD */
|
||||
return yy_default[stateno];
|
||||
}else{
|
||||
assert( i>=0 && i<(int)(sizeof(yy_action)/sizeof(yy_action[0])) );
|
||||
return yy_action[i];
|
||||
}
|
||||
}while(1);
|
||||
|
@ -685,13 +679,15 @@ static void yy_shift(
|
|||
yyTraceShift(yypParser, yyNewState, "Shift");
|
||||
}
|
||||
|
||||
/* The following table contains information about every rule that
|
||||
** is used during the reduce.
|
||||
*/
|
||||
static const struct {
|
||||
YYCODETYPE lhs; /* Symbol on the left-hand side of the rule */
|
||||
signed char nrhs; /* Negative of the number of RHS symbols in the rule */
|
||||
} yyRuleInfo[] = {
|
||||
/* For rule J, yyRuleInfoLhs[J] contains the symbol on the left-hand side
|
||||
** of that rule */
|
||||
static const YYCODETYPE yyRuleInfoLhs[] = {
|
||||
%%
|
||||
};
|
||||
|
||||
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
|
||||
** of symbols on the right-hand side of that rule. */
|
||||
static const signed char yyRuleInfoNRhs[] = {
|
||||
%%
|
||||
};
|
||||
|
||||
|
@ -722,16 +718,20 @@ static YYACTIONTYPE yy_reduce(
|
|||
(void)yyLookahead;
|
||||
(void)yyLookaheadToken;
|
||||
yymsp = yypParser->yytos;
|
||||
assert( yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) );
|
||||
#ifndef NDEBUG
|
||||
if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){
|
||||
yysize = yyRuleInfo[yyruleno].nrhs;
|
||||
if( yyTraceFILE ){
|
||||
yysize = yyRuleInfoNRhs[yyruleno];
|
||||
if( yysize ){
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s], go to state %d.\n",
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s, pop back to state %d.\n",
|
||||
yyTracePrompt,
|
||||
yyruleno, yyRuleName[yyruleno], yymsp[yysize].stateno);
|
||||
yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action",
|
||||
yymsp[yysize].stateno);
|
||||
}else{
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s].\n",
|
||||
yyTracePrompt, yyruleno, yyRuleName[yyruleno]);
|
||||
fprintf(yyTraceFILE, "%sReduce %d [%s]%s.\n",
|
||||
yyTracePrompt, yyruleno, yyRuleName[yyruleno],
|
||||
yyruleno<YYNRULE_WITH_ACTION ? "" : " without external action");
|
||||
}
|
||||
}
|
||||
#endif /* NDEBUG */
|
||||
|
@ -739,7 +739,7 @@ static YYACTIONTYPE yy_reduce(
|
|||
/* 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 ){
|
||||
if( yyRuleInfoNRhs[yyruleno]==0 ){
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){
|
||||
yypParser->yyhwm++;
|
||||
|
@ -781,9 +781,9 @@ static YYACTIONTYPE yy_reduce(
|
|||
%%
|
||||
/********** End reduce actions ************************************************/
|
||||
};
|
||||
assert( yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) );
|
||||
yygoto = yyRuleInfo[yyruleno].lhs;
|
||||
yysize = yyRuleInfo[yyruleno].nrhs;
|
||||
assert( yyruleno<sizeof(yyRuleInfoLhs)/sizeof(yyRuleInfoLhs[0]) );
|
||||
yygoto = yyRuleInfoLhs[yyruleno];
|
||||
yysize = yyRuleInfoNRhs[yyruleno];
|
||||
yyact = yy_find_reduce_action(yymsp[yysize].stateno,(YYCODETYPE)yygoto);
|
||||
|
||||
/* There are no SHIFTREDUCE actions on nonterminals because the table
|
||||
|
@ -987,10 +987,9 @@ void Parse(
|
|||
yymajor = YYNOCODE;
|
||||
}else{
|
||||
while( yypParser->yytos >= yypParser->yystack
|
||||
&& yymx != YYERRORSYMBOL
|
||||
&& (yyact = yy_find_reduce_action(
|
||||
yypParser->yytos->stateno,
|
||||
YYERRORSYMBOL)) >= YY_MIN_REDUCE
|
||||
YYERRORSYMBOL)) > YY_MAX_SHIFTREDUCE
|
||||
){
|
||||
yy_pop_parser_stack(yypParser);
|
||||
}
|
||||
|
@ -1067,12 +1066,11 @@ void Parse(
|
|||
*/
|
||||
int ParseFallback(int iToken){
|
||||
#ifdef YYFALLBACK
|
||||
if( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) ){
|
||||
return yyFallback[iToken];
|
||||
}
|
||||
assert( iToken<(int)(sizeof(yyFallback)/sizeof(yyFallback[0])) );
|
||||
return yyFallback[iToken];
|
||||
#else
|
||||
(void)iToken;
|
||||
#endif
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
Make ParseInit and ParseFinalize static to fix -Wmissing-prototypes in
|
||||
dtd_grammar.c. Hide ParseFinalize to fix -Wunused-function since this feature
|
||||
dtd_grammar.c. Hide ParseFallback to fix -Wunused-function since this feature
|
||||
is not used by Wireshark.
|
||||
|
||||
Mark yymajor as _U_ since none of the lemon grammar files seem to use it in
|
||||
their %syntax_error directive, this fixes -Wunused-parameter
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lempar.c
|
||||
+++ b/lempar.c
|
||||
@@ -319,7 +319,7 @@ static int yyGrowStack(yyParser *p){
|
||||
|
||||
@@ -317,7 +317,7 @@ static int yyGrowStack(yyParser *p){
|
||||
|
||||
/* Initialize a new parser that has already been allocated.
|
||||
*/
|
||||
-void ParseInit(void *yypRawParser ParseCTX_PDECL){
|
||||
|
@ -15,7 +16,7 @@ their %syntax_error directive, this fixes -Wunused-parameter
|
|||
yyParser *yypParser = (yyParser*)yypRawParser;
|
||||
ParseCTX_STORE
|
||||
#ifdef YYTRACKMAXSTACKDEPTH
|
||||
@@ -426,7 +426,7 @@ static void yy_pop_parser_stack(yyParser *pParser){
|
||||
@@ -424,7 +424,7 @@ static void yy_pop_parser_stack(yyParser *pParser){
|
||||
/*
|
||||
** Clear all secondary memory allocations from the parser
|
||||
*/
|
||||
|
@ -33,16 +34,16 @@ their %syntax_error directive, this fixes -Wunused-parameter
|
|||
ParseTOKENTYPE yyminor /* The minor type of the error token */
|
||||
){
|
||||
ParseARG_FETCH
|
||||
@@ -1060,6 +1060,7 @@ void Parse(
|
||||
@@ -1059,6 +1059,7 @@ void Parse(
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+#if 0
|
||||
/*
|
||||
** Return the fallback token corresponding to canonical token iToken, or
|
||||
** 0 if iToken has no fallback.
|
||||
@@ -1074,3 +1075,4 @@ int ParseFallback(int iToken){
|
||||
#endif
|
||||
@@ -1072,3 +1073,4 @@ int ParseFallback(int iToken){
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
+#endif
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
Avoid dead store warning, the same assignment happens later in this function.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -3950,7 +3950,7 @@ void print_stack_union(
|
||||
@@ -4090,7 +4101,7 @@ void print_stack_union(
|
||||
int *plineno, /* Pointer to the line number */
|
||||
int mhflag /* True if generating makeheaders output */
|
||||
){
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
Assertions to avoid false null-pointer dereferences.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -690,11 +690,13 @@ int acttab_insert(acttab *p, int makeItSafe){
|
||||
@@ -695,11 +695,13 @@ int acttab_insert(acttab *p, int makeItSafe){
|
||||
fprintf(stderr,"malloc failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -12,10 +13,10 @@ Assertions to avoid false null-pointer dereferences.
|
|||
}
|
||||
}
|
||||
+ assert(p->aAction); /* Hint for CSA (for p->aAction[i] below) */
|
||||
|
||||
|
||||
/* Scan the existing action table looking for an offset that is a
|
||||
** duplicate of the current transaction set. Fall out of the loop
|
||||
@@ -1078,6 +1080,7 @@ void FindLinks(struct lemon *lemp)
|
||||
@@ -1083,6 +1091,7 @@ void FindLinks(struct lemon *lemp)
|
||||
** which the link is attached. */
|
||||
for(i=0; i<lemp->nstate; i++){
|
||||
stp = lemp->sorted[i];
|
||||
|
@ -23,10 +24,10 @@ Assertions to avoid false null-pointer dereferences.
|
|||
for(cfp=stp->cfp; cfp; cfp=cfp->next){
|
||||
cfp->stp = stp;
|
||||
}
|
||||
@@ -1684,6 +1687,7 @@ int main(int argc, char **argv)
|
||||
@@ -1695,6 +1704,7 @@ int main(int argc, char **argv)
|
||||
/* Parse the input file */
|
||||
Parse(&lem);
|
||||
if( lem.errorcnt ) exit(lem.errorcnt);
|
||||
if( lem.printPreprocessed || lem.errorcnt ) exit(lem.errorcnt);
|
||||
+ assert(lem.rule); /* Hint for CSA (no errors => rule found). */
|
||||
if( lem.nrule==0 ){
|
||||
fprintf(stderr,"Empty grammar.\n");
|
||||
|
|
|
@ -4,9 +4,10 @@ false positive (use-after-free). Change done with:
|
|||
sed -e 's#\*\(x[1-4]a\) = array;$#memcpy(\1, \&array, sizeof(array)); /* & */#'
|
||||
|
||||
Link: https://bugs.llvm.org/show_bug.cgi?id=39356
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -5076,7 +5076,7 @@ int Strsafe_insert(const char *data)
|
||||
@@ -5338,7 +5349,7 @@ int Strsafe_insert(const char *data)
|
||||
array.ht[h] = newnp;
|
||||
}
|
||||
free(x1a->tbl);
|
||||
|
@ -15,7 +16,7 @@ Link: https://bugs.llvm.org/show_bug.cgi?id=39356
|
|||
}
|
||||
/* Insert the new data */
|
||||
h = ph & (x1a->size-1);
|
||||
@@ -5244,7 +5244,7 @@ int Symbol_insert(struct symbol *data, const char *key)
|
||||
@@ -5506,7 +5517,7 @@ int Symbol_insert(struct symbol *data, const char *key)
|
||||
array.ht[h] = newnp;
|
||||
}
|
||||
free(x2a->tbl);
|
||||
|
@ -24,7 +25,7 @@ Link: https://bugs.llvm.org/show_bug.cgi?id=39356
|
|||
}
|
||||
/* Insert the new data */
|
||||
h = ph & (x2a->size-1);
|
||||
@@ -5441,7 +5441,7 @@ int State_insert(struct state *data, struct config *key)
|
||||
@@ -5703,7 +5714,7 @@ int State_insert(struct state *data, struct config *key)
|
||||
array.ht[h] = newnp;
|
||||
}
|
||||
free(x3a->tbl);
|
||||
|
@ -33,7 +34,7 @@ Link: https://bugs.llvm.org/show_bug.cgi?id=39356
|
|||
}
|
||||
/* Insert the new data */
|
||||
h = ph & (x3a->size-1);
|
||||
@@ -5580,7 +5580,7 @@ int Configtable_insert(struct config *data)
|
||||
@@ -5842,7 +5853,7 @@ int Configtable_insert(struct config *data)
|
||||
array.ht[h] = newnp;
|
||||
}
|
||||
free(x4a->tbl);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
Avoid leaking pathbuf when path==0 by marking allocation failures as fatal.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -3413,6 +3413,7 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
|
||||
@@ -3538,6 +3548,7 @@ PRIVATE char *pathsearch(char *argv0, char *name, int modemask)
|
||||
if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
|
||||
pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 );
|
||||
path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
The memory of pathsearch is leaked by tplt_open. Instead of functionally modify
|
||||
the code to fix the leak, just assert that we will never reach that code path
|
||||
since Wireshark always sets the template option.
|
||||
|
||||
Not suitable for proposing to upstream since the assumption might not hold!
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -3505,6 +3505,9 @@ PRIVATE FILE *tplt_open(struct lemon *lemp)
|
||||
char *tpltname;
|
||||
char *cp;
|
||||
|
||||
+ /* We always require the -T option, avoid memleak in the other code path. */
|
||||
+ assert(user_templatename);
|
||||
+
|
||||
/* first, see if user specified a template filename on the command line. */
|
||||
if (user_templatename != 0) {
|
||||
if( access(user_templatename,004)==-1 ){
|
|
@ -1,17 +0,0 @@
|
|||
Fix memory leak in ReportTable, the data structure does not escape this
|
||||
function (directly or indirectly via another function), so freeing it seems the
|
||||
right thing to do.
|
||||
|
||||
acttab_free was added upstream in commit 5c0b1c80aa, 2003-10-21 via
|
||||
"Convert lemon to use a single perfect hash table for storing the actions.
|
||||
This should make the resulting parser both smaller and faster. (CVS 1112)"
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -4418,6 +4418,7 @@ void ReportTable(
|
||||
}
|
||||
}
|
||||
fprintf(out, "};\n"); lineno++;
|
||||
+ acttab_free(pActtab);
|
||||
|
||||
/* Output the yy_shift_ofst[] table */
|
||||
n = lemp->nxstate;
|
|
@ -1,9 +1,10 @@
|
|||
CSA thought that stp would leak if State_insert returns early: when x3a is NULL
|
||||
(memory allocation failure) or when the state existed before (cannot happen for
|
||||
the initial state). So annotate it as such.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
--- a/lemon.c
|
||||
+++ b/lemon.c
|
||||
@@ -990,7 +990,11 @@ PRIVATE struct state *getstate(struct lemon *lemp)
|
||||
@@ -993,7 +995,13 @@ PRIVATE struct state *getstate(struct lemon *lemp)
|
||||
stp->cfp = cfp; /* Remember the configuration closure */
|
||||
stp->statenum = lemp->nstate++; /* Every state gets a sequence number */
|
||||
stp->ap = 0; /* No actions, yet. */
|
||||
|
@ -11,7 +12,9 @@ the initial state). So annotate it as such.
|
|||
+ int ret =
|
||||
+#endif
|
||||
State_insert(stp,stp->bp); /* Add to the state table */
|
||||
+#ifndef NDEBUG
|
||||
+ assert(ret == 1); /* CSA hint: stp did not leak, it has escaped. */
|
||||
+#endif
|
||||
buildshifts(lemp,stp); /* Recursively compute successor states */
|
||||
}
|
||||
return stp;
|
||||
|
|
Loading…
Reference in New Issue