~drizzle-trunk/drizzle/development

390.1.2 by Monty Taylor
Fixed copyright headers in drizzled/
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2008 Sun Microsystems
5
 *
6
 *  This program is free software; you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation; version 2 of the License.
9
 *
10
 *  This program is distributed in the hope that it will be useful,
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 *  GNU General Public License for more details.
14
 *
15
 *  You should have received a copy of the GNU General Public License
16
 *  along with this program; if not, write to the Free Software
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
 */
1 by brian
clean slate
19
20
/**
21
  @file
22
23
  @details
24
@verbatim
25
The idea of presented algorithm see in 
26
"The Art of Computer Programming" by Donald E. Knuth
27
Volume 3 "Sorting and searching"
28
(chapter 6.3 "Digital searching" - name and number of chapter 
29
   is back translation from Russian edition :))
30
31
as illustration of data structures, imagine next table:
32
33
static SYMBOL symbols[] = {
34
  { "ADD",              SYM(ADD),0,0},
35
  { "AND",              SYM(AND),0,0},
36
  { "DAY",              SYM(DAY_SYM),0,0},
37
};
38
39
for this structure, presented program generate next searching-structure:
40
41
+-----------+-+-+-+
42
|       len |1|2|3|
43
+-----------+-+-+-+
44
|first_char |0|0|a|
45
|last_char  |0|0|d|
46
|link       |0|0|+|
47
                 |
48
                 V
49
       +----------+-+-+-+--+
50
       |    1 char|a|b|c|d |
51
       +----------+-+-+-+--+
52
       |first_char|b|0|0|0 |
53
       |last_char |n|0|0|-1|
54
       |link      |+|0|0|+ |
55
                   |     |
56
                   |     V
57
                   |  symbols[2] ( "DAY" )
58
                   V
59
+----------+--+-+-+-+-+-+-+-+-+-+--+
60
|    2 char|d |e|f|j|h|i|j|k|l|m|n |
61
+----------+--+-+-+-+-+-+-+-+-+-+--+
62
|first_char|0 |0|0|0|0|0|0|0|0|0|0 |
63
|last_char |-1|0|0|0|0|0|0|0|0|0|-1|
64
|link      |+ |0|0|0|0|0|0|0|0|0|+ |
65
            |                    |
66
            V                    V
67
         symbols[0] ( "ADD" )  symbols[1] ( "AND" )
68
69
for optimization, link is the 16-bit index in 'symbols' or 'sql_functions'
70
or search-array..
71
72
So, we can read full search-structure as 32-bit word
73
@endverbatim
74
75
@todo
76
    use instead to_upper_lex, special array 
77
    (substitute chars) without skip codes..
78
@todo
79
    try use reverse order of comparing..
80
81
*/
82
83
#define NO_YACC_SYMBOLS
212.5.39 by Monty Taylor
Phew. Moved my_base and my_global.
84
#include "global.h"
212.5.13 by Monty Taylor
Moved my_sys/my_pthread/my_nosys and mysys_err to mysys.
85
#include <mysys/my_sys.h>
212.5.45 by Monty Taylor
Removed excess AM_CPPFLAGS from the tree. Now the only thing that should be in the include path should be -I${top_srcdir} and -I${top_builddir}w
86
#include <mystrings/m_string.h>
212.5.21 by Monty Taylor
Moved my_getopt.h
87
#include <mysys/my_getopt.h>
1 by brian
clean slate
88
#include "lex.h"
89
520.4.44 by mordred
A whole bunch of solaris/sun studio compile fixes.
90
using namespace std;
91
1 by brian
clean slate
92
const char *default_dbug_option="d:t:o,/tmp/gen_lex_hash.trace";
93
94
struct my_option my_long_options[] =
95
{
96
  {"help", '?', "Display help and exit",
97
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
98
  {"version", 'V', "Output version information and exit",
99
   0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
100
  {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
101
};
102
103
struct hash_lex_struct
104
{
105
  int first_char;
106
  char last_char;
107
  union{
108
    hash_lex_struct *char_tails;
109
    int iresult;
110
  };
111
  int ithis;
112
};
113
114
hash_lex_struct *get_hash_struct_by_len(hash_lex_struct **root_by_len,
115
					    int len, int *max_len)
116
{
117
  if (*max_len<len){
118
    *root_by_len= (hash_lex_struct *)realloc((char*)*root_by_len,
119
                                             sizeof(hash_lex_struct)*len);
120
    hash_lex_struct *cur, *end= *root_by_len + len;
121
    for (cur= *root_by_len + *max_len; cur<end; cur++)
122
      cur->first_char= 0;
123
    *max_len= len;
124
  }
125
  return (*root_by_len)+(len-1);
126
}
127
128
void insert_into_hash(hash_lex_struct *root, const char *name, 
129
		      int len_from_begin, int index, int function)
130
{
131
  hash_lex_struct *end, *cur, *tails;
132
133
  if (!root->first_char)
134
  {
135
    root->first_char= -1;
136
    root->iresult= index;
137
    return;
138
  }
139
140
  if (root->first_char == -1)
141
  {
142
    int index2= root->iresult;
143
    const char *name2= (index2 < 0 ? sql_functions[-index2-1] :
144
			symbols[index2]).name + len_from_begin;
481 by Brian Aker
Remove all of uchar.
145
    root->first_char= (int) (unsigned char) name2[0];
1 by brian
clean slate
146
    root->last_char= (char) root->first_char;
147
    tails= (hash_lex_struct*)malloc(sizeof(hash_lex_struct));
148
    root->char_tails= tails;
149
    tails->first_char= -1;
150
    tails->iresult= index2;
151
  }
152
153
  size_t real_size= (root->last_char-root->first_char+1);
154
155
  if (root->first_char>(*name))
156
  {
157
    size_t new_size= root->last_char-(*name)+1;
158
    if (new_size<real_size) printf("error!!!!\n");
159
    tails= root->char_tails;
160
    tails= (hash_lex_struct*)realloc((char*)tails,
161
				       sizeof(hash_lex_struct)*new_size);
162
    root->char_tails= tails;
163
    memmove(tails+(new_size-real_size),tails,real_size*sizeof(hash_lex_struct));
164
    end= tails + new_size - real_size;
165
    for (cur= tails; cur<end; cur++)
166
      cur->first_char= 0;
481 by Brian Aker
Remove all of uchar.
167
    root->first_char= (int) (unsigned char) *name;
1 by brian
clean slate
168
  }
169
170
  if (root->last_char<(*name))
171
  {
172
    size_t new_size= (*name)-root->first_char+1;
173
    if (new_size<real_size) printf("error!!!!\n");
174
    tails= root->char_tails;
175
    tails= (hash_lex_struct*)realloc((char*)tails,
176
				    sizeof(hash_lex_struct)*new_size);
177
    root->char_tails= tails;
178
    end= tails + new_size;
179
    for (cur= tails+real_size; cur<end; cur++)
180
      cur->first_char= 0;
181
    root->last_char= (*name);
182
  }
183
184
  insert_into_hash(root->char_tails+(*name)-root->first_char,
185
		   name+1,len_from_begin+1,index,function);
186
}
187
188
189
hash_lex_struct *root_by_len= 0;
190
int max_len=0;
191
192
hash_lex_struct *root_by_len2= 0;
193
int max_len2=0;
194
195
void insert_symbols()
196
{
197
  size_t i= 0;
198
  SYMBOL *cur;
199
  for (cur= symbols; i<array_elements(symbols); cur++, i++){
200
    hash_lex_struct *root= 
201
      get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
202
    insert_into_hash(root,cur->name,0,i,0);
203
  }
204
}
205
206
void insert_sql_functions()
207
{
208
  int i= 0;
209
  SYMBOL *cur;
210
  for (cur= sql_functions; i < (int) array_elements(sql_functions); cur++, i++)
211
  {
212
    hash_lex_struct *root= 
213
      get_hash_struct_by_len(&root_by_len,cur->length,&max_len);
214
    insert_into_hash(root,cur->name,0,-i-1,1);
215
  }
216
}
217
218
void calc_length()
219
{
220
  SYMBOL *cur, *end= symbols + array_elements(symbols);
221
  for (cur= symbols; cur < end; cur++)
481 by Brian Aker
Remove all of uchar.
222
    cur->length=(unsigned char) strlen(cur->name);
1 by brian
clean slate
223
  end= sql_functions + array_elements(sql_functions);
224
  for (cur= sql_functions; cur<end; cur++)
481 by Brian Aker
Remove all of uchar.
225
    cur->length=(unsigned char) strlen(cur->name);
1 by brian
clean slate
226
}
227
228
void generate_find_structs()
229
{
230
  root_by_len= 0;
231
  max_len=0;
232
233
  insert_symbols();
234
235
  root_by_len2= root_by_len;
236
  max_len2= max_len;
237
238
  root_by_len= 0;
239
  max_len= 0;
240
241
  insert_symbols();
242
  insert_sql_functions();
243
}
244
245
char *hash_map= 0;
246
int size_hash_map= 0;
247
77.1.15 by Monty Taylor
Bunch of warning cleanups.
248
/* Ok. I honestly don't know why this has no problem and
249
 * array_elements macro doesn't. But it works.
250
 */
251
static inline uint32_t array_elements_func(SYMBOL * symbols) {
252
  return sizeof(symbols)/sizeof(symbols[0]);
253
}
254
1 by brian
clean slate
255
void add_struct_to_map(hash_lex_struct *st)
256
{
257
  st->ithis= size_hash_map/4;
258
  size_hash_map+= 4;
259
  hash_map= (char*)realloc((char*)hash_map,size_hash_map);
260
  hash_map[size_hash_map-4]= (char) (st->first_char == -1 ? 0 :
77.1.15 by Monty Taylor
Bunch of warning cleanups.
261
                                     st->first_char);
1 by brian
clean slate
262
  hash_map[size_hash_map-3]= (char) (st->first_char == -1 ||
77.1.15 by Monty Taylor
Bunch of warning cleanups.
263
                                     st->first_char == 0 ? 0 : st->last_char);
1 by brian
clean slate
264
  if (st->first_char == -1)
265
  {
206 by Brian Aker
Removed final uint dead types.
266
    hash_map[size_hash_map-2]= ((unsigned int)(int16_t)st->iresult)&255;
267
    hash_map[size_hash_map-1]= ((unsigned int)(int16_t)st->iresult)>>8;
1 by brian
clean slate
268
  }
269
  else if (st->first_char == 0)
270
  {
206 by Brian Aker
Removed final uint dead types.
271
    hash_map[size_hash_map-2]= ((unsigned int)(int16_t)array_elements_func(symbols))&255;
272
    hash_map[size_hash_map-1]= ((unsigned int)(int16_t)array_elements(symbols))>>8;
1 by brian
clean slate
273
  }
274
}
275
276
277
void add_structs_to_map(hash_lex_struct *st, int len)
278
{
279
  hash_lex_struct *cur, *end= st+len;
280
  for (cur= st; cur<end; cur++)
281
    add_struct_to_map(cur);
282
  for (cur= st; cur<end; cur++)
283
  {
284
    if (cur->first_char && cur->first_char != -1)
285
      add_structs_to_map(cur->char_tails,cur->last_char-cur->first_char+1);
286
  }
287
}
288
289
void set_links(hash_lex_struct *st, int len)
290
{
291
  hash_lex_struct *cur, *end= st+len;
292
  for (cur= st; cur<end; cur++)
293
  {
294
    if (cur->first_char != 0 && cur->first_char != -1)
295
    {
296
      int ilink= cur->char_tails->ithis;
297
      hash_map[cur->ithis*4+2]= ilink%256;
298
      hash_map[cur->ithis*4+3]= ilink/256;
299
      set_links(cur->char_tails,cur->last_char-cur->first_char+1);
300
    }
301
  }
302
}
303
304
305
void print_hash_map(const char *name)
306
{
307
  char *cur;
308
  int i;
309
481 by Brian Aker
Remove all of uchar.
310
  printf("static unsigned char %s[%d]= {\n",name,size_hash_map);
1 by brian
clean slate
311
  for (i=0, cur= hash_map; i<size_hash_map; i++, cur++)
312
  {
313
    switch(i%4){
314
    case 0: case 1:
315
      if (!*cur)
316
	printf("0,   ");
317
      else
318
	printf("\'%c\', ",*cur);
319
      break;
481 by Brian Aker
Remove all of uchar.
320
    case 2: printf("%u, ",(uint)(unsigned char)*cur); break;
321
    case 3: printf("%u,\n",(uint)(unsigned char)*cur); break;
1 by brian
clean slate
322
    }
323
  }
324
  printf("};\n");
325
}
326
327
328
void print_find_structs()
329
{
330
  add_structs_to_map(root_by_len,max_len);
331
  set_links(root_by_len,max_len);
332
  print_hash_map("sql_functions_map");
333
334
  hash_map= 0;
335
  size_hash_map= 0;
336
337
  printf("\n");
338
339
  add_structs_to_map(root_by_len2,max_len2);
340
  set_links(root_by_len2,max_len2);
341
  print_hash_map("symbols_map");
342
}
343
344
345
static void usage(int version)
346
{
347
  printf("%s  Ver 3.6 Distrib %s, for %s (%s)\n",
546 by Monty Taylor
Cleaned up version.h. (And by cleaned, I mean removed)
348
	 my_progname, VERSION, SYSTEM_TYPE, MACHINE_TYPE);
1 by brian
clean slate
349
  if (version)
350
    return;
390.1.2 by Monty Taylor
Fixed copyright headers in drizzled/
351
  puts("Copyright (C) 2008 Sun Microsystems, Inc.");
1 by brian
clean slate
352
  puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
353
and you are welcome to modify and redistribute it under the GPL license\n");
354
  puts("This program generates a perfect hashing function for the sql_lex.cc");
355
  printf("Usage: %s [OPTIONS]\n\n", my_progname);
356
  my_print_help(my_long_options);
357
}
358
359
143 by Brian Aker
Bool cleanup.
360
extern "C" bool
1 by brian
clean slate
361
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
362
	       char *argument __attribute__((unused)))
363
{
364
  switch(optid) {
365
  case 'V':
366
    usage(1);
367
    exit(0);
368
  case 'I':
369
  case '?':
370
    usage(0);
371
    exit(0);
372
  }
373
  return 0;
374
}
375
376
377
static int get_options(int argc, char **argv)
378
{
379
  int ho_error;
380
381
  if ((ho_error= handle_options(&argc, &argv, my_long_options, get_one_option)))
382
    exit(ho_error);
383
384
  if (argc >= 1)
385
  {
386
    usage(0);
387
     exit(1);
388
  }
389
  return(0);
390
}
391
392
393
int check_dup_symbols(SYMBOL *s1, SYMBOL *s2)
394
{
395
  if (s1->length!=s2->length || strncmp(s1->name,s2->name,s1->length))
396
    return 0;
397
398
  const char *err_tmpl= "\ngen_lex_hash fatal error : \
399
Unfortunately gen_lex_hash can not generate a hash,\n since \
400
your lex.h has duplicate definition for a symbol \"%s\"\n\n";
401
  printf (err_tmpl,s1->name);
402
  fprintf (stderr,err_tmpl,s1->name);
403
404
  return 1;
405
}
406
407
408
int check_duplicates()
409
{
410
  SYMBOL *cur1, *cur2, *s_end, *f_end;
411
412
  s_end= symbols + array_elements(symbols);
413
  f_end= sql_functions + array_elements(sql_functions);
414
415
  for (cur1= symbols; cur1<s_end; cur1++)
416
  {
417
    for (cur2= cur1+1; cur2<s_end; cur2++)
418
    {
419
      if (check_dup_symbols(cur1,cur2))
420
	return 1;
421
    }
422
    for (cur2= sql_functions; cur2<f_end; cur2++)
423
    {
424
      if (check_dup_symbols(cur1,cur2))
425
	return 1;
426
    }
427
  }
428
429
  for (cur1= sql_functions; cur1<f_end; cur1++)
430
  {
431
    for (cur2= cur1+1; cur2< f_end; cur2++)
432
    {
433
      if (check_dup_symbols(cur1,cur2))
434
	return 1;
435
    }
436
  }
437
  return 0;
438
}
439
440
441
int main(int argc,char **argv)
442
{
443
  MY_INIT(argv[0]);
444
445
  if (get_options(argc,(char **) argv))
446
    exit(1);
447
448
  /* Broken up to indicate that it's not advice to you, gentle reader. */
449
  printf("/*\n\n  Do " "not " "edit " "this " "file " "directly!\n\n*/\n");
450
390.1.2 by Monty Taylor
Fixed copyright headers in drizzled/
451
  printf("/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*- \n"
452
         " *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab: \n"
453
         " * \n"
454
         " *  Copyright (C) 2008 Sun Microsystems \n"
455
         " * \n"
456
         " *  This program is free software; you can redistribute it and/or modify \n"
457
         " *  it under the terms of the GNU General Public License as published by \n"
458
         " *  the Free Software Foundation; version 2 of the License. \n"
459
         " * \n"
460
         " *  This program is distributed in the hope that it will be useful, \n"
461
         " *  but WITHOUT ANY WARRANTY; without even the implied warranty of \n"
462
         " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the \n"
463
         " *  GNU General Public License for more details. \n"
464
         " * \n"
465
         " *  You should have received a copy of the GNU General Public License \n"
466
         " *  along with this program; if not, write to the Free Software \n"
467
         " *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA \n"
468
         " */\n");
1 by brian
clean slate
469
470
  /* Broken up to indicate that it's not advice to you, gentle reader. */
471
  printf("/* Do " "not " "edit " "this " "file!  This is generated by "
472
         "gen_lex_hash.cc\nthat seeks for a perfect hash function */\n\n");
473
  printf("#include \"lex.h\"\n\n");
474
475
  calc_length();
476
477
  if (check_duplicates())
478
    exit(1);
479
480
  generate_find_structs();
481
  print_find_structs();
482
483
  printf("\nstatic unsigned int sql_functions_max_len=%d;\n", max_len);
484
  printf("\nstatic unsigned int symbols_max_len=%d;\n\n", max_len2);
485
486
  printf("\
487
static SYMBOL *get_hash_symbol(const char *s,\n\
488
                               unsigned int len,bool function)\n\
489
{\n\
481 by Brian Aker
Remove all of uchar.
490
  register unsigned char *hash_map;\n\
1 by brian
clean slate
491
  register const char *cur_str= s;\n\
492
\n\
493
  if (len == 0) {\n\
494
    return(NULL);\n\
495
  }\n"
496
);
497
498
  printf("\
499
  if (function){\n\
500
    if (len>sql_functions_max_len) return 0;\n\
501
    hash_map= sql_functions_map;\n\
205 by Brian Aker
uint32 -> uin32_t
502
    register uint32_t cur_struct= uint4korr(hash_map+((len-1)*4));\n\
1 by brian
clean slate
503
\n\
504
    for (;;){\n\
481 by Brian Aker
Remove all of uchar.
505
      register unsigned char first_char= (unsigned char)cur_struct;\n\
1 by brian
clean slate
506
\n\
507
      if (first_char == 0)\n\
508
      {\n\
206 by Brian Aker
Removed final uint dead types.
509
        register int16_t ires= (int16_t)(cur_struct>>16);\n\
1 by brian
clean slate
510
        if (ires==array_elements(symbols)) return 0;\n\
511
        register SYMBOL *res;\n\
512
        if (ires>=0) \n\
513
          res= symbols+ires;\n\
514
        else\n\
515
          res= sql_functions-ires-1;\n\
482 by Brian Aker
Remove uint.
516
        register uint32_t count= cur_str-s;\n\
1 by brian
clean slate
517
        return lex_casecmp(cur_str,res->name+count,len-count) ? 0 : res;\n\
518
      }\n\
519
\n\
481 by Brian Aker
Remove all of uchar.
520
      register unsigned char cur_char= (unsigned char)to_upper_lex[(unsigned char)*cur_str];\n\
1 by brian
clean slate
521
      if (cur_char<first_char) return 0;\n\
522
      cur_struct>>=8;\n\
481 by Brian Aker
Remove all of uchar.
523
      if (cur_char>(unsigned char)cur_struct) return 0;\n\
1 by brian
clean slate
524
\n\
525
      cur_struct>>=8;\n\
526
      cur_struct= uint4korr(hash_map+\n\
206 by Brian Aker
Removed final uint dead types.
527
                        (((uint16_t)cur_struct + cur_char - first_char)*4));\n\
1 by brian
clean slate
528
      cur_str++;\n\
529
    }\n"
530
);
531
532
  printf("\
533
  }else{\n\
534
    if (len>symbols_max_len) return 0;\n\
535
    hash_map= symbols_map;\n\
205 by Brian Aker
uint32 -> uin32_t
536
    register uint32_t cur_struct= uint4korr(hash_map+((len-1)*4));\n\
1 by brian
clean slate
537
\n\
538
    for (;;){\n\
481 by Brian Aker
Remove all of uchar.
539
      register unsigned char first_char= (unsigned char)cur_struct;\n\
1 by brian
clean slate
540
\n\
541
      if (first_char==0){\n\
206 by Brian Aker
Removed final uint dead types.
542
        register int16_t ires= (int16_t)(cur_struct>>16);\n\
1 by brian
clean slate
543
        if (ires==array_elements(symbols)) return 0;\n\
544
        register SYMBOL *res= symbols+ires;\n\
482 by Brian Aker
Remove uint.
545
        register uint32_t count= cur_str-s;\n\
1 by brian
clean slate
546
        return lex_casecmp(cur_str,res->name+count,len-count)!=0 ? 0 : res;\n\
547
      }\n\
548
\n\
481 by Brian Aker
Remove all of uchar.
549
      register unsigned char cur_char= (unsigned char)to_upper_lex[(unsigned char)*cur_str];\n\
1 by brian
clean slate
550
      if (cur_char<first_char) return 0;\n\
551
      cur_struct>>=8;\n\
481 by Brian Aker
Remove all of uchar.
552
      if (cur_char>(unsigned char)cur_struct) return 0;\n\
1 by brian
clean slate
553
\n\
554
      cur_struct>>=8;\n\
555
      cur_struct= uint4korr(hash_map+\n\
206 by Brian Aker
Removed final uint dead types.
556
                        (((uint16_t)cur_struct + cur_char - first_char)*4));\n\
1 by brian
clean slate
557
      cur_str++;\n\
558
    }\n\
559
  }\n\
560
}\n"
561
);
562
  my_end(0);
563
  exit(0);
564
}
565