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