"autoreply" flag: autogenerate standard xxx_reply_t messages
[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             nameidx = 0;
586             the_lexer_state = STRING_STATE;
587             goto again;
588
589         case '@':
590             nameidx = 0;
591             the_lexer_state = HELPER_STATE;
592             goto again;
593
594         case '/':
595             c = getc_char (ifp);
596             if (feof (ifp))
597                 return (EOF);
598
599             if (c == '/') {
600                 the_lexer_state = CPP_COMMENT_STATE;
601                 goto again;
602             } else if (c == '*') {
603                 the_lexer_state = C_COMMENT_STATE;
604                 goto again;
605             } else {
606                 fprintf (stderr, "unknown token /%c at line %d\n",
607                          c, the_lexer_linenumber);
608                 return (BARF);
609             }
610
611         case '\\':
612             c = getc_char (ifp);
613             if (feof (ifp))
614                 return (EOF);
615             
616             /* Note fallthrough... */
617
618         default:
619             if (isalpha (c) || c == '_') {
620                 namebuf [0] = c;
621                 nameidx = 1;
622                 the_lexer_state = NAME_STATE;
623                 goto again;
624             } else if (isdigit(c)) {
625                 namebuf [0] = c;
626                 nameidx = 1;
627                 the_lexer_state = NUMBER_STATE;
628                 goto again;
629             }
630
631             fprintf (stderr, "unknown token %c at line %d\n",
632                      c, the_lexer_linenumber);
633             return (BARF);
634         }
635
636         /*
637          * NAME state -- eat the rest of a name 
638          */
639     case NAME_STATE:
640         c = getc_char (ifp);
641         if (feof (ifp))
642             return (EOF);
643         
644         if (!isalnum (c) && c != '_') {
645             ungetc_char (c, ifp);
646             namebuf [nameidx] = 0;
647             the_lexer_state = START_STATE;
648             return (name_check (namebuf, &yylval));
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         /*
658          * NUMBER state -- eat the rest of a number
659          */
660     case NUMBER_STATE:
661         c = getc_char (ifp);
662         if (feof (ifp))
663             return (EOF);
664         
665         if (!isdigit (c)) {
666             ungetc_char (c, ifp);
667             namebuf [nameidx] = 0;
668             the_lexer_state = START_STATE;
669             yylval = (void *) atol(namebuf);
670             return (NUMBER);
671         }                
672         if (nameidx >= (MAXNAME-1)) {
673             fprintf(stderr, "lex input buffer overflow...\n");
674             exit(1);
675         }
676         namebuf [nameidx++] = c;
677         goto again;
678
679         /*
680          * C_COMMENT state -- eat a peach
681          */
682     case C_COMMENT_STATE:
683         c = getc_char (ifp);
684         if (feof (ifp))
685             return (EOF);
686         if (c == '*') {
687             c = getc_char (ifp);
688             if (feof (ifp))
689                 return (EOF);
690             if (c == '/') {
691                 the_lexer_state = START_STATE;
692                 goto again;
693             }
694         }
695         if (c == '\n')
696             the_lexer_linenumber++;
697         goto again;
698             
699         /*
700          * CPP_COMMENT state -- eat a plum 
701          */
702
703     case CPP_COMMENT_STATE:
704         c = getc_char (ifp);
705         if (feof (ifp))
706             return (EOF);
707         if (c == '\n') {
708             the_lexer_linenumber++;
709             the_lexer_state = START_STATE;
710             goto again;
711         }
712         goto again;
713
714     case STRING_STATE:
715         c = getc_char (ifp);
716         if (feof (ifp))
717             return (EOF);
718         switch (c) {
719         case '\\':
720             c = getc_char (ifp);
721             if (feof (ifp))
722                 return (EOF);
723             namebuf[nameidx++] = c;
724             goto again;
725
726         case '"':
727             namebuf[nameidx] = 0;
728             yylval = (YYSTYPE) sxerox (namebuf);
729             the_lexer_state = START_STATE;
730             return (STRING);
731
732         default:
733             if (c == '\n')
734                 the_lexer_linenumber++;
735
736             if (nameidx >= (MAXNAME-1)) {
737                 fprintf(stderr, "lex input buffer overflow...\n");
738                 exit(1);
739             }
740             namebuf[nameidx++] = c;
741             goto again;
742         }
743         break;
744
745     case HELPER_STATE:
746         c = getc_char (ifp);
747         if (feof (ifp))
748             return (EOF);
749         switch (c) {
750         case '\\':
751             c = getc_char (ifp);
752             if (feof (ifp))
753                 return (EOF);
754             namebuf[nameidx] = c;
755             goto again;
756
757         case '@':
758             namebuf[nameidx] = 0;
759             yylval = (YYSTYPE) sxerox (namebuf);
760             the_lexer_state = START_STATE;
761             return (HELPER_STRING);
762
763         default:
764             if (c == '\n')
765                 the_lexer_linenumber++;
766
767             /*
768              * CPP makes it approximately impossible to 
769              * type "#define FOO 123", so we provide a 
770              * lexical trick to achieve that result 
771              */
772
773             if (c == '$')
774                 c = '#';
775
776             if (nameidx >= (MAXNAME-1)) {
777                 fprintf(stderr, "lex input buffer overflow...\n");
778                 exit(1);
779             }
780             namebuf[nameidx++] = c;
781             goto again;
782         }
783         break;
784
785     case LINE_PRAGMA_STATE:
786         /* We're only interested in lines of the form # 259 "foo.c" 17 */
787
788         switch (lp_substate) {
789
790         case LP_INITIAL_WHITESPACE: /* no number seen yet */
791             c = getc_char(ifp);
792             if (feof(ifp))
793                 return(EOF);
794             if (c >= '0' && c <= '9') {
795                 namebuf[nameidx++] = c;
796                 lp_substate = LP_LINE_NUMBER;
797             } else if (c == '\n') {
798                 goto lp_end_of_line;
799             } else if (c != ' ' && c != '\t') {
800                 /* Nothing */
801             } else {
802                 lp_substate = LP_OTHER;
803             }
804             goto again;
805
806         case LP_LINE_NUMBER:    /* eating linenumber */
807             c = getc_char(ifp);
808             if (feof(ifp))
809                 return(EOF);
810             if (c >= '0' && c <= '9') {
811                 namebuf[nameidx++] = c;
812             } else if (c == ' ' || c == '\t') {
813                 namebuf[nameidx++] = 0;
814                 the_lexer_linenumber = atol(namebuf);
815                 lp_substate = LP_PRE_FILENAME_WHITESPACE;
816             } else if (c == '\n') {
817                 goto lp_end_of_line;
818             } else {
819                 lp_substate = LP_OTHER;
820             }
821             goto again;
822
823         case LP_PRE_FILENAME_WHITESPACE: /* awaiting filename */
824             c = getc_char(ifp);
825             if (feof(ifp))
826                 return(EOF);
827             
828             if (c == '"') {
829                 lp_substate = LP_FILENAME;
830                 nameidx = 0;
831             } else if (c == ' ' || c == '\t') {
832                 /* nothing */
833             } else if (c == '\n') {
834                 goto lp_end_of_line;
835             } else {
836                 lp_substate = LP_OTHER;
837             }
838             goto again;
839
840         case LP_FILENAME:       /* eating filename */
841             c = getc_char(ifp);
842             if (feof(ifp))
843                 return(EOF);
844
845             if (c == '"') {
846                 lp_substate = LP_POST_FILENAME;
847                 namebuf[nameidx] = 0;
848             } else if (c == '\n') {
849                 goto lp_end_of_line; /* syntax error... */
850             } else {
851                 namebuf[nameidx++] = c;
852             }
853             goto again;
854
855         case LP_POST_FILENAME:  /* ignoring rest of line */
856         case LP_OTHER:
857             c = getc_char(ifp);
858             if (feof(ifp))
859                 return(EOF);
860
861             if (c == '\n') {
862                 if (lp_substate == LP_POST_FILENAME) {
863                     if (current_filename_allocated) {
864                         current_filename_allocated = 0;
865                         free(current_filename);
866                     }
867
868                     if (!strcmp(namebuf, "<stdin>")) {
869                         current_filename = input_filename;
870                     } else {
871                         current_filename = sxerox(namebuf);
872                         current_filename_allocated = 1;
873                     }
874                 }
875             lp_end_of_line:
876                 the_lexer_state = START_STATE;
877                 nameidx = 0;
878             }
879             goto again;
880         }
881         break;
882     }
883     fprintf (stderr, "LEXER BUG!\n");
884     exit (1);
885     /* NOTREACHED */
886     return (0);
887 }
888
889 /*
890  * Parse a token and side-effect input_crc
891  * in a whitespace- and comment-insensitive fashion.
892  */
893 int yylex (void)
894 {
895     /*
896      * Accumulate a crc32-based signature while processing the
897      * input file.  The goal is to come up with a magic number
898      * which changes precisely when the original input file changes
899      * but which ignores whitespace changes.
900      */
901     unsigned long crc = input_crc;
902     int node_type = yylex_1 ();
903     unsigned long crc2 = message_crc;
904     int use_helper_string = 0;
905     unsigned short code;
906
907     switch (node_type) {
908     case PRIMTYPE:
909     case NAME:
910     case NUMBER:
911     case STRING:
912     case HELPER_STRING: 
913         use_helper_string = 1;
914         break;
915
916      /* Other node types have no "substate" */
917      /* This code is written in this curious fashion because we
918       * want the generated CRC to be independent of the particular
919       * values a particular version of lex/bison assigned to various states.
920       */
921
922     case RPAR:               code = 258; break;
923     case LPAR:               code = 259; break;
924     case SEMI:               code = 260; break;
925     case LBRACK:             code = 261; break;
926     case RBRACK:             code = 262; break;
927     case BARF:               code = 265; break;
928     case TPACKED:            code = 266; break;
929     case DEFINE:             code = 267; break;
930     case LCURLY:             code = 268; break;
931     case RCURLY:             code = 269; break;
932     case UNION:              code = 271; break;
933     case COMMA:              code = 273; break;
934     case NOVERSION:          code = 274; break;
935     case MANUAL_PRINT:       code = 275; break;
936     case MANUAL_ENDIAN:      code = 276; break;
937     case TYPEONLY:           code = 278; break;
938     case DONT_TRACE:         code = 279; break;
939     case AUTOREPLY:          code = 280; break;
940         
941     case EOF: code = ~0; break; /* hysterical compatibility */
942
943     default:
944         fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
945                 node_type);
946         exit(1);
947     }
948
949     if (use_helper_string)
950     {
951         /* We know these types accumulated token text into namebuf */
952         /* HELPER_STRING may still contain C comments.  Argh. */
953         crc = crc_eliding_c_comments (namebuf, crc);
954         crc2 = crc_eliding_c_comments (namebuf, crc2);
955     } else
956     {
957         crc = CRC16 (crc, code);
958         crc2 = CRC16 (crc2, code);
959     }
960
961     input_crc = crc;
962     message_crc = crc2;
963     return (node_type);
964 }
965
966 /*
967  * name_check -- see if the name we just ate
968  * matches a known keyword.  If so, set yylval
969  * to a new instance of <subclass of node>, and return PARSER_MACRO
970  *
971  * Otherwise, set yylval to sxerox (s) and return NAME
972  */
973
974 static struct keytab {
975     char *name;
976     enum node_subclass subclass_id;
977 } keytab [] = 
978 /* Keep the table sorted, binary search used below! */
979 {
980     {"autoreply",       NODE_AUTOREPLY},
981     {"define",          NODE_DEFINE},  
982     {"dont_trace",      NODE_DONT_TRACE},
983     {"f64",             NODE_F64},
984     {"i16",             NODE_I16},
985     {"i32",             NODE_I32},
986     {"i64",             NODE_I64},
987     {"i8",              NODE_I8},
988     {"manual_endian",   NODE_MANUAL_ENDIAN},
989     {"manual_print",    NODE_MANUAL_PRINT},
990     {"noversion",       NODE_NOVERSION},
991     {"packed",          NODE_PACKED},
992     {"typeonly",        NODE_TYPEONLY},
993     {"u16",             NODE_U16},
994     {"u32",             NODE_U32},
995     {"u64",             NODE_U64},
996     {"u8",              NODE_U8},
997     {"union",           NODE_UNION},
998     {"uword",           NODE_UWORD},
999 };
1000  
1001 static int name_check (const char *s, YYSTYPE *token_value)
1002 {
1003     enum node_subclass subclass_id;
1004     int top, bot, mid;
1005     int result;
1006
1007     for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1; 
1008          bot >= top; ) {
1009         mid = (top + bot) / 2;
1010         result = name_compare (s, keytab[mid].name);
1011         if (result < 0)
1012             bot = mid - 1;
1013         else if (result > 0)
1014             top = mid + 1;
1015         else {
1016             subclass_id = keytab[mid].subclass_id;
1017
1018             switch (subclass_id) {
1019             case NODE_U8:
1020             case NODE_U16:
1021             case NODE_U32:
1022             case NODE_U64:
1023             case NODE_I8:
1024             case NODE_I16:
1025             case NODE_I32:
1026             case NODE_I64:
1027             case NODE_F64:
1028             case NODE_UWORD:
1029                 *token_value = make_node(subclass_id);
1030                 return (PRIMTYPE);
1031
1032             case NODE_PACKED:
1033                 *token_value = make_node(subclass_id);
1034                 return (TPACKED);
1035
1036             case NODE_DEFINE:
1037                 message_crc = 0;
1038                 *token_value = make_node(subclass_id);
1039                 return(DEFINE);
1040
1041             case NODE_MANUAL_PRINT:
1042                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT;
1043                 return (MANUAL_PRINT);
1044
1045             case NODE_MANUAL_ENDIAN:
1046                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN;
1047                 return (MANUAL_ENDIAN);
1048
1049             case NODE_TYPEONLY:
1050                 *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY;
1051                 return(TYPEONLY);
1052
1053             case NODE_DONT_TRACE:
1054                 *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE;
1055                 return(DONT_TRACE);
1056
1057             case NODE_AUTOREPLY:
1058                 *token_value = (YYSTYPE) NODE_FLAG_AUTOREPLY;
1059                 return(AUTOREPLY);
1060
1061             case NODE_NOVERSION:
1062                 return(NOVERSION);
1063
1064             case NODE_UNION:
1065                 return(UNION);
1066
1067             default:
1068                 fprintf (stderr, "fatal: keytab botch!\n");
1069                 exit (1);
1070             }
1071         }
1072     }
1073     *token_value = (YYSTYPE) sxerox (s);
1074     return (NAME);
1075 }
1076
1077 /*
1078  * sxerox
1079  */
1080
1081 char *sxerox (const char *s)
1082 {
1083     int len = strlen (s);
1084     char *rv;
1085
1086     rv = (char *) malloc (len+1);
1087     if (rv == 0) {
1088         fprintf(stderr, "Out of memory...");
1089         exit (1);
1090     }
1091         
1092     strcpy (rv, s);
1093     return (rv);
1094 }
1095
1096 /*
1097  * name_compare
1098  */
1099
1100 int name_compare (const char *s1, const char *s2)
1101 {
1102     char c1, c2;
1103
1104     while (*s1 && *s2) {
1105         c1 = *s1++;
1106         c2 = *s2++;
1107
1108         c1 = tolower (c1);
1109         c2 = tolower (c2);
1110         if (c1 < c2)
1111             return (-1);
1112         else if (c1 > c2)
1113             return (1);
1114     }
1115     if (*s1 < *s2)
1116         return (-1);
1117     else if (*s1 > *s2)
1118         return (1);
1119     return (0);
1120 }