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