Add API calls for packet generator
[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         fclose (ofp);
394         if (ofile) {
395             printf ("Removing %s\n", ofile);
396             unlink (ofile);
397         }
398         if (pythonfile) {
399             printf ("Removing %s\n", pythonfile);
400             unlink (pythonfile);
401         }
402         exit (1);
403     }
404     exit (0);
405 }
406
407 /*
408  * usage
409  */
410 static void usage (char *progname)
411 {
412     fprintf (stderr, 
413              "usage: %s --input <filename> [--output <filename>] [--python <filename>]\n%s",
414              progname,
415              "          [--yydebug] [--dump-tree]\n");
416     exit (1);
417 }
418
419 /*
420  * yyerror 
421  */
422 void yyerror (char *s)
423 {
424     fprintf (stderr, "%s:%d %s\n", current_filename, the_lexer_linenumber, s);
425 }
426
427 static char namebuf [MAXNAME];
428
429 /*
430  * yylex (well, yylex_1: The real yylex below does crc-hackery)
431  */
432 static int yylex_1 (void)
433 {
434     int nameidx=0;
435     char c;
436     int at_bol=1;
437     enum { LP_INITIAL_WHITESPACE, LP_LINE_NUMBER,
438            LP_PRE_FILENAME_WHITESPACE, LP_FILENAME,
439            LP_POST_FILENAME,
440            LP_OTHER
441     } lp_substate = LP_INITIAL_WHITESPACE;
442
443  again:
444     switch (the_lexer_state) {
445         /*
446          * START state -- looking for something interesting 
447          */
448     case START_STATE:
449         c = getc (ifp);
450         if (feof (ifp))
451             return (EOF);
452
453         switch (c) {
454         case '\n':
455             the_lexer_linenumber++;
456             at_bol=1;
457             goto again;
458
459         case '#':
460             if (!at_bol) {
461                 fprintf (stderr, "unknown token /%c at line %d\n",
462                          c, the_lexer_linenumber);
463                 return (BARF);
464             }
465             
466             the_lexer_state = LINE_PRAGMA_STATE;
467             lp_substate = LP_INITIAL_WHITESPACE;
468             goto again;
469
470             /* FALLTHROUGH */
471         case '\t':
472         case ' ':
473             goto again;
474             
475         case '(':
476             return (LPAR);
477
478         case ')':
479             return (RPAR);
480
481         case ';':
482             return (SEMI);
483
484         case '[':
485             return (LBRACK);
486             
487         case ']':
488             return (RBRACK);
489
490         case '{':
491             return (LCURLY);
492             
493         case '}':
494             return (RCURLY);
495
496         case ',':
497             return (COMMA);
498
499         case '"':
500             nameidx = 0;
501             the_lexer_state = STRING_STATE;
502             goto again;
503
504         case '@':
505             nameidx = 0;
506             the_lexer_state = HELPER_STATE;
507             goto again;
508
509         case '/':
510             c = getc (ifp);
511             if (feof (ifp))
512                 return (EOF);
513
514             if (c == '/') {
515                 the_lexer_state = CPP_COMMENT_STATE;
516                 goto again;
517             } else if (c == '*') {
518                 the_lexer_state = C_COMMENT_STATE;
519                 goto again;
520             } else {
521                 fprintf (stderr, "unknown token /%c at line %d\n",
522                          c, the_lexer_linenumber);
523                 return (BARF);
524             }
525
526         case '\\':
527             c = getc (ifp);
528             if (feof (ifp))
529                 return (EOF);
530             
531             /* Note fallthrough... */
532
533         default:
534             if (isalpha (c) || c == '_') {
535                 namebuf [0] = c;
536                 nameidx = 1;
537                 the_lexer_state = NAME_STATE;
538                 goto again;
539             } else if (isdigit(c)) {
540                 namebuf [0] = c;
541                 nameidx = 1;
542                 the_lexer_state = NUMBER_STATE;
543                 goto again;
544             }
545
546             fprintf (stderr, "unknown token %c at line %d\n",
547                      c, the_lexer_linenumber);
548             return (BARF);
549         }
550
551         /*
552          * NAME state -- eat the rest of a name 
553          */
554     case NAME_STATE:
555         c = getc (ifp);
556         if (feof (ifp))
557             return (EOF);
558         
559         if (!isalnum (c) && c != '_') {
560             ungetc (c, ifp);
561             namebuf [nameidx] = 0;
562             the_lexer_state = START_STATE;
563             return (name_check (namebuf, &yylval));
564         }                
565         if (nameidx >= (MAXNAME-1)) {
566             fprintf(stderr, "lex input buffer overflow...\n");
567             exit(1);
568         }
569         namebuf [nameidx++] = c;
570         goto again;
571         
572         /*
573          * NUMBER state -- eat the rest of a number
574          */
575     case NUMBER_STATE:
576         c = getc (ifp);
577         if (feof (ifp))
578             return (EOF);
579         
580         if (!isdigit (c)) {
581             ungetc (c, ifp);
582             namebuf [nameidx] = 0;
583             the_lexer_state = START_STATE;
584             yylval = (void *) atol(namebuf);
585             return (NUMBER);
586         }                
587         if (nameidx >= (MAXNAME-1)) {
588             fprintf(stderr, "lex input buffer overflow...\n");
589             exit(1);
590         }
591         namebuf [nameidx++] = c;
592         goto again;
593
594         /*
595          * C_COMMENT state -- eat a peach
596          */
597     case C_COMMENT_STATE:
598         c = getc (ifp);
599         if (feof (ifp))
600             return (EOF);
601         if (c == '*') {
602             c = getc (ifp);
603             if (feof (ifp))
604                 return (EOF);
605             if (c == '/') {
606                 the_lexer_state = START_STATE;
607                 goto again;
608             }
609         }
610         if (c == '\n')
611             the_lexer_linenumber++;
612         goto again;
613             
614         /*
615          * CPP_COMMENT state -- eat a plum 
616          */
617
618     case CPP_COMMENT_STATE:
619         c = getc (ifp);
620         if (feof (ifp))
621             return (EOF);
622         if (c == '\n') {
623             the_lexer_linenumber++;
624             the_lexer_state = START_STATE;
625             goto again;
626         }
627         goto again;
628
629     case STRING_STATE:
630         c = getc (ifp);
631         if (feof (ifp))
632             return (EOF);
633         switch (c) {
634         case '\\':
635             c = getc (ifp);
636             if (feof (ifp))
637                 return (EOF);
638             namebuf[nameidx++] = c;
639             goto again;
640
641         case '"':
642             namebuf[nameidx] = 0;
643             yylval = (YYSTYPE) sxerox (namebuf);
644             the_lexer_state = START_STATE;
645             return (STRING);
646
647         default:
648             if (c == '\n')
649                 the_lexer_linenumber++;
650
651             if (nameidx >= (MAXNAME-1)) {
652                 fprintf(stderr, "lex input buffer overflow...\n");
653                 exit(1);
654             }
655             namebuf[nameidx++] = c;
656             goto again;
657         }
658         break;
659
660     case HELPER_STATE:
661         c = getc (ifp);
662         if (feof (ifp))
663             return (EOF);
664         switch (c) {
665         case '\\':
666             c = getc (ifp);
667             if (feof (ifp))
668                 return (EOF);
669             namebuf[nameidx] = c;
670             goto again;
671
672         case '@':
673             namebuf[nameidx] = 0;
674             yylval = (YYSTYPE) sxerox (namebuf);
675             the_lexer_state = START_STATE;
676             return (HELPER_STRING);
677
678         default:
679             if (c == '\n')
680                 the_lexer_linenumber++;
681
682             /*
683              * CPP makes it approximately impossible to 
684              * type "#define FOO 123", so we provide a 
685              * lexical trick to achieve that result 
686              */
687
688             if (c == '$')
689                 c = '#';
690
691             if (nameidx >= (MAXNAME-1)) {
692                 fprintf(stderr, "lex input buffer overflow...\n");
693                 exit(1);
694             }
695             namebuf[nameidx++] = c;
696             goto again;
697         }
698         break;
699
700     case LINE_PRAGMA_STATE:
701         /* We're only interested in lines of the form # 259 "foo.c" 17 */
702
703         switch (lp_substate) {
704
705         case LP_INITIAL_WHITESPACE: /* no number seen yet */
706             c = getc(ifp);
707             if (feof(ifp))
708                 return(EOF);
709             if (c >= '0' && c <= '9') {
710                 namebuf[nameidx++] = c;
711                 lp_substate = LP_LINE_NUMBER;
712             } else if (c == '\n') {
713                 goto lp_end_of_line;
714             } else if (c != ' ' && c != '\t') {
715                 /* Nothing */
716             } else {
717                 lp_substate = LP_OTHER;
718             }
719             goto again;
720
721         case LP_LINE_NUMBER:    /* eating linenumber */
722             c = getc(ifp);
723             if (feof(ifp))
724                 return(EOF);
725             if (c >= '0' && c <= '9') {
726                 namebuf[nameidx++] = c;
727             } else if (c == ' ' || c == '\t') {
728                 namebuf[nameidx++] = 0;
729                 the_lexer_linenumber = atol(namebuf);
730                 lp_substate = LP_PRE_FILENAME_WHITESPACE;
731             } else if (c == '\n') {
732                 goto lp_end_of_line;
733             } else {
734                 lp_substate = LP_OTHER;
735             }
736             goto again;
737
738         case LP_PRE_FILENAME_WHITESPACE: /* awaiting filename */
739             c = getc(ifp);
740             if (feof(ifp))
741                 return(EOF);
742             
743             if (c == '"') {
744                 lp_substate = LP_FILENAME;
745                 nameidx = 0;
746             } else if (c == ' ' || c == '\t') {
747                 /* nothing */
748             } else if (c == '\n') {
749                 goto lp_end_of_line;
750             } else {
751                 lp_substate = LP_OTHER;
752             }
753             goto again;
754
755         case LP_FILENAME:       /* eating filename */
756             c = getc(ifp);
757             if (feof(ifp))
758                 return(EOF);
759
760             if (c == '"') {
761                 lp_substate = LP_POST_FILENAME;
762                 namebuf[nameidx] = 0;
763             } else if (c == '\n') {
764                 goto lp_end_of_line; /* syntax error... */
765             } else {
766                 namebuf[nameidx++] = c;
767             }
768             goto again;
769
770         case LP_POST_FILENAME:  /* ignoring rest of line */
771         case LP_OTHER:
772             c = getc(ifp);
773             if (feof(ifp))
774                 return(EOF);
775
776             if (c == '\n') {
777                 if (lp_substate == LP_POST_FILENAME) {
778                     if (current_filename_allocated) {
779                         current_filename_allocated = 0;
780                         free(current_filename);
781                     }
782
783                     if (!strcmp(namebuf, "<stdin>")) {
784                         current_filename = input_filename;
785                     } else {
786                         current_filename = sxerox(namebuf);
787                         current_filename_allocated = 1;
788                     }
789                 }
790             lp_end_of_line:
791                 the_lexer_state = START_STATE;
792                 at_bol = 1;
793                 nameidx = 0;
794             }
795             goto again;
796         }
797         break;
798     }
799     fprintf (stderr, "LEXER BUG!\n");
800     exit (1);
801     /* NOTREACHED */
802     return (0);
803 }
804
805 /*
806  * Parse a token and side-effect input_crc
807  * in a whitespace- and comment-insensitive fashion.
808  */
809 int yylex (void)
810 {
811     /*
812      * Accumulate a crc32-based signature while processing the
813      * input file.  The goal is to come up with a magic number
814      * which changes precisely when the original input file changes
815      * but which ignores whitespace changes.
816      */
817     unsigned long crc = input_crc;
818     int node_type = yylex_1 ();
819
820     switch (node_type) {
821     case PRIMTYPE:
822     case NAME:
823     case NUMBER:
824     case STRING:
825     case HELPER_STRING: {
826         /* We know these types accumulated token text into namebuf */
827         /* HELPER_STRING may still contain C comments.  Argh. */
828         crc = crc_eliding_c_comments (namebuf, crc);
829         break;
830     }
831
832      /* Other node types have no "substate" */
833      /* This code is written in this curious fashion because we
834       * want the generated CRC to be independent of the particular
835       * values a particular version of lex/bison assigned to various states.
836       */
837
838     /* case NAME:            crc = CRC16 (crc, 257); break; */
839     case RPAR:               crc = CRC16 (crc, 258); break;
840     case LPAR:               crc = CRC16 (crc, 259); break;
841     case SEMI:               crc = CRC16 (crc, 260); break;
842     case LBRACK:             crc = CRC16 (crc, 261); break;
843     case RBRACK:             crc = CRC16 (crc, 262); break;
844     /* case NUMBER:          crc = CRC16 (crc, 263); break; */
845     /* case PRIMTYPE:        crc = CRC16 (crc, 264); break; */
846     case BARF:               crc = CRC16 (crc, 265); break;
847     case TPACKED:            crc = CRC16 (crc, 266); break;
848     case DEFINE:             crc = CRC16 (crc, 267); break;
849     case LCURLY:             crc = CRC16 (crc, 268); break;
850     case RCURLY:             crc = CRC16 (crc, 269); break;
851     /* case STRING:          crc = CRC16 (crc, 270); break; */
852     case UNION:              crc = CRC16 (crc, 271); break;
853     /* case HELPER_STRING:   crc = CRC16 (crc, 272); break; */
854     case COMMA:              crc = CRC16 (crc, 273); break;
855     case NOVERSION:          crc = CRC16 (crc, 274); break;
856     case MANUAL_PRINT:       crc = CRC16 (crc, 275); break;
857     case MANUAL_ENDIAN:      crc = CRC16 (crc, 276); break;
858     case TYPEONLY:           crc = CRC16 (crc, 278); break;
859     case DONT_TRACE:         crc = CRC16 (crc, 279); break;
860         
861     case EOF: crc = CRC16 (crc, ~0); break; /* hysterical compatibility */
862
863     default:
864         fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
865                 node_type);
866         exit(1);
867     }
868
869     input_crc = crc;
870     return (node_type);
871 }
872
873
874 /*
875  * name_check -- see if the name we just ate
876  * matches a known keyword.  If so, set yylval
877  * to a new instance of <subclass of node>, and return PARSER_MACRO
878  *
879  * Otherwise, set yylval to sxerox (s) and return NAME
880  */
881
882 static struct keytab {
883     char *name;
884     enum node_subclass subclass_id;
885 } keytab [] = 
886 /* Keep the table sorted, binary search used below! */
887 {
888     {"define",          NODE_DEFINE},  
889     {"dont_trace",      NODE_DONT_TRACE},
890     {"f64",             NODE_F64},
891     {"i16",             NODE_I16},
892     {"i32",             NODE_I32},
893     {"i64",             NODE_I64},
894     {"i8",              NODE_I8},
895     {"manual_endian",   NODE_MANUAL_ENDIAN},
896     {"manual_print",    NODE_MANUAL_PRINT},
897     {"noversion",       NODE_NOVERSION},
898     {"packed",          NODE_PACKED},
899     {"typeonly",        NODE_TYPEONLY},
900     {"u16",             NODE_U16},
901     {"u32",             NODE_U32},
902     {"u64",             NODE_U64},
903     {"u8",              NODE_U8},
904     {"union",           NODE_UNION},
905     {"uword",           NODE_UWORD},
906 };
907  
908 static int name_check (const char *s, YYSTYPE *token_value)
909 {
910     enum node_subclass subclass_id;
911     int top, bot, mid;
912     int result;
913
914     for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1; 
915          bot >= top; ) {
916         mid = (top + bot) / 2;
917         result = name_compare (s, keytab[mid].name);
918         if (result < 0)
919             bot = mid - 1;
920         else if (result > 0)
921             top = mid + 1;
922         else {
923             subclass_id = keytab[mid].subclass_id;
924
925             switch (subclass_id) {
926             case NODE_U8:
927             case NODE_U16:
928             case NODE_U32:
929             case NODE_U64:
930             case NODE_I8:
931             case NODE_I16:
932             case NODE_I32:
933             case NODE_I64:
934             case NODE_F64:
935             case NODE_UWORD:
936                 *token_value = make_node(subclass_id);
937                 return (PRIMTYPE);
938
939             case NODE_PACKED:
940                 *token_value = make_node(subclass_id);
941                 return (TPACKED);
942
943             case NODE_DEFINE:
944                 *token_value = make_node(subclass_id);
945                 return(DEFINE);
946
947             case NODE_MANUAL_PRINT:
948                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT;
949                 return (MANUAL_PRINT);
950
951             case NODE_MANUAL_ENDIAN:
952                 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN;
953                 return (MANUAL_ENDIAN);
954
955             case NODE_TYPEONLY:
956                 *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY;
957                 return(TYPEONLY);
958
959             case NODE_DONT_TRACE:
960                 *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE;
961                 return(DONT_TRACE);
962
963             case NODE_NOVERSION:
964                 return(NOVERSION);
965
966             case NODE_UNION:
967                 return(UNION);
968
969             default:
970                 fprintf (stderr, "fatal: keytab botch!\n");
971                 exit (1);
972             }
973         }
974     }
975     *token_value = (YYSTYPE) sxerox (s);
976     return (NAME);
977 }
978
979 /*
980  * sxerox
981  */
982
983 char *sxerox (const char *s)
984 {
985     int len = strlen (s);
986     char *rv;
987
988     rv = (char *) malloc (len+1);
989     strcpy (rv, s);
990     return (rv);
991 }
992
993 /*
994  * name_compare
995  */
996
997 int name_compare (const char *s1, const char *s2)
998 {
999     char c1, c2;
1000
1001     while (*s1 && *s2) {
1002         c1 = *s1++;
1003         c2 = *s2++;
1004
1005         c1 = tolower (c1);
1006         c2 = tolower (c2);
1007         if (c1 < c2)
1008             return (-1);
1009         else if (c1 > c2)
1010             return (1);
1011     }
1012     if (*s1 < *s2)
1013         return (-1);
1014     else if (*s1 > *s2)
1015         return (1);
1016     return (0);
1017 }