/ Diff
Login

Differences From Artifact [796930d5]:

To Artifact [624b24c5]:


    45     45   
    46     46   /*
    47     47   ** Compilers are getting increasingly pedantic about type conversions
    48     48   ** as C evolves ever closer to Ada....  To work around the latest problems
    49     49   ** we have to define the following variant of strlen().
    50     50   */
    51     51   #define lemonStrlen(X)   ((int)strlen(X))
           52  +
           53  +/*
           54  +** Compilers are starting to complain about the use of sprintf() and strcpy(),
           55  +** saying they are unsafe.  So we define our own versions of those routines too.
           56  +**
           57  +** There are three routines here:  lemon_sprintf(), lemon_vsprintf(), and
           58  +** lemon_addtext().  The first two are replacements for sprintf() and vsprintf().
           59  +** The third is a helper routine for vsnprintf() that adds texts to the end of a
           60  +** buffer, making sure the buffer is always zero-terminated.
           61  +**
           62  +** The string formatter is a minimal subset of stdlib sprintf() supporting only
           63  +** a few simply conversions:
           64  +**
           65  +**   %d
           66  +**   %s
           67  +**   %.*s
           68  +**
           69  +*/
           70  +static void lemon_addtext(
           71  +  char *zBuf,           /* The buffer to which text is added */
           72  +  int *pnUsed,          /* Slots of the buffer used so far */
           73  +  const char *zIn,      /* Text to add */
           74  +  int nIn,              /* Bytes of text to add.  -1 to use strlen() */
           75  +  int iWidth            /* Field width.  Negative to left justify */
           76  +){
           77  +  if( nIn<0 ) for(nIn=0; zIn[nIn]; nIn++){}
           78  +  while( iWidth>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth--; }
           79  +  if( nIn==0 ) return;
           80  +  memcpy(&zBuf[*pnUsed], zIn, nIn);
           81  +  *pnUsed += nIn;
           82  +  while( (-iWidth)>nIn ){ zBuf[(*pnUsed)++] = ' '; iWidth++; }
           83  +  zBuf[*pnUsed] = 0;
           84  +}
           85  +static int lemon_vsprintf(char *str, const char *zFormat, va_list ap){
           86  +  int i, j, k, c, size;
           87  +  int nUsed = 0;
           88  +  const char *z;
           89  +  char zTemp[50];
           90  +  str[0] = 0;
           91  +  for(i=j=0; (c = zFormat[i])!=0; i++){
           92  +    if( c=='%' ){
           93  +      int iWidth = 0;
           94  +      lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0);
           95  +      c = zFormat[++i];
           96  +      if( isdigit(c) || (c=='-' && isdigit(zFormat[i+1])) ){
           97  +        if( c=='-' ) i++;
           98  +        while( isdigit(zFormat[i]) ) iWidth = iWidth*10 + zFormat[i++] - '0';
           99  +        if( c=='-' ) iWidth = -iWidth;
          100  +        c = zFormat[i];
          101  +      }
          102  +      if( c=='d' ){
          103  +        int v = va_arg(ap, int);
          104  +        if( v<0 ){
          105  +          lemon_addtext(str, &nUsed, "-", 1, iWidth);
          106  +          v = -v;
          107  +        }else if( v==0 ){
          108  +          lemon_addtext(str, &nUsed, "0", 1, iWidth);
          109  +        }
          110  +        k = 0;
          111  +        while( v>0 ){
          112  +          k++;
          113  +          zTemp[sizeof(zTemp)-k] = (v%10) + '0';
          114  +          v /= 10;
          115  +        }
          116  +        lemon_addtext(str, &nUsed, &zTemp[sizeof(zTemp)-k], k, iWidth);
          117  +      }else if( c=='s' ){
          118  +        z = va_arg(ap, const char*);
          119  +        lemon_addtext(str, &nUsed, z, -1, iWidth);
          120  +      }else if( c=='.' && memcmp(&zFormat[i], ".*s", 3)==0 ){
          121  +        i += 2;
          122  +        k = va_arg(ap, int);
          123  +        z = va_arg(ap, const char*);
          124  +        lemon_addtext(str, &nUsed, z, k, iWidth);
          125  +      }else if( c=='%' ){
          126  +        lemon_addtext(str, &nUsed, "%", 1, 0);
          127  +      }else{
          128  +        fprintf(stderr, "illegal format\n");
          129  +        exit(1);
          130  +      }
          131  +      j = i+1;
          132  +    }
          133  +  }
          134  +  lemon_addtext(str, &nUsed, &zFormat[j], i-j, 0);
          135  +  return nUsed;
          136  +}
          137  +static int lemon_sprintf(char *str, const char *format, ...){
          138  +  va_list ap;
          139  +  int rc;
          140  +  va_start(ap, format);
          141  +  rc = lemon_vsprintf(str, format, ap);
          142  +  va_end(ap);
          143  +  return rc;
          144  +}
          145  +static void lemon_strcpy(char *dest, const char *src){
          146  +  while( (*(dest++) = *(src++))!=0 ){}
          147  +}
          148  +static void lemon_strcat(char *dest, const char *src){
          149  +  while( *dest ) dest++;
          150  +  lemon_strcpy(dest, src);
          151  +}
          152  +
    52    153   
    53    154   /* a few forward declarations... */
    54    155   struct rule;
    55    156   struct lemon;
    56    157   struct action;
    57    158   
    58    159   static struct action *Action_new(void);
................................................................................
  1363   1464     }
  1364   1465     paz = &azDefine[nDefine-1];
  1365   1466     *paz = (char *) malloc( lemonStrlen(z)+1 );
  1366   1467     if( *paz==0 ){
  1367   1468       fprintf(stderr,"out of memory\n");
  1368   1469       exit(1);
  1369   1470     }
  1370         -  strcpy(*paz, z);
         1471  +  lemon_strcpy(*paz, z);
  1371   1472     for(z=*paz; *z && *z!='='; z++){}
  1372   1473     *z = 0;
  1373   1474   }
  1374   1475   
  1375   1476   static char *user_templatename = NULL;
  1376   1477   static void handle_T_option(char *z){
  1377   1478     user_templatename = (char *) malloc( lemonStrlen(z)+1 );
  1378   1479     if( user_templatename==0 ){
  1379   1480       memory_error();
  1380   1481     }
  1381         -  strcpy(user_templatename, z);
         1482  +  lemon_strcpy(user_templatename, z);
  1382   1483   }
  1383   1484   
  1384   1485   /* The main program.  Parse the command line and do it... */
  1385   1486   int main(int argc, char **argv)
  1386   1487   {
  1387   1488     static int version = 0;
  1388   1489     static int rpflag = 0;
................................................................................
  1443   1544     if( lem.errorcnt ) exit(lem.errorcnt);
  1444   1545     if( lem.nrule==0 ){
  1445   1546       fprintf(stderr,"Empty grammar.\n");
  1446   1547       exit(1);
  1447   1548     }
  1448   1549   
  1449   1550     /* Count and index the symbols of the grammar */
  1450         -  lem.nsymbol = Symbol_count();
  1451   1551     Symbol_new("{default}");
         1552  +  lem.nsymbol = Symbol_count();
  1452   1553     lem.symbols = Symbol_arrayof();
  1453         -  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
  1454         -  qsort(lem.symbols,lem.nsymbol+1,sizeof(struct symbol*), Symbolcmpp);
  1455         -  for(i=0; i<=lem.nsymbol; i++) lem.symbols[i]->index = i;
         1554  +  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
         1555  +  qsort(lem.symbols,lem.nsymbol,sizeof(struct symbol*), Symbolcmpp);
         1556  +  for(i=0; i<lem.nsymbol; i++) lem.symbols[i]->index = i;
         1557  +  while( lem.symbols[i-1]->type==MULTITERMINAL ){ i--; }
         1558  +  assert( strcmp(lem.symbols[i-1]->name,"{default}")==0 );
         1559  +  lem.nsymbol = i - 1;
  1456   1560     for(i=1; isupper(lem.symbols[i]->name[0]); i++);
  1457   1561     lem.nterminal = i;
  1458   1562   
  1459   1563     /* Generate a reprint of the grammar, if requested on the command line */
  1460   1564     if( rpflag ){
  1461   1565       Reprint(&lem);
  1462   1566     }else{
................................................................................
  1936   2040     PRECEDENCE_MARK_1,
  1937   2041     PRECEDENCE_MARK_2,
  1938   2042     RESYNC_AFTER_RULE_ERROR,
  1939   2043     RESYNC_AFTER_DECL_ERROR,
  1940   2044     WAITING_FOR_DESTRUCTOR_SYMBOL,
  1941   2045     WAITING_FOR_DATATYPE_SYMBOL,
  1942   2046     WAITING_FOR_FALLBACK_ID,
  1943         -  WAITING_FOR_WILDCARD_ID
         2047  +  WAITING_FOR_WILDCARD_ID,
         2048  +  WAITING_FOR_CLASS_ID,
         2049  +  WAITING_FOR_CLASS_TOKEN
  1944   2050   };
  1945   2051   struct pstate {
  1946   2052     char *filename;       /* Name of the input file */
  1947   2053     int tokenlineno;      /* Linenumber at which current token starts */
  1948   2054     int errorcnt;         /* Number of errors so far */
  1949   2055     char *tokenstart;     /* Text of current token */
  1950   2056     struct lemon *gp;     /* Global state vector */
  1951   2057     enum e_state state;        /* The state of the parser */
  1952   2058     struct symbol *fallback;   /* The fallback token */
         2059  +  struct symbol *tkclass;    /* Token class symbol */
  1953   2060     struct symbol *lhs;        /* Left-hand side of current rule */
  1954   2061     const char *lhsalias;      /* Alias for the LHS */
  1955   2062     int nrhs;                  /* Number of right-hand side symbols seen */
  1956   2063     struct symbol *rhs[MAXRHS];  /* RHS symbols */
  1957   2064     const char *alias[MAXRHS]; /* Aliases for each RHS symbol (or NULL) */
  1958   2065     struct rule *prevrule;     /* Previous rule parsed */
  1959   2066     const char *declkeyword;   /* Keyword of a declaration */
................................................................................
  2250   2357           }else if( strcmp(x,"type")==0 ){
  2251   2358             psp->state = WAITING_FOR_DATATYPE_SYMBOL;
  2252   2359           }else if( strcmp(x,"fallback")==0 ){
  2253   2360             psp->fallback = 0;
  2254   2361             psp->state = WAITING_FOR_FALLBACK_ID;
  2255   2362           }else if( strcmp(x,"wildcard")==0 ){
  2256   2363             psp->state = WAITING_FOR_WILDCARD_ID;
         2364  +        }else if( strcmp(x,"token_class")==0 ){
         2365  +          psp->state = WAITING_FOR_CLASS_ID;
  2257   2366           }else{
  2258   2367             ErrorMsg(psp->filename,psp->tokenlineno,
  2259   2368               "Unknown declaration keyword: \"%%%s\".",x);
  2260   2369             psp->errorcnt++;
  2261   2370             psp->state = RESYNC_AFTER_DECL_ERROR;
  2262   2371           }
  2263   2372         }else{
................................................................................
  2343   2452           n = nOld + nNew + 20;
  2344   2453           addLineMacro = !psp->gp->nolinenosflag && psp->insertLineMacro &&
  2345   2454                           (psp->decllinenoslot==0 || psp->decllinenoslot[0]!=0);
  2346   2455           if( addLineMacro ){
  2347   2456             for(z=psp->filename, nBack=0; *z; z++){
  2348   2457               if( *z=='\\' ) nBack++;
  2349   2458             }
  2350         -          sprintf(zLine, "#line %d ", psp->tokenlineno);
         2459  +          lemon_sprintf(zLine, "#line %d ", psp->tokenlineno);
  2351   2460             nLine = lemonStrlen(zLine);
  2352   2461             n += nLine + lemonStrlen(psp->filename) + nBack;
  2353   2462           }
  2354   2463           *psp->declargslot = (char *) realloc(*psp->declargslot, n);
  2355   2464           zBuf = *psp->declargslot + nOld;
  2356   2465           if( addLineMacro ){
  2357   2466             if( nOld && zBuf[-1]!='\n' ){
................................................................................
  2417   2526             psp->gp->wildcard = sp;
  2418   2527           }else{
  2419   2528             ErrorMsg(psp->filename, psp->tokenlineno,
  2420   2529               "Extra wildcard to token: %s", x);
  2421   2530             psp->errorcnt++;
  2422   2531           }
  2423   2532         }
         2533  +      break;
         2534  +    case WAITING_FOR_CLASS_ID:
         2535  +      if( !islower(x[0]) ){
         2536  +        ErrorMsg(psp->filename, psp->tokenlineno,
         2537  +          "%%token_class must be followed by an identifier: ", x);
         2538  +        psp->errorcnt++;
         2539  +        psp->state = RESYNC_AFTER_DECL_ERROR;
         2540  +     }else if( Symbol_find(x) ){
         2541  +        ErrorMsg(psp->filename, psp->tokenlineno,
         2542  +          "Symbol \"%s\" already used", x);
         2543  +        psp->errorcnt++;
         2544  +        psp->state = RESYNC_AFTER_DECL_ERROR;
         2545  +      }else{
         2546  +        psp->tkclass = Symbol_new(x);
         2547  +        psp->tkclass->type = MULTITERMINAL;
         2548  +        psp->state = WAITING_FOR_CLASS_TOKEN;
         2549  +      }
         2550  +      break;
         2551  +    case WAITING_FOR_CLASS_TOKEN:
         2552  +      if( x[0]=='.' ){
         2553  +        psp->state = WAITING_FOR_DECL_OR_RULE;
         2554  +      }else if( isupper(x[0]) || ((x[0]=='|' || x[0]=='/') && isupper(x[1])) ){
         2555  +        struct symbol *msp = psp->tkclass;
         2556  +        msp->nsubsym++;
         2557  +        msp->subsym = (struct symbol **) realloc(msp->subsym,
         2558  +          sizeof(struct symbol*)*msp->nsubsym);
         2559  +        if( !isupper(x[0]) ) x++;
         2560  +        msp->subsym[msp->nsubsym-1] = Symbol_new(x);
         2561  +      }else{
         2562  +        ErrorMsg(psp->filename, psp->tokenlineno,
         2563  +          "%%token_class argument \"%s\" should be a token", x);
         2564  +        psp->errorcnt++;
         2565  +        psp->state = RESYNC_AFTER_DECL_ERROR;
         2566  +      }
  2424   2567         break;
  2425   2568       case RESYNC_AFTER_RULE_ERROR:
  2426   2569   /*      if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
  2427   2570   **      break; */
  2428   2571       case RESYNC_AFTER_DECL_ERROR:
  2429   2572         if( x[0]=='.' ) psp->state = WAITING_FOR_DECL_OR_RULE;
  2430   2573         if( x[0]=='%' ) psp->state = WAITING_FOR_DECL_KEYWORD;
................................................................................
  2712   2855     char *cp;
  2713   2856   
  2714   2857     name = (char*)malloc( lemonStrlen(lemp->filename) + lemonStrlen(suffix) + 5 );
  2715   2858     if( name==0 ){
  2716   2859       fprintf(stderr,"Can't allocate space for a filename.\n");
  2717   2860       exit(1);
  2718   2861     }
  2719         -  strcpy(name,lemp->filename);
         2862  +  lemon_strcpy(name,lemp->filename);
  2720   2863     cp = strrchr(name,'.');
  2721   2864     if( cp ) *cp = 0;
  2722         -  strcat(name,suffix);
         2865  +  lemon_strcat(name,suffix);
  2723   2866     return name;
  2724   2867   }
  2725   2868   
  2726   2869   /* Open a file with a name based on the name of the input file,
  2727   2870   ** but with a different (specified) suffix, and return a pointer
  2728   2871   ** to the stream */
  2729   2872   PRIVATE FILE *file_open(
................................................................................
  2772   2915     }
  2773   2916     for(rp=lemp->rule; rp; rp=rp->next){
  2774   2917       printf("%s",rp->lhs->name);
  2775   2918       /*    if( rp->lhsalias ) printf("(%s)",rp->lhsalias); */
  2776   2919       printf(" ::=");
  2777   2920       for(i=0; i<rp->nrhs; i++){
  2778   2921         sp = rp->rhs[i];
  2779         -      printf(" %s", sp->name);
  2780   2922         if( sp->type==MULTITERMINAL ){
         2923  +        printf(" %s", sp->subsym[0]->name);
  2781   2924           for(j=1; j<sp->nsubsym; j++){
  2782   2925             printf("|%s", sp->subsym[j]->name);
  2783   2926           }
         2927  +      }else{
         2928  +        printf(" %s", sp->name);
  2784   2929         }
  2785   2930         /* if( rp->rhsalias[i] ) printf("(%s)",rp->rhsalias[i]); */
  2786   2931       }
  2787   2932       printf(".");
  2788   2933       if( rp->precsym ) printf(" [%s]",rp->precsym->name);
  2789   2934       /* if( rp->code ) printf("\n    %s",rp->code); */
  2790   2935       printf("\n");
................................................................................
  2798   2943     int i, j;
  2799   2944     rp = cfp->rp;
  2800   2945     fprintf(fp,"%s ::=",rp->lhs->name);
  2801   2946     for(i=0; i<=rp->nrhs; i++){
  2802   2947       if( i==cfp->dot ) fprintf(fp," *");
  2803   2948       if( i==rp->nrhs ) break;
  2804   2949       sp = rp->rhs[i];
  2805         -    fprintf(fp," %s", sp->name);
  2806   2950       if( sp->type==MULTITERMINAL ){
         2951  +      fprintf(fp," %s", sp->subsym[0]->name);
  2807   2952         for(j=1; j<sp->nsubsym; j++){
  2808   2953           fprintf(fp,"|%s",sp->subsym[j]->name);
  2809   2954         }
         2955  +    }else{
         2956  +      fprintf(fp," %s", sp->name);
  2810   2957       }
  2811   2958     }
  2812   2959   }
  2813   2960   
  2814   2961   /* #define TEST */
  2815   2962   #if 0
  2816   2963   /* Print a set */
................................................................................
  2912   3059       stp = lemp->sorted[i];
  2913   3060       fprintf(fp,"State %d:\n",stp->statenum);
  2914   3061       if( lemp->basisflag ) cfp=stp->bp;
  2915   3062       else                  cfp=stp->cfp;
  2916   3063       while( cfp ){
  2917   3064         char buf[20];
  2918   3065         if( cfp->dot==cfp->rp->nrhs ){
  2919         -        sprintf(buf,"(%d)",cfp->rp->index);
         3066  +        lemon_sprintf(buf,"(%d)",cfp->rp->index);
  2920   3067           fprintf(fp,"    %5s ",buf);
  2921   3068         }else{
  2922   3069           fprintf(fp,"          ");
  2923   3070         }
  2924   3071         ConfigPrint(fp,cfp);
  2925   3072         fprintf(fp,"\n");
  2926   3073   #if 0
................................................................................
  2977   3124   #else
  2978   3125     cp = strrchr(argv0,'/');
  2979   3126   #endif
  2980   3127     if( cp ){
  2981   3128       c = *cp;
  2982   3129       *cp = 0;
  2983   3130       path = (char *)malloc( lemonStrlen(argv0) + lemonStrlen(name) + 2 );
  2984         -    if( path ) sprintf(path,"%s/%s",argv0,name);
         3131  +    if( path ) lemon_sprintf(path,"%s/%s",argv0,name);
  2985   3132       *cp = c;
  2986   3133     }else{
  2987   3134       pathlist = getenv("PATH");
  2988   3135       if( pathlist==0 ) pathlist = ".:/bin:/usr/bin";
  2989   3136       pathbuf = (char *) malloc( lemonStrlen(pathlist) + 1 );
  2990   3137       path = (char *)malloc( lemonStrlen(pathlist)+lemonStrlen(name)+2 );
  2991   3138       if( (pathbuf != 0) && (path!=0) ){
  2992   3139         pathbufptr = pathbuf;
  2993         -      strcpy(pathbuf, pathlist);
         3140  +      lemon_strcpy(pathbuf, pathlist);
  2994   3141         while( *pathbuf ){
  2995   3142           cp = strchr(pathbuf,':');
  2996   3143           if( cp==0 ) cp = &pathbuf[lemonStrlen(pathbuf)];
  2997   3144           c = *cp;
  2998   3145           *cp = 0;
  2999         -        sprintf(path,"%s/%s",pathbuf,name);
         3146  +        lemon_sprintf(path,"%s/%s",pathbuf,name);
  3000   3147           *cp = c;
  3001   3148           if( c==0 ) pathbuf[0] = 0;
  3002   3149           else pathbuf = &cp[1];
  3003   3150           if( access(path,modemask)==0 ) break;
  3004   3151         }
  3005   3152         free(pathbufptr);
  3006   3153       }
................................................................................
  3083   3230         return 0;
  3084   3231       }
  3085   3232       return in;
  3086   3233     }
  3087   3234   
  3088   3235     cp = strrchr(lemp->filename,'.');
  3089   3236     if( cp ){
  3090         -    sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
         3237  +    lemon_sprintf(buf,"%.*s.lt",(int)(cp-lemp->filename),lemp->filename);
  3091   3238     }else{
  3092         -    sprintf(buf,"%s.lt",lemp->filename);
         3239  +    lemon_sprintf(buf,"%s.lt",lemp->filename);
  3093   3240     }
  3094   3241     if( access(buf,004)==0 ){
  3095   3242       tpltname = buf;
  3096   3243     }else if( access(templatename,004)==0 ){
  3097   3244       tpltname = templatename;
  3098   3245     }else{
  3099   3246       tpltname = pathsearch(lemp->argv0,templatename,0);
................................................................................
  3236   3383       alloced = n + sizeof(zInt)*2 + used + 200;
  3237   3384       z = (char *) realloc(z,  alloced);
  3238   3385     }
  3239   3386     if( z==0 ) return empty;
  3240   3387     while( n-- > 0 ){
  3241   3388       c = *(zText++);
  3242   3389       if( c=='%' && n>0 && zText[0]=='d' ){
  3243         -      sprintf(zInt, "%d", p1);
         3390  +      lemon_sprintf(zInt, "%d", p1);
  3244   3391         p1 = p2;
  3245         -      strcpy(&z[used], zInt);
         3392  +      lemon_strcpy(&z[used], zInt);
  3246   3393         used += lemonStrlen(&z[used]);
  3247   3394         zText++;
  3248   3395         n--;
  3249   3396       }else{
  3250   3397         z[used++] = c;
  3251   3398       }
  3252   3399     }
................................................................................
  3463   3610       if( types[hash]==0 ){
  3464   3611         sp->dtnum = hash + 1;
  3465   3612         types[hash] = (char*)malloc( lemonStrlen(stddt)+1 );
  3466   3613         if( types[hash]==0 ){
  3467   3614           fprintf(stderr,"Out of memory.\n");
  3468   3615           exit(1);
  3469   3616         }
  3470         -      strcpy(types[hash],stddt);
         3617  +      lemon_strcpy(types[hash],stddt);
  3471   3618       }
  3472   3619     }
  3473   3620   
  3474   3621     /* Print out the definition of YYTOKENTYPE and YYMINORTYPE */
  3475   3622     name = lemp->name ? lemp->name : "Parse";
  3476   3623     lineno = *plineno;
  3477   3624     if( mhflag ){ fprintf(out,"#if INTERFACE\n"); lineno++; }
................................................................................
  3549   3696   ** Write text on "out" that describes the rule "rp".
  3550   3697   */
  3551   3698   static void writeRuleText(FILE *out, struct rule *rp){
  3552   3699     int j;
  3553   3700     fprintf(out,"%s ::=", rp->lhs->name);
  3554   3701     for(j=0; j<rp->nrhs; j++){
  3555   3702       struct symbol *sp = rp->rhs[j];
  3556         -    fprintf(out," %s", sp->name);
  3557         -    if( sp->type==MULTITERMINAL ){
         3703  +    if( sp->type!=MULTITERMINAL ){
         3704  +      fprintf(out," %s", sp->name);
         3705  +    }else{
  3558   3706         int k;
         3707  +      fprintf(out," %s", sp->subsym[0]->name);
  3559   3708         for(k=1; k<sp->nsubsym; k++){
  3560   3709           fprintf(out,"|%s",sp->subsym[k]->name);
  3561   3710         }
  3562   3711       }
  3563   3712     }
  3564   3713   }
  3565   3714   
................................................................................
  3852   4001       }
  3853   4002     }
  3854   4003     tplt_xfer(lemp->name, in, out, &lineno);
  3855   4004   
  3856   4005     /* Generate a table containing the symbolic name of every symbol
  3857   4006     */
  3858   4007     for(i=0; i<lemp->nsymbol; i++){
  3859         -    sprintf(line,"\"%s\",",lemp->symbols[i]->name);
         4008  +    lemon_sprintf(line,"\"%s\",",lemp->symbols[i]->name);
  3860   4009       fprintf(out,"  %-15s",line);
  3861   4010       if( (i&3)==3 ){ fprintf(out,"\n"); lineno++; }
  3862   4011     }
  3863   4012     if( (i&3)!=0 ){ fprintf(out,"\n"); lineno++; }
  3864   4013     tplt_xfer(lemp->name,in,out,&lineno);
  3865   4014   
  3866   4015     /* Generate a table containing a text string that describes every
................................................................................
  4019   4168   
  4020   4169     if( lemp->tokenprefix ) prefix = lemp->tokenprefix;
  4021   4170     else                    prefix = "";
  4022   4171     in = file_open(lemp,".h","rb");
  4023   4172     if( in ){
  4024   4173       int nextChar;
  4025   4174       for(i=1; i<lemp->nterminal && fgets(line,LINESIZE,in); i++){
  4026         -      sprintf(pattern,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
         4175  +      lemon_sprintf(pattern,"#define %s%-30s %3d\n",
         4176  +                    prefix,lemp->symbols[i]->name,i);
  4027   4177         if( strcmp(line,pattern) ) break;
  4028   4178       }
  4029   4179       nextChar = fgetc(in);
  4030   4180       fclose(in);
  4031   4181       if( i==lemp->nterminal && nextChar==EOF ){
  4032   4182         /* No change in the file.  Don't rewrite it. */
  4033   4183         return;
  4034   4184       }
  4035   4185     }
  4036   4186     out = file_open(lemp,".h","wb");
  4037   4187     if( out ){
  4038   4188       for(i=1; i<lemp->nterminal; i++){
  4039         -      fprintf(out,"#define %s%-30s %2d\n",prefix,lemp->symbols[i]->name,i);
         4189  +      fprintf(out,"#define %s%-30s %3d\n",prefix,lemp->symbols[i]->name,i);
  4040   4190       }
  4041   4191       fclose(out);  
  4042   4192     }
  4043   4193     return;
  4044   4194   }
  4045   4195   
  4046   4196   /* Reduce the size of the action tables, if possible, by making use
................................................................................
  4249   4399   {
  4250   4400     const char *z;
  4251   4401     char *cpy;
  4252   4402   
  4253   4403     if( y==0 ) return 0;
  4254   4404     z = Strsafe_find(y);
  4255   4405     if( z==0 && (cpy=(char *)malloc( lemonStrlen(y)+1 ))!=0 ){
  4256         -    strcpy(cpy,y);
         4406  +    lemon_strcpy(cpy,y);
  4257   4407       z = cpy;
  4258   4408       Strsafe_insert(z);
  4259   4409     }
  4260   4410     MemoryCheck(z);
  4261   4411     return z;
  4262   4412   }
  4263   4413   
................................................................................
  4402   4552       sp->useCnt = 0;
  4403   4553       Symbol_insert(sp,sp->name);
  4404   4554     }
  4405   4555     sp->useCnt++;
  4406   4556     return sp;
  4407   4557   }
  4408   4558   
  4409         -/* Compare two symbols for working purposes
         4559  +/* Compare two symbols for sorting purposes.  Return negative,
         4560  +** zero, or positive if a is less then, equal to, or greater
         4561  +** than b.
  4410   4562   **
  4411   4563   ** Symbols that begin with upper case letters (terminals or tokens)
  4412   4564   ** must sort before symbols that begin with lower case letters
  4413         -** (non-terminals).  Other than that, the order does not matter.
         4565  +** (non-terminals).  And MULTITERMINAL symbols (created using the
         4566  +** %token_class directive) must sort at the very end. Other than
         4567  +** that, the order does not matter.
  4414   4568   **
  4415   4569   ** We find experimentally that leaving the symbols in their original
  4416   4570   ** order (the order they appeared in the grammar file) gives the
  4417   4571   ** smallest parser tables in SQLite.
  4418   4572   */
  4419   4573   int Symbolcmpp(const void *_a, const void *_b)
  4420   4574   {
  4421         -  const struct symbol **a = (const struct symbol **) _a;
  4422         -  const struct symbol **b = (const struct symbol **) _b;
  4423         -  int i1 = (**a).index + 10000000*((**a).name[0]>'Z');
  4424         -  int i2 = (**b).index + 10000000*((**b).name[0]>'Z');
  4425         -  assert( i1!=i2 || strcmp((**a).name,(**b).name)==0 );
  4426         -  return i1-i2;
         4575  +  const struct symbol *a = *(const struct symbol **) _a;
         4576  +  const struct symbol *b = *(const struct symbol **) _b;
         4577  +  int i1 = a->type==MULTITERMINAL ? 3 : a->name[0]>'Z' ? 2 : 1;
         4578  +  int i2 = b->type==MULTITERMINAL ? 3 : b->name[0]>'Z' ? 2 : 1;
         4579  +  return i1==i2 ? a->index - b->index : i1 - i2;
  4427   4580   }
  4428   4581   
  4429   4582   /* There is one instance of the following structure for each
  4430   4583   ** associative array of type "x2".
  4431   4584   */
  4432   4585   struct s_x2 {
  4433   4586     int size;               /* The number of available slots. */