UnQL

Check-in [340cf0441f]
Login

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

Overview
Comment:Keywords "true", "false", and "null" are now lower-case. ("NULL" can also optionally be all upper-case.) Use && and || instead of AND and OR.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 340cf0441f074c039d1180f822bbfe525cf4dbca
User & Date: drh 2011-07-15 18:22:48
Context
2011-07-15
18:36
Change the NOT operator into !. check-in: 59096a3d9c user: drh tags: trunk
18:22
Keywords "true", "false", and "null" are now lower-case. ("NULL" can also optionally be all upper-case.) Use && and || instead of AND and OR. check-in: 340cf0441f user: drh tags: trunk
18:14
Add the bitwise expression operators (&, |, <<, >> and ~). Also fix the unary minus operator. check-in: d06f20c02a user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/tokenize.c.

82
83
84
85
86
87
88
89
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140

141
142
143
144
145

146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297




298
299

300
301
302
303
304
305
306
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 57 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 295 bytes of keywords in 204 bytes */
  /*   BEGINSERTRUELSELECTFALSEACHAVINGROUPDATESCAPEXCEPTALLIKEXISTS      */
  /*   ANDELETEASCENDINGLOBETWEENOTCOLLATECOLLECTIONULLIMITCOMMIT         */
  /*   CREATEDESCENDINGDROPRAGMAFLATTENIFROMINTERSECTINTOFFSETORDER       */
  /*   OLLBACKUNIONVALUEWHEREBY                                           */
  static const char zText[203] = {

    'B','E','G','I','N','S','E','R','T','R','U','E','L','S','E','L','E','C',
    'T','F','A','L','S','E','A','C','H','A','V','I','N','G','R','O','U','P',
    'D','A','T','E','S','C','A','P','E','X','C','E','P','T','A','L','L','I',
    'K','E','X','I','S','T','S','A','N','D','E','L','E','T','E','A','S','C',
    'E','N','D','I','N','G','L','O','B','E','T','W','E','E','N','O','T','C',
    'O','L','L','A','T','E','C','O','L','L','E','C','T','I','O','N','U','L',
    'L','I','M','I','T','C','O','M','M','I','T','C','R','E','A','T','E','D',
    'E','S','C','E','N','D','I','N','G','D','R','O','P','R','A','G','M','A',
    'F','L','A','T','T','E','N','I','F','R','O','M','I','N','T','E','R','S',
    'E','C','T','I','N','T','O','F','F','S','E','T','O','R','D','E','R','O',
    'L','L','B','A','C','K','U','N','I','O','N','V','A','L','U','E','W','H',
    'E','R','E','B','Y',
  };
  static const unsigned char aHash[80] = {
       0,  49,  47,  13,  34,  23,  48,   1,   0,   9,   0,  15,  26,
      10,  12,   0,   0,  45,   0,   8,  37,  36,  29,   0,   0,   0,
       0,  38,   0,   0,   0,  19,   0,   0,   0,  42,   0,   0,   5,
       0,   0,   0,   0,  46,   0,   0,   0,   0,   0,   0,   0,   0,
      25,  30,  41,  24,  43,  28,   0,  17,  33,  40,  20,  44,   0,
      39,   6,   0,   0,  35,   0,   0,  27,  18,   0,   0,   0,  31,
      22,  16,
  };
  static const unsigned char aNext[49] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
       0,   3,   4,   0,   0,   0,   0,   0,   2,   0,   0,   0,   0,
      21,   0,   0,   0,  11,   0,   0,   0,   0,   0,   0,  14,   0,
       0,   0,   0,   7,  32,   0,   0,   0,   0,   0,
  };
  static const unsigned char aLen[49] = {
       5,   6,   4,   4,   6,   5,   4,   6,   5,   6,   6,   6,   3,
       4,   6,   2,   3,   6,   2,   3,   9,   4,   7,   3,   7,  10,
       4,   5,   6,   6,   4,  10,   2,   4,   6,   7,   2,   4,   9,
       4,   6,   3,   2,   5,   8,   5,   5,   5,   2,
  };
  static const unsigned short int aOffset[49] = {
       0,   3,   8,  11,  13,  19,  23,  26,  31,  34,  39,  44,  50,
      52,  55,  57,  61,  63,  69,  69,  69,  77,  80,  86,  89,  96,
     105, 108, 113, 119, 125, 125, 132, 135, 138, 144, 151, 152, 156,
     165, 168, 171, 174, 174, 178, 186, 191, 196, 201,
  };
  static const unsigned char aCode[49] = {
    TK_BEGIN,      TK_INSERT,     TK_TRUE,       TK_ELSE,       TK_SELECT,     
    TK_FALSE,      TK_FLATTENOP,  TK_HAVING,     TK_GROUP,      TK_UPDATE,     
    TK_ESCAPE,     TK_EXCEPT,     TK_ALL,        TK_LIKEOP,     TK_EXISTS,     

    TK_IS,         TK_AND,        TK_DELETE,     TK_AS,         TK_ASCENDING,  
    TK_ASCENDING,  TK_LIKEOP,     TK_BETWEEN,    TK_NOT,        TK_COLLATE,    
    TK_COLLECTION, TK_NULL,       TK_LIMIT,      TK_COMMIT,     TK_CREATE,     
    TK_DESCENDING, TK_DESCENDING, TK_IN,         TK_DROP,       TK_PRAGMA,     
    TK_FLATTENOP,  TK_IF,         TK_FROM,       TK_INTERSECT,  TK_INTO,       

    TK_OFFSET,     TK_SET,        TK_OR,         TK_ORDER,      TK_ROLLBACK,   
    TK_UNION,      TK_VALUE,      TK_WHERE,      TK_BY,         
  };
  int h, i;
  if( n<2 || z[0]<'A' || z[0]>'Z' ) return TK_ID;
  h = (z[0]*4 ^ z[n-1]*3 ^ n) % 80;
  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){
      return aCode[i];
    }
  }
  return TK_ID;
}
#define XJD1_N_KEYWORD 49

/* End of the automatically generated hash code
*********************************************************************/

/*
** Return the length of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
................................................................................
      }
    }
    case '|': {
      if( z[1]!='|' ){
        *tokenType = TK_BITOR;
        return 1;
      }else{
        *tokenType = TK_CONCAT;
        return 2;
      }
    }
    case ',': {
      *tokenType = TK_COMMA;
      return 1;
    }
    case ':': {
      *tokenType = TK_COLON;
      return 1;
    }
    case '&': {




      *tokenType = TK_BITAND;
      return 1;

    }
    case '~': {
      *tokenType = TK_BITNOT;
      return 1;
    }
    case '"': {
      int delim = z[0];







|

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


|
|
|
|
|
|
|

|
|
|
|
|

|
|
|
|
|

|
|
|
|
|

|
|
|
|
>
|
<
|

|
>
|
<


|








|







 







|












>
>
>
>
|
|
>







82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142

143
144
145
146
147

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40   /* f8..ff    ........ */
};

/**********************************************************************
** The following code is automatically generated
** by ../tool/mkkeywordhash.c
*/
/* Hash score: 58 */
static int keywordCode(const char *z, int n){
  /* zText[] encodes 300 bytes of keywords in 211 bytes */
  /*   BEGINTORDEROLLBACKELSELECTGROUPDATEACHAVINGLOBETWEENULLIKE         */
  /*   SCAPEXISTSALLIMITANDELETEXCEPTASCENDINGCOLLATECOLLECTIONOT         */
  /*   CREATEDESCENDINGDROPRAGMAFLATTENIFROMUNIONVALUEWHEREBYCOMMIT       */
  /*   INSERTINTERSECTOFFSETfalsenulltrue                                 */
  static const char zText[210] = {
    'B','E','G','I','N','T','O','R','D','E','R','O','L','L','B','A','C','K',
    'E','L','S','E','L','E','C','T','G','R','O','U','P','D','A','T','E','A',
    'C','H','A','V','I','N','G','L','O','B','E','T','W','E','E','N','U','L',
    'L','I','K','E','S','C','A','P','E','X','I','S','T','S','A','L','L','I',
    'M','I','T','A','N','D','E','L','E','T','E','X','C','E','P','T','A','S',

    'C','E','N','D','I','N','G','C','O','L','L','A','T','E','C','O','L','L',
    'E','C','T','I','O','N','O','T','C','R','E','A','T','E','D','E','S','C',
    'E','N','D','I','N','G','D','R','O','P','R','A','G','M','A','F','L','A',
    'T','T','E','N','I','F','R','O','M','U','N','I','O','N','V','A','L','U',
    'E','W','H','E','R','E','B','Y','C','O','M','M','I','T','I','N','S','E',
    'R','T','I','N','T','E','R','S','E','C','T','O','F','F','S','E','T','f',
    'a','l','s','e','n','u','l','l','t','r','u','e',
  };
  static const unsigned char aHash[80] = {
       0,  42,  40,  19,  34,  13,  41,   1,  49,   8,   0,  50,  28,
       9,  23,   0,   0,   5,  48,  11,  37,  36,  43,   0,   0,   0,
       0,  38,   0,   0,   0,  24,   0,   0,   0,  47,   0,   0,   7,
       0,   0,   0,   0,  39,   0,   0,   0,   0,   0,   0,   0,   0,
      27,  30,  46,  29,  10,  20,   0,  21,  33,   2,  25,  32,   0,
      45,   0,   0,   0,  35,   0,   0,  26,  22,   0,   0,   0,  31,
      44,  18,
  };
  static const unsigned char aNext[50] = {
       0,   0,   0,   0,   0,   0,   0,   0,   0,   3,   0,   0,   0,
       0,   0,   0,   0,   6,   0,   0,   0,   0,   0,   0,   0,  14,
       0,   0,   0,   0,  16,   4,   0,   0,   0,   0,   0,  15,   0,
       0,   0,   0,   0,  12,   0,   0,   0,   0,   0,  17,
  };
  static const unsigned char aLen[50] = {
       5,   4,   2,   5,   8,   4,   6,   5,   6,   4,   6,   4,   7,
       4,   4,   6,   6,   2,   3,   5,   3,   6,   6,   2,   3,   9,
       7,  10,   3,   6,   4,  10,   2,   4,   6,   7,   2,   4,   5,
       5,   5,   2,   6,   6,   9,   6,   3,   5,   4,   4,
  };
  static const unsigned short int aOffset[50] = {
       0,   3,   6,   6,  10,  18,  20,  26,  29,  34,  37,  42,  45,
      51,  54,  57,  62,  64,  68,  70,  75,  77,  82,  88,  88,  88,
      97, 104, 113, 116, 122, 122, 129, 132, 135, 141, 148, 149, 153,
     158, 163, 168, 170, 176, 182, 191, 194, 197, 202, 206,
  };
  static const unsigned char aCode[50] = {
    TK_BEGIN,      TK_INTO,       TK_OR,         TK_ORDER,      TK_ROLLBACK,   
    TK_ELSE,       TK_SELECT,     TK_GROUP,      TK_UPDATE,     TK_FLATTENOP,  
    TK_HAVING,     TK_LIKEOP,     TK_BETWEEN,    TK_NULL,       TK_LIKEOP,     
    TK_ESCAPE,     TK_EXISTS,     TK_IS,         TK_ALL,        TK_LIMIT,      
    TK_AND,        TK_DELETE,     TK_EXCEPT,     TK_AS,         TK_ASCENDING,  

    TK_ASCENDING,  TK_COLLATE,    TK_COLLECTION, TK_NOT,        TK_CREATE,     
    TK_DESCENDING, TK_DESCENDING, TK_IN,         TK_DROP,       TK_PRAGMA,     
    TK_FLATTENOP,  TK_IF,         TK_FROM,       TK_UNION,      TK_VALUE,      
    TK_WHERE,      TK_BY,         TK_COMMIT,     TK_INSERT,     TK_INTERSECT,  
    TK_OFFSET,     TK_SET,        TK_FALSE,      TK_NULL,       TK_TRUE,       

  };
  int h, i;
  if( n<2 ) return TK_ID;
  h = (z[0]*4 ^ z[n-1]*3 ^ n) % 80;
  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){
    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){
      return aCode[i];
    }
  }
  return TK_ID;
}
#define XJD1_N_KEYWORD 50

/* End of the automatically generated hash code
*********************************************************************/

/*
** Return the length of the token that begins at z[0]. 
** Store the token type in *tokenType before returning.
................................................................................
      }
    }
    case '|': {
      if( z[1]!='|' ){
        *tokenType = TK_BITOR;
        return 1;
      }else{
        *tokenType = TK_OR;
        return 2;
      }
    }
    case ',': {
      *tokenType = TK_COMMA;
      return 1;
    }
    case ':': {
      *tokenType = TK_COLON;
      return 1;
    }
    case '&': {
      if( z[1]=='&' ){
        *tokenType = TK_AND;
        return 2;
      }else{
        *tokenType = TK_BITAND;
        return 1;
      }
    }
    case '~': {
      *tokenType = TK_BITNOT;
      return 1;
    }
    case '"': {
      int delim = z[0];

Changes to test/base02.test.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
..
99
100
101
102
103
104
105
106
-- Basic sanity checking.
--
.new t1.db
CREATE COLLECTION c1;
INSERT INTO c1 VALUE { x:true };

.testcase 1
SELECT 1  FROM c1 WHERE TRUE;
SELECT 2  FROM c1 WHERE 1.0;
SELECT 3  FROM c1 WHERE 0.1;
SELECT 4  FROM c1 WHERE -0.1;
SELECT 5  FROM c1 WHERE {a:1};
SELECT 6  FROM c1 WHERE [1];
SELECT 7  FROM c1 WHERE "x";
SELECT 8  FROM c1 WHERE "1";
SELECT 9  FROM c1 WHERE "0";
SELECT 10 FROM c1 WHERE "false";
.result 1 2 3 4 5 6 7 8 9 10

.testcase 2
SELECT 1 FROM c1 WHERE FALSE;
SELECT 2 FROM c1 WHERE NULL;
SELECT 3 FROM c1 WHERE 0.0;
SELECT 4 FROM c1 WHERE "";
.result

.testcase 3
SELECT TRUE AND TRUE FROM c1;
SELECT TRUE AND FALSE FROM c1;
SELECT FALSE AND TRUE FROM c1;
SELECT FALSE AND FALSE FROM c1;
SELECT "cat" AND "dog" FROM c1;
SELECT "" AND "dog" FROM c1;
.result true false false false "dog" "" 

.testcase 4
SELECT TRUE OR TRUE FROM c1;
SELECT TRUE OR FALSE FROM c1;
SELECT FALSE OR TRUE FROM c1;
SELECT FALSE OR FALSE FROM c1;
SELECT "cat" OR "dog" FROM c1;
SELECT "" OR "dog" FROM c1;
.result true true true false "cat" "dog"

.testcase 5
SELECT NOT TRUE  FROM c1;
SELECT NOT FALSE FROM c1;
SELECT NOT "cat" FROM c1;
SELECT NOT "" FROM c1;
.result false true false true

.testcase 6
SELECT 1 & 2               FROM c1;
SELECT "5" & 4             FROM c1;
................................................................................
.result 8 49 69

.testcase 15
SELECT 1 - 7 FROM c1;
SELECT 45 - 4 FROM c1;
SELECT 67 - 2 FROM c1;
.result -6 41 65








|












|






|
|
|
|
|
|



|
|
|
|
|
|



|
|







 







<
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
..
99
100
101
102
103
104
105

-- Basic sanity checking.
--
.new t1.db
CREATE COLLECTION c1;
INSERT INTO c1 VALUE { x:true };

.testcase 1
SELECT 1  FROM c1 WHERE true;
SELECT 2  FROM c1 WHERE 1.0;
SELECT 3  FROM c1 WHERE 0.1;
SELECT 4  FROM c1 WHERE -0.1;
SELECT 5  FROM c1 WHERE {a:1};
SELECT 6  FROM c1 WHERE [1];
SELECT 7  FROM c1 WHERE "x";
SELECT 8  FROM c1 WHERE "1";
SELECT 9  FROM c1 WHERE "0";
SELECT 10 FROM c1 WHERE "false";
.result 1 2 3 4 5 6 7 8 9 10

.testcase 2
SELECT 1 FROM c1 WHERE false;
SELECT 2 FROM c1 WHERE NULL;
SELECT 3 FROM c1 WHERE 0.0;
SELECT 4 FROM c1 WHERE "";
.result

.testcase 3
SELECT true && true FROM c1;
SELECT true && false FROM c1;
SELECT false && true FROM c1;
SELECT false && false FROM c1;
SELECT "cat" && "dog" FROM c1;
SELECT "" && "dog" FROM c1;
.result true false false false "dog" "" 

.testcase 4
SELECT true || true FROM c1;
SELECT true || false FROM c1;
SELECT false || true FROM c1;
SELECT false || false FROM c1;
SELECT "cat" || "dog" FROM c1;
SELECT "" || "dog" FROM c1;
.result true true true false "cat" "dog"

.testcase 5
SELECT NOT true  FROM c1;
SELECT NOT false FROM c1;
SELECT NOT "cat" FROM c1;
SELECT NOT "" FROM c1;
.result false true false true

.testcase 6
SELECT 1 & 2               FROM c1;
SELECT "5" & 4             FROM c1;
................................................................................
.result 8 49 69

.testcase 15
SELECT 1 - 7 FROM c1;
SELECT 45 - 4 FROM c1;
SELECT 67 - 2 FROM c1;
.result -6 41 65

Changes to tool/mkkeywordhash.c.

74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
..
90
91
92
93
94
95
96

97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
  { "DESC",         "TK_DESCENDING", },
  { "DROP",         "TK_DROP",       },
  { "EACH",         "TK_FLATTENOP",  },
  { "ELSE",         "TK_ELSE",       },
  { "ESCAPE",       "TK_ESCAPE",     },
  { "EXCEPT",       "TK_EXCEPT",     },
  { "EXISTS",       "TK_EXISTS",     },
  { "FALSE",        "TK_FALSE",      },
  { "FLATTEN",      "TK_FLATTENOP",  },
  { "FROM",         "TK_FROM",       },
  { "GLOB",         "TK_LIKEOP",     },
  { "GROUP",        "TK_GROUP",      },
  { "HAVING",       "TK_HAVING",     },
  { "IF",           "TK_IF",         },
  { "INSERT",       "TK_INSERT",     },
................................................................................
  { "IN",           "TK_IN",         },
  { "INTO",         "TK_INTO",       },
  { "IS",           "TK_IS",         },
  { "LIKE",         "TK_LIKEOP",     },
  { "LIMIT",        "TK_LIMIT",      },
  { "NOT",          "TK_NOT",        },
  { "NULL",         "TK_NULL",       },

  { "OFFSET",       "TK_OFFSET",     },
  { "ORDER",        "TK_ORDER",      },
  { "OR",           "TK_OR",         },
  { "PRAGMA",       "TK_PRAGMA",     },
  { "ROLLBACK",     "TK_ROLLBACK",   },
  { "SELECT",       "TK_SELECT",     },
  { "SET",          "TK_SET",        },
  { "TRUE",         "TK_TRUE",       },
  { "UNION",        "TK_UNION",      },
  { "UPDATE",       "TK_UPDATE",     },
  { "VALUE",        "TK_VALUE",      },
  { "WHERE",        "TK_WHERE",      },
};

/* Number of keywords */
................................................................................
      printf("\n");
      j = 0;
    }
  }
  printf("%s  };\n", j==0 ? "" : "\n");

  printf("  int h, i;\n");
  printf("  if( n<2 || z[0]<'A' || z[0]>'Z' ) return TK_ID;\n");
  printf("  h = (z[0]*4 ^ z[n-1]*3 ^ n) %% %d;\n", bestSize);
  printf("  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
  printf("    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){\n");
  printf("      return aCode[i];\n");
  printf("    }\n");
  printf("  }\n");
  printf("  return TK_ID;\n");







|







 







>







|







 







|







74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
..
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
...
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
  { "DESC",         "TK_DESCENDING", },
  { "DROP",         "TK_DROP",       },
  { "EACH",         "TK_FLATTENOP",  },
  { "ELSE",         "TK_ELSE",       },
  { "ESCAPE",       "TK_ESCAPE",     },
  { "EXCEPT",       "TK_EXCEPT",     },
  { "EXISTS",       "TK_EXISTS",     },
  { "false",        "TK_FALSE",      },
  { "FLATTEN",      "TK_FLATTENOP",  },
  { "FROM",         "TK_FROM",       },
  { "GLOB",         "TK_LIKEOP",     },
  { "GROUP",        "TK_GROUP",      },
  { "HAVING",       "TK_HAVING",     },
  { "IF",           "TK_IF",         },
  { "INSERT",       "TK_INSERT",     },
................................................................................
  { "IN",           "TK_IN",         },
  { "INTO",         "TK_INTO",       },
  { "IS",           "TK_IS",         },
  { "LIKE",         "TK_LIKEOP",     },
  { "LIMIT",        "TK_LIMIT",      },
  { "NOT",          "TK_NOT",        },
  { "NULL",         "TK_NULL",       },
  { "null",         "TK_NULL",       },
  { "OFFSET",       "TK_OFFSET",     },
  { "ORDER",        "TK_ORDER",      },
  { "OR",           "TK_OR",         },
  { "PRAGMA",       "TK_PRAGMA",     },
  { "ROLLBACK",     "TK_ROLLBACK",   },
  { "SELECT",       "TK_SELECT",     },
  { "SET",          "TK_SET",        },
  { "true",         "TK_TRUE",       },
  { "UNION",        "TK_UNION",      },
  { "UPDATE",       "TK_UPDATE",     },
  { "VALUE",        "TK_VALUE",      },
  { "WHERE",        "TK_WHERE",      },
};

/* Number of keywords */
................................................................................
      printf("\n");
      j = 0;
    }
  }
  printf("%s  };\n", j==0 ? "" : "\n");

  printf("  int h, i;\n");
  printf("  if( n<2 ) return TK_ID;\n");
  printf("  h = (z[0]*4 ^ z[n-1]*3 ^ n) %% %d;\n", bestSize);
  printf("  for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){\n");
  printf("    if( aLen[i]==n && memcmp(&zText[aOffset[i]],z,n)==0 ){\n");
  printf("      return aCode[i];\n");
  printf("    }\n");
  printf("  }\n");
  printf("  return TK_ID;\n");