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