/ Check-in [3c5aa850]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Lemon collapses common destructors and reduce actions into a single case. (CVS 1837)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:3c5aa850eeec5c75c5200a3707852cc5fc9e780b
User & Date: drh 2004-07-20 14:06:52
Context
2004-07-20
18:23
Simplify the where.c logic by flipping expression over so that the controlling variable is always on the left. (CVS 1838) check-in: ec8bfa38 user: drh tags: trunk
14:06
Lemon collapses common destructors and reduce actions into a single case. (CVS 1837) check-in: 3c5aa850 user: drh tags: trunk
12:45
Add the '%ifdef' capability to lemon. Other minor changes. (CVS 1836) check-in: 522ff721 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Show Whitespace Changes Patch

Changes to src/os_unix.c.

57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

#if defined(THREADSAFE) && defined(__linux__)
#define getpid pthread_self
#endif

/*
** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
** section 6.5.2.2 lines 483 through 490 specify that when a process
** sets or clears a lock, that operation overrides any prior locks set







|







57
58
59
60
61
62
63
64
65
66
67
68
69
70
71


/*
** Include code that is common to all os_*.c files
*/
#include "os_common.h"

#if defined(THREADSAFE) && THREADSAFE && defined(__linux__)
#define getpid pthread_self
#endif

/*
** Here is the dirt on POSIX advisory locks:  ANSI STD 1003.1 (1996)
** section 6.5.2.2 lines 483 through 490 specify that when a process
** sets or clears a lock, that operation overrides any prior locks set

Changes to src/parse.y.

10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.129 2004/06/30 09:49:24 danielk1977 Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){







|







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
**
*************************************************************************
** This file contains SQLite's grammar for SQL.  Process this file
** using the lemon parser generator to generate C code that runs
** the parser.  Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
** @(#) $Id: parse.y,v 1.130 2004/07/20 14:06:52 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
%default_type {Token}
%extra_argument {Parse *pParse}
%syntax_error {
  if( pParse->zErrMsg==0 ){

Changes to tool/lemon.c.

2996
2997
2998
2999
3000
3001
3002
3003
3004

3005
3006
3007
3008
3009

3010

3011

































3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023

3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036

3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
....
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079




























3080
3081
3082
3083
3084
3085
3086
....
3565
3566
3567
3568
3569
3570
3571












3572
3573
3574
3575
3576
3577
3578
....
3600
3601
3602
3603
3604
3605
3606





3607






3608
3609
3610
3611
3612
3613
3614
  }else{
    ret = lemp->vardest!=0 || sp->destructor!=0;
  }
  return ret;
}

/* 
** Generate code which executes when the rule "rp" is reduced.  Write
** the code to "out".  Make sure lineno stays up-to-date.

*/
PRIVATE void emit_code(out,rp,lemp,lineno)
FILE *out;
struct rule *rp;
struct lemon *lemp;

int *lineno;

{

































 char *cp, *xp;
 int linecnt = 0;
 int i;
 char lhsused = 0;    /* True if the LHS element has been used */
 char used[MAXRHS];   /* True for each RHS element which is used */

 for(i=0; i<rp->nrhs; i++) used[i] = 0;
 lhsused = 0;

 /* Generate code to do the reduce action */
 if( rp->code ){
   fprintf(out,"#line %d \"%s\"\n{",rp->line,lemp->filename);

   for(cp=rp->code; *cp; cp++){
     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 ){
         fprintf(out,"yygotominor.yy%d",rp->lhs->dtnum);
         cp = xp;
         lhsused = 1;
       }else{
         for(i=0; i<rp->nrhs; i++){
           if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){

             fprintf(out,"yymsp[%d].minor.yy%d",i-rp->nrhs+1,rp->rhs[i]->dtnum);
             cp = xp;
             used[i] = 1;
             break;
           }
         }
       }
       *xp = saved;
     }
     if( *cp=='\n' ) linecnt++;
     fputc(*cp,out);
   } /* End loop */
   (*lineno) += 3 + linecnt;
   fprintf(out,"}\n#line %d \"%s\"\n",*lineno,lemp->outname);
 } /* End if( rp->code ) */

 /* Check to make sure the LHS has been used */
 if( rp->lhsalias && !lhsused ){
   ErrorMsg(lemp->filename,rp->ruleline,
     "Label \"%s\" for \"%s(%s)\" is never used.",
       rp->lhsalias,rp->lhs->name,rp->lhsalias);
   lemp->errorcnt++;
................................................................................
   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) ){
       fprintf(out,"  yy_destructor(%d,&yymsp[%d].minor);\n",
          rp->rhs[i]->index,i-rp->nrhs+1); (*lineno)++;
     }else{
       fprintf(out,"        /* No destructor defined for %s */\n",
        rp->rhs[i]->name);
        (*lineno)++;
     }
   }
 }




























 return;
}

/*
** Print the definition of the union used for the parser's data stack.
** This union contains fields for every possible data type for tokens
** and nonterminals.  In the process of computing and printing this
................................................................................
      fprintf(out,"      break;\n"); lineno++;
    }
  }
  for(i=0; i<lemp->nsymbol; i++){
    struct symbol *sp = lemp->symbols[i];
    if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
    fprintf(out,"    case %d:\n",sp->index); lineno++;












    emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
    fprintf(out,"      break;\n"); lineno++;
  }
  if( lemp->vardest ){
    struct symbol *dflt_sp = 0;
    for(i=0; i<lemp->nsymbol; i++){
      struct symbol *sp = lemp->symbols[i];
................................................................................
  for(rp=lemp->rule; rp; rp=rp->next){
    fprintf(out,"  { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
  }
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate code which execution during each REDUCE action */
  for(rp=lemp->rule; rp; rp=rp->next){





    fprintf(out,"      case %d:\n",rp->index); lineno++;






    emit_code(out,rp,lemp,&lineno);
    fprintf(out,"        break;\n"); lineno++;
  }
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate code which executes if a parse fails */
  tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);







|
|
>

<
|
|
|
>
|
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
<
|
|
|

|
|

<
<
<
>







|





>
|








|
<
|
<
<
<







 







|
|
|
|
<
<
|
|
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>

>
>
>
>
>
>







2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006

3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047

3048
3049
3050
3051
3052
3053
3054



3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079

3080



3081
3082
3083
3084
3085
3086
3087
....
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103


3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
....
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
....
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
  }else{
    ret = lemp->vardest!=0 || sp->destructor!=0;
  }
  return ret;
}

/*
** Append text to a dynamically allocated string.  If zText is 0 then
** reset the string to be empty again.  Always return the complete text
** of the string (which is overwritten with each call).
*/

PRIVATE char *append_str(char *zText, int n, int p1, int p2){
  static char *z = 0;
  static int alloced = 0;
  static int used = 0;
  int i, c;
  char zInt[40];

  if( zText==0 ){
    used = 0;
    return z;
  }
  if( n<=0 ) n = strlen(zText);
  if( n+sizeof(zInt)*2+used >= alloced ){
    alloced = n + sizeof(zInt)*2 + used + 200;
    z = realloc(z,  alloced);
  }
  if( z==0 ) return "";
  while( n-- > 0 ){
    c = *(zText++);
    if( c=='%' && zText[0]=='d' ){
      sprintf(zInt, "%d", p1);
      p1 = p2;
      strcpy(&z[used], zInt);
      used += strlen(&z[used]);
      zText++;
      n--;
    }else{
      z[used++] = c;
    }
  }
  z[used] = 0;
  return z;
}

/*
** 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.  Return a new string stored in space obtained from malloc.
*/
PRIVATE char *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 */

  for(i=0; i<rp->nrhs; i++) used[i] = 0;
  lhsused = 0;




  append_str(0,0,0,0);
  for(cp=rp->code; *cp; cp++){
    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",-1,rp->lhs->dtnum,0);
        cp = xp;
        lhsused = 1;
      }else{
        for(i=0; i<rp->nrhs; i++){
          if( rp->rhsalias[i] && strcmp(cp,rp->rhsalias[i])==0 ){
            append_str("yymsp[%d].minor.yy%d",-1,
                       i-rp->nrhs+1,rp->rhs[i]->dtnum);
            cp = xp;
            used[i] = 1;
            break;
          }
        }
      }
      *xp = saved;
    }
    append_str(cp, 1, 0, 0);

  } /* End loop */




  /* Check to make sure the LHS has been used */
  if( rp->lhsalias && !lhsused ){
    ErrorMsg(lemp->filename,rp->ruleline,
      "Label \"%s\" for \"%s(%s)\" is never used.",
        rp->lhsalias,rp->lhs->name,rp->lhsalias);
    lemp->errorcnt++;
................................................................................
    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(%d,&yymsp[%d].minor);\n", -1,
           rp->rhs[i]->index,i-rp->nrhs+1);
      }else{
        /* No destructor defined for this term */


      }
    }
  }
  cp = append_str(0,0,0,0);
  rp->code = Strsafe(cp);
}

/* 
** Generate code which executes when the rule "rp" is reduced.  Write
** the code to "out".  Make sure lineno stays up-to-date.
*/
PRIVATE void emit_code(out,rp,lemp,lineno)
FILE *out;
struct rule *rp;
struct lemon *lemp;
int *lineno;
{
 char *cp;
 int linecnt = 0;

 /* Generate code to do the reduce action */
 if( rp->code ){
   fprintf(out,"#line %d \"%s\"\n{",rp->line,lemp->filename);
   fprintf(out,"%s",rp->code);
   for(cp=rp->code; *cp; cp++){
     if( *cp=='\n' ) linecnt++;
   } /* End loop */
   (*lineno) += 3 + linecnt;
   fprintf(out,"}\n#line %d \"%s\"\n",*lineno,lemp->outname);
 } /* End if( rp->code ) */

 return;
}

/*
** Print the definition of the union used for the parser's data stack.
** This union contains fields for every possible data type for tokens
** and nonterminals.  In the process of computing and printing this
................................................................................
      fprintf(out,"      break;\n"); lineno++;
    }
  }
  for(i=0; i<lemp->nsymbol; i++){
    struct symbol *sp = lemp->symbols[i];
    if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue;
    fprintf(out,"    case %d:\n",sp->index); lineno++;

    /* Combine duplicate destructors into a single case */
    for(j=i+1; j<lemp->nsymbol; j++){
      struct symbol *sp2 = lemp->symbols[j];
      if( sp2 && sp2->type!=TERMINAL && sp2->destructor
          && sp2->dtnum==sp->dtnum
          && strcmp(sp->destructor,sp2->destructor)==0 ){
         fprintf(out,"    case %d:\n",sp2->index); lineno++;
         sp2->destructor = 0;
      }
    }

    emit_destructor_code(out,lemp->symbols[i],lemp,&lineno);
    fprintf(out,"      break;\n"); lineno++;
  }
  if( lemp->vardest ){
    struct symbol *dflt_sp = 0;
    for(i=0; i<lemp->nsymbol; i++){
      struct symbol *sp = lemp->symbols[i];
................................................................................
  for(rp=lemp->rule; rp; rp=rp->next){
    fprintf(out,"  { %d, %d },\n",rp->lhs->index,rp->nrhs); lineno++;
  }
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate code which execution during each REDUCE action */
  for(rp=lemp->rule; rp; rp=rp->next){
    if( rp->code ) translate_code(lemp, rp);
  }
  for(rp=lemp->rule; rp; rp=rp->next){
    struct rule *rp2;
    if( rp->code==0 ) continue;
    fprintf(out,"      case %d:\n",rp->index); lineno++;
    for(rp2=rp->next; rp2; rp2=rp2->next){
      if( rp2->code==rp->code ){
        fprintf(out,"      case %d:\n",rp2->index); lineno++;
        rp2->code = 0;
      }
    }
    emit_code(out,rp,lemp,&lineno);
    fprintf(out,"        break;\n"); lineno++;
  }
  tplt_xfer(lemp->name,in,out,&lineno);

  /* Generate code which executes if a parse fails */
  tplt_print(out,lemp,lemp->failure,lemp->failureln,&lineno);