• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
keywordCompare1(const void * a,const void * b)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 }
keywordCompare2(const void * a,const void * b)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 }
keywordCompare3(const void * a,const void * b)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 */
findById(int id)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 */
main(int argc,char ** argv)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