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