blob: d9f82c2b9f17b7e08da56e638df507a2d97dbea5 [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
Dave Barach0d056e52017-09-28 15:11:16 -0400584 case '.':
585 return (DOT);
586
Damjan Marion7cd468a2016-12-19 23:05:39 +0100587 case '"':
588 nameidx = 0;
589 the_lexer_state = STRING_STATE;
590 goto again;
591
592 case '@':
593 nameidx = 0;
594 the_lexer_state = HELPER_STATE;
595 goto again;
596
597 case '/':
598 c = getc_char (ifp);
599 if (feof (ifp))
600 return (EOF);
601
602 if (c == '/') {
603 the_lexer_state = CPP_COMMENT_STATE;
604 goto again;
605 } else if (c == '*') {
606 the_lexer_state = C_COMMENT_STATE;
607 goto again;
608 } else {
609 fprintf (stderr, "unknown token /%c at line %d\n",
610 c, the_lexer_linenumber);
611 return (BARF);
612 }
613
614 case '\\':
615 c = getc_char (ifp);
616 if (feof (ifp))
617 return (EOF);
618
619 /* Note fallthrough... */
620
621 default:
622 if (isalpha (c) || c == '_') {
623 namebuf [0] = c;
624 nameidx = 1;
625 the_lexer_state = NAME_STATE;
626 goto again;
627 } else if (isdigit(c)) {
628 namebuf [0] = c;
629 nameidx = 1;
630 the_lexer_state = NUMBER_STATE;
631 goto again;
632 }
633
634 fprintf (stderr, "unknown token %c at line %d\n",
635 c, the_lexer_linenumber);
636 return (BARF);
637 }
638
639 /*
640 * NAME state -- eat the rest of a name
641 */
642 case NAME_STATE:
643 c = getc_char (ifp);
644 if (feof (ifp))
645 return (EOF);
646
647 if (!isalnum (c) && c != '_') {
Dave Barach11b8dbf2017-04-24 10:46:54 -0400648 ungetc_char (c, ifp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100649 namebuf [nameidx] = 0;
650 the_lexer_state = START_STATE;
651 return (name_check (namebuf, &yylval));
652 }
653 if (nameidx >= (MAXNAME-1)) {
654 fprintf(stderr, "lex input buffer overflow...\n");
655 exit(1);
656 }
657 namebuf [nameidx++] = c;
658 goto again;
659
660 /*
661 * NUMBER state -- eat the rest of a number
662 */
663 case NUMBER_STATE:
664 c = getc_char (ifp);
665 if (feof (ifp))
666 return (EOF);
667
668 if (!isdigit (c)) {
Dave Barach11b8dbf2017-04-24 10:46:54 -0400669 ungetc_char (c, ifp);
Damjan Marion7cd468a2016-12-19 23:05:39 +0100670 namebuf [nameidx] = 0;
671 the_lexer_state = START_STATE;
672 yylval = (void *) atol(namebuf);
673 return (NUMBER);
674 }
675 if (nameidx >= (MAXNAME-1)) {
676 fprintf(stderr, "lex input buffer overflow...\n");
677 exit(1);
678 }
679 namebuf [nameidx++] = c;
680 goto again;
681
682 /*
683 * C_COMMENT state -- eat a peach
684 */
685 case C_COMMENT_STATE:
686 c = getc_char (ifp);
687 if (feof (ifp))
688 return (EOF);
689 if (c == '*') {
690 c = getc_char (ifp);
691 if (feof (ifp))
692 return (EOF);
693 if (c == '/') {
694 the_lexer_state = START_STATE;
695 goto again;
696 }
697 }
698 if (c == '\n')
699 the_lexer_linenumber++;
700 goto again;
701
702 /*
703 * CPP_COMMENT state -- eat a plum
704 */
705
706 case CPP_COMMENT_STATE:
707 c = getc_char (ifp);
708 if (feof (ifp))
709 return (EOF);
710 if (c == '\n') {
711 the_lexer_linenumber++;
712 the_lexer_state = START_STATE;
713 goto again;
714 }
715 goto again;
716
717 case STRING_STATE:
718 c = getc_char (ifp);
719 if (feof (ifp))
720 return (EOF);
721 switch (c) {
722 case '\\':
723 c = getc_char (ifp);
724 if (feof (ifp))
725 return (EOF);
726 namebuf[nameidx++] = c;
727 goto again;
728
729 case '"':
730 namebuf[nameidx] = 0;
731 yylval = (YYSTYPE) sxerox (namebuf);
732 the_lexer_state = START_STATE;
733 return (STRING);
734
735 default:
736 if (c == '\n')
737 the_lexer_linenumber++;
738
739 if (nameidx >= (MAXNAME-1)) {
740 fprintf(stderr, "lex input buffer overflow...\n");
741 exit(1);
742 }
743 namebuf[nameidx++] = c;
744 goto again;
745 }
746 break;
747
748 case HELPER_STATE:
749 c = getc_char (ifp);
750 if (feof (ifp))
751 return (EOF);
752 switch (c) {
753 case '\\':
754 c = getc_char (ifp);
755 if (feof (ifp))
756 return (EOF);
757 namebuf[nameidx] = c;
758 goto again;
759
760 case '@':
761 namebuf[nameidx] = 0;
762 yylval = (YYSTYPE) sxerox (namebuf);
763 the_lexer_state = START_STATE;
764 return (HELPER_STRING);
765
766 default:
767 if (c == '\n')
768 the_lexer_linenumber++;
769
770 /*
771 * CPP makes it approximately impossible to
772 * type "#define FOO 123", so we provide a
773 * lexical trick to achieve that result
774 */
775
776 if (c == '$')
777 c = '#';
778
779 if (nameidx >= (MAXNAME-1)) {
780 fprintf(stderr, "lex input buffer overflow...\n");
781 exit(1);
782 }
783 namebuf[nameidx++] = c;
784 goto again;
785 }
786 break;
787
788 case LINE_PRAGMA_STATE:
789 /* We're only interested in lines of the form # 259 "foo.c" 17 */
790
791 switch (lp_substate) {
792
793 case LP_INITIAL_WHITESPACE: /* no number seen yet */
794 c = getc_char(ifp);
795 if (feof(ifp))
796 return(EOF);
797 if (c >= '0' && c <= '9') {
798 namebuf[nameidx++] = c;
799 lp_substate = LP_LINE_NUMBER;
800 } else if (c == '\n') {
801 goto lp_end_of_line;
802 } else if (c != ' ' && c != '\t') {
803 /* Nothing */
804 } else {
805 lp_substate = LP_OTHER;
806 }
807 goto again;
808
809 case LP_LINE_NUMBER: /* eating linenumber */
810 c = getc_char(ifp);
811 if (feof(ifp))
812 return(EOF);
813 if (c >= '0' && c <= '9') {
814 namebuf[nameidx++] = c;
815 } else if (c == ' ' || c == '\t') {
816 namebuf[nameidx++] = 0;
817 the_lexer_linenumber = atol(namebuf);
818 lp_substate = LP_PRE_FILENAME_WHITESPACE;
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_PRE_FILENAME_WHITESPACE: /* awaiting filename */
827 c = getc_char(ifp);
828 if (feof(ifp))
829 return(EOF);
830
831 if (c == '"') {
832 lp_substate = LP_FILENAME;
833 nameidx = 0;
834 } else if (c == ' ' || c == '\t') {
835 /* nothing */
836 } else if (c == '\n') {
837 goto lp_end_of_line;
838 } else {
839 lp_substate = LP_OTHER;
840 }
841 goto again;
842
843 case LP_FILENAME: /* eating filename */
844 c = getc_char(ifp);
845 if (feof(ifp))
846 return(EOF);
847
848 if (c == '"') {
849 lp_substate = LP_POST_FILENAME;
850 namebuf[nameidx] = 0;
851 } else if (c == '\n') {
852 goto lp_end_of_line; /* syntax error... */
853 } else {
854 namebuf[nameidx++] = c;
855 }
856 goto again;
857
858 case LP_POST_FILENAME: /* ignoring rest of line */
859 case LP_OTHER:
860 c = getc_char(ifp);
861 if (feof(ifp))
862 return(EOF);
863
864 if (c == '\n') {
865 if (lp_substate == LP_POST_FILENAME) {
866 if (current_filename_allocated) {
867 current_filename_allocated = 0;
868 free(current_filename);
869 }
870
871 if (!strcmp(namebuf, "<stdin>")) {
872 current_filename = input_filename;
873 } else {
874 current_filename = sxerox(namebuf);
875 current_filename_allocated = 1;
876 }
877 }
878 lp_end_of_line:
879 the_lexer_state = START_STATE;
880 nameidx = 0;
881 }
882 goto again;
883 }
884 break;
885 }
886 fprintf (stderr, "LEXER BUG!\n");
887 exit (1);
888 /* NOTREACHED */
889 return (0);
890}
891
892/*
893 * Parse a token and side-effect input_crc
894 * in a whitespace- and comment-insensitive fashion.
895 */
896int yylex (void)
897{
898 /*
899 * Accumulate a crc32-based signature while processing the
900 * input file. The goal is to come up with a magic number
901 * which changes precisely when the original input file changes
902 * but which ignores whitespace changes.
903 */
904 unsigned long crc = input_crc;
905 int node_type = yylex_1 ();
906 unsigned long crc2 = message_crc;
907 int use_helper_string = 0;
908 unsigned short code;
909
910 switch (node_type) {
911 case PRIMTYPE:
912 case NAME:
913 case NUMBER:
914 case STRING:
915 case HELPER_STRING:
916 use_helper_string = 1;
917 break;
918
919 /* Other node types have no "substate" */
920 /* This code is written in this curious fashion because we
921 * want the generated CRC to be independent of the particular
922 * values a particular version of lex/bison assigned to various states.
923 */
924
925 case RPAR: code = 258; break;
926 case LPAR: code = 259; break;
927 case SEMI: code = 260; break;
928 case LBRACK: code = 261; break;
929 case RBRACK: code = 262; break;
930 case BARF: code = 265; break;
931 case TPACKED: code = 266; break;
932 case DEFINE: code = 267; break;
933 case LCURLY: code = 268; break;
934 case RCURLY: code = 269; break;
935 case UNION: code = 271; break;
936 case COMMA: code = 273; break;
937 case NOVERSION: code = 274; break;
938 case MANUAL_PRINT: code = 275; break;
939 case MANUAL_ENDIAN: code = 276; break;
940 case TYPEONLY: code = 278; break;
941 case DONT_TRACE: code = 279; break;
Dave Barach11b8dbf2017-04-24 10:46:54 -0400942 case AUTOREPLY: code = 280; break;
Dave Barach0d056e52017-09-28 15:11:16 -0400943 case DOT: code = 281; break;
944 case VL_API_VERSION: code = 282; break;
Damjan Marion7cd468a2016-12-19 23:05:39 +0100945
946 case EOF: code = ~0; break; /* hysterical compatibility */
947
948 default:
949 fprintf(stderr, "yylex: node_type %d missing state CRC cookie\n",
950 node_type);
951 exit(1);
952 }
953
954 if (use_helper_string)
955 {
956 /* We know these types accumulated token text into namebuf */
957 /* HELPER_STRING may still contain C comments. Argh. */
958 crc = crc_eliding_c_comments (namebuf, crc);
959 crc2 = crc_eliding_c_comments (namebuf, crc2);
960 } else
961 {
962 crc = CRC16 (crc, code);
963 crc2 = CRC16 (crc2, code);
964 }
965
966 input_crc = crc;
967 message_crc = crc2;
968 return (node_type);
969}
970
971/*
972 * name_check -- see if the name we just ate
973 * matches a known keyword. If so, set yylval
974 * to a new instance of <subclass of node>, and return PARSER_MACRO
975 *
976 * Otherwise, set yylval to sxerox (s) and return NAME
977 */
978
979static struct keytab {
980 char *name;
981 enum node_subclass subclass_id;
982} keytab [] =
983/* Keep the table sorted, binary search used below! */
984{
Dave Barach11b8dbf2017-04-24 10:46:54 -0400985 {"autoreply", NODE_AUTOREPLY},
Damjan Marion7cd468a2016-12-19 23:05:39 +0100986 {"define", NODE_DEFINE},
987 {"dont_trace", NODE_DONT_TRACE},
988 {"f64", NODE_F64},
989 {"i16", NODE_I16},
990 {"i32", NODE_I32},
991 {"i64", NODE_I64},
992 {"i8", NODE_I8},
993 {"manual_endian", NODE_MANUAL_ENDIAN},
994 {"manual_print", NODE_MANUAL_PRINT},
995 {"noversion", NODE_NOVERSION},
996 {"packed", NODE_PACKED},
997 {"typeonly", NODE_TYPEONLY},
998 {"u16", NODE_U16},
999 {"u32", NODE_U32},
1000 {"u64", NODE_U64},
1001 {"u8", NODE_U8},
1002 {"union", NODE_UNION},
1003 {"uword", NODE_UWORD},
Dave Barach0d056e52017-09-28 15:11:16 -04001004 {"vl_api_version", NODE_VERSION},
Damjan Marion7cd468a2016-12-19 23:05:39 +01001005};
1006
1007static int name_check (const char *s, YYSTYPE *token_value)
1008{
1009 enum node_subclass subclass_id;
1010 int top, bot, mid;
1011 int result;
1012
1013 for (top = 0, bot = (sizeof(keytab) / sizeof(struct keytab))-1;
1014 bot >= top; ) {
1015 mid = (top + bot) / 2;
1016 result = name_compare (s, keytab[mid].name);
1017 if (result < 0)
1018 bot = mid - 1;
1019 else if (result > 0)
1020 top = mid + 1;
1021 else {
1022 subclass_id = keytab[mid].subclass_id;
1023
1024 switch (subclass_id) {
1025 case NODE_U8:
1026 case NODE_U16:
1027 case NODE_U32:
1028 case NODE_U64:
1029 case NODE_I8:
1030 case NODE_I16:
1031 case NODE_I32:
1032 case NODE_I64:
1033 case NODE_F64:
1034 case NODE_UWORD:
1035 *token_value = make_node(subclass_id);
1036 return (PRIMTYPE);
1037
1038 case NODE_PACKED:
1039 *token_value = make_node(subclass_id);
1040 return (TPACKED);
1041
1042 case NODE_DEFINE:
1043 message_crc = 0;
1044 *token_value = make_node(subclass_id);
1045 return(DEFINE);
1046
1047 case NODE_MANUAL_PRINT:
1048 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_PRINT;
1049 return (MANUAL_PRINT);
1050
1051 case NODE_MANUAL_ENDIAN:
1052 *token_value = (YYSTYPE) NODE_FLAG_MANUAL_ENDIAN;
1053 return (MANUAL_ENDIAN);
1054
1055 case NODE_TYPEONLY:
1056 *token_value = (YYSTYPE) NODE_FLAG_TYPEONLY;
1057 return(TYPEONLY);
1058
1059 case NODE_DONT_TRACE:
1060 *token_value = (YYSTYPE) NODE_FLAG_DONT_TRACE;
1061 return(DONT_TRACE);
1062
Dave Barach11b8dbf2017-04-24 10:46:54 -04001063 case NODE_AUTOREPLY:
1064 *token_value = (YYSTYPE) NODE_FLAG_AUTOREPLY;
1065 return(AUTOREPLY);
1066
Damjan Marion7cd468a2016-12-19 23:05:39 +01001067 case NODE_NOVERSION:
1068 return(NOVERSION);
1069
Dave Barach0d056e52017-09-28 15:11:16 -04001070 case NODE_VERSION:
1071 return(VL_API_VERSION);
1072
Damjan Marion7cd468a2016-12-19 23:05:39 +01001073 case NODE_UNION:
1074 return(UNION);
1075
1076 default:
1077 fprintf (stderr, "fatal: keytab botch!\n");
1078 exit (1);
1079 }
1080 }
1081 }
1082 *token_value = (YYSTYPE) sxerox (s);
1083 return (NAME);
1084}
1085
1086/*
1087 * sxerox
1088 */
1089
1090char *sxerox (const char *s)
1091{
1092 int len = strlen (s);
1093 char *rv;
1094
1095 rv = (char *) malloc (len+1);
1096 if (rv == 0) {
1097 fprintf(stderr, "Out of memory...");
1098 exit (1);
1099 }
1100
1101 strcpy (rv, s);
1102 return (rv);
1103}
1104
1105/*
1106 * name_compare
1107 */
1108
1109int name_compare (const char *s1, const char *s2)
1110{
1111 char c1, c2;
1112
1113 while (*s1 && *s2) {
1114 c1 = *s1++;
1115 c2 = *s2++;
1116
1117 c1 = tolower (c1);
1118 c2 = tolower (c2);
1119 if (c1 < c2)
1120 return (-1);
1121 else if (c1 > c2)
1122 return (1);
1123 }
1124 if (*s1 < *s2)
1125 return (-1);
1126 else if (*s1 > *s2)
1127 return (1);
1128 return (0);
1129}