Home | History | Annotate | Download | only in tool
      1 /*
      2 ** Compile and run this standalone program in order to generate code that
      3 ** implements a function that will translate alphabetic identifiers into
      4 ** parser token codes.
      5 */
      6 #include <stdio.h>
      7 #include <string.h>
      8 #include <stdlib.h>
      9 #include <assert.h>
     10 
     11 /*
     12 ** A header comment placed at the beginning of generated code.
     13 */
     14 static const char zHdr[] =
     15   "/***** This file contains automatically generated code ******\n"
     16   "**\n"
     17   "** The code in this file has been automatically generated by\n"
     18   "**\n"
     19   "**   sqlite/tool/mkkeywordhash.c\n"
     20   "**\n"
     21   "** The code in this file implements a function that determines whether\n"
     22   "** or not a given identifier is really an SQL keyword.  The same thing\n"
     23   "** might be implemented more directly using a hand-written hash table.\n"
     24   "** But by using this automatically generated code, the size of the code\n"
     25   "** is substantially reduced.  This is important for embedded applications\n"
     26   "** on platforms with limited memory.\n"
     27   "*/\n"
     28 ;
     29 
     30 /*
     31 ** All the keywords of the SQL language are stored in a hash
     32 ** table composed of instances of the following structure.
     33 */
     34 typedef struct Keyword Keyword;
     35 struct Keyword {
     36   char *zName;         /* The keyword name */
     37   char *zTokenType;    /* Token value for this keyword */
     38   int mask;            /* Code this keyword if non-zero */
     39   int id;              /* Unique ID for this record */
     40   int hash;            /* Hash on the keyword */
     41   int offset;          /* Offset to start of name string */
     42   int len;             /* Length of this keyword, not counting final \000 */
     43   int prefix;          /* Number of characters in prefix */
     44   int longestSuffix;   /* Longest suffix that is a prefix on another word */
     45   int iNext;           /* Index in aKeywordTable[] of next with same hash */
     46   int substrId;        /* Id to another keyword this keyword is embedded in */
     47   int substrOffset;    /* Offset into substrId for start of this keyword */
     48   char zOrigName[20];  /* Original keyword name before processing */
     49 };
     50 
     51 /*
     52 ** Define masks used to determine which keywords are allowed
     53 */
     54 #ifdef SQLITE_OMIT_ALTERTABLE
     55 #  define ALTER      0
     56 #else
     57 #  define ALTER      0x00000001
     58 #endif
     59 #define ALWAYS       0x00000002
     60 #ifdef SQLITE_OMIT_ANALYZE
     61 #  define ANALYZE    0
     62 #else
     63 #  define ANALYZE    0x00000004
     64 #endif
     65 #ifdef SQLITE_OMIT_ATTACH
     66 #  define ATTACH     0
     67 #else
     68 #  define ATTACH     0x00000008
     69 #endif
     70 #ifdef SQLITE_OMIT_AUTOINCREMENT
     71 #  define AUTOINCR   0
     72 #else
     73 #  define AUTOINCR   0x00000010
     74 #endif
     75 #ifdef SQLITE_OMIT_CAST
     76 #  define CAST       0
     77 #else
     78 #  define CAST       0x00000020
     79 #endif
     80 #ifdef SQLITE_OMIT_COMPOUND_SELECT
     81 #  define COMPOUND   0
     82 #else
     83 #  define COMPOUND   0x00000040
     84 #endif
     85 #ifdef SQLITE_OMIT_CONFLICT_CLAUSE
     86 #  define CONFLICT   0
     87 #else
     88 #  define CONFLICT   0x00000080
     89 #endif
     90 #ifdef SQLITE_OMIT_EXPLAIN
     91 #  define EXPLAIN    0
     92 #else
     93 #  define EXPLAIN    0x00000100
     94 #endif
     95 #ifdef SQLITE_OMIT_FOREIGN_KEY
     96 #  define FKEY       0
     97 #else
     98 #  define FKEY       0x00000200
     99 #endif
    100 #ifdef SQLITE_OMIT_PRAGMA
    101 #  define PRAGMA     0
    102 #else
    103 #  define PRAGMA     0x00000400
    104 #endif
    105 #ifdef SQLITE_OMIT_REINDEX
    106 #  define REINDEX    0
    107 #else
    108 #  define REINDEX    0x00000800
    109 #endif
    110 #ifdef SQLITE_OMIT_SUBQUERY
    111 #  define SUBQUERY   0
    112 #else
    113 #  define SUBQUERY   0x00001000
    114 #endif
    115 #ifdef SQLITE_OMIT_TRIGGER
    116 #  define TRIGGER    0
    117 #else
    118 #  define TRIGGER    0x00002000
    119 #endif
    120 #if defined(SQLITE_OMIT_AUTOVACUUM) && \
    121     (defined(SQLITE_OMIT_VACUUM) || defined(SQLITE_OMIT_ATTACH))
    122 #  define VACUUM     0
    123 #else
    124 #  define VACUUM     0x00004000
    125 #endif
    126 #ifdef SQLITE_OMIT_VIEW
    127 #  define VIEW       0
    128 #else
    129 #  define VIEW       0x00008000
    130 #endif
    131 #ifdef SQLITE_OMIT_VIRTUALTABLE
    132 #  define VTAB       0
    133 #else
    134 #  define VTAB       0x00010000
    135 #endif
    136 #ifdef SQLITE_OMIT_AUTOVACUUM
    137 #  define AUTOVACUUM 0
    138 #else
    139 #  define AUTOVACUUM 0x00020000
    140 #endif
    141 
    142 /*
    143 ** These are the keywords
    144 */
    145 static Keyword aKeywordTable[] = {
    146   { "ABORT",            "TK_ABORT",        CONFLICT|TRIGGER       },
    147   { "ACTION",           "TK_ACTION",       FKEY                   },
    148   { "ADD",              "TK_ADD",          ALTER                  },
    149   { "AFTER",            "TK_AFTER",        TRIGGER                },
    150   { "ALL",              "TK_ALL",          ALWAYS                 },
    151   { "ALTER",            "TK_ALTER",        ALTER                  },
    152   { "ANALYZE",          "TK_ANALYZE",      ANALYZE                },
    153   { "AND",              "TK_AND",          ALWAYS                 },
    154   { "AS",               "TK_AS",           ALWAYS                 },
    155   { "ASC",              "TK_ASC",          ALWAYS                 },
    156   { "ATTACH",           "TK_ATTACH",       ATTACH                 },
    157   { "AUTOINCREMENT",    "TK_AUTOINCR",     AUTOINCR               },
    158   { "BEFORE",           "TK_BEFORE",       TRIGGER                },
    159   { "BEGIN",            "TK_BEGIN",        ALWAYS                 },
    160   { "BETWEEN",          "TK_BETWEEN",      ALWAYS                 },
    161   { "BY",               "TK_BY",           ALWAYS                 },
    162   { "CASCADE",          "TK_CASCADE",      FKEY                   },
    163   { "CASE",             "TK_CASE",         ALWAYS                 },
    164   { "CAST",             "TK_CAST",         CAST                   },
    165   { "CHECK",            "TK_CHECK",        ALWAYS                 },
    166   { "COLLATE",          "TK_COLLATE",      ALWAYS                 },
    167   { "COLUMN",           "TK_COLUMNKW",     ALTER                  },
    168   { "COMMIT",           "TK_COMMIT",       ALWAYS                 },
    169   { "CONFLICT",         "TK_CONFLICT",     CONFLICT               },
    170   { "CONSTRAINT",       "TK_CONSTRAINT",   ALWAYS                 },
    171   { "CREATE",           "TK_CREATE",       ALWAYS                 },
    172   { "CROSS",            "TK_JOIN_KW",      ALWAYS                 },
    173   { "CURRENT_DATE",     "TK_CTIME_KW",     ALWAYS                 },
    174   { "CURRENT_TIME",     "TK_CTIME_KW",     ALWAYS                 },
    175   { "CURRENT_TIMESTAMP","TK_CTIME_KW",     ALWAYS                 },
    176   { "DATABASE",         "TK_DATABASE",     ATTACH                 },
    177   { "DEFAULT",          "TK_DEFAULT",      ALWAYS                 },
    178   { "DEFERRED",         "TK_DEFERRED",     ALWAYS                 },
    179   { "DEFERRABLE",       "TK_DEFERRABLE",   FKEY                   },
    180   { "DELETE",           "TK_DELETE",       ALWAYS                 },
    181   { "DESC",             "TK_DESC",         ALWAYS                 },
    182   { "DETACH",           "TK_DETACH",       ATTACH                 },
    183   { "DISTINCT",         "TK_DISTINCT",     ALWAYS                 },
    184   { "DROP",             "TK_DROP",         ALWAYS                 },
    185   { "END",              "TK_END",          ALWAYS                 },
    186   { "EACH",             "TK_EACH",         TRIGGER                },
    187   { "ELSE",             "TK_ELSE",         ALWAYS                 },
    188   { "ESCAPE",           "TK_ESCAPE",       ALWAYS                 },
    189   { "EXCEPT",           "TK_EXCEPT",       COMPOUND               },
    190   { "EXCLUSIVE",        "TK_EXCLUSIVE",    ALWAYS                 },
    191   { "EXISTS",           "TK_EXISTS",       ALWAYS                 },
    192   { "EXPLAIN",          "TK_EXPLAIN",      EXPLAIN                },
    193   { "FAIL",             "TK_FAIL",         CONFLICT|TRIGGER       },
    194   { "FOR",              "TK_FOR",          TRIGGER                },
    195   { "FOREIGN",          "TK_FOREIGN",      FKEY                   },
    196   { "FROM",             "TK_FROM",         ALWAYS                 },
    197   { "FULL",             "TK_JOIN_KW",      ALWAYS                 },
    198   { "GLOB",             "TK_LIKE_KW",      ALWAYS                 },
    199   { "GROUP",            "TK_GROUP",        ALWAYS                 },
    200   { "HAVING",           "TK_HAVING",       ALWAYS                 },
    201   { "IF",               "TK_IF",           ALWAYS                 },
    202   { "IGNORE",           "TK_IGNORE",       CONFLICT|TRIGGER       },
    203   { "IMMEDIATE",        "TK_IMMEDIATE",    ALWAYS                 },
    204   { "IN",               "TK_IN",           ALWAYS                 },
    205   { "INDEX",            "TK_INDEX",        ALWAYS                 },
    206   { "INDEXED",          "TK_INDEXED",      ALWAYS                 },
    207   { "INITIALLY",        "TK_INITIALLY",    FKEY                   },
    208   { "INNER",            "TK_JOIN_KW",      ALWAYS                 },
    209   { "INSERT",           "TK_INSERT",       ALWAYS                 },
    210   { "INSTEAD",          "TK_INSTEAD",      TRIGGER                },
    211   { "INTERSECT",        "TK_INTERSECT",    COMPOUND               },
    212   { "INTO",             "TK_INTO",         ALWAYS                 },
    213   { "IS",               "TK_IS",           ALWAYS                 },
    214   { "ISNULL",           "TK_ISNULL",       ALWAYS                 },
    215   { "JOIN",             "TK_JOIN",         ALWAYS                 },
    216   { "KEY",              "TK_KEY",          ALWAYS                 },
    217   { "LEFT",             "TK_JOIN_KW",      ALWAYS                 },
    218   { "LIKE",             "TK_LIKE_KW",      ALWAYS                 },
    219   { "LIMIT",            "TK_LIMIT",        ALWAYS                 },
    220   { "MATCH",            "TK_MATCH",        ALWAYS                 },
    221   { "NATURAL",          "TK_JOIN_KW",      ALWAYS                 },
    222   { "NO",               "TK_NO",           FKEY                   },
    223   { "NOT",              "TK_NOT",          ALWAYS                 },
    224   { "NOTNULL",          "TK_NOTNULL",      ALWAYS                 },
    225   { "NULL",             "TK_NULL",         ALWAYS                 },
    226   { "OF",               "TK_OF",           ALWAYS                 },
    227   { "OFFSET",           "TK_OFFSET",       ALWAYS                 },
    228   { "ON",               "TK_ON",           ALWAYS                 },
    229   { "OR",               "TK_OR",           ALWAYS                 },
    230   { "ORDER",            "TK_ORDER",        ALWAYS                 },
    231   { "OUTER",            "TK_JOIN_KW",      ALWAYS                 },
    232   { "PLAN",             "TK_PLAN",         EXPLAIN                },
    233   { "PRAGMA",           "TK_PRAGMA",       PRAGMA                 },
    234   { "PRIMARY",          "TK_PRIMARY",      ALWAYS                 },
    235   { "QUERY",            "TK_QUERY",        EXPLAIN                },
    236   { "RAISE",            "TK_RAISE",        TRIGGER                },
    237   { "REFERENCES",       "TK_REFERENCES",   FKEY                   },
    238   { "REGEXP",           "TK_LIKE_KW",      ALWAYS                 },
    239   { "REINDEX",          "TK_REINDEX",      REINDEX                },
    240   { "RELEASE",          "TK_RELEASE",      ALWAYS                 },
    241   { "RENAME",           "TK_RENAME",       ALTER                  },
    242   { "REPLACE",          "TK_REPLACE",      CONFLICT               },
    243   { "RESTRICT",         "TK_RESTRICT",     FKEY                   },
    244   { "RIGHT",            "TK_JOIN_KW",      ALWAYS                 },
    245   { "ROLLBACK",         "TK_ROLLBACK",     ALWAYS                 },
    246   { "ROW",              "TK_ROW",          TRIGGER                },
    247   { "SAVEPOINT",        "TK_SAVEPOINT",    ALWAYS                 },
    248   { "SELECT",           "TK_SELECT",       ALWAYS                 },
    249   { "SET",              "TK_SET",          ALWAYS                 },
    250   { "TABLE",            "TK_TABLE",        ALWAYS                 },
    251   { "TEMP",             "TK_TEMP",         ALWAYS                 },
    252   { "TEMPORARY",        "TK_TEMP",         ALWAYS                 },
    253   { "THEN",             "TK_THEN",         ALWAYS                 },
    254   { "TO",               "TK_TO",           ALWAYS                 },
    255   { "TRANSACTION",      "TK_TRANSACTION",  ALWAYS                 },
    256   { "TRIGGER",          "TK_TRIGGER",      TRIGGER                },
    257   { "UNION",            "TK_UNION",        COMPOUND               },
    258   { "UNIQUE",           "TK_UNIQUE",       ALWAYS                 },
    259   { "UPDATE",           "TK_UPDATE",       ALWAYS                 },
    260   { "USING",            "TK_USING",        ALWAYS                 },
    261   { "VACUUM",           "TK_VACUUM",       VACUUM                 },
    262   { "VALUES",           "TK_VALUES",       ALWAYS                 },
    263   { "VIEW",             "TK_VIEW",         VIEW                   },
    264   { "VIRTUAL",          "TK_VIRTUAL",      VTAB                   },
    265   { "WHEN",             "TK_WHEN",         ALWAYS                 },
    266   { "WHERE",            "TK_WHERE",        ALWAYS                 },
    267 };
    268 
    269 /* Number of keywords */
    270 static int nKeyword = (sizeof(aKeywordTable)/sizeof(aKeywordTable[0]));
    271 
    272 /* An array to map all upper-case characters into their corresponding
    273 ** lower-case character.
    274 */
    275 const unsigned char sqlite3UpperToLower[] = {
    276       0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16, 17,
    277      18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
    278      36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
    279      54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99,100,101,102,103,
    280     104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,
    281     122, 91, 92, 93, 94, 95, 96, 97, 98, 99,100,101,102,103,104,105,106,107,
    282     108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,
    283     126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
    284     144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,
    285     162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,
    286     180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,
    287     198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,
    288     216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,
    289     234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,
    290     252,253,254,255
    291 };
    292 #define UpperToLower sqlite3UpperToLower
    293 
    294 /*
    295 ** Comparision function for two Keyword records
    296 */
    297 static int keywordCompare1(const void *a, const void *b){
    298   const Keyword *pA = (Keyword*)a;
    299   const Keyword *pB = (Keyword*)b;
    300   int n = pA->len - pB->len;
    301   if( n==0 ){
    302     n = strcmp(pA->zName, pB->zName);
    303   }
    304   assert( n!=0 );
    305   return n;
    306 }
    307 static int keywordCompare2(const void *a, const void *b){
    308   const Keyword *pA = (Keyword*)a;
    309   const Keyword *pB = (Keyword*)b;
    310   int n = pB->longestSuffix - pA->longestSuffix;
    311   if( n==0 ){
    312     n = strcmp(pA->zName, pB->zName);
    313   }
    314   assert( n!=0 );
    315   return n;
    316 }
    317 static int keywordCompare3(const void *a, const void *b){
    318   const Keyword *pA = (Keyword*)a;
    319   const Keyword *pB = (Keyword*)b;
    320   int n = pA->offset - pB->offset;
    321   if( n==0 ) n = pB->id - pA->id;
    322   assert( n!=0 );
    323   return n;
    324 }
    325 
    326 /*
    327 ** Return a KeywordTable entry with the given id
    328 */
    329 static Keyword *findById(int id){
    330   int i;
    331   for(i=0; i<nKeyword; i++){
    332     if( aKeywordTable[i].id==id ) break;
    333   }
    334   return &aKeywordTable[i];
    335 }
    336 
    337 /*
    338 ** This routine does the work.  The generated code is printed on standard
    339 ** output.
    340 */
    341 int main(int argc, char **argv){
    342   int i, j, k, h;
    343   int bestSize, bestCount;
    344   int count;
    345   int nChar;
    346   int totalLen = 0;
    347   int aHash[1000];  /* 1000 is much bigger than nKeyword */
    348   char zText[2000];
    349 
    350   /* Remove entries from the list of keywords that have mask==0 */
    351   for(i=j=0; i<nKeyword; i++){
    352     if( aKeywordTable[i].mask==0 ) continue;
    353     if( j<i ){
    354       aKeywordTable[j] = aKeywordTable[i];
    355     }
    356     j++;
    357   }
    358   nKeyword = j;
    359 
    360   /* Fill in the lengths of strings and hashes for all entries. */
    361   for(i=0; i<nKeyword; i++){
    362     Keyword *p = &aKeywordTable[i];
    363     p->len = strlen(p->zName);
    364     assert( p->len<sizeof(p->zOrigName) );
    365     strcpy(p->zOrigName, p->zName);
    366     totalLen += p->len;
    367     p->hash = (UpperToLower[(int)p->zName[0]]*4) ^
    368               (UpperToLower[(int)p->zName[p->len-1]]*3) ^ p->len;
    369     p->id = i+1;
    370   }
    371 
    372   /* Sort the table from shortest to longest keyword */
    373   qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare1);
    374 
    375   /* Look for short keywords embedded in longer keywords */
    376   for(i=nKeyword-2; i>=0; i--){
    377     Keyword *p = &aKeywordTable[i];
    378     for(j=nKeyword-1; j>i && p->substrId==0; j--){
    379       Keyword *pOther = &aKeywordTable[j];
    380       if( pOther->substrId ) continue;
    381       if( pOther->len<=p->len ) continue;
    382       for(k=0; k<=pOther->len-p->len; k++){
    383         if( memcmp(p->zName, &pOther->zName[k], p->len)==0 ){
    384           p->substrId = pOther->id;
    385           p->substrOffset = k;
    386           break;
    387         }
    388       }
    389     }
    390   }
    391 
    392   /* Compute the longestSuffix value for every word */
    393   for(i=0; i<nKeyword; i++){
    394     Keyword *p = &aKeywordTable[i];
    395     if( p->substrId ) continue;
    396     for(j=0; j<nKeyword; j++){
    397       Keyword *pOther;
    398       if( j==i ) continue;
    399       pOther = &aKeywordTable[j];
    400       if( pOther->substrId ) continue;
    401       for(k=p->longestSuffix+1; k<p->len && k<pOther->len; k++){
    402         if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
    403           p->longestSuffix = k;
    404         }
    405       }
    406     }
    407   }
    408 
    409   /* Sort the table into reverse order by length */
    410   qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare2);
    411 
    412   /* Fill in the offset for all entries */
    413   nChar = 0;
    414   for(i=0; i<nKeyword; i++){
    415     Keyword *p = &aKeywordTable[i];
    416     if( p->offset>0 || p->substrId ) continue;
    417     p->offset = nChar;
    418     nChar += p->len;
    419     for(k=p->len-1; k>=1; k--){
    420       for(j=i+1; j<nKeyword; j++){
    421         Keyword *pOther = &aKeywordTable[j];
    422         if( pOther->offset>0 || pOther->substrId ) continue;
    423         if( pOther->len<=k ) continue;
    424         if( memcmp(&p->zName[p->len-k], pOther->zName, k)==0 ){
    425           p = pOther;
    426           p->offset = nChar - k;
    427           nChar = p->offset + p->len;
    428           p->zName += k;
    429           p->len -= k;
    430           p->prefix = k;
    431           j = i;
    432           k = p->len;
    433         }
    434       }
    435     }
    436   }
    437   for(i=0; i<nKeyword; i++){
    438     Keyword *p = &aKeywordTable[i];
    439     if( p->substrId ){
    440       p->offset = findById(p->substrId)->offset + p->substrOffset;
    441     }
    442   }
    443 
    444   /* Sort the table by offset */
    445   qsort(aKeywordTable, nKeyword, sizeof(aKeywordTable[0]), keywordCompare3);
    446 
    447   /* Figure out how big to make the hash table in order to minimize the
    448   ** number of collisions */
    449   bestSize = nKeyword;
    450   bestCount = nKeyword*nKeyword;
    451   for(i=nKeyword/2; i<=2*nKeyword; i++){
    452     for(j=0; j<i; j++) aHash[j] = 0;
    453     for(j=0; j<nKeyword; j++){
    454       h = aKeywordTable[j].hash % i;
    455       aHash[h] *= 2;
    456       aHash[h]++;
    457     }
    458     for(j=count=0; j<i; j++) count += aHash[j];
    459     if( count<bestCount ){
    460       bestCount = count;
    461       bestSize = i;
    462     }
    463   }
    464 
    465   /* Compute the hash */
    466   for(i=0; i<bestSize; i++) aHash[i] = 0;
    467   for(i=0; i<nKeyword; i++){
    468     h = aKeywordTable[i].hash % bestSize;
    469     aKeywordTable[i].iNext = aHash[h];
    470     aHash[h] = i+1;
    471   }
    472 
    473   /* Begin generating code */
    474   printf("%s", zHdr);
    475   printf("/* Hash score: %d */\n", bestCount);
    476   printf("static int keywordCode(const char *z, int n){\n");
    477   printf("  /* zText[] encodes %d bytes of keywords in %d bytes */\n",
    478           totalLen + nKeyword, nChar+1 );
    479   for(i=j=k=0; i<nKeyword; i++){
    480     Keyword *p = &aKeywordTable[i];
    481     if( p->substrId ) continue;
    482     memcpy(&zText[k], p->zName, p->len);
    483     k += p->len;
    484     if( j+p->len>70 ){
    485       printf("%*s */\n", 74-j, "");
    486       j = 0;
    487     }
    488     if( j==0 ){
    489       printf("  /*   ");
    490       j = 8;
    491     }
    492     printf("%s", p->zName);
    493     j += p->len;
    494   }
    495   if( j>0 ){
    496     printf("%*s */\n", 74-j, "");
    497   }
    498   printf("  static const char zText[%d] = {\n", nChar);
    499   zText[nChar] = 0;
    500   for(i=j=0; i<k; i++){
    501     if( j==0 ){
    502       printf("    ");
    503     }
    504     if( zText[i]==0 ){
    505       printf("0");
    506     }else{
    507       printf("'%c',", zText[i]);
    508     }
    509     j += 4;
    510     if( j>68 ){
    511       printf("\n");
    512       j = 0;
    513     }
    514   }
    515   if( j>0 ) printf("\n");
    516   printf("  };\n");
    517 
    518   printf("  static const unsigned char aHash[%d] = {\n", bestSize);
    519   for(i=j=0; i<bestSize; i++){
    520     if( j==0 ) printf("    ");
    521     printf(" %3d,", aHash[i]);
    522     j++;
    523     if( j>12 ){
    524       printf("\n");
    525       j = 0;
    526     }
    527   }
    528   printf("%s  };\n", j==0 ? "" : "\n");
    529 
    530   printf("  static const unsigned char aNext[%d] = {\n", nKeyword);
    531   for(i=j=0; i<nKeyword; i++){
    532     if( j==0 ) printf("    ");
    533     printf(" %3d,", aKeywordTable[i].iNext);
    534     j++;
    535     if( j>12 ){
    536       printf("\n");
    537       j = 0;
    538     }
    539   }
    540   printf("%s  };\n", j==0 ? "" : "\n");
    541 
    542   printf("  static const unsigned char aLen[%d] = {\n", nKeyword);
    543   for(i=j=0; i<nKeyword; i++){
    544     if( j==0 ) printf("    ");
    545     printf(" %3d,", aKeywordTable[i].len+aKeywordTable[i].prefix);
    546     j++;
    547     if( j>12 ){
    548       printf("\n");
    549       j = 0;
    550     }
    551   }
    552   printf("%s  };\n", j==0 ? "" : "\n");
    553 
    554   printf("  static const unsigned short int aOffset[%d] = {\n", nKeyword);
    555   for(i=j=0; i<nKeyword; i++){
    556     if( j==0 ) printf("    ");
    557     printf(" %3d,", aKeywordTable[i].offset);
    558     j++;
    559     if( j>12 ){
    560       printf("\n");
    561       j = 0;
    562     }
    563   }
    564   printf("%s  };\n", j==0 ? "" : "\n");
    565 
    566   printf("  static const unsigned char aCode[%d] = {\n", nKeyword);
    567   for(i=j=0; i<nKeyword; i++){
    568     char *zToken = aKeywordTable[i].zTokenType;
    569     if( j==0 ) printf("    ");
    570     printf("%s,%*s", zToken, (int)(14-strlen(zToken)), "");
    571     j++;
    572     if( j>=5 ){
    573       printf("\n");
    574       j = 0;
    575     }
    576   }
    577   printf("%s  };\n", j==0 ? "" : "\n");
    578 
    579   printf("  int h, i;\n");
    580   printf("  if( n<2 ) return TK_ID;\n");
    581   printf("  h = ((charMap(z[0])*4) ^\n"
    582          "      (charMap(z[n-1])*3) ^\n"
    583          "      n) %% %d;\n", bestSize);
    584   printf("  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
    585   printf("    if( aLen[i]==n &&"
    586                    " sqlite3StrNICmp(&zText[aOffset[i]],z,n)==0 ){\n");
    587   for(i=0; i<nKeyword; i++){
    588     printf("      testcase( i==%d ); /* %s */\n",
    589            i, aKeywordTable[i].zOrigName);
    590   }
    591   printf("      return aCode[i];\n");
    592   printf("    }\n");
    593   printf("  }\n");
    594   printf("  return TK_ID;\n");
    595   printf("}\n");
    596   printf("int sqlite3KeywordCode(const unsigned char *z, int n){\n");
    597   printf("  return keywordCode((char*)z, n);\n");
    598   printf("}\n");
    599   printf("#define SQLITE_N_KEYWORD %d\n", nKeyword);
    600 
    601   return 0;
    602 }
    603