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