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*/
14static 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*/
34typedef struct Keyword Keyword;
35struct 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*/
145static 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 */
270static 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*/
275const 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*/
297static 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}
307static 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}
317static 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*/
329static 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*/
341int 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