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