| Index: third_party/sqlite/src/tool/lemon.c
|
| diff --git a/third_party/sqlite/src/tool/lemon.c b/third_party/sqlite/src/tool/lemon.c
|
| index d704deb624d42b39ca455db5bc5617e2197d62d9..aa0f4e3e9ca39c39ebb5fa4f3877de8e4b33c648 100644
|
| --- a/third_party/sqlite/src/tool/lemon.c
|
| +++ b/third_party/sqlite/src/tool/lemon.c
|
| @@ -263,7 +263,8 @@ struct symbol {
|
| int useCnt; /* Number of times used */
|
| char *destructor; /* Code which executes whenever this symbol is
|
| ** popped from the stack during error processing */
|
| - int destLineno; /* Line number for start of destructor */
|
| + int destLineno; /* Line number for start of destructor. Set to
|
| + ** -1 for duplicate destructors. */
|
| char *datatype; /* The data type of information held by this
|
| ** object. Only used if type==NONTERMINAL */
|
| int dtnum; /* The data type number. In the parser, the value
|
| @@ -286,9 +287,15 @@ struct rule {
|
| const char **rhsalias; /* An alias for each RHS symbol (NULL if none) */
|
| int line; /* Line number at which code begins */
|
| 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 canReduce; /* True if this rule is ever reduced */
|
| + Boolean doesReduce; /* Reduce actions occur after optimization */
|
| struct rule *nextlhs; /* Next rule with the same LHS */
|
| struct rule *next; /* Next rule in the global list */
|
| };
|
| @@ -336,6 +343,7 @@ struct action {
|
| struct state *stp; /* The new state, if a shift */
|
| struct rule *rp; /* The rule, if a reduce */
|
| } x;
|
| + struct symbol *spOpt; /* SHIFTREDUCE optimization to this symbol */
|
| struct action *next; /* Next action for this state */
|
| struct action *collide; /* Next action with the same hash */
|
| };
|
| @@ -346,7 +354,7 @@ struct state {
|
| struct config *bp; /* The basis configurations for this state */
|
| struct config *cfp; /* All configurations in this set */
|
| int statenum; /* Sequential number for this state */
|
| - struct action *ap; /* Array of actions for this state */
|
| + struct action *ap; /* List of actions for this state */
|
| int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */
|
| int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */
|
| int iDfltReduce; /* Default action is to REDUCE by this rule */
|
| @@ -370,6 +378,7 @@ struct plink {
|
| struct lemon {
|
| struct state **sorted; /* Table of states sorted by state number */
|
| struct rule *rule; /* List of all rules */
|
| + struct rule *startRule; /* First rule */
|
| int nstate; /* Number of states */
|
| int nxstate; /* nstate with tail degenerate states removed */
|
| int nrule; /* Number of rules */
|
| @@ -526,6 +535,7 @@ void Action_add(
|
| *app = newaction;
|
| newaction->type = type;
|
| newaction->sp = sp;
|
| + newaction->spOpt = 0;
|
| if( type==SHIFT ){
|
| newaction->x.stp = (struct state *)arg;
|
| }else{
|
| @@ -856,12 +866,12 @@ void FindStates(struct lemon *lemp)
|
| 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->rule->lhs->name);
|
| +symbol instead.",lemp->start,lemp->startRule->lhs->name);
|
| lemp->errorcnt++;
|
| - sp = lemp->rule->lhs;
|
| + sp = lemp->startRule->lhs;
|
| }
|
| }else{
|
| - sp = lemp->rule->lhs;
|
| + sp = lemp->startRule->lhs;
|
| }
|
|
|
| /* Make sure the start symbol doesn't occur on the right-hand side of
|
| @@ -1115,9 +1125,9 @@ void FindActions(struct lemon *lemp)
|
| /* Add the accepting token */
|
| if( lemp->start ){
|
| sp = Symbol_find(lemp->start);
|
| - if( sp==0 ) sp = lemp->rule->lhs;
|
| + if( sp==0 ) sp = lemp->startRule->lhs;
|
| }else{
|
| - sp = lemp->rule->lhs;
|
| + sp = lemp->startRule->lhs;
|
| }
|
| /* Add to the first state (which is always the starting state of the
|
| ** finite state machine) an action to ACCEPT if the lookahead is the
|
| @@ -1495,6 +1505,54 @@ static void handle_T_option(char *z){
|
| lemon_strcpy(user_templatename, z);
|
| }
|
|
|
| +/* Merge together to lists of rules ordered by rule.iRule */
|
| +static struct rule *Rule_merge(struct rule *pA, struct rule *pB){
|
| + struct rule *pFirst = 0;
|
| + struct rule **ppPrev = &pFirst;
|
| + while( pA && pB ){
|
| + if( pA->iRule<pB->iRule ){
|
| + *ppPrev = pA;
|
| + ppPrev = &pA->next;
|
| + pA = pA->next;
|
| + }else{
|
| + *ppPrev = pB;
|
| + ppPrev = &pB->next;
|
| + pB = pB->next;
|
| + }
|
| + }
|
| + if( pA ){
|
| + *ppPrev = pA;
|
| + }else{
|
| + *ppPrev = pB;
|
| + }
|
| + return pFirst;
|
| +}
|
| +
|
| +/*
|
| +** Sort a list of rules in order of increasing iRule value
|
| +*/
|
| +static struct rule *Rule_sort(struct rule *rp){
|
| + 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++){
|
| + rp = Rule_merge(x[i], rp);
|
| + x[i] = 0;
|
| + }
|
| + x[i] = rp;
|
| + rp = pNext;
|
| + }
|
| + rp = 0;
|
| + for(i=0; i<sizeof(x)/sizeof(x[0]); i++){
|
| + rp = Rule_merge(x[i], rp);
|
| + }
|
| + return rp;
|
| +}
|
| +
|
| /* forward reference */
|
| static const char *minimum_size_type(int lwr, int upr, int *pnByte);
|
|
|
| @@ -1543,6 +1601,7 @@ int main(int argc, char **argv)
|
| int i;
|
| int exitcode;
|
| struct lemon lem;
|
| + struct rule *rp;
|
|
|
| OptInit(argv,options,stderr);
|
| if( version ){
|
| @@ -1589,6 +1648,19 @@ int main(int argc, char **argv)
|
| for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++);
|
| lem.nterminal = i;
|
|
|
| + /* Assign sequential rule numbers. Start with 0. Put rules that have no
|
| + ** reduce action C-code associated with them last, so that the switch()
|
| + ** statement that selects reduction actions will have a smaller jump table.
|
| + */
|
| + for(i=0, rp=lem.rule; rp; rp=rp->next){
|
| + rp->iRule = rp->code ? i++ : -1;
|
| + }
|
| + for(rp=lem.rule; rp; rp=rp->next){
|
| + if( rp->iRule<0 ) rp->iRule = i++;
|
| + }
|
| + lem.startRule = lem.rule;
|
| + lem.rule = Rule_sort(lem.rule);
|
| +
|
| /* Generate a reprint of the grammar, if requested on the command line */
|
| if( rpflag ){
|
| Reprint(&lem);
|
| @@ -2148,6 +2220,7 @@ to follow the previous rule.");
|
| }else{
|
| psp->prevrule->line = psp->tokenlineno;
|
| psp->prevrule->code = &x[1];
|
| + psp->prevrule->noCode = 0;
|
| }
|
| }else if( x[0]=='[' ){
|
| psp->state = PRECEDENCE_MARK_1;
|
| @@ -2254,6 +2327,7 @@ to follow the previous rule.");
|
| rp->lhsalias = psp->lhsalias;
|
| rp->nrhs = psp->nrhs;
|
| rp->code = 0;
|
| + rp->noCode = 1;
|
| rp->precsym = 0;
|
| rp->index = psp->gp->nrule++;
|
| rp->nextlhs = rp->lhs->rule;
|
| @@ -3052,13 +3126,13 @@ int PrintAction(
|
| }
|
| case REDUCE: {
|
| struct rule *rp = ap->x.rp;
|
| - fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->index);
|
| + fprintf(fp,"%*s reduce %-7d",indent,ap->sp->name,rp->iRule);
|
| RulePrint(fp, rp, -1);
|
| break;
|
| }
|
| case SHIFTREDUCE: {
|
| struct rule *rp = ap->x.rp;
|
| - fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->index);
|
| + fprintf(fp,"%*s shift-reduce %-7d",indent,ap->sp->name,rp->iRule);
|
| RulePrint(fp, rp, -1);
|
| break;
|
| }
|
| @@ -3071,7 +3145,7 @@ int PrintAction(
|
| case SRCONFLICT:
|
| case RRCONFLICT:
|
| fprintf(fp,"%*s reduce %-7d ** Parsing conflict **",
|
| - indent,ap->sp->name,ap->x.rp->index);
|
| + indent,ap->sp->name,ap->x.rp->iRule);
|
| break;
|
| case SSCONFLICT:
|
| fprintf(fp,"%*s shift %-7d ** Parsing conflict **",
|
| @@ -3088,7 +3162,7 @@ int PrintAction(
|
| case RD_RESOLVED:
|
| if( showPrecedenceConflict ){
|
| fprintf(fp,"%*s reduce %-7d -- dropped by precedence",
|
| - indent,ap->sp->name,ap->x.rp->index);
|
| + indent,ap->sp->name,ap->x.rp->iRule);
|
| }else{
|
| result = 0;
|
| }
|
| @@ -3097,6 +3171,9 @@ int PrintAction(
|
| result = 0;
|
| break;
|
| }
|
| + if( result && ap->spOpt ){
|
| + fprintf(fp," /* because %s==%s */", ap->sp->name, ap->spOpt->name);
|
| + }
|
| return result;
|
| }
|
|
|
| @@ -3119,7 +3196,7 @@ void ReportOutput(struct lemon *lemp)
|
| while( cfp ){
|
| char buf[20];
|
| if( cfp->dot==cfp->rp->nrhs ){
|
| - lemon_sprintf(buf,"(%d)",cfp->rp->index);
|
| + lemon_sprintf(buf,"(%d)",cfp->rp->iRule);
|
| fprintf(fp," %5s ",buf);
|
| }else{
|
| fprintf(fp," ");
|
| @@ -3220,8 +3297,8 @@ PRIVATE int compute_action(struct lemon *lemp, struct action *ap)
|
| int act;
|
| switch( ap->type ){
|
| case SHIFT: act = ap->x.stp->statenum; break;
|
| - case SHIFTREDUCE: act = ap->x.rp->index + lemp->nstate; break;
|
| - case REDUCE: act = ap->x.rp->index + lemp->nstate+lemp->nrule; break;
|
| + case SHIFTREDUCE: act = ap->x.rp->iRule + lemp->nstate; break;
|
| + case REDUCE: act = ap->x.rp->iRule + lemp->nstate+lemp->nrule; break;
|
| case ERROR: act = lemp->nstate + lemp->nrule*2; break;
|
| case ACCEPT: act = lemp->nstate + lemp->nrule*2 + 1; break;
|
| default: act = -1; break;
|
| @@ -3430,6 +3507,7 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2){
|
| int c;
|
| char zInt[40];
|
| if( zText==0 ){
|
| + if( used==0 && z!=0 ) z[0] = 0;
|
| used = 0;
|
| return z;
|
| }
|
| @@ -3463,15 +3541,23 @@ 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
|
| -** the symbols in this string so that the refer to elements of the parser
|
| -** stack.
|
| +** Write and transform the rp->code string so that symbols are expanded.
|
| +** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate.
|
| +**
|
| +** 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;
|
| int i;
|
| - char lhsused = 0; /* True if the LHS element has been used */
|
| - char used[MAXRHS]; /* True for each RHS element which is used */
|
| + 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 lhsdirect; /* True if LHS writes directly into stack */
|
| + 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;
|
| lhsused = 0;
|
| @@ -3480,25 +3566,89 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
|
| static char newlinestr[2] = { '\n', '\0' };
|
| rp->code = newlinestr;
|
| rp->line = rp->ruleline;
|
| + rp->noCode = 1;
|
| + }else{
|
| + rp->noCode = 0;
|
| + }
|
| +
|
| +
|
| + 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 no 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));
|
| + rp->noCode = 0;
|
| + }
|
| + }else if( rp->lhsalias==0 ){
|
| + /* There is no LHS value symbol. */
|
| + lhsdirect = 1;
|
| + }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);
|
|
|
| /* This const cast is wrong but harmless, if we're careful. */
|
| 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]!='_')) ){
|
| char saved;
|
| for(xp= &cp[1]; ISALNUM(*xp) || *xp=='_'; xp++);
|
| saved = *xp;
|
| *xp = 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;
|
| lhsused = 1;
|
| }else{
|
| for(i=0; i<rp->nrhs; i++){
|
| 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
|
| ** the token number of X, not the value of X */
|
| append_str("yymsp[%d].major",-1,i-rp->nrhs+1,0);
|
| @@ -3523,6 +3673,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
|
| append_str(cp, 1, 0, 0);
|
| } /* 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 */
|
| if( rp->lhsalias && !lhsused ){
|
| ErrorMsg(lemp->filename,rp->ruleline,
|
| @@ -3531,27 +3686,58 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){
|
| lemp->errorcnt++;
|
| }
|
|
|
| - /* Generate destructor code for RHS symbols which are not used in the
|
| - ** reduce code */
|
| + /* Generate destructor code for RHS minor values which are not referenced.
|
| + ** Generate error messages for unused labels and duplicate labels.
|
| + */
|
| for(i=0; i<rp->nrhs; i++){
|
| - if( rp->rhsalias[i] && !used[i] ){
|
| - ErrorMsg(lemp->filename,rp->ruleline,
|
| - "Label %s for \"%s(%s)\" is never used.",
|
| - rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
|
| - lemp->errorcnt++;
|
| - }else if( rp->rhsalias[i]==0 ){
|
| - if( has_destructor(rp->rhs[i],lemp) ){
|
| - append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
|
| - rp->rhs[i]->index,i-rp->nrhs+1);
|
| - }else{
|
| - /* No destructor defined for this term */
|
| + 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,
|
| + "Label %s for \"%s(%s)\" is never used.",
|
| + rp->rhsalias[i],rp->rhs[i]->name,rp->rhsalias[i]);
|
| + lemp->errorcnt++;
|
| }
|
| + }else if( i>0 && has_destructor(rp->rhs[i],lemp) ){
|
| + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0,
|
| + rp->rhs[i]->index,i-rp->nrhs+1);
|
| }
|
| }
|
| - if( rp->code ){
|
| - cp = append_str(0,0,0,0);
|
| - rp->code = Strsafe(cp?cp:"");
|
| +
|
| + /* 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);
|
| }
|
| +
|
| + /* Suffix code generation complete */
|
| + cp = append_str(0,0,0,0);
|
| + if( cp && cp[0] ){
|
| + rp->codeSuffix = Strsafe(cp);
|
| + rp->noCode = 0;
|
| + }
|
| +
|
| + return rc;
|
| }
|
|
|
| /*
|
| @@ -3566,6 +3752,12 @@ PRIVATE void emit_code(
|
| ){
|
| 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 */
|
| if( rp->code ){
|
| if( !lemp->nolinenosflag ){
|
| @@ -3573,15 +3765,23 @@ PRIVATE void emit_code(
|
| tplt_linedir(out,rp->line,lemp->filename);
|
| }
|
| fprintf(out,"{%s",rp->code);
|
| - for(cp=rp->code; *cp; cp++){
|
| - if( *cp=='\n' ) (*lineno)++;
|
| - } /* End loop */
|
| + for(cp=rp->code; *cp; cp++){ if( *cp=='\n' ) (*lineno)++; }
|
| fprintf(out,"}\n"); (*lineno)++;
|
| if( !lemp->nolinenosflag ){
|
| (*lineno)++;
|
| 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;
|
| }
|
| @@ -3954,6 +4154,18 @@ void ReportTable(
|
| }
|
| free(ax);
|
|
|
| + /* Mark rules that are actually used for reduce actions after all
|
| + ** optimizations have been applied
|
| + */
|
| + for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE;
|
| + for(i=0; i<lemp->nxstate; i++){
|
| + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
|
| + if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){
|
| + ap->x.rp->doesReduce = i;
|
| + }
|
| + }
|
| + }
|
| +
|
| /* Finish rendering the constants now that the action table has
|
| ** been computed */
|
| fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++;
|
| @@ -4019,20 +4231,21 @@ void ReportTable(
|
| fprintf(out, "};\n"); lineno++;
|
|
|
| /* Output the yy_shift_ofst[] table */
|
| - fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++;
|
| n = lemp->nxstate;
|
| while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--;
|
| - fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
|
| - fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
|
| - fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
|
| + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++;
|
| + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++;
|
| + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++;
|
| + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++;
|
| fprintf(out, "static const %s yy_shift_ofst[] = {\n",
|
| - minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++;
|
| + minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz));
|
| + lineno++;
|
| lemp->tablesize += n*sz;
|
| for(i=j=0; i<n; i++){
|
| int ofst;
|
| stp = lemp->sorted[i];
|
| ofst = stp->iTknOfst;
|
| - if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1;
|
| + if( ofst==NO_OFFSET ) ofst = lemp->nactiontab;
|
| if( j==0 ) fprintf(out," /* %5d */ ", i);
|
| fprintf(out, " %4d,", ofst);
|
| if( j==9 || i==n-1 ){
|
| @@ -4122,7 +4335,7 @@ void ReportTable(
|
| ** when tracing REDUCE actions.
|
| */
|
| for(i=0, rp=lemp->rule; rp; rp=rp->next, i++){
|
| - assert( rp->index==i );
|
| + assert( rp->iRule==i );
|
| fprintf(out," /* %3d */ \"", i);
|
| writeRuleText(out, rp);
|
| fprintf(out,"\",\n"); lineno++;
|
| @@ -4172,6 +4385,7 @@ void ReportTable(
|
| for(i=0; i<lemp->nsymbol; i++){
|
| struct symbol *sp = lemp->symbols[i];
|
| if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
|
| + if( sp->destLineno<0 ) continue; /* Already emitted */
|
| fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++;
|
|
|
| /* Combine duplicate destructors into a single case */
|
| @@ -4182,7 +4396,7 @@ void ReportTable(
|
| && strcmp(sp->destructor,sp2->destructor)==0 ){
|
| fprintf(out," case %d: /* %s */\n",
|
| sp2->index, sp2->name); lineno++;
|
| - sp2->destructor = 0;
|
| + sp2->destLineno = -1; /* Avoid emitting this destructor again */
|
| }
|
| }
|
|
|
| @@ -4206,38 +4420,51 @@ void ReportTable(
|
| tplt_xfer(lemp->name,in,out,&lineno);
|
|
|
| /* Generate code which execution during each REDUCE action */
|
| + i = 0;
|
| 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 */
|
| for(rp=lemp->rule; rp; rp=rp->next){
|
| struct rule *rp2; /* Other rules with the same action */
|
| - if( rp->code==0 ) continue;
|
| - if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */
|
| - fprintf(out," case %d: /* ", rp->index);
|
| + if( rp->codeEmitted ) continue;
|
| + if( rp->noCode ){
|
| + /* No C code actions, so this will be part of the "default:" rule */
|
| + continue;
|
| + }
|
| + fprintf(out," case %d: /* ", rp->iRule);
|
| writeRuleText(out, rp);
|
| fprintf(out, " */\n"); lineno++;
|
| for(rp2=rp->next; rp2; rp2=rp2->next){
|
| - if( rp2->code==rp->code ){
|
| - fprintf(out," case %d: /* ", rp2->index);
|
| + if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix
|
| + && rp2->codeSuffix==rp->codeSuffix ){
|
| + fprintf(out," case %d: /* ", rp2->iRule);
|
| writeRuleText(out, rp2);
|
| - fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->index); lineno++;
|
| - rp2->code = 0;
|
| + fprintf(out," */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++;
|
| + rp2->codeEmitted = 1;
|
| }
|
| }
|
| emit_code(out,rp,lemp,&lineno);
|
| fprintf(out," break;\n"); lineno++;
|
| - rp->code = 0;
|
| + rp->codeEmitted = 1;
|
| }
|
| /* Finally, output the default: rule. We choose as the default: all
|
| ** empty actions. */
|
| fprintf(out," default:\n"); lineno++;
|
| for(rp=lemp->rule; rp; rp=rp->next){
|
| - if( rp->code==0 ) continue;
|
| - assert( rp->code[0]=='\n' && rp->code[1]==0 );
|
| - fprintf(out," /* (%d) ", rp->index);
|
| + if( rp->codeEmitted ) continue;
|
| + assert( rp->noCode );
|
| + fprintf(out," /* (%d) ", rp->iRule);
|
| writeRuleText(out, rp);
|
| - fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->index); lineno++;
|
| + if( rp->doesReduce ){
|
| + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;
|
| + }else{
|
| + fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n",
|
| + rp->iRule); lineno++;
|
| + }
|
| }
|
| fprintf(out," break;\n"); lineno++;
|
| tplt_xfer(lemp->name,in,out,&lineno);
|
| @@ -4308,7 +4535,7 @@ void ReportHeader(struct lemon *lemp)
|
| void CompressTables(struct lemon *lemp)
|
| {
|
| struct state *stp;
|
| - struct action *ap, *ap2;
|
| + struct action *ap, *ap2, *nextap;
|
| struct rule *rp, *rp2, *rbest;
|
| int nbest, n;
|
| int i;
|
| @@ -4385,6 +4612,36 @@ void CompressTables(struct lemon *lemp)
|
| }
|
| }
|
| }
|
| +
|
| + /* If a SHIFTREDUCE action specifies a rule that has a single RHS term
|
| + ** (meaning that the SHIFTREDUCE will land back in the state where it
|
| + ** started) and if there is no C-code associated with the reduce action,
|
| + ** then we can go ahead and convert the action to be the same as the
|
| + ** action for the RHS of the rule.
|
| + */
|
| + for(i=0; i<lemp->nstate; i++){
|
| + stp = lemp->sorted[i];
|
| + for(ap=stp->ap; ap; ap=nextap){
|
| + nextap = ap->next;
|
| + if( ap->type!=SHIFTREDUCE ) continue;
|
| + rp = ap->x.rp;
|
| + if( rp->noCode==0 ) continue;
|
| + if( rp->nrhs!=1 ) continue;
|
| +#if 1
|
| + /* Only apply this optimization to non-terminals. It would be OK to
|
| + ** apply it to terminal symbols too, but that makes the parser tables
|
| + ** larger. */
|
| + if( ap->sp->index<lemp->nterminal ) continue;
|
| +#endif
|
| + /* If we reach this point, it means the optimization can be applied */
|
| + nextap = ap;
|
| + for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){}
|
| + assert( ap2!=0 );
|
| + ap->spOpt = ap2->sp;
|
| + ap->type = ap2->type;
|
| + ap->x = ap2->x;
|
| + }
|
| + }
|
| }
|
|
|
|
|
|
|