[sqlite] Lemon-generated parser gives an assertion failure

2017-04-25 Thread Kelvin Sherlock
The test case can be simplified to:

bug.lemon:
---

%include {
#include 
#include 
#include 
#include "bug.h"
}
%code {
int main(void) {

void *pParser;

pParser = ParseAlloc(malloc);
if (!pParser) {
printf("out of memory\n");
exit(1);
}

ParseTrace(stderr, "Debug: ");

Parse(pParser, X, 0);
Parse(pParser, 0, 0);
ParseFree(pParser, free);
return 0;
}
}


main ::= decls.
decls ::= . 
decls ::= decls decl.

decl ::= X

—

which generates this code:

  default:
  /* (0) main ::= decls */ yytestcase(yyruleno==0);
  /* (1) decls ::= (OPTIMIZED OUT) */ assert(yyruleno!=1);
break;

I believe the issue is line 4164 which should be … = LEMON_TRUE.  Currently, 
when i=0, all rules will erroneously be optimized out.

  4157/* Mark rules that are actually used for reduce actions after all
  4158** optimizations have been applied
  4159*/
  4160for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE;
  4161for(i=0; inxstate; i++){
  4162  for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){
  4163if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){
  4164  ap->x.rp->doesReduce = i;
  4165}
  4166  }
  4167}

Kelvin Sherlock

___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


[sqlite] Lemon: Simple recursive rule causes assertion failed: stateno <= YY_SHIFT_COUNT

2017-04-24 Thread Kelvin Sherlock
This lemon bug was reported about 6 months ago:


8<

%include {
#include 
#include 
#include 
#include "lemon-bug.h"
}

%code {
int main()
{
void *pParser;

pParser = ParseAlloc(malloc);
if (!pParser)
{
printf("out of memory\n");
exit(1);
}

ParseTrace(stderr, "Debug: ");

Parse(pParser, CMDNAME, 0);
Parse(pParser, INTEGER, 0);
Parse(pParser, TEXT, 0);
Parse(pParser, EOL, 0);

Parse(pParser, CMDNAME, 0);
Parse(pParser, INTEGER, 0);
Parse(pParser, TEXT, 0);
Parse(pParser, EOL, 0);

Parse(pParser, 0, 0);
ParseFree(pParser, free);
return 0;
}
}


database ::= entrylist.

entrylist ::= command.
entrylist ::= entrylist command.

command ::= CMDNAME cmdargs EOL. 
cmdargs ::= .
cmdargs ::= cmdargs cmdarg.

cmdarg ::= INTEGER.
cmdarg ::= TEXT.


8<


./lemon-bug 
Debug: Input 'CMDNAME'
Debug: Shift 'CMDNAME', go to state 3
Debug: Return. Stack=[CMDNAME]
Debug: Input 'INTEGER'
Assertion failed: (stateno <= YY_SHIFT_COUNT), function yy_find_shift_action, 
file lemon-bug.c, line 512.
Abort trap: 6

which generates this code:

#define YY_MAX_SHIFT 3
#define YY_SHIFT_COUNT(2)
#define YY_SHIFT_USE_DFLT (13)
static const unsigned char yy_shift_ofst[] = {
 /* 0 */ 7,1,6,
};
…

  assert( stateno <= YY_SHIFT_COUNT );

without the shift table compression -- lemon.c line 4235:
while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n—;

it will generate this:

#define YY_SHIFT_COUNT(3)
static const unsigned char yy_shift_ofst[] = {
 /* 0 */ 7,1,6,   13,
};

and the assert doesn’t fail.

Most of the time (and in the case of SQLite parse.y) the shift table won’t 
compress and YY_MAX_SHIFT == YY_SHIFT_COUNT.
Given that, it probably shouldn’t try to compress the shift table.

Kelvin Sherlock



___
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users


[sqlite] Lemon reduce action merge bug

2016-04-30 Thread Kelvin Sherlock

> On Apr 29, 2016, at 7:29 AM, Richard Hipp  wrote:
> 
> On 4/28/16, Kelvin Sherlock  wrote:
>> I believe the lemon reduce action optimizer needs to compare the codePrefix
>> and codeSuffix.
> 
> Thanks for the bug report.  A fix has now been checked in.
> 
> -- 
> D. Richard Hipp
> drh at sqlite.org

Here are a couple more edge cases I noticed:

---

bug_report ::= rule.

%destructor malloc{free($$)}

rule ::= .
rule ::= malloc . /* 1 */
rule ::= malloc malloc . /* 2 */

malloc(X) ::= ID . { X = malloc(100); }

---

1. the rhs[0] destructor will not be called since the lhsalias null check 
happens first and the codePrefix is never generated.

The empty lhsalias check can be moved down to compensate:

@@ -3552,30 +3552,30 @@ PRIVATE int translate_code(struct lemon *lemp, struct 
rule *rp){
   if( rp->code==0 ){
 static char newlinestr[2] = { '\n', '\0' };
 rp->code = newlinestr;
 rp->line = rp->ruleline;
   }


-  if( rp->lhsalias==0 ){
-/* There is no LHS value symbol. */
-lhsdirect = 1;
-  }else if( rp->nrhs==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 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);
   append_str("  yy_destructor(yypParser,%d,[%d].minor);\n", 0,
  rp->rhs[0]->index,1-rp->nrhs);
   rp->codePrefix = Strsafe(append_str(0,0,0,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;


2. if there is a codePrefix or codeSuffix but no code, it will be merged into 
the default rule and the prefix/suffix will be lost.

@@ -3715,7 +3715,7 @@ PRIVATE int translate_code(struct lemon *lemp, struct 
rule *rp){

   /* Suffix code generation complete */
   cp = append_str(0,0,0,0);
-  if( cp ) rp->codeSuffix = Strsafe(cp);
+  if( cp && cp[0] ) rp->codeSuffix = Strsafe(cp);

   return rc;
 }

@@ -4397,7 +4397,8 @@ void ReportTable(
   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: */
+if( rp->code[0]=='\n' && rp->code[1]==0 && rp->codePrefix==0
+  && rp->codeSuffix==0 ) continue; /* Will be default: */
 fprintf(out,"  case %d: /* ", rp->iRule);
 writeRuleText(out, rp);
 fprintf(out, " */\n"); lineno++;
@@ -4419,7 +4420,8 @@ void ReportTable(
   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 );
+assert( rp->code[0]=='\n' && rp->code[1]==0 && rp->codePrefix==0
+  && rp->codeSuffix==0 );
 fprintf(out,"  /* (%d) ", rp->iRule);
 writeRuleText(out, rp);
 fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++;


Thanks,
Kelvin




[sqlite] Lemon reduce action merge bug

2016-04-28 Thread Kelvin Sherlock
I believe the lemon reduce action optimizer needs to compare the codePrefix and 
codeSuffix. Consider this example:

8<

%type malloc {void *}
%destructor malloc {free($$)}
%type contrived_example {int}

bug_report ::= contrived_example.

contrived_example(LHS) ::= INT INT INT. { LHS = 0; }
contrived_example(LHS) ::= malloc malloc malloc. { LHS = 0; }

malloc(LHS) ::= . { LHS = malloc(100); } 

8< 

Since the code (but not the codeSuffix) matches, they will be merged together 
into this:

  case 0: /* contrived_example ::= INT INT INT */
  case 1: /* contrived_example ::= malloc malloc malloc */ 
yytestcase(yyruleno==1);
#line 8 "bug.lemon"
{ yymsp[-2].minor.yy4 = 0; }
#line 725 "bug.c"
break;

or this:

/** Begin reduce actions **/
  case 0: /* contrived_example ::= malloc malloc malloc */
  case 1: /* contrived_example ::= INT INT INT */ yytestcase(yyruleno==1);
{  yy_destructor(yypParser,3,[-2].minor);
#line 8 "bug.lemon"
{ yymsp[-2].minor.yy4 = 0; }
#line 726 "bug.c"
  yy_destructor(yypParser,3,[-1].minor);
  yy_destructor(yypParser,3,[0].minor);
}
break;

depending on which rule is first.

patch:

diff --git a/lemon.c b/lemon.c
index 903fe97..dca5a08 100644
--- a/lemon.c
+++ b/lemon.c
@@ -4402,7 +4402,11 @@ void ReportTable(
 writeRuleText(out, rp);
 fprintf(out, " */\n"); lineno++;
 for(rp2=rp->next; rp2; rp2=rp2->next){
-  if( rp2->code==rp->code ){
+  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->iRule); lineno++;


Thanks,
Kelvin Sherlock