Graphviz 12.0.1~dev.20240716.0800
Loading...
Searching...
No Matches
extoken.c
Go to the documentation of this file.
1/*************************************************************************
2 * Copyright (c) 2011 AT&T Intellectual Property
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-v10.html
7 *
8 * Contributors: Details at https://graphviz.org
9 *************************************************************************/
10
11/*
12 * Glenn Fowler
13 * AT&T Research
14 *
15 * expression library default lexical analyzer
16 */
17
18#include "config.h"
19#include <cgraph/agxbuf.h>
20#include <cgraph/gv_ctype.h>
21#include <cgraph/streq.h>
22#include <cgraph/unreachable.h>
23#include <expr/exlib.h>
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#if defined(TRACE_lex) && TRACE_lex
30
31/*
32 * trace c for op
33 */
34
35static void
36trace(Expr_t* ex, int lev, char* op, int c)
37{
38 char* s = 0;
39 char* t;
40 bool free_t = false;
41 char buf[16];
42 void* x = 0;
43
44 t = "";
45 switch (c)
46 {
47 case 0:
48 s = " EOF";
49 break;
50 case '=':
51 s = t = buf;
52 *t++ = ' ';
53 if (!lev && ex_lval.op != c)
54 *t++ = ex_lval.op;
55 *t++ = c;
56 *t = 0;
57 break;
58 case AND:
59 s = " AND ";
60 t = "&&";
61 break;
62 case DEC:
63 s = " DEC ";
64 t = "--";
65 break;
66 case DECLARE:
67 s = " DECLARE ";
68 t = ex_lval.id->name;
69 break;
70 case DYNAMIC:
71 s = " DYNAMIC ";
72 t = ex_lval.id->name;
73 x = (void*)ex_lval.id;
74 break;
75 case EQ:
76 s = " EQ ";
77 t = "==";
78 break;
79 case FLOATING:
80 s = " FLOATING ";
81 snprintf(t = buf, sizeof(buf), "%f", ex_lval.floating);
82 break;
83 case GE:
84 s = " GE ";
85 t = ">=";
86 break;
87 case CONSTANT:
88 s = " CONSTANT ";
89 t = ex_lval.id->name;
90 break;
91 case ID:
92 s = " ID ";
93 t = ex_lval.id->name;
94 break;
95 case INC:
96 s = "INC ";
97 t = "++";
98 break;
99 case INTEGER:
100 s = " INTEGER ";
101 snprintf(t = buf, sizeof(buf), "%lld", ex_lval.integer);
102 break;
103 case LABEL:
104 s = " LABEL ";
105 t = ex_lval.id->name;
106 break;
107 case LE:
108 s = " LE ";
109 t = "<=";
110 break;
111 case LSH:
112 s = " LSH ";
113 t = "<<";
114 break;
115 case NAME:
116 s = " NAME ";
117 t = ex_lval.id->name;
118 x = (void*)ex_lval.id;
119 break;
120 case NE:
121 s = " NE ";
122 t = "!=";
123 break;
124 case OR:
125 s = " OR ";
126 t = "||";
127 break;
128 case RSH:
129 s = " RSH ";
130 t = ">>";
131 break;
132 case STRING:
133 s = " STRING ";
134 t = fmtesc(ex_lval.string);
135 free_t = true;
136 break;
137 case UNSIGNED:
138 s = " UNSIGNED ";
139 snprintf(t = buf, sizeof(buf), "%llu", (unsigned long long)ex_lval.integer);
140 break;
141 case BREAK:
142 s = " break";
143 break;
144 case CASE:
145 s = " case";
146 break;
147 case CONTINUE:
148 s = " continue";
149 break;
150 case DEFAULT:
151 s = " default";
152 break;
153 case ELSE:
154 s = " else";
155 break;
156 case EXIT:
157 s = " exit";
158 break;
159 case FOR:
160 s = " for";
161 break;
162 case ITERATER:
163 s = " forf";
164 break;
165 case GSUB:
166 s = " gsub";
167 break;
168 case IF:
169 s = " if";
170 break;
171 case IN_OP:
172 s = " in";
173 break;
174 case PRAGMA:
175 s = " pragma";
176 break;
177 case PRINT:
178 s = " print";
179 break;
180 case PRINTF:
181 s = " printf";
182 break;
183 case QUERY:
184 s = " query";
185 break;
186 case RAND:
187 s = " rand";
188 break;
189 case RETURN:
190 s = " return";
191 break;
192 case SPLIT:
193 s = " split";
194 break;
195 case SPRINTF:
196 s = " sprintf";
197 break;
198 case SRAND:
199 s = " srand";
200 break;
201 case SUB:
202 s = " sub";
203 break;
204 case SUBSTR:
205 s = " substr";
206 break;
207 case SWITCH:
208 s = " switch";
209 break;
210 case TOKENS:
211 s = " tokens";
212 break;
213 case UNSET:
214 s = " unset";
215 break;
216 case WHILE:
217 s = " while";
218 break;
219 default:
220 if (c < 0177)
221 {
222 s = buf;
223 *s++ = c;
224 *s = 0;
225 t = fmtesc(buf);
226 free_t = true;
227 s = " ";
228 }
229 break;
230 }
231 if (x)
232 error(TRACE_lex + lev, "%s: [%d] %04d%s%s (%x)", op, ex->input->nesting, c, s, t, x);
233
234 else
235 error(TRACE_lex + lev, "%s: [%d] %04d%s%s", op, ex->input->nesting, c, s, t);
236 if (free_t) {
237 free(t);
238 }
239}
240
241/*
242 * trace wrapper for extoken()
243 */
244
245extern int _extoken_fn_(Expr_t*);
246
247int
249{
250 int c;
251
252#define extoken_fn _extoken_fn_
253
254 c = extoken_fn(ex);
255 trace(ex, 0, "ex_lex", c);
256 return c;
257}
258
259#else
260
261#define trace(p,a,b,c) do { } while (0)
262
263#endif
264
265/*
266 * get the next expression char
267 */
268
269static int
271{
272 int c;
273
274 for (;;)
275 {
276 if ((c = ex->input->peek))
277 ex->input->peek = 0;
278 else if (ex->input->pp)
279 {
280 if (!(c = *ex->input->pp++))
281 {
282 ex->input->pp = 0;
283 continue;
284 }
285 }
286 else if (ex->input->fp)
287 {
288 if ((c = getc(ex->input->fp)) == EOF)
289 {
290 if (!expop(ex))
291 continue;
292 else trace(ex, -1, "expop fp FAIL", 0);
293 c = 0;
294 }
295 }
296 else c = 0;
297 if (c == '\n')
298 setcontext(ex);
299 else if (c)
300 putcontext(ex, c);
301 trace(ex, -3, "ex--lex", c);
302 return c;
303 }
304}
305
306/*
307 * get the next expression token
308 */
309
310int
312{
313 int c;
314 char* s;
315 int q;
316 char* e;
317 Dt_t* v;
318
319 if (ex->eof || ex->errors)
320 return 0;
321 again:
322 for (;;)
323 switch (c = lex(ex))
324 {
325 case 0:
326 goto eof;
327 case '/':
328 switch (q = lex(ex))
329 {
330 case '*':
331 for (;;) switch (lex(ex))
332 {
333 case '\n':
334 if (error_info.line)
336 else error_info.line = 2;
337 continue;
338 case '*':
339 switch (lex(ex))
340 {
341 case 0:
342 goto eof;
343 case '\n':
344 if (error_info.line)
346 else error_info.line = 2;
347 break;
348 case '*':
349 exunlex(ex, '*');
350 break;
351 case '/':
352 goto again;
353 }
354 break;
355 }
356 break;
357 case '/':
358 while ((c = lex(ex)) != '\n')
359 if (!c)
360 goto eof;
361 break;
362 default:
363 goto opeq;
364 }
365 /*FALLTHROUGH*/
366 case '\n':
367 if (error_info.line)
369 else error_info.line = 2;
370 /*FALLTHROUGH*/
371 case ' ':
372 case '\t':
373 case '\r':
374 break;
375 case '(':
376 case '{':
377 case '[':
378 ex->input->nesting++;
379 return ex_lval.op = c;
380 case ')':
381 case '}':
382 case ']':
383 ex->input->nesting--;
384 return ex_lval.op = c;
385 case '+':
386 case '-':
387 if ((q = lex(ex)) == c)
388 return ex_lval.op = c == '+' ? INC : DEC;
389 goto opeq;
390 case '*':
391 case '%':
392 case '^':
393 q = lex(ex);
394 opeq:
395 ex_lval.op = c;
396 if (q == '=')
397 c = '=';
398 else if (q == '%' && c == '%')
399 {
400 goto eof;
401 }
402 else exunlex(ex, q);
403 return c;
404 case '&':
405 case '|':
406 if ((q = lex(ex)) == '=')
407 {
408 ex_lval.op = c;
409 return '=';
410 }
411 if (q == c)
412 c = c == '&' ? AND : OR;
413 else exunlex(ex, q);
414 return ex_lval.op = c;
415 case '<':
416 case '>':
417 if ((q = lex(ex)) == c)
418 {
419 ex_lval.op = c = c == '<' ? LSH : RSH;
420 if ((q = lex(ex)) == '=')
421 c = '=';
422 else exunlex(ex, q);
423 return c;
424 }
425 goto relational;
426 case '=':
427 case '!':
428 q = lex(ex);
429 relational:
430 if (q == '=') switch (c)
431 {
432 case '<':
433 c = LE;
434 break;
435 case '>':
436 c = GE;
437 break;
438 case '=':
439 c = EQ;
440 break;
441 case '!':
442 c = NE;
443 break;
444 default:
445 UNREACHABLE();
446 }
447 else exunlex(ex, q);
448 return ex_lval.op = c;
449 case '#':
450 if (!ex->linewrap) {
451 s = ex->linep - 1;
452 while (s > ex->line && gv_isspace(*(s - 1)))
453 s--;
454 if (s == ex->line)
455 {
456 switch (extoken_fn(ex))
457 {
458 case DYNAMIC:
459 case ID:
460 case NAME:
461 s = ex_lval.id->name;
462 break;
463 default:
464 s = "";
465 break;
466 }
467 if (streq(s, "include"))
468 {
469 if (extoken_fn(ex) != STRING)
470 exerror("#%s: string argument expected", s);
471 else if (!expush(ex, ex_lval.string, 1, NULL))
472 {
473 setcontext(ex);
474 goto again;
475 }
476 }
477 else exerror("unknown directive");
478 }
479 }
480 return ex_lval.op = c;
481 case '\'':
482 case '"':
483 q = c;
484 agxbclear(&ex->tmp);
485 ex->input->nesting++;
486 while ((c = lex(ex)) != q)
487 {
488 if (c == '\\')
489 {
490 agxbputc(&ex->tmp, '\\');
491 c = lex(ex);
492 }
493 if (!c)
494 {
495 exerror("unterminated %c string", q);
496 goto eof;
497 }
498 if (c == '\n')
499 {
500 if (error_info.line)
502 else error_info.line = 2;
503 }
504 agxbputc(&ex->tmp, (char)c);
505 }
506 ex->input->nesting--;
507 s = agxbuse(&ex->tmp);
508 if (q == '"' || (ex->disc->flags & EX_CHARSTRING))
509 {
510 if (!(ex_lval.string = vmstrdup(ex->vm, s)))
511 goto eof;
513 return STRING;
514 }
516 return INTEGER;
517 case '.':
518 if (gv_isdigit(c = lex(ex)))
519 {
520 agxbclear(&ex->tmp);
521 agxbput(&ex->tmp, "0.");
522 goto floating;
523 }
524 exunlex(ex, c);
525 return ex_lval.op = '.';
526 case '0': case '1': case '2': case '3': case '4':
527 case '5': case '6': case '7': case '8': case '9': {
528 agxbclear(&ex->tmp);
529 agxbputc(&ex->tmp, (char)c);
530 q = INTEGER;
531 int b = 0;
532 if ((c = lex(ex)) == 'x' || c == 'X')
533 {
534 b = 16;
535 agxbputc(&ex->tmp, (char)c);
536 for (c = lex(ex); gv_isxdigit(c); c = lex(ex))
537 {
538 agxbputc(&ex->tmp, (char)c);
539 }
540 }
541 else
542 {
543 while (gv_isdigit(c))
544 {
545 agxbputc(&ex->tmp, (char)c);
546 c = lex(ex);
547 }
548 if (c == '#')
549 {
550 agxbputc(&ex->tmp, (char)c);
551 do
552 {
553 agxbputc(&ex->tmp, (char)c);
554 } while (gv_isalnum(c = lex(ex)));
555 }
556 else
557 {
558 if (c == '.')
559 {
560 floating:
561 q = FLOATING;
562 agxbputc(&ex->tmp, (char)c);
563 while (gv_isdigit(c = lex(ex)))
564 agxbputc(&ex->tmp, (char)c);
565 }
566 if (c == 'e' || c == 'E')
567 {
568 q = FLOATING;
569 agxbputc(&ex->tmp, (char)c);
570 if ((c = lex(ex)) == '-' || c == '+')
571 {
572 agxbputc(&ex->tmp, (char)c);
573 c = lex(ex);
574 }
575 while (gv_isdigit(c))
576 {
577 agxbputc(&ex->tmp, (char)c);
578 c = lex(ex);
579 }
580 }
581 }
582 }
583 s = agxbuse(&ex->tmp);
584 if (q == FLOATING)
585 ex_lval.floating = strtod(s, &e);
586 else
587 {
588 if (c == 'u' || c == 'U')
589 {
590 q = UNSIGNED;
591 c = lex(ex);
592 ex_lval.integer = strtoull(s, &e, b);
593 }
594 else
595 ex_lval.integer = strtoll(s, &e, b);
596 }
597 exunlex(ex, c);
598 if (*e || gv_isalpha(c) || c == '_' || c == '$')
599 {
600 exerror("%s: invalid numeric constant", s);
601 goto eof;
602 }
603 return q;
604 }
605 default:
606 if (gv_isalpha(c) || c == '_' || c == '$')
607 {
608 agxbclear(&ex->tmp);
609 agxbputc(&ex->tmp, (char)c);
610 while (gv_isalnum(c = lex(ex)) || c == '_' || c == '$')
611 agxbputc(&ex->tmp, (char)c);
612 exunlex(ex, c);
613 s = agxbuse(&ex->tmp);
614 /* v = expr.declare ? dtview(ex->symbols, NULL) : (Dt_t*)0; FIX */
615 v = (Dt_t*)0;
616 ex_lval.id = dtmatch(ex->symbols, s);
617 if (v)
618 dtview(ex->symbols, v);
619 if (!ex_lval.id)
620 {
621 if (!(ex_lval.id = calloc(1, sizeof(Exid_t) + strlen(s) - EX_NAMELEN + 1)))
622 {
623 exnospace();
624 goto eof;
625 }
626 strcpy(ex_lval.id->name, s);
627 ex_lval.id->lex = NAME;
629
630 /*
631 * LABELs are in the parent scope!
632 */
633
634 if (c == ':' && !expr.nolabel && ex->frame && ex->frame->view)
635 dtinsert(ex->frame->view, ex_lval.id);
636 else
638 }
639
640 /*
641 * lexical analyzer state controlled by the grammar
642 */
643
644 switch (ex_lval.id->lex)
645 {
646 case DECLARE:
647 if (ex_lval.id->index == CHARACTER)
648 {
649 /*
650 * `char*' === `string'
651 * the * must immediately follow char
652 */
653
654 if (c == '*')
655 {
656 lex(ex);
658 }
659 }
660 break;
661 case NAME:
662 /*
663 * action labels are disambiguated from ?:
664 * through the expr.nolabel grammar hook
665 * the : must immediately follow labels
666 */
667
668 if (c == ':' && !expr.nolabel)
669 return LABEL;
670 break;
671 case PRAGMA:
672 /*
673 * user specific statement stripped and
674 * passed as string
675 */
676
677 {
678 int b;
679 int n;
680 int pc = 0;
681 int po;
682 int t;
683
684 /*UNDENT...*/
685 agxbclear(&ex->tmp);
686 b = 1;
687 n = 0;
688 po = 0;
689 for (c = t = lex(ex);; c = lex(ex))
690 {
691 switch (c)
692 {
693 case 0:
694 goto eof;
695 case '/':
696 switch (q = lex(ex))
697 {
698 case '*':
699 for (;;)
700 {
701 switch (lex(ex))
702 {
703 case '\n':
704 if (error_info.line)
706 else error_info.line = 2;
707 continue;
708 case '*':
709 switch (lex(ex))
710 {
711 case 0:
712 goto eof;
713 case '\n':
714 if (error_info.line)
716 else error_info.line = 2;
717 continue;
718 case '*':
719 exunlex(ex, '*');
720 continue;
721 case '/':
722 break;
723 default:
724 continue;
725 }
726 break;
727 default: // ignore; keep consuming characters
728 break;
729 }
730 if (!b++)
731 goto eof;
732 agxbputc(&ex->tmp, ' ');
733 break;
734 }
735 break;
736 case '/':
737 while ((c = lex(ex)) != '\n')
738 if (!c)
739 goto eof;
740 if (error_info.line)
742 else error_info.line = 2;
743 b = 1;
744 agxbputc(&ex->tmp, '\n');
745 break;
746 default:
747 b = 0;
748 agxbputc(&ex->tmp, (char)c);
749 agxbputc(&ex->tmp, (char)q);
750 break;
751 }
752 continue;
753 case '\n':
754 if (error_info.line)
756 else error_info.line = 2;
757 b = 1;
758 agxbputc(&ex->tmp, '\n');
759 continue;
760 case ' ':
761 case '\t':
762 if (!b++)
763 goto eof;
764 agxbputc(&ex->tmp, ' ');
765 continue;
766 case '(':
767 case '{':
768 case '[':
769 b = 0;
770 if (!po)
771 {
772 switch (po = c)
773 {
774 case '(':
775 pc = ')';
776 break;
777 case '{':
778 pc = '}';
779 break;
780 case '[':
781 pc = ']';
782 break;
783 default:
784 UNREACHABLE();
785 }
786 n++;
787 }
788 else if (c == po)
789 n++;
790 agxbputc(&ex->tmp, (char)c);
791 continue;
792 case ')':
793 case '}':
794 case ']':
795 b = 0;
796 if (!po)
797 {
798 exunlex(ex, c);
799 break;
800 }
801 agxbputc(&ex->tmp, (char)c);
802 if (c == pc && --n <= 0)
803 {
804 if (t == po)
805 break;
806 po = 0;
807 }
808 continue;
809 case ';':
810 b = 0;
811 if (!n)
812 break;
813 agxbputc(&ex->tmp, (char)c);
814 continue;
815 case '\'':
816 case '"':
817 b = 0;
818 agxbputc(&ex->tmp, (char)c);
819 ex->input->nesting++;
820 q = c;
821 while ((c = lex(ex)) != q)
822 {
823 if (c == '\\')
824 {
825 agxbputc(&ex->tmp, '\\');
826 c = lex(ex);
827 }
828 if (!c)
829 {
830 exerror("unterminated %c string", q);
831 goto eof;
832 }
833 if (c == '\n')
834 {
835 if (error_info.line)
837 else error_info.line = 2;
838 }
839 agxbputc(&ex->tmp, (char)c);
840 }
841 ex->input->nesting--;
842 continue;
843 default:
844 b = 0;
845 agxbputc(&ex->tmp, (char)c);
846 continue;
847 }
848 break;
849 }
850 ex->disc->reff(ex, NULL, ex_lval.id, NULL);
851
852 /*..INDENT*/
853 }
854 goto again;
855 }
856 return ex_lval.id->lex;
857 }
858 return ex_lval.op = c;
859 }
860 eof:
861 ex->eof = 1;
862 return ex_lval.op = ';';
863}
static size_t agxbput(agxbuf *xb, const char *s)
append string s into xb
Definition agxbuf.h:249
static void agxbclear(agxbuf *xb)
resets pointer to data
Definition agxbuf.h:273
static int agxbputc(agxbuf *xb, char c)
add character to buffer
Definition agxbuf.h:256
static char * agxbuse(agxbuf *xb)
Definition agxbuf.h:286
int chrtoi(const char *)
Definition chrtoi.c:22
char * fmtesc(const char *as)
Definition fmtesc.c:132
void stresc(char *)
Definition stresc.c:20
#define dtmatch(d, o)
Definition cdt.h:192
#define dtinsert(d, o)
Definition cdt.h:193
CDT_API Dt_t * dtview(Dt_t *, Dt_t *)
Definition dtview.c:91
void error(int level, const char *s,...)
Definition error.c:83
Error_info_t error_info
Definition error.c:23
void exerror(const char *format,...)
Definition exerror.c:62
Exstate_t expr
#define setcontext(p)
Definition exlib.h:128
#define id_string
Definition exlib.h:124
#define putcontext(p, c)
Definition exlib.h:127
#define exunlex(p, c)
Definition exlib.h:126
char * exnospace(void)
Definition exnospace.c:25
#define UNSIGNED
Definition exparse.c:237
#define ELSE
Definition exparse.c:253
#define CHARACTER
Definition exparse.c:238
#define DYNAMIC
Definition exparse.c:252
#define RSH
Definition exparse.c:307
#define OR
Definition exparse.c:300
#define GE
Definition exparse.c:305
#define DEFAULT
Definition exparse.c:251
#define ITERATER
Definition exparse.c:259
#define WHILE
Definition exparse.c:284
#define NE
Definition exparse.c:303
#define SRAND
Definition exparse.c:277
#define SUB
Definition exparse.c:279
#define LSH
Definition exparse.c:306
#define FLOATING
Definition exparse.c:239
#define FOR
Definition exparse.c:255
#define IN_OP
Definition exparse.c:308
#define SUBSTR
Definition exparse.c:280
#define TOKENS
Definition exparse.c:282
#define RAND
Definition exparse.c:272
#define PRINT
Definition exparse.c:268
#define SPRINTF
Definition exparse.c:276
EX_STYPE ex_lval
#define CONSTANT
Definition exparse.c:248
#define LE
Definition exparse.c:304
#define GSUB
Definition exparse.c:257
#define PRAGMA
Definition exparse.c:266
#define UNSET
Definition exparse.c:283
#define CONTINUE
Definition exparse.c:249
#define EQ
Definition exparse.c:302
#define BREAK
Definition exparse.c:245
#define IF
Definition exparse.c:261
#define SWITCH
Definition exparse.c:281
#define AND
Definition exparse.c:301
#define DECLARE
Definition exparse.c:250
#define EXIT
Definition exparse.c:254
#define PRINTF
Definition exparse.c:269
#define QUERY
Definition exparse.c:271
#define CASE
Definition exparse.c:247
#define INC
Definition exparse.c:310
#define DEC
Definition exparse.c:311
$1 lex
Definition exparse.y:209
#define EX_NAMELEN
Definition expr.h:51
#define EX_CHARSTRING
Definition expr.h:44
int expop(Expr_t *)
int expush(Expr_t *, const char *, int, FILE *)
int extoken_fn(Expr_t *ex)
Definition extoken.c:311
#define trace(p, a, b, c)
Definition extoken.c:261
#define LABEL
Definition gmlparse.c:396
#define NAME
Definition gmlparse.c:416
#define ID
Definition gmlparse.c:415
#define STRING
Definition gmlparse.c:414
#define INTEGER
Definition gmlparse.c:412
void free(void *)
node NULL
Definition grammar.y:149
replacements for ctype.h functions
static bool gv_isxdigit(int c)
Definition gv_ctype.h:71
static bool gv_isalnum(int c)
Definition gv_ctype.h:43
static bool gv_isdigit(int c)
Definition gv_ctype.h:41
static bool gv_isalpha(int c)
Definition gv_ctype.h:29
static bool gv_isspace(int c)
Definition gv_ctype.h:55
#define SPLIT(x, n, s)
Definition htmltable.c:1273
static bool streq(const char *a, const char *b)
are a and b equal?
Definition streq.h:11
#define RETURN(v)
Definition strmatch.c:144
int line
Definition error.h:27
Definition expr.h:93
long isstatic
Definition expr.h:102
long lex
Definition expr.h:95
char name[EX_NAMELEN]
Definition expr.h:103
long index
Definition expr.h:96
Definition expr.h:202
Dt_t * symbols
Definition expr.h:204
Vmalloc_t * vm
Definition expr.h:206
int instatic
Definition exlib.h:161
int nolabel
Definition exlib.h:155
int statics
Definition exlib.h:162
Definition cdt.h:104
struct Exid_s * id
Definition exparse.c:324
char * string
Definition exparse.c:327
long long integer
Definition exparse.c:325
double floating
Definition exparse.c:322
int op
Definition exparse.c:326
Definition grammar.c:93
#define UNREACHABLE()
Definition unreachable.h:30
char * vmstrdup(Vmalloc_t *, const char *)
Definition vmstrdup.c:19