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