b41eb5ec665d6d0da094effe7f014ab7aac63c06
[vpp.git] / vppapigen / lex.c
1 /* 
2  *------------------------------------------------------------------
3  * lex.c - API generator lexical analyzer
4  *
5  * Copyright (c) 1996-2009 Cisco and/or its affiliates.
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at:
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *------------------------------------------------------------------
18  */
19
20 #include <stdio.h>
21 #include <ctype.h>
22 #include <time.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26
27 #include "lex.h"
28 #include "node.h"
29 #include "gram.h"
30
31 FILE *ifp, *ofp, *javafp, *jnifp;
32 char *java_class = "vppApi";
33 char *vlib_app_name = "vpp";
34 int dump_tree;
35 time_t starttime;
36 char *input_filename;
37 char *current_filename;
38 int current_filename_allocated;
39 unsigned long input_crc;
40 int yydebug;
41
42 /*
43  * lexer variable definitions 
44  */
45
46 static const char *version = "0.1";
47 static int the_lexer_linenumber = 1;
48 static enum lex_state the_lexer_state = START_STATE;
49
50 /*
51  * private prototypes
52  */
53 static void usage (char *);
54 static int name_check (const char *, YYSTYPE *);
55 static int name_compare (const char *, const char *);
56 extern int yydebug;
57 extern YYSTYPE yylval;
58
59 unsigned int crc32c_table[256] = { 
60   0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,  
61   0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,  
62   0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,  
63   0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,  
64   0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,  
65   0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,  
66   0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,  
67   0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,  
68   0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,  
69   0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,  
70   0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,  
71   0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,  
72   0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,  
73   0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,  
74   0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,  
75   0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,  
76   0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,  
77   0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,  
78   0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,  
79   0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,  
80   0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,  
81   0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,  
82   0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,  
83   0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,  
84   0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,  
85   0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,  
86   0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,  
87   0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,  
88   0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,  
89   0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,  
90   0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,  
91   0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,  
92   0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,  
93   0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,  
94   0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,  
95   0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,  
96   0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,  
97   0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,  
98   0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,  
99   0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,  
100   0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,  
101   0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,  
102   0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,  
103   0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,  
104   0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,  
105   0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,  
106   0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,  
107   0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,  
108   0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,  
109   0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,  
110   0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,  
111   0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,  
112   0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,  
113   0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,  
114   0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,  
115   0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,  
116   0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,  
117   0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,  
118   0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,  
119   0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,  
120   0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,  
121   0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,  
122   0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,  
123   0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351  
124 }; 
125
126 static inline unsigned long CRC8 (unsigned long crc,
127                                   unsigned char d)
128 {
129     return ((crc >> 8) ^ crc32c_table[(crc ^ d) & 0xFF]);
130 }
131 static inline unsigned long CRC16 (unsigned long crc,
132                                    unsigned short d)
133 {
134     crc = CRC8 (crc, d & 0xff);
135     d = d >> 8;
136     crc = CRC8 (crc, d & 0xff);
137     return crc;
138 }
139
140
141 static unsigned long
142 crc_eliding_c_comments (const char *buf, unsigned long crc)
143 {
144     const char *p;
145     enum { cOTHER,              /*  */
146            cSTRING,             /* "...    */
147            cSBACKSLASH,         /* "...\   */
148            cCHAR,               /* '...    */
149            cCBACKSLASH,         /* '...\   */
150            cSLASH,              /* /       */
151            cSLASH_SLASH,        /* //...   */
152            cSLASH_STAR,         /* / *...  */
153            cSTAR                /* / *...* */
154     } ss = cOTHER;
155
156     for (p = buf; ;) {
157         unsigned char c = *p++;
158
159         switch (c) {
160         case 0:
161             switch (ss) {
162             case cOTHER:
163                 return (crc);
164             case cSTRING: case cSBACKSLASH:
165             case cCHAR: case cCBACKSLASH:
166             case cSLASH: case cSLASH_SLASH: case cSLASH_STAR: case cSTAR:
167                 fprintf (stderr, "Inopportune EOF: %s\n", buf);
168                 exit (1);
169             }
170             break;
171         case '\"':
172             switch (ss) {
173             case cOTHER: ss = cSTRING; break; /* start string */
174             case cSTRING: ss = cOTHER; break; /* end string */
175             case cSBACKSLASH: ss = cSTRING; break;
176             case cCHAR: break;
177             case cCBACKSLASH: ss = cCHAR; break;
178             case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break;
179             case cSLASH_SLASH: continue; /* in comment */
180             case cSLASH_STAR: continue; /* in comment */
181             case cSTAR: ss = cSLASH_STAR; continue; /* in comment */
182             }
183             break;
184         case '\\':
185             switch (ss) {
186             case cOTHER: break;
187             case cSTRING: ss = cSBACKSLASH; break;
188             case cSBACKSLASH: ss = cSTRING; break;
189             case cCHAR: ss = cCBACKSLASH; break;
190             case cCBACKSLASH: ss = cCHAR; break;
191             case cSLASH: crc = CRC8 (crc, '/'); ; ss = cOTHER; break;
192             case cSLASH_SLASH: continue; /* in comment */
193             case cSLASH_STAR: continue; /* in comment */
194             case cSTAR: ss = cSLASH_STAR; continue; /* in comment */
195             }
196             break;
197         case '/':
198             switch (ss) {
199             case cOTHER: ss = cSLASH; continue; /* potential comment */
200             case cSTRING: break;
201             case cSBACKSLASH: ss = cSTRING; break;
202             case cCHAR: break;
203             case cCBACKSLASH: ss = cCHAR; break;
204             case cSLASH: ss = cSLASH_SLASH; continue; /* start comment */
205             case cSLASH_SLASH: continue; /* in comment */
206             case cSLASH_STAR: continue; /* in comment */
207             case cSTAR: ss = cOTHER; continue; /* end of comment */
208             }
209             break;
210         case '*':
211             switch (ss) {
212             case cOTHER: break;
213             case cSTRING: break;
214             case cSBACKSLASH: ss = cSTRING; break;
215             case cCHAR: break;
216             case cCBACKSLASH: ss = cCHAR; break;
217             case cSLASH: ss = cSLASH_STAR; continue; /* start comment */
218             case cSLASH_SLASH: continue; /* in comment */
219             case cSLASH_STAR: ss = cSTAR; continue; /* potential end */
220             case cSTAR: continue; /* still potential end of comment */
221             }
222             break;
223         case '\n': case '\r': case ' ': case '\t': case '\014':
224             switch (ss) {
225             case cOTHER: continue; /* ignore all whitespace */
226             case cSTRING: break;
227             case cSBACKSLASH: ss = cSTRING; break;
228             case cCHAR: break;
229             case cCBACKSLASH: ss = cCHAR; break;
230             case cSLASH: c = '/'; ss = cOTHER; break;
231             case cSLASH_SLASH:
232                 if (c == '\n' || c == '\r') ss = cOTHER; /* end comment */
233                 continue;
234             case cSLASH_STAR: continue; /* in comment */
235             case cSTAR: ss = cSLASH_STAR; continue; /* in comment */
236             }
237         default:
238             switch (ss) {
239             case cOTHER: break;
240             case cSTRING: break;
241             case cSBACKSLASH: ss = cSTRING; break;
242             case cCHAR: break;
243             case cCBACKSLASH: ss = cCHAR; break;
244             case cSLASH: crc = CRC8 (crc, '/'); ss = cOTHER; break;
245             case cSLASH_SLASH: continue; /* in comment */
246             case cSLASH_STAR: continue; /* in comment */
247             case cSTAR: ss = cSLASH_STAR; continue; /* in comment */
248             }
249         }
250         crc = CRC8 (crc, c);
251     }
252 }
253
254 /*
255  * main 
256  */
257 int main (int argc, char **argv)
258 {
259     int curarg = 1;
260     char *ofile=0;
261     char *jofile=0;
262     char *jnifile=0;
263     char *show_name=0;
264
265     while (curarg < argc) {
266         if (!strncmp (argv [curarg], "--verbose", 3)) {
267             fprintf (stderr, "%s version %s\n", argv [0], version);
268             curarg++;
269             continue;
270         }
271         
272         if (!strncmp (argv [curarg], "--yydebug", 3)) {
273             yydebug = 1;
274             curarg++;
275             continue;
276         }
277         
278         if (!strncmp (argv [curarg], "--dump", 3)) {
279             dump_tree = 1;
280             curarg++;
281             continue;
282         }
283         
284         if (!strncmp (argv[curarg], "--show-name", 3)) {
285             curarg++;
286             if (curarg < argc) {
287                 show_name = argv[curarg];
288                 curarg++;
289                 continue;
290             } else {
291                 fprintf(stderr, "Missing filename after --show-name \n");
292                 exit(1);
293             }
294         }
295
296         if (!strncmp (argv [curarg], "--input", 3)) {
297             curarg++;
298             if (curarg < argc) {
299                 input_filename = argv[curarg];
300                 if (!strcmp (argv [curarg], "-"))
301                     ifp = stdin;
302                 else
303                     ifp = fopen (argv [curarg], "r");
304                 if (ifp == NULL) {
305                     fprintf (stderr, "Couldn't open input file %s\n", 
306                              argv[curarg]);
307                     exit (1);
308                 }
309                 curarg++;
310             } else {
311                 fprintf(stderr, "Missing filename after --input\n");
312                 exit(1);
313             }
314             continue;
315         }
316         if (!strncmp (argv [curarg], "--output", 3)) {
317             curarg++;
318             if (curarg < argc) {
319                 ofp = fopen (argv[curarg], "w");
320                 if (ofp == NULL) {
321                     fprintf (stderr, "Couldn't open output file %s\n", 
322                          argv[curarg]);
323                     exit (1);
324                 }
325                 ofile = argv[curarg];
326                 curarg++;
327             } else {
328                 fprintf(stderr, "Missing filename after --output\n");
329                 exit(1);
330             }
331             continue;
332         }
333         if (!strncmp (argv [curarg], "--java", 4)) {
334             curarg++;
335             if (curarg < argc) {
336                 javafp = fopen (argv[curarg], "w");
337                 if (javafp == NULL) {
338                     fprintf (stderr, "Couldn't open java output file %s\n", 
339                          argv[curarg]);
340                     exit (1);
341                 }
342                 jofile = argv[curarg];
343                 curarg++;
344             } else {
345                 fprintf(stderr, "Missing filename after --java\n");
346                 exit(1);
347             }
348             continue;
349         }
350         if (!strncmp (argv [curarg], "--jni", 4)) {
351             curarg++;
352             if (curarg < argc) {
353                 jnifp = fopen (argv[curarg], "w");
354                 if (jnifp == NULL) {
355                     fprintf (stderr, "Couldn't open jni output file %s\n", 
356                          argv[curarg]);
357                     exit (1);
358                 }
359                 jnifile = argv[curarg];
360                 curarg++;
361             } else {
362                 fprintf(stderr, "Missing filename after --jni\n");
363                 exit(1);
364             }
365             continue;
366         }
367         if (!strncmp (argv [curarg], "--app", 4)) {
368             curarg++;
369             if (curarg < argc) {
370                 vlib_app_name = argv[curarg];
371                 curarg++;
372             } else {
373                 fprintf(stderr, "Missing app name after --app\n");
374                 exit(1);
375             }
376             continue;
377         }
378         if (!strncmp (argv [curarg], "--class", 3)) {
379             curarg++;
380             if (curarg < argc) {
381                 java_class = argv[curarg];
382                 curarg++;
383             } else {
384                 fprintf(stderr, "Missing class name after --class\n");
385                 exit(1);
386             }
387             continue;
388         }
389
390         usage(argv[0]);
391         exit (1);
392     }
393     if (ofp == NULL) {
394         ofile = 0;
395     }
396     if (javafp == NULL) {
397         jofile = 0;
398     }
399     if (jnifp == NULL) {
400         jnifile = 0;
401     }
402     if (ifp == NULL) {
403         fprintf(stderr, "No input file specified...\n");
404         exit(1);
405     }
406     if (show_name) {
407         input_filename = show_name;
408     }
409
410     starttime = time (0);
411
412     if (yyparse() == 0) {
413         fclose (ifp);
414         curarg -= 2;
415         if (ofile) {
416             printf ("Output written to %s\n", ofile);
417             fclose (ofp);
418         }
419         if (jofile) {
420             printf ("Java class defn written to %s\n", jofile);
421             fclose (javafp);
422         }
423         if (jnifile) {
424             printf ("Java native bindings written to %s\n", jnifile);
425             fclose (jnifp);
426         }
427     }
428     else {
429         fclose (ifp);
430         fclose (ofp);
431         if (ofile) {
432             printf ("Removing %s\n", ofile);
433             unlink (ofile);
434         }
435         fclose (javafp);
436         if (jofile) {
437             printf ("Removing %s\n", jofile);
438             unlink (jofile);
439         }
440         if (jnifile) {
441             printf ("Removing %s\n", jnifile);
442             unlink (jnifile);
443         }
444         exit (1);
445     }
446     exit (0);
447 }
448
449 /*
450  * usage
451  */
452 static void usage (char *progname)
453 {
454     fprintf (stderr, 
455              "usage: %s --input <filename> [--output <filename>]\n%s",
456              progname,
457              "          [--yydebug] [--dump-tree]\n");
458     exit (1);
459 }
460
461 /*
462  * yyerror 
463  */
464 void yyerror (char *s)
465 {
466     fprintf (stderr, "%s:%d %s\n", current_filename, the_lexer_linenumber, s);
467 }
468
469 static char namebuf [MAXNAME];
470
471 /*
472  * yylex (well, yylex_1: The real yylex below does crc-hackery)
473  */
474 static int yylex_1 (void)
475 {
476     int nameidx=0;
477     char c;
478     int at_bol=1;
479     enum { LP_INITIAL_WHITESPACE, LP_LINE_NUMBER,
480            LP_PRE_FILENAME_WHITESPACE, LP_FILENAME,
481            LP_POST_FILENAME,
482            LP_OTHER
483     } lp_substate = LP_INITIAL_WHITESPACE;
484
485  again:
486     switch (the_lexer_state) {
487         /*
488          * START state -- looking for something interesting 
489          */
490     case START_STATE:
491         c = getc (ifp);
492         if (feof (ifp))
493             return (EOF);
494
495         switch (c) {
496         case '\n':
497             the_lexer_linenumber++;
498             at_bol=1;
499             goto again;
500
501         case '#':
502             if (!at_bol) {
503                 fprintf (stderr, "unknown token /%c at line %d\n",
504                          c, the_lexer_linenumber);
505                 return (BARF);
506             }
507             
508             the_lexer_state = LINE_PRAGMA_STATE;
509             lp_substate = LP_INITIAL_WHITESPACE;
510             goto again;
511
512             /* FALLTHROUGH */
513         case '\t':
514         case ' ':
515             goto again;
516             
517         case '(':
518             return (LPAR);
519
520         case ')':
521             return (RPAR);
522
523         case ';':
524             return (SEMI);
525
526         case '[':
527             return (LBRACK);
528             
529         case ']':
530             return (RBRACK);
531
532         case '{':
533             return (LCURLY);
534             
535         case '}':
536             return (RCURLY);
537
538         case ',':
539             return (COMMA);
540
541         case '"':
542             nameidx = 0;
543             the_lexer_state = STRING_STATE;
544             goto again;
545
546         case '@':
547             nameidx = 0;
548             the_lexer_state = HELPER_STATE;
549             goto again;
550
551         case '/':
552             c = getc (ifp);
553             if (feof (ifp))
554                 return (EOF);
555
556             if (c == '/') {
557                 the_lexer_state = CPP_COMMENT_STATE;
558                 goto again;
559             } else if (c == '*') {
560                 the_lexer_state = C_COMMENT_STATE;
561                 goto again;
562             } else {
563                 fprintf (stderr, "unknown token /%c at line %d\n",
564                          c, the_lexer_linenumber);
565                 return (BARF);
566             }
567
568         case '\\':
569             c = getc (ifp);
570             if (feof (ifp))
571                 return (EOF);
572             
573             /* Note fallthrough... */
574
575         default:
576             if (isalpha (c) || c == '_') {
577                 namebuf [0] = c;
578                 nameidx = 1;
579                 the_lexer_state = NAME_STATE;
580                 goto again;
581             } else if (isdigit(c)) {
582                 namebuf [0] = c;
583                 nameidx = 1;
584                 the_lexer_state = NUMBER_STATE;
585                 goto again;
586             }
587
588             fprintf (stderr, "unknown token %c at line %d\n",
589                      c, the_lexer_linenumber);
590             return (BARF);
591         }
592
593         /*
594          * NAME state -- eat the rest of a name 
595          */
596     case NAME_STATE:
597         c = getc (ifp);
598         if (feof (ifp))
599             return (EOF);
600         
601         if (!isalnum (c) && c != '_') {
602             ungetc (c, ifp);
603             namebuf [nameidx] = 0;
604             the_lexer_state = START_STATE;
605             return (name_check (namebuf, &yylval));
606         }                
607         if (nameidx >= (MAXNAME-1)) {
608             fprintf(stderr, "lex input buffer overflow...\n");
609             exit(1);
610         }
611         namebuf [nameidx++] = c;
612         goto again;
613         
614         /*
615          * NUMBER state -- eat the rest of a number
616          */
617     case NUMBER_STATE:
618         c = getc (ifp);
619         if (feof (ifp))
620             return (EOF);
621         
622         if (!isdigit (c)) {
623             ungetc (c, ifp);
624             namebuf [nameidx] = 0;
625             the_lexer_state = START_STATE;
626             yylval = (void *) atol(namebuf);
627             return (NUMBER);
628         }                
629         if (nameidx >= (MAXNAME-1)) {
630             fprintf(stderr, "lex input buffer overflow...\n");
631             exit(1);
632         }
633         namebuf [nameidx++] = c;
634         goto again;
635
636         /*
637          * C_COMMENT state -- eat a peach
638          */
639     case C_COMMENT_STATE:
640         c = getc (ifp);
641         if (feof (ifp))
642             return (EOF);
643         if (c == '*') {
644             c = getc (ifp);
645             if (feof (ifp))
646                 return (EOF);
647             if (c == '/') {
648                 the_lexer_state = START_STATE;
649                 goto again;
650             }
651         }
652         if (c == '\n')
653             the_lexer_linenumber++;
654         goto again;
655             
656         /*
657          * CPP_COMMENT state -- eat a plum 
658          */
659
660     case CPP_COMMENT_STATE:
661         c = getc (ifp);
662         if (feof (ifp))
663             return (EOF);
664         if (c == '\n') {
665             the_lexer_linenumber++;
666             the_lexer_state = START_STATE;
667             goto again;
668         }
669         goto again;
670
671     case STRING_STATE:
672         c = getc (ifp);
673         if (feof (ifp))
674             return (EOF);
675         switch (c) {
676         case '\\':
677             c = getc (ifp);
678             if (feof (ifp))
679                 return (EOF);
680             namebuf[nameidx++] = c;
681             goto again;
682
683         case '"':
684             namebuf[nameidx] = 0;
685             yylval = (YYSTYPE) sxerox (namebuf);
686             the_lexer_state = START_STATE;
687             return (STRING);
688
689         default:
690             if (c == '\n')
691                 the_lexer_linenumber++;
692
693             if (nameidx >= (MAXNAME-1)) {
694                 fprintf(stderr, "lex input buffer overflow...\n");
695                 exit(1);
696             }
697             namebuf[nameidx++] = c;
698             goto again;
699         }
700         break;
701
702     case HELPER_STATE:
703         c = getc (ifp);
704         if (feof (ifp))
705             return (EOF);
706         switch (c) {
707         case '\\':
708             c = getc (ifp);
709             if (feof (ifp))
710                 return (EOF);
711             namebuf[nameidx] = c;
712             goto again;
713
714         case '@':
715             namebuf[nameidx] = 0;
716             yylval = (YYSTYPE) sxerox (namebuf);
717             the_lexer_state = START_STATE;
718             return (HELPER_STRING);
719
720         default:
721             if (c == '\n')
722                 the_lexer_linenumber++;
723
724             /*
725              * CPP makes it approximately impossible to 
726              * type "#define FOO 123", so we provide a 
727              * lexical trick to achieve that result 
728              */
729
730             if (c == '$')
731                 c = '#';
732
733             if (nameidx >= (MAXNAME-1)) {
734                 fprintf(stderr, "lex input buffer overflow...\n");
735                 exit(1);
736             }
737             namebuf[nameidx++] = c;
738             goto again;
739         }
740         break;
741
742     case LINE_PRAGMA_STATE:
743         /* We're only interested in lines of the form # 259 "foo.c" 17 */
744
745         switch (lp_substate) {
746
747         case LP_INITIAL_WHITESPACE: /* no number seen yet */
748             c = getc(ifp);
749             if (feof(ifp))
750                 return(EOF);
751             if (c >= '0' && c <= '9') {
752                 namebuf[nameidx++] = c;
753                 lp_substate = LP_LINE_NUMBER;
754             } else if (c == '\n') {
755                 goto lp_end_of_line;
756             } else if (c != ' ' && c != '\t') {
757                 /* Nothing */
758             } else {
759                 lp_substate = LP_OTHER;
760             }
761             goto again;
762
763         case LP_LINE_NUMBER:    /* eating linenumber */
764             c = getc(ifp);
765             if (feof(ifp))
766                 return(EOF);
767             if (c >= '0' && c <= '9') {
768                 namebuf[nameidx++] = c;
769             } else if (c == ' ' || c == '\t') {
770                 namebuf[nameidx++] = 0;
771                 the_lexer_linenumber = atol(namebuf);
772                 lp_substate = LP_PRE_FILENAME_WHITESPACE;
773             } else if (c == '\n') {
774                 goto lp_end_of_line;
775             } else {
776                 lp_substate = LP_OTHER;
777             }
778             goto again;
779
780         case LP_PRE_FILENAME_WHITESPACE: /* awaiting filename */
781             c = getc(ifp);
782             if (feof(ifp))
783                 return(EOF);
784             
785             if (c == '"') {
786                 lp_substate = LP_FILENAME;
787                 nameidx = 0;
788             } else if (c == ' ' || c == '\t') {
789                 /* nothing */
790             } else if (c == '\n') {
791                 goto lp_end_of_line;
792             } else {
793                 lp_substate = LP_OTHER;
794             }
795             goto again;
796
797         case LP_FILENAME:       /* eating filename */
798             c = getc(ifp);
799             if (feof(ifp))
800                 return(EOF);
801
802             if (c == '"') {
803                 lp_substate = LP_POST_FILENAME;
804                 namebuf[nameidx] = 0;
805             } else if (c == '\n') {
806                 goto lp_end_of_line; /* syntax error... */
807             } else {
808                 namebuf[nameidx++] = c;
809             }
810             goto again;
811
812         case LP_POST_FILENAME:  /* ignoring rest of line */
813         case LP_OTHER:
814             c = getc(ifp);
815             if (feof(ifp))
816                 return(EOF);
817
818             if (c == '\n') {
819                 if (lp_substate == LP_POST_FILENAME) {
820                     if (current_filename_allocated) {
821                         current_filename_allocated = 0;
822                         free(current_filename);
823                     }
824
825                     if (!strcmp(namebuf, "<stdin>")) {
826                         current_filename = input_filename;
827                     } else {
828                         current_filename = sxerox(namebuf);
829                         current_filename_allocated = 1;
830                     }
831                 }
832             lp_end_of_line:
833                 the_lexer_state = START_STATE;
834                 at_bol = 1;
835                 nameidx = 0;
836             }
837             goto again;
838         }
839         break;
840     }
841     fprintf (stderr, "LEXER BUG!\n");
842     exit (1);
843     /* NOTREACHED */
844     return (0);
845 }
846
847 /*
848  * Parse a token and side-effect input_crc
849  * in a whitespace- and comment-insensitive fashion.
850  */
851 int yylex (void)
852 {
853     /*
854      * Accumulate a crc32-based signature while processing the
855      * input file.  The goal is to come up with a magic number
856      * which changes precisely when the original input file changes
857      * but which ignores whitespace changes.
858      */
859     unsigned long crc = input_crc;
860     int node_type = yylex_1 ();
861
862     switch (node_type) {
863     case PRIMTYPE:
864     case NAME:
865     case NUMBER:
866     case STRING:
867     case HELPER_STRING: {
868         /* We know these types accumulated token text into namebuf */
869         /* HELPER_STRING may still contain C comments.  Argh. */
870         crc = crc_eliding_c_comments (namebuf, crc);
871         break;
872     }
873
874      /* Other node types have no "substate" */
875      /* This code is written in this curious fashion because we
876       * want the generated CRC to be independent of the particular
877       * values a particular version of lex/bison assigned to various states.
878       */
879
880     /* case NAME:            crc = CRC16 (crc, 257); break; */
881     case RPAR:               crc = CRC16 (crc, 258); break;
882     case LPAR:               crc = CRC16 (crc, 259); break;
883     case SEMI:               crc = CRC16 (crc, 260); break;
884     case LBRACK:             crc = CRC16 (crc, 261); break;
885     case RBRACK:             crc = CRC16 (crc, 262); break;
886     /* case NUMBER:          crc = CRC16 (crc, 263); break; */
887     /* case PRIMTYPE:        crc = CRC16 (crc, 264); break; */
888     case BARF:               crc = CRC16 (crc, 265); break;
889     case TPACKED:            crc = CRC16 (crc, 266); break;
890     case DEFINE:             crc = CRC16 (crc, 267); break;
891     case LCURLY:             crc = CRC16 (crc, 268); break;
892     case RCURLY:             crc = CRC16 (crc, 269); break;
893     /* case STRING:          crc = CRC16 (crc, 270); break; */
894     case UNION:              crc = CRC16 (crc, 271); break;
895     /* case HELPER_STRING:   crc = CRC16 (crc, 272); break; */
896     case COMMA:              crc = CRC16 (crc, 273); break;
897     case NOVERSION:          crc = CRC16 (crc, 274); break;
898     case MANUAL_PRINT:       crc = CRC16 (crc, 275); break;
899     case MANUAL_ENDIAN:      crc = CRC16 (crc, 276); break;
900     case MANUAL_JAVA:        crc = CRC16 (crc, 277); break;
901     case TYPEONLY:           crc = CRC16 (crc, 278); break;
902     case DONT_TRACE:         crc = CRC16 (crc, 279); break;
903         
904     case EOF: crc = CRC16 (crc, ~0); break; /* hysterical compatibility */
905
906     default:
907         fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
908                 node_type);
909         exit(1);
910     }
911
912     input_crc = crc;
913     return (node_type);
914 }
915
916
917 /*
918  * name_check -- see if the name we just ate
919  * matches a known keyword.  If so, set yylval
920  * to a new instance of <subclass of node>, and return PARSER_MACRO
921  *
922  * Otherwise, set yylval to sxerox (s) and return NAME
923  */
924
925 static struct keytab {
926     char *name;
927     enum node_subclass subclass_id;
928 } keytab [] = 
929 /* Keep the table sorted, binary search used below! */
930 {
931     {"define",          NODE_DEFINE},  
932     {"dont_trace",      NODE_DONT_TRACE},
933     {"f64",             NODE_F64},
934     {"i16",             NODE_I16},
935     {"i32",             NODE_I32},
936     {"i64",             NODE_I64},
937     {"i8",              NODE_I8},
938     {"manual_endian",   NODE_MANUAL_ENDIAN},
939     {"manual_java",     NODE_MANUAL_JAVA},
940     {"manual_print",    NODE_MANUAL_PRINT},
941     {"noversion",       NODE_NOVERSION},
942     {"packed",          NODE_PACKED},
943     {"typeonly",        NODE_TYPEONLY},
944     {"u16",             NODE_U16},
945     {"u32",             NODE_U32},
946     {"u64",             NODE_U64},
947     {"u8",              NODE_U8},
948     {"union",           NODE_UNION},
949     {"uword",           NODE_UWORD},
950 };
951  
952 static int name_check (const char *s, YYSTYPE *token_value)
953 {
954     enum node_subclass subclass_id;
955     int top, bot, mid;
956     int result;
957
958     for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1; 
959          bot >= top; ) {
960         mid = (top + bot) / 2;
961         result = name_compare (s, keytab[mid].name);
962         if (result < 0)
963             bot = mid - 1;
964         else if (result > 0)
965             top = mid + 1;
966         else {
967             subclass_id = keytab[mid].subclass_id;
968
969             switch (subclass_id) {
970             case NODE_U8:
971             case NODE_U16:
972             case NODE_U32:
973             case NODE_U64:
974             case NODE_I8:
975             case NODE_I16:
976             case NODE_I32:
977             case NODE_I64:
978             case NODE_F64:
979             case NODE_UWORD:
980                 *token_value = make_node(subclass_id);
981                 return (PRIMTYPE);
982
983             case NODE_PACKED:
984                 *token_value = make_node(subclass_id);
985                 return (TPACKED);
986
987             case NODE_DEFINE:
988                 *token_value = make_node(subclass_id);
989                 return(DEFINE);
990
991             case NODE_MANUAL_PRINT:
992                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT;
993                 return (MANUAL_PRINT);
994
995             case NODE_MANUAL_ENDIAN:
996                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN;
997                 return (MANUAL_ENDIAN);
998
999             case NODE_MANUAL_JAVA:
1000                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_JAVA;
1001                 return (MANUAL_JAVA);
1002
1003             case NODE_TYPEONLY:
1004                 *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY;
1005                 return(TYPEONLY);
1006
1007             case NODE_DONT_TRACE:
1008                 *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE;
1009                 return(DONT_TRACE);
1010
1011             case NODE_NOVERSION:
1012                 return(NOVERSION);
1013
1014             case NODE_UNION:
1015                 return(UNION);
1016
1017             default:
1018                 fprintf (stderr, "fatal: keytab botch!\n");
1019                 exit (1);
1020             }
1021         }
1022     }
1023     *token_value = (YYSTYPE) sxerox (s);
1024     return (NAME);
1025 }
1026
1027 /*
1028  * sxerox
1029  */
1030
1031 char *sxerox (const char *s)
1032 {
1033     int len = strlen (s);
1034     char *rv;
1035
1036     rv = (char *) malloc (len+1);
1037     strcpy (rv, s);
1038     return (rv);
1039 }
1040
1041 /*
1042  * name_compare
1043  */
1044
1045 int name_compare (const char *s1, const char *s2)
1046 {
1047     char c1, c2;
1048
1049     while (*s1 && *s2) {
1050         c1 = *s1++;
1051         c2 = *s2++;
1052
1053         c1 = tolower (c1);
1054         c2 = tolower (c2);
1055         if (c1 < c2)
1056             return (-1);
1057         else if (c1 > c2)
1058             return (1);
1059     }
1060     if (*s1 < *s2)
1061         return (-1);
1062     else if (*s1 > *s2)
1063         return (1);
1064     return (0);
1065 }