Bug Summary

File:tools/unix/zacc.c
Warning:line 567, column 8
Null pointer passed to 1st parameter expecting 'nonnull'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name zacc.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/home/kfp/aldor/aldor/aldor/tools/unix -fcoverage-compilation-dir=/home/kfp/aldor/aldor/aldor/tools/unix -resource-dir /usr/local/lib/clang/18 -D PACKAGE_NAME="aldor" -D PACKAGE_TARNAME="aldor" -D PACKAGE_VERSION="1.4.0" -D PACKAGE_STRING="aldor 1.4.0" -D PACKAGE_BUGREPORT="aldor@xinutec.org" -D PACKAGE_URL="" -D PACKAGE="aldor" -D VERSION="1.4.0" -D YYTEXT_POINTER=1 -D HAVE_STDIO_H=1 -D HAVE_STDLIB_H=1 -D HAVE_STRING_H=1 -D HAVE_INTTYPES_H=1 -D HAVE_STDINT_H=1 -D HAVE_STRINGS_H=1 -D HAVE_SYS_STAT_H=1 -D HAVE_SYS_TYPES_H=1 -D HAVE_UNISTD_H=1 -D STDC_HEADERS=1 -D HAVE_LIBREADLINE=1 -D HAVE_READLINE_READLINE_H=1 -D HAVE_READLINE_HISTORY=1 -D HAVE_READLINE_HISTORY_H=1 -D USE_GLOOP_SHELL=1 -D GENERATOR_COROUTINES=0 -D HAVE_DLFCN_H=1 -D LT_OBJDIR=".libs/" -I . -internal-isystem /usr/local/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-empty-body -Wno-enum-compare -Wno-missing-field-initializers -Wno-unused -Wno-unused-parameter -Wno-error=format -Wno-error=type-limits -Wno-error=strict-aliasing -Wno-sign-compare -Wno-error=shift-negative-value -Wno-error=clobbered -Wno-implicit-function-declaration -std=c99 -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /tmp/scan-build-2026-01-15-223856-845667-1 -x c zacc.c
1/*
2 * 2-level grammar implementation.
3 *
4 * zacc [-y yaccfile] [-c cfile] [-v] [-p] infile
5 *
6 * This command accepts a grammar file and produces a yacc file as output.
7 * The grammar file looks like yacc, with the following differences:
8 *
9 * 1. Rules may be parameterized
10 * E.g. List(S): Nothing | List(S) S ;
11 *
12 * 2. Rules may be typed
13 * E.g. Node<pt>: '(' Node ')' | Node '+' Node ;
14 * List(S)<l>: Nothing | List(S) S ;
15 *
16 * 3. A default type for rules or tokens can be given:
17 * E.g. %default-token-type <tok>
18 * %default-rule-type <pt>
19 *
20 * A name which is used but does not have a rule is assumed to be a token.
21 *
22 * If a name is only used preceded by a back quote, then no type declaration
23 * is made for it.
24 * E.g. List(S,f): Nothing { $$ = 0; } | List(S,f) S { $$ = f($2,$1); } ;
25 * conslist: List(TK_Int, `cons);
26 *
27 * A rule typed as <void> is not given a type even in the presence of
28 * a "%default-rule-type".
29 *
30 * 4. A C source file may be included to obtain values for tokens:
31 * E.g. %include-enum "token.h" tokenTag
32 * produces %token statements for the entries in ``enum tokenTag''.
33 *
34 * The "-y" option gives a name to the generated yacc file and says to keep it.
35 * The "-c" option gives a name to the generated C file and says to keep it.
36 * The "-v" option causes the program to print debug messages.
37 * The "-p" option causes the token symbols to be prefaced with "YY_".
38 */
39
40# include <stdio.h>
41# include <stdlib.h>
42# include <string.h>
43# include <time.h>
44# include <unistd.h>
45# include "zacc.h"
46# include "zaccgram.h"
47# include "cenum.h"
48
49#define COMMENTARY
50
51/*
52 * Things imported.
53 */
54
55extern FILE *yyin;
56extern int yydebug;
57extern int yyparse();
58
59extern char *ctime();
60/*extern char *malloc();*/
61/*extern char *strcpy();*/
62
63/*
64 * Forward declarations for utilities.
65 */
66
67char * mustAlloc of((int))(int);
68char * strAlloc of((char *))(char *);
69FILE * mustOpen of((char *fname, char *mode))(char *fname, char *mode);
70char * timeNow of((void))(void);
71void fatalErr of((void))(void);
72char * fnameDir of((char *))(char *);
73
74
75/******************************************************************************
76 *
77 * :: Top-level global variables.
78 *
79 *****************************************************************************/
80
81#define DEFAULT_YACC_FILE"zacc.out" "zacc.out"
82#define DEFAULT_C_FILE"y.tab.c" "y.tab.c"
83
84static int verbose=0; /* -v flag given. */
85static char *prefix=""; /* -p flag prefix. */
86
87static char *yfile="zacc.out"; /* -y file name. */
88static int hadyfile=0;
89
90static char *cfile="y.tab.c"; /* -c file name. */
91static int hadcfile=0;
92
93static char *fnin; /* Name of input file. */
94static char *dirin; /* Directory part of input filename. */
95static FILE *fout; /* Output stream for yacc generation. */
96
97static int passno; /* Pass number. */
98static int errcount = 0; /* Number of syntax errors. */
99
100static char *dfltTokenType = 0; /* Default type for tokens. */
101static char *dfltRuleType = 0; /* Default type for rules. */
102static int hasPctType = 0; /* %type used? */
103
104static int isExtra(); /* Is this a XXX_START or XXX_LIMIT word? */
105static int isTerminal(); /* Is the given word a terminal (token)? */
106static void prWord(); /* Print the given word. */
107
108struct phrUse;
109struct phrDef;
110struct phrInfo;
111
112int yylex();
113void handleRule();
114void _2_endRule();
115void _2_startRule();
116void _2_endPhraseName();
117void _2_seeArg();
118void _2_seeType();
119void _2_seeName();
120void _2_endCommand();
121void _2_startCommand();
122void _2_seeIncludeEnum();
123void _2_wholeEpilog();
124void _2_endProlog();
125void _2_startProlog();
126void _2_endRule();
127void _2_startPhraseName();
128void _2_midRule();
129void _1_endRule();
130void _1_midRule();
131void _1_startRule();
132void _1_seeType();
133void _1_endPhraseName();
134void _1_seeArg();
135void _1_seeName();
136void _1_startPhraseName();
137void _1_seeIncludeEnum();
138void _1_endCommand();
139void _1_startCommand();
140void _1_wholeEpilog();
141void _1_endProlog();
142void _1_startProlog();
143struct phrUse *findUse(struct phrInfo *pinfo, struct phrDef *context, struct phrUse *);
144void _1_();
145void _1_();
146
147
148static int inLhs, inAction; /* context information */
149
150
151/******************************************************************************
152 *
153 * :: Top-level entry point and parser tie-ins.
154 *
155 *****************************************************************************/
156
157
158void
159zaccPass(char *fn, int n)
160{
161 yyin = mustOpen(fn, "r");
162 fnin = fn;
163 passno = n;
164 yyparse();
165 fclose(yyin);
166}
167
168
169void
170zacc(char *fn, char *yfn)
171{
172 dirin = fnameDir(fn);
173
174 fout = mustOpen(yfn, "w");
175
176#ifdef COMMENTARY
177 fprintf(fout, "/*\n * \"zacc\" output from \"%s\" on %s\n */\n\n",
178 fn, timeNow());
179#endif
180 zaccPass(fn, 1);
181 if (errcount > 0) exit(3);
182 zaccPass(fn, 2);
183
184 fclose(fout);
185}
186
187int
188main(int argc, char **argv)
189{
190 int options = 1;
191
192 while (options) {
193 if (argc > 1 && !strcmp(argv[1], "-v")) {
194 verbose = 1;
195 argc--, argv++;
196 continue;
197 }
198 if (argc > 1 && !strcmp(argv[1], "-p")) {
199 prefix = "_YY_";
200 argc--, argv++;
201 continue;
202 }
203 if (argc > 2 && !strcmp(argv[1], "-y")) {
204 yfile = argv[2];
205 hadyfile = 1;
206 argc -= 2, argv += 2;
207 continue;
208 }
209 if (argc > 2 && !strcmp(argv[1], "-c")) {
210 cfile = argv[2];
211 hadcfile = 1;
212 argc -= 2, argv += 2;
213 continue;
214 }
215 options = 0;
216 }
217
218 if (argc != 2) fatalErr();
219
220 if (hadyfile || hadcfile) {
221 zacc(argv[1], yfile);
222 }
223 if (hadcfile) {
224 char cmd[500];
225 int rc;
226
227 sprintf(cmd, "yacc %s", yfile);
228 if (verbose) printf("Exec: %s\n", cmd);
229 rc = system(cmd);
230 if (rc != 0) {
231 fprintf(stderrstderr, "Yacc failed on file \"%s\"\n", yfile);
232 return 3;
233 }
234 if (!hadyfile) unlink(yfile);
235
236 rc = rename("y.tab.c", cfile);
237 if (rc != 0) {
238 fprintf(stderrstderr,
239 "Rename failed from \"y.tab.c\" to \"%s\"\n",
240 cfile);
241 return 3;
242 }
243
244 }
245
246 return 0;
247}
248
249int lineNo;
250
251int
252yyerror(char *s)
253{
254 fprintf(stderrstderr, "\"%s\", line %d: %s\n", fnin, lineNo, s);
255 return errcount++;
256}
257
258void
259incLineCount()
260{
261 lineNo++;
262}
263
264int tokEcho; /* In "token", echo the string. */
265int tokEnlist; /* In "token", add a link to the token list. */
266
267struct tokList {
268 int tag;
269 char *str;
270 struct tokList *next;
271 int show; /* for rule emission */
272} *tokListHead, *tokListTail;
273
274void
275token(int tag, char *str)
276{
277 /*
278 * To finesse parser lookahead.
279 */
280 static char *prevTok = "";
281 static int prevEcho= 1;
282
283 yylval.str = strAlloc(str);
284
285 if (prevEcho && tokEcho)
286 prWord(fout, prevTok);
287
288 prevEcho = tokEcho;
289 prevTok = yylval.str;
290
291 if (tag == TK_PctId277 && !strcmp(str, "%type"))
292 hasPctType = 1;
293
294 if (tag == TK_NewLine283) incLineCount();
295
296 if (tokEnlist) {
297 struct tokList *t;
298 t = (struct tokList *) mustAlloc(sizeof(struct tokList));
299 t->tag = inAction ? TK_CTok281 : tag;
300 t->str = yylval.str;
301 t->show= 0;
302 t->next= 0;
303
304 if (!tokListHead)
305 tokListHead = tokListTail = t;
306 else {
307 tokListTail->next = t;
308 tokListTail = t;
309 }
310 }
311}
312
313
314/******************************************************************************
315 *
316 * :: Grammar actions
317 *
318 *****************************************************************************/
319
320void
321startProlog()
322{
323 inLhs = 0;
324 inAction = 0;
325
326 switch (passno) {
327 case 1: _1_startProlog(); break;
328 case 2: _2_startProlog(); break;
329 }
330}
331
332void
333endProlog()
334{
335 switch (passno) {
336 case 1: _1_endProlog(); break;
337 case 2: _2_endProlog(); break;
338 }
339}
340
341
342void
343wholeEpilog()
344{
345 switch (passno) {
346 case 1: _1_wholeEpilog(); break;
347 case 2: _2_wholeEpilog(); break;
348 }
349}
350
351
352void
353startCommand()
354{
355 switch (passno) {
356 case 1: _1_startCommand(); break;
357 case 2: _2_startCommand(); break;
358 }
359}
360
361void
362endCommand()
363{
364 switch (passno) {
365 case 1: _1_endCommand(); break;
366 case 2: _2_endCommand(); break;
367 }
368}
369
370
371void
372seeTokenType(char *str)
373{
374 dfltTokenType = str;
375}
376
377void
378seeIncludeEnum(char *fname, char *ename)
379{
380 char fbuf[500];
381 int i;
382
383 /* Convert "\"foo.h\"" -> "dirin/foo.h" */
384 if (*fname == '"') fname++;
385 for (i = 0; dirin[i]; i++) fbuf[i] = dirin[i];
386 fbuf[i++] = '/';
387 while (*fname && *fname != '"') fbuf[i++] = *fname++;
388 fbuf[i] = 0;
389
390 switch (passno) {
391 case 1: _1_seeIncludeEnum(fbuf, ename); break;
392 case 2: _2_seeIncludeEnum(fbuf, ename); break;
393 }
394}
395
396void
397seeRuleType(char *str)
398{
399 dfltRuleType = str;
400}
401
402void
403startPhraseName()
404{
405 switch (passno) {
406 case 1: _1_startPhraseName(); break;
407 case 2: _2_startPhraseName(); break;
408 }
409}
410
411void
412seeName(char *str)
413{
414 switch(passno) {
415 case 1: _1_seeName(str); break;
416 case 2: _2_seeName(str); break;
417 }
418}
419
420void
421seeArg(char *str)
422{
423 switch(passno) {
424 case 1: _1_seeArg(str); break;
425 case 2: _2_seeArg(str); break;
426 }
427}
428
429void
430endPhraseName()
431{
432 switch(passno) {
433 case 1: _1_endPhraseName(); break;
434 case 2: _2_endPhraseName(); break;
435 }
436}
437
438void
439seeType(char *str)
440{
441 switch(passno) {
442 case 1: _1_seeType(str); break;
443 case 2: _2_seeType(str); break;
444 }
445}
446
447
448void
449startRule()
450{
451 inLhs = 1;
452
453 switch(passno) {
454 case 1: _1_startRule(); break;
455 case 2: _2_startRule(); break;
456 }
457}
458
459void
460midRule()
461{
462 inLhs = 0;
463
464 switch(passno) {
465 case 1: _1_midRule(); break;
466 case 2: _2_midRule(); break;
467 }
468}
469
470void
471endRule()
472{
473 switch(passno) {
1
Control jumps to 'case 2:' at line 475
474 case 1: _1_endRule(); break;
475 case 2: _2_endRule(); break;
2
Calling '_2_endRule'
476 }
477}
478
479void
480startAction()
481{
482 inAction = 1;
483}
484
485void
486endAction()
487{
488 inAction = 0;
489}
490
491
492/******************************************************************************
493 *
494 * :: Structures for Pass 1.
495 *
496 *****************************************************************************/
497
498
499/*
500 * These structures maintain information on rules defined and used.
501 *
502 * E.g. z(a,b)<tok> : OPren x(b) y(q,r) a CPren ;
503 */
504
505static char * argName[] = { "&1","&2","&3","&4","&5","&6","&7","&8","&9" };
506# define MAXARGC(9) (9)
507
508struct phrInfo {
509 char *name;
510 int argc;
511 char *argv[MAXARGC(9)];
512};
513
514struct phrDef {
515 char *name; /* z */
516 int argc; /* 2 */
517 char *type; /* tok */
518 struct phrDef *next;
519};
520
521struct phrUse {
522 struct phrInfo info; /* x(&2) ; y(q) */
523 struct phrDef *context; /* ^{z,2,..} ; 0 */
524 struct phrUse *next;
525};
526
527struct phrDef *phrDefList = 0;
528struct phrUse *phrUseList = 0;
529
530struct phrUse *tokenSet, *genSet;
531
532#define UNQ(s)( ((s)[0] == '`') ? (s) + 1 : (s) ) ( ((s)[0] == '`') ? (s) + 1 : (s) )
533void
534fprintInfo(FILE *fout, struct phrInfo *pinfo)
535{
536 int i;
537
538 prWord(fout, UNQ(pinfo->name)( ((pinfo->name)[0] == '`') ? (pinfo->name) + 1 : (pinfo
->name) )
);
539
540 if (pinfo->argc == 0) return;
541
542 for (i = 0; i < pinfo->argc; i++) {
543 fprintf(fout, "_");
544 prWord(fout, UNQ(pinfo->argv[i])( ((pinfo->argv[i])[0] == '`') ? (pinfo->argv[i]) + 1 :
(pinfo->argv[i]) )
);
545 }
546 fprintf(fout, "_");
547}
548
549/* Does the arg use &1, etc? */
550int
551usesBV(struct phrInfo *pinfo)
552{
553 int i, j;
554 for (i = 0; i < pinfo->argc; i++)
555 for (j = 0; j < MAXARGC(9); j++)
556 if (pinfo->argv[i] == argName[j]) return 1;
557 return 0;
558}
559
560/* Rename bound variables to &1, etc. */
561char *
562renameBV(char *str, struct phrInfo *pinfo)
563{
564 int i;
565
566 for (i = 0; i < pinfo->argc; i++)
43
Loop condition is true. Entering loop body
567 if (!strcmp(str, pinfo->argv[i]))
44
Null pointer passed to 1st parameter expecting 'nonnull'
568 return argName[i];
569
570 return str;
571}
572
573int
574unnameBV(char *str)
575{
576 int i;
577 for (i = 0; i < MAXARGC(9); i++)
578 if (str == argName[i]) return i;
579 return -1;
580}
581
582struct phrUse *
583instance(struct phrUse *withFV, struct phrUse *withBV)
584{
585 struct phrUse *inst;
586 int i;
587
588 inst = (struct phrUse *) mustAlloc(sizeof(struct phrUse));
589 inst->context = 0;
590 inst->next = 0;
591
592 inst->info = withFV->info;
593
594 for (i = 0; i < withFV->info.argc; i++) {
595 int a = unnameBV(withFV->info.argv[i]);
596
597 if (a >= 0) inst->info.argv[i] = withBV->info.argv[a];
598 }
599
600 return inst;
601}
602
603struct phrDef *
604findDef(char *str, struct phrDef *l)
605{
606 for ( ; l; l = l->next) {
607 if (!strcmp(str, l->name)) return l;
608 }
609 return 0;
610}
611
612struct phrUse *
613findUse(struct phrInfo *pinfo, struct phrDef *context, struct phrUse *l)
614{
615 for ( ; l; l = l->next) {
616 int different = strcmp(pinfo->name, l->info.name);
617 int i;
618 for (i = 0; !different && i < pinfo->argc; i++)
619 different = strcmp(pinfo->argv[i], l->info.argv[i]);
620 if (!different)
621 different = l->context && (l->context != context);
622 if (!different)
623 return l;
624 }
625 return 0;
626}
627
628
629struct phrDef *
630addDef(char *name, int argc, char *type)
631{
632 struct phrDef *def;
633
634 def = findDef(name, phrDefList);
635
636 if (!def) {
637 def = (struct phrDef *) mustAlloc(sizeof(struct phrDef));
638 def->name = name;
639 def->argc = argc;
640 def->type = type;
641 def->next = phrDefList;
642 phrDefList = def;
643 }
644 else {
645 if (def->argc != argc)
646 fatalErr();
647 if (def->type && type && strcmp(def->type, type))
648 fatalErr();
649 if (type && !(def->type))
650 def->type = type;
651 }
652 return def;
653}
654
655struct phrDef *
656defListNReverse(struct phrDef *l)
657{
658 struct phrDef *r, *t;
659
660 r = 0;
661 while(l) {
662 t = l->next;
663 l->next = r;
664 r = l;
665 l = t;
666 }
667 return r;
668}
669
670int
671dontAddUse(char *str)
672{
673 int i;
674
675 if (*str == '`') return 1;
676 if (!strcmp(str, "error")) return 1;
677
678 for (i = 0; i < MAXARGC(9); i++)
679 if (str == argName[i]) return 1;
680 return 0;
681}
682
683struct phrUse *
684addUse(struct phrInfo *pinfo, struct phrDef *context)
685{
686 struct phrUse *use;
687
688 if (dontAddUse(pinfo->name))
689 return phrUseList;
690
691 use = findUse(pinfo, context, phrUseList);
692
693 if (!use) {
694 use = (struct phrUse *) mustAlloc(sizeof(struct phrUse));
695 use->info = *pinfo;
696 use->context = usesBV(pinfo) ? context : 0;
697 use->next = phrUseList;
698 phrUseList = use;
699 }
700 return phrUseList;
701}
702
703
704void
705showDefs(struct phrDef *l)
706{
707 for ( ; l; l = l->next) {
708 fprintf(stdoutstdout, "\t%s", l->name);
709 if (l->argc > 0)
710 fprintf(stdoutstdout, "[%d]", l->argc);
711 if (l->type)
712 fprintf(stdoutstdout,"<%s>", l->type);
713 fprintf(stdoutstdout,"\n");
714 }
715}
716
717void
718showUses(struct phrUse *l)
719{
720 for ( ; l; l = l->next) {
721 int i;
722 fprintf(stdoutstdout, "\t%s", l->info.name);
723 if (l->info.argc > 0) {
724 fprintf(stdoutstdout, "(");
725 for (i = 0; i < l->info.argc; i++)
726 fprintf(stdoutstdout, " %s", l->info.argv[i]);
727 fprintf(stdoutstdout, ")");
728
729 if (l->context)
730 fprintf(stdoutstdout, " in %s", l->context->name);
731 }
732 fprintf(stdoutstdout, "\n");
733 }
734}
735
736void
737phraseClosure()
738{
739 struct phrUse *withFV = 0, *undone = 0;
740 int n;
741
742 phrDefList = defListNReverse(phrDefList);
743
744 tokenSet = 0;
745 genSet = 0;
746
747 while (phrUseList) {
748 struct phrUse *t;
749
750 t = phrUseList; phrUseList = phrUseList->next;
751
752 if (t->context) {
753 t->next = withFV; withFV = t;
754 }
755 else if (!findDef(t->info.name, phrDefList)) {
756 if (t->info.argc != 0) fatalErr();
757 t->next = tokenSet; tokenSet = t;
758 }
759 else if(t->info.argc > 0) {
760 t->next = undone; undone = t;
761 }
762 }
763
764 if (verbose) {
765 printf("Starting to compute closure.\n");
766 printf("-- Defined rules and metarules:\n");
767 showDefs(phrDefList);
768 printf("-- Metarule uses:\n");
769 showUses(withFV);
770 }
771
772 for (n = 0; undone; n++) {
773 struct phrUse *u0, *u1, *l;
774
775 if (verbose) {
776 printf("Iteration %d.\n", n);
777/*
778 printf("-- Done forms:\n");
779 showUses(undone);
780 printf("-- So far generated rules:\n");
781 showUses(genSet);
782*/
783 }
784
785 u0 = undone;
786 undone = undone->next;
787
788 u0->next = genSet;
789 genSet = u0;
790
791 for (l = withFV; l; l = l->next) {
792 if (!strcmp(l->context->name, u0->info.name)) {
793 u1 = instance(l, u0);
794 if (!findUse(&(u1->info), 0, undone) &&
795 !findUse(&(u1->info), 0, genSet) )
796 {
797 u1->next = undone; undone = u1;
798 }
799 }
800 }
801 }
802
803 if (verbose) {
804 printf("-- Implicit tokens:\n");
805 showUses(tokenSet);
806 printf("-- Generated rules:\n");
807 showUses(genSet);
808 }
809}
810
811
812/*
813 * Code to gather information about parameterized phrases as they are parsed.
814 */
815
816static struct phrInfo phrInfo;
817static struct phrInfo lhsInfo;
818static char *lhsType;
819static struct phrDef *lhsDef;
820
821void
822_1_startProlog()
823{
824 tokEcho = 0;
825 tokEnlist = 0;
826}
827
828void
829_1_endProlog()
830{
831 if (hasPctType && (dfltTokenType || dfltRuleType))
832 fatalErr();
833}
834
835void
836_1_wholeEpilog()
837{
838 while (yylex() != 0)
839 ;
840
841 phraseClosure();
842}
843
844void
845_1_startCommand()
846{
847}
848
849void
850_1_endCommand()
851{
852}
853
854static EnumItem inclEnums = 0;
855
856void
857_1_seeIncludeEnum(char *fname, char *ename)
858{
859 EnumItem tt;
860
861 tt = skimEnums(fname, 1, &ename);
862 if (!tt) {
863 fprintf(stderrstderr, "Could not find enumeration %s in file %s.\n",
864 ename, fname);
865 exit(3);
866 }
867 inclEnums = skimNConcat(inclEnums, tt);
868}
869
870void
871_1_startPhraseName()
872{
873 phrInfo.name = 0;
874 phrInfo.argc = 0;
875}
876
877void
878_1_seeName(char *str)
879{
880 phrInfo.name = (!inLhs) ? renameBV(str, &lhsInfo) : str;
881}
882
883void
884_1_seeArg(char *str)
885{
886 if (phrInfo.argc == MAXARGC(9))
887 fatalErr();
888
889 str = (!inLhs) ? renameBV(str, &lhsInfo) : str;
890 phrInfo.argv[phrInfo.argc++] = str;
891
892 if (!inLhs) {
893 struct phrInfo argInfo;
894 argInfo.name = str;
895 argInfo.argc = 0;
896 addUse(&argInfo, lhsDef);
897 }
898}
899
900void
901_1_endPhraseName()
902{
903 if (inLhs)
904 lhsInfo = phrInfo;
905 else
906 addUse(&phrInfo, lhsDef);
907}
908
909void
910_1_seeType(char *str)
911{
912 if (passno != 1) return;
913
914 lhsType = str;
915}
916
917
918void
919_1_startRule()
920{
921 lhsType = 0;
922 lhsDef = 0;
923}
924
925void
926_1_midRule()
927{
928 lhsDef = addDef(lhsInfo.name, lhsInfo.argc, lhsType);
929}
930
931void
932_1_endRule()
933{
934}
935
936
937/******************************************************************************
938 *
939 * :: Functions for pass 2.
940 *
941 *****************************************************************************/
942
943static int
944isTerminal(char *w)
945{
946 struct phrUse *l = tokenSet;
947
948 for (l = tokenSet; l; l = l->next)
949 if (!strcmp(w, l->info.name)) return 1;
950
951 return 0;
952}
953
954char *extraSuffix[] = { "_START", "_LIMIT", 0 };
955
956static int
957isExtra(char *w)
958{
959 char *x;
960 int i, nx, nw;
961
962 nw = strlen(w);
963
964 for (i = 0; extraSuffix[i]; i++) {
965 x = extraSuffix[i];
966 nx = strlen(x);
967
968 if (nx > nw) continue;
969 if (!strcmp(w + (nw-nx), x)) return 1;
970
971 }
972 return 0;
973}
974
975static void
976prWord(FILE *fout, char *w)
977{
978 char *p;
979 p = isTerminal(w) ? prefix : "";
980 fprintf(fout, "%s%s", p, w);
981
982}
983
984void
985_2_startProlog()
986{ tokEcho = 1;
987 tokEnlist= 1;
988
989 tokListHead = 0;
990 tokListTail = 0;
991}
992
993void
994_2_endProlog()
995{
996 struct phrUse *ul;
997 struct phrDef *dl;
998 char *type;
999 int n = 0;
1000
1001 /*
1002 * Emit type declarations.
1003 */
1004
1005 if (dfltTokenType) {
1006#ifdef COMMENTARY
1007 fprintf(fout, "\n/*\n * Generated type declarations:\n */\n");
1008#endif
1009 for (ul = tokenSet; ul; ul = ul->next, n++) {
1010 fprintf(fout, "%%type <%s> ", dfltTokenType);
1011 prWord(fout, ul->info.name);
1012 fprintf(fout, "\n");
1013 }
1014 fprintf(fout, "\n");
1015 }
1016
1017 for (dl = phrDefList; dl; dl = dl->next) {
1018 if (dl->name[0] == '`')
1019 continue;
1020 if (dl->argc == 0) {
1021 type = 0;
1022 if (dl->type)
1023 type = dl->type;
1024 else if (dfltRuleType)
1025 type = dfltRuleType;
1026 if (type && strcmp(type, "void")) {
1027 n++;
1028 fprintf(fout, "%%type <%s> %s\n",
1029 type, dl->name);
1030 }
1031 }
1032 else for (ul = genSet; ul; ul = ul->next) {
1033 if (!strcmp(dl->name, ul->info.name)) {
1034 type = 0;
1035 if (dl->type)
1036 type = dl->type;
1037 else if (dfltRuleType)
1038 type = dfltRuleType;
1039 if (type && strcmp(type, "void")) {
1040 n++;
1041 fprintf(fout, "%%type <%s> ", type);
1042 fprintInfo(fout, &(ul->info));
1043 fprintf(fout, "\n");
1044 }
1045 }
1046 }
1047 }
1048 if (n > 0)
1049 fprintf(fout,"\n");
1050}
1051
1052void
1053_2_wholeEpilog()
1054{
1055 while (yylex() != 0) ;
1056
1057 token(TK_Other282, ""); /* Force echo of last token read */
1058}
1059
1060void
1061_2_seeIncludeEnum(char *fname, char *ename)
1062{
1063 EnumItem el, tl;
1064 el = skimEnums(fname, 1, &ename);
1065
1066#ifdef COMMENTARY
1067 fprintf(fout, "\n/*\n * Included token declarations:\n */\n");
1068#endif
1069 for (tl = el; tl; tl = tl->next) {
1070 if (isExtra(tl->id)) continue;
1071 fprintf(fout, "%%token %s%s %d\n", prefix, tl->id, tl->value);
1072 }
1073 fprintf(fout, "\n");
1074
1075 skimFree(el);
1076}
1077
1078void
1079_2_startCommand()
1080{
1081 tokEcho = 0;
1082}
1083
1084void
1085_2_endCommand()
1086{
1087 tokEcho = 1;
1088}
1089
1090void
1091_2_startPhraseName()
1092{
1093}
1094
1095void
1096_2_seeName(char *str)
1097{
1098}
1099
1100void
1101_2_seeArg(char *str)
1102{
1103}
1104
1105void
1106_2_endPhraseName()
1107{
1108}
1109
1110void
1111_2_seeType(char *str)
1112{
1113}
1114
1115void
1116_2_startRule()
1117{
1118 tokEcho = 0;
1119 tokListHead = tokListTail;
1120}
1121
1122void
1123_2_midRule()
1124{
1125}
1126
1127void
1128_2_endRule()
1129{
1130 tokEcho = 1;
1131 handleRule(tokListHead);
3
Calling 'handleRule'
1132}
1133
1134
1135struct tokList *
1136nextMeaty(struct tokList *tl)
1137{
1138 while (tl && (tl->tag == TK_Space263 || tl->tag == TK_Comment262))
1139 tl = tl->next;
1140 return tl;
1141}
1142
1143void
1144emitRule(struct tokList *tl0, struct phrUse *use)
1145{
1146 struct tokList *tl;
1147 char *str;
1148
1149 for (tl = tl0; tl; tl = tl->next) {
1150 if (!tl->show) continue;
1151
1152 str = tl->str;
1153
1154 switch (tl->tag) {
1155 case TK_CTok281:
1156 case TK_Id258: {
1157 if (use) {
1158 int a = unnameBV(str);
1159 if (a >= 0) str = use->info.argv[a];
1160 }
1161 if (*str == '`') str++;
1162 prWord(fout, str);
1163 break;
1164 }
1165 case TK_OPren268:
1166 case TK_Comma266:
1167 case TK_CPren269:
1168 fprintf(fout, "_");
1169 break;
1170 default:
1171 fprintf(fout, "%s", str);
1172 }
1173 }
1174}
1175
1176
1177void
1178handleRule(struct tokList *tl0)
1179{
1180 struct tokList *tl;
1181 struct phrInfo info;
1182 struct phrUse *ul;
1183 int inAppl, inType; /* For removing words */
1184 int n;
1185
1186 /*
1187 * Preprocess:
1188 * 1. Remove type decl as well as spaces and comments within
1189 * metarule applications.
1190 * 2. Rename bound variables to standard names.
1191 */
1192
1193 inAppl = inType = 0;
1194 for (tl = tl0; tl; tl = tl->next) {
4
Loop condition is true. Entering loop body
11
Loop condition is true. Entering loop body
18
Loop condition is true. Entering loop body
25
Loop condition is false. Execution continues on line 1218
1195 if (tl->tag == TK_Id258) {
5
Assuming field 'tag' is equal to TK_Id
6
Taking true branch
12
Assuming field 'tag' is equal to TK_Id
13
Taking true branch
19
Assuming field 'tag' is equal to TK_Id
20
Taking true branch
1196 struct tokList *tn = nextMeaty(tl->next);
1197 inAppl = inAppl
6.1
'inAppl' is 0
13.1
'inAppl' is 0
20.1
'inAppl' is 0
|| (tn
6.2
'tn' is non-null
13.2
'tn' is non-null
&& tn->tag == TK_OPren268);
7
Assuming field 'tag' is not equal to TK_OPren
14
Assuming field 'tag' is not equal to TK_OPren
21
Assuming 'tn' is null
1198 }
1199 else if (tl->tag == TK_OAngle272) {
1200 inType = 1;
1201 }
1202
1203 if (inAppl
7.1
'inAppl' is 0
14.1
'inAppl' is 0
21.1
'inAppl' is 0
&& (tl->tag == TK_Comment262 || tl->tag == TK_Space263))
1204 tl->show = 0;
1205 else if (inType
7.2
'inType' is 0
14.2
'inType' is 0
21.2
'inType' is 0
)
8
Taking false branch
15
Taking false branch
22
Taking false branch
1206 tl->show = 0;
1207 else
1208 tl->show = 1;
1209
1210 if (tl->tag
8.1
Field 'tag' is not equal to TK_CPren
15.1
Field 'tag' is not equal to TK_CPren
22.1
Field 'tag' is not equal to TK_CPren
== TK_CPren269) {
9
Taking false branch
16
Taking false branch
23
Taking false branch
1211 inAppl = 0;
1212 }
1213 else if (tl->tag
9.1
Field 'tag' is not equal to TK_CAngle
16.1
Field 'tag' is not equal to TK_CAngle
23.1
Field 'tag' is not equal to TK_CAngle
== TK_CAngle273) {
10
Taking false branch
17
Taking false branch
24
Taking false branch
1214 inType = 0;
1215 }
1216 }
1217
1218 info.name = 0;
1219 info.argc = 0;
1220
1221 for (tl = tl0; tl; tl = tl->next) {
26
Loop condition is true. Entering loop body
30
Loop condition is true. Entering loop body
35
Loop condition is true. Entering loop body
40
Loop condition is false. Execution continues on line 1234
1222 if (!tl->show
26.1
Field 'show' is 1
30.1
Field 'show' is 1
35.1
Field 'show' is 1
)
27
Taking false branch
31
Taking false branch
36
Taking false branch
1223 continue;
1224 if (tl->tag
27.1
Field 'tag' is equal to TK_Id
31.1
Field 'tag' is equal to TK_Id
36.1
Field 'tag' is equal to TK_Id
== TK_Id258) {
28
Taking true branch
32
Taking true branch
37
Taking true branch
1225 if (!info.name
28.1
Field 'name' is null
)
29
Taking true branch
33
Assuming field 'name' is null
34
Taking true branch
38
Assuming field 'name' is non-null
39
Taking false branch
1226 info.name = tl->str;
1227 else
1228 info.argv[info.argc++] = tl->str;
1229 }
1230 else if (tl->tag == TK_Colon264)
1231 break;
1232 }
1233
1234 for (tl = tl0; tl; tl = tl->next) {
1235 if (tl->tag
40.1
Field 'tag' is equal to TK_Id
== TK_Id258 || tl->tag == TK_CTok281)
1236 tl->str = renameBV(tl->str, &info);
41
Passing null pointer value via 1st parameter 'str'
42
Calling 'renameBV'
1237 }
1238
1239 /*
1240 * Emit rule instances.
1241 */
1242
1243 if (info.argc == 0) {
1244 emitRule(tl0, 0);
1245 }
1246 else for (n = 0, ul = genSet; ul; n++, ul = ul->next) {
1247 if (!strcmp(info.name, ul->info.name)) {
1248 if (n != 0) fprintf(fout, "\n");
1249 emitRule(tl0, ul);
1250 }
1251 }
1252}
1253
1254/*****************************************************************************
1255 *
1256 * :: Utilities
1257 *
1258 *****************************************************************************/
1259
1260char *
1261mustAlloc(int n)
1262{
1263 /*extern char *malloc();*/
1264 char *s;
1265 s = malloc(n);
1266 if (!s) fatalErr();
1267 return s;
1268}
1269
1270char *
1271strAlloc(char *str)
1272{
1273 return strcpy(mustAlloc(strlen(str) + 1), str);
1274}
1275
1276char *
1277fnameDir(char *fn)
1278{
1279 int i, n, slashPos;
1280 char *d;
1281
1282 n = strlen(fn);
1283 slashPos = -1;
1284 for (i = n-1; i >= 0 && slashPos == -1; i--)
1285 if (fn[i] == '/') slashPos = i;
1286
1287 if (slashPos == -1)
1288 d = strAlloc(".");
1289 else {
1290 d = mustAlloc(slashPos+1);
1291 strncpy(d, fn, slashPos);
1292 d[slashPos] = 0;
1293 }
1294 return d;
1295}
1296
1297FILE *
1298mustOpen(char *fname, char *mode)
1299{
1300 FILE *f;
1301 f = fopen(fname, mode);
1302 if (!f) fatalErr();
1303 return f;
1304}
1305
1306char *
1307timeNow()
1308{
1309 char *s;
1310 long t;
1311
1312 t = time(0);
1313 s = ctime(&t);
1314
1315 s[strlen(s)-1] = 0;
1316 return s;
1317}
1318
1319void
1320fatalErr()
1321{
1322#if 0
1323 va_list argp;
1324#endif
1325
1326 fprintf(stderrstderr, "zacc (fatal error): ");
1327#if 0
1328 va_start(argp, fmt)__builtin_va_start(argp, fmt);
1329 vfprintf(stderrstderr, fmt, argp);
1330 va_end(argp)__builtin_va_end(argp);
1331#endif
1332 fprintf(stderrstderr, "\n");
1333
1334 exit(3);
1335}