From 8a18e5c7eb57c8e56bd91815078229a46219060c Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Sun, 20 Mar 2016 10:50:28 -0500 Subject: [PATCH] Lemon update 2016-02-17 01:18:33 on branch parser-performance - In Lemon, add the ability for the left-most RHS label to be the same as the LHS label, causing the LHS values to be written directly into the stack. (user: drh) --- tools/lemon/lemon.c | 133 ++++++++++++++++++++++++++++++++++++------- tools/lemon/lempar.c | 2 - 2 files changed, 112 insertions(+), 23 deletions(-) diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index a70220572..7eb72b652 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -190,6 +190,8 @@ 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 */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ Boolean canReduce; /* True if this rule is ever reduced */ @@ -3365,6 +3367,7 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2, int bNoSubst) int c; char zInt[40]; if( zText==0 ){ + if( used==0 && z!=0 ) z[0] = 0; used = 0; return z; } @@ -3406,7 +3409,9 @@ PRIVATE void 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 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 */ for(i=0; inrhs; i++) used[i] = 0; lhsused = 0; @@ -3417,6 +3422,47 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ rp->line = rp->ruleline; } + if( rp->lhsalias==0 ){ + /* There is no LHS value symbol. */ + lhsdirect = 1; + }else if( rp->nrhs==0 ){ + /* If there are no RHS symbols, then writing directly to the LHS is ok */ + lhsdirect = 1; + }else if( rp->rhsalias[0]==0 ){ + /* The left-most RHS symbol has not value. LHS direct is ok. But + ** we have to call the distructor on the RHS symbol first. */ + lhsdirect = 1; + if( has_destructor(rp->rhs[0],lemp) ){ + append_str(0,0,0,0,0); + append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, + rp->rhs[0]->index,1-rp->nrhs,0); + rp->codePrefix = Strsafe(append_str(0,0,0,0,0)); + } + }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ + /* The LHS symbol and the left-most RHS symbol are the same, so + ** direct writing is allowed */ + lhsdirect = 1; + lhsused = 1; + used[0] = 1; + if( rp->lhs->dtnum!=rp->rhs[0]->dtnum ){ + ErrorMsg(lemp->filename,rp->ruleline, + "%s(%s) and %s(%s) share the same label but have " + "different datatypes.", + rp->lhs->name, rp->lhsalias, rp->rhs[0]->name, rp->rhsalias[0]); + lemp->errorcnt++; + } + }else{ + lhsdirect = 0; + } + if( lhsdirect ){ + sprintf(zLhs, "yymsp[%d].minor.yy%d",1-rp->nrhs,rp->lhs->dtnum); + }else{ + append_str(0,0,0,0,0); + append_str(" YYMINORTYPE yylhsminor;\n", 0, 0, 0, 0); + rp->codePrefix = Strsafe(append_str(0,0,0,0,0)); + sprintf(zLhs, "yylhsminor.yy%d",rp->lhs->dtnum); + } + append_str(0,0,0,0,0); /* This const cast is wrong but harmless, if we're careful. */ @@ -3427,7 +3473,7 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ saved = *xp; *xp = 0; if( rp->lhsalias && strcmp(cp,rp->lhsalias)==0 ){ - append_str("yygotominor.yy%d",0,rp->lhs->dtnum,0,0); + append_str(zLhs,0,0,0,0); cp = xp; lhsused = 1; }else{ @@ -3458,6 +3504,11 @@ PRIVATE void translate_code(struct lemon *lemp, struct rule *rp){ append_str(cp, 1, 0, 0, 1); } /* End loop */ + /* Main code generation completed */ + cp = append_str(0,0,0,0,0); + if( cp && cp[0] ) rp->code = Strsafe(cp); + append_str(0,0,0,0,0); + /* Check to make sure the LHS has been used */ if( rp->lhsalias && !lhsused ){ ErrorMsg(lemp->filename,rp->ruleline, @@ -3466,27 +3517,53 @@ 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; inrhs; 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,0); - }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; jrhsalias[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,0); } } - if( rp->code ){ - cp = append_str(0,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, 0); + append_str(zLhs, 0, 0, 0, 0); + append_str(";\n", 0, 0, 0, 0); } + + /* Suffix code generation complete */ + cp = append_str(0,0,0,0,0); + if( cp ) rp->codeSuffix = Strsafe(cp); } /* @@ -3501,6 +3578,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 ){ @@ -3508,15 +3591,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; } diff --git a/tools/lemon/lempar.c b/tools/lemon/lempar.c index 3a440983d..b3ab0da06 100644 --- a/tools/lemon/lempar.c +++ b/tools/lemon/lempar.c @@ -623,7 +623,6 @@ static void yy_reduce( ){ int yygoto; /* The next state */ int yyact; /* The next action */ - YYMINORTYPE yygotominor; /* The LHS of the rule reduced */ yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; @@ -687,7 +686,6 @@ static void yy_reduce( yymsp -= yysize-1; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; - yymsp->minor = yygotominor; yyTraceShift(yypParser, yyact); }else{ assert( yyact == YY_ACCEPT_ACTION );