xref: /minix/external/bsd/byacc/dist/main.c (revision 84d9c625)
1 /*	$NetBSD: main.c,v 1.8 2013/04/06 14:52:24 christos Exp $	*/
2 
3 #include "defs.h"
4 
5 #include <sys/cdefs.h>
6 __RCSID("$NetBSD: main.c,v 1.8 2013/04/06 14:52:24 christos Exp $");
7 /* Id: main.c,v 1.40 2012/09/29 13:11:00 Adrian.Bunk Exp  */
8 
9 #include <signal.h>
10 #include <unistd.h>		/* for _exit() */
11 
12 
13 #ifdef HAVE_MKSTEMP
14 # define USE_MKSTEMP 1
15 #elif defined(HAVE_FCNTL_H)
16 # define USE_MKSTEMP 1
17 # include <fcntl.h>		/* for open(), O_EXCL, etc. */
18 #else
19 # define USE_MKSTEMP 0
20 #endif
21 
22 #if USE_MKSTEMP
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 
26 typedef struct _my_tmpfiles
27 {
28     struct _my_tmpfiles *next;
29     char *name;
30 }
31 MY_TMPFILES;
32 
33 static MY_TMPFILES *my_tmpfiles;
34 #endif /* USE_MKSTEMP */
35 
36 char dflag;
37 char gflag;
38 char iflag;
39 char lflag;
40 static char oflag;
41 char rflag;
42 char sflag;
43 char tflag;
44 char vflag;
45 
46 const char *symbol_prefix;
47 const char *myname = "yacc";
48 
49 int lineno;
50 int outline;
51 
52 static char empty_string[] = "";
53 static char default_file_prefix[] = "y";
54 static int explicit_file_name;
55 
56 static char *file_prefix = default_file_prefix;
57 
58 char *code_file_name;
59 char *input_file_name = empty_string;
60 char *defines_file_name;
61 char *externs_file_name;
62 
63 static char *graph_file_name;
64 static char *output_file_name;
65 static char *verbose_file_name;
66 
67 FILE *action_file;	/*  a temp file, used to save actions associated    */
68 			/*  with rules until the parser is written          */
69 FILE *code_file;	/*  y.code.c (used when the -r option is specified) */
70 FILE *defines_file;	/*  y.tab.h                                         */
71 FILE *externs_file;	/*  y.tab.i                                         */
72 FILE *input_file;	/*  the input file                                  */
73 FILE *output_file;	/*  y.tab.c                                         */
74 FILE *text_file;	/*  a temp file, used to save text until all        */
75 			/*  symbols have been defined                       */
76 FILE *union_file;	/*  a temp file, used to save the union             */
77 			/*  definition until all symbol have been           */
78 			/*  defined                                         */
79 FILE *verbose_file;	/*  y.output                                        */
80 FILE *graph_file;	/*  y.dot                                           */
81 
82 int nitems;
83 int nrules;
84 int nsyms;
85 int ntokens;
86 int nvars;
87 
88 Value_t start_symbol;
89 char **symbol_name;
90 char **symbol_pname;
91 Value_t *symbol_value;
92 short *symbol_prec;
93 char *symbol_assoc;
94 
95 int pure_parser;
96 int exit_code;
97 
98 Value_t *ritem;
99 Value_t *rlhs;
100 Value_t *rrhs;
101 Value_t *rprec;
102 Assoc_t *rassoc;
103 Value_t **derives;
104 char *nullable;
105 
106 /*
107  * Since fclose() is called via the signal handler, it might die.  Don't loop
108  * if there is a problem closing a file.
109  */
110 #define DO_CLOSE(fp) \
111 	if (fp != 0) { \
112 	    FILE *use = fp; \
113 	    fp = 0; \
114 	    fclose(use); \
115 	}
116 
117 static int got_intr = 0;
118 
119 void
120 done(int k)
121 {
122     DO_CLOSE(input_file);
123     DO_CLOSE(output_file);
124 
125     DO_CLOSE(action_file);
126     DO_CLOSE(defines_file);
127     DO_CLOSE(graph_file);
128     DO_CLOSE(text_file);
129     DO_CLOSE(union_file);
130     DO_CLOSE(verbose_file);
131 
132     if (got_intr)
133 	_exit(EXIT_FAILURE);
134 
135 #ifdef NO_LEAKS
136     if (rflag)
137 	DO_FREE(code_file_name);
138 
139     if (dflag)
140 	DO_FREE(defines_file_name);
141 
142     if (iflag)
143 	DO_FREE(externs_file_name);
144 
145     if (oflag)
146 	DO_FREE(output_file_name);
147 
148     if (vflag)
149 	DO_FREE(verbose_file_name);
150 
151     if (gflag)
152 	DO_FREE(graph_file_name);
153 
154     lr0_leaks();
155     lalr_leaks();
156     mkpar_leaks();
157     output_leaks();
158     reader_leaks();
159 #endif
160 
161     if (rflag)
162 	DO_CLOSE(code_file);
163 
164     exit(k);
165 }
166 
167 static void
168 onintr(int sig GCC_UNUSED)
169 {
170     got_intr = 1;
171     done(EXIT_FAILURE);
172 }
173 
174 static void
175 set_signals(void)
176 {
177 #ifdef SIGINT
178     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
179 	signal(SIGINT, onintr);
180 #endif
181 #ifdef SIGTERM
182     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
183 	signal(SIGTERM, onintr);
184 #endif
185 #ifdef SIGHUP
186     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
187 	signal(SIGHUP, onintr);
188 #endif
189 }
190 
191 static void
192 usage(void)
193 {
194     static const char *msg[] =
195     {
196 	""
197 	,"Options:"
198 	,"  -b file_prefix        set filename prefix (default \"y.\")"
199 	,"  -d                    write definitions (y.tab.h)"
200 	,"  -i                    write interface (y.tab.i)"
201 	,"  -g                    write a graphical description"
202 	,"  -l                    suppress #line directives"
203 	,"  -o output_file        (default \"y.tab.c\")"
204 	,"  -p symbol_prefix      set symbol prefix (default \"yy\")"
205 	,"  -P                    create a reentrant parser, e.g., \"%pure-parser\""
206 	,"  -r                    produce separate code and table files (y.code.c)"
207 	,"  -s                    suppress #define's for quoted names in %token lines"
208 	,"  -t                    add debugging support"
209 	,"  -v                    write description (y.output)"
210 	,"  -V                    show version information and exit"
211     };
212     unsigned n;
213 
214     fflush(stdout);
215     fprintf(stderr, "Usage: %s [options] filename\n", myname);
216     for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n)
217 	fprintf(stderr, "%s\n", msg[n]);
218 
219     exit(1);
220 }
221 
222 static void
223 setflag(int ch)
224 {
225     switch (ch)
226     {
227     case 'd':
228 	dflag = 1;
229 	break;
230 
231     case 'g':
232 	gflag = 1;
233 	break;
234 
235     case 'i':
236 	iflag = 1;
237 	break;
238 
239     case 'l':
240 	lflag = 1;
241 	break;
242 
243     case 'P':
244 	pure_parser = 1;
245 	break;
246 
247     case 'r':
248 	rflag = 1;
249 	break;
250 
251     case 's':
252 	sflag = 1;
253 	break;
254 
255     case 't':
256 	tflag = 1;
257 	break;
258 
259     case 'v':
260 	vflag = 1;
261 	break;
262 
263     case 'V':
264 	printf("%s - %s\n", myname, VERSION);
265 	exit(EXIT_SUCCESS);
266 
267     case 'y':
268 	/* noop for bison compatibility. byacc is already designed to be posix
269 	 * yacc compatible. */
270 	break;
271 
272     default:
273 	usage();
274     }
275 }
276 
277 static void
278 getargs(int argc, char *argv[])
279 {
280     int i;
281     char *s;
282     int ch;
283 
284     if (argc > 0)
285 	myname = argv[0];
286 
287     for (i = 1; i < argc; ++i)
288     {
289 	s = argv[i];
290 	if (*s != '-')
291 	    break;
292 	switch (ch = *++s)
293 	{
294 	case '\0':
295 	    input_file = stdin;
296 	    if (i + 1 < argc)
297 		usage();
298 	    return;
299 
300 	case '-':
301 	    ++i;
302 	    goto no_more_options;
303 
304 	case 'b':
305 	    if (*++s)
306 		file_prefix = s;
307 	    else if (++i < argc)
308 		file_prefix = argv[i];
309 	    else
310 		usage();
311 	    continue;
312 
313 	case 'o':
314 	    if (*++s)
315 		output_file_name = s;
316 	    else if (++i < argc)
317 		output_file_name = argv[i];
318 	    else
319 		usage();
320 	    explicit_file_name = 1;
321 	    continue;
322 
323 	case 'p':
324 	    if (*++s)
325 		symbol_prefix = s;
326 	    else if (++i < argc)
327 		symbol_prefix = argv[i];
328 	    else
329 		usage();
330 	    continue;
331 
332 	default:
333 	    setflag(ch);
334 	    break;
335 	}
336 
337 	for (;;)
338 	{
339 	    switch (ch = *++s)
340 	    {
341 	    case '\0':
342 		goto end_of_option;
343 
344 	    default:
345 		setflag(ch);
346 		break;
347 	    }
348 	}
349       end_of_option:;
350     }
351 
352   no_more_options:;
353     if (i + 1 != argc)
354 	usage();
355     input_file_name = argv[i];
356 }
357 
358 void *
359 allocate(size_t n)
360 {
361     void *p;
362 
363     p = NULL;
364     if (n)
365     {
366 	p = CALLOC(1, n);
367 	NO_SPACE(p);
368     }
369     return (p);
370 }
371 
372 #define CREATE_FILE_NAME(dest, suffix) \
373 	dest = TMALLOC(char, len + strlen(suffix) + 1); \
374 	NO_SPACE(dest); \
375 	strcpy(dest, file_prefix); \
376 	strcpy(dest + len, suffix)
377 
378 static void
379 create_file_names(void)
380 {
381     size_t len;
382     const char *defines_suffix;
383     const char *externs_suffix;
384     char *prefix;
385 
386     prefix = NULL;
387     defines_suffix = DEFINES_SUFFIX;
388     externs_suffix = EXTERNS_SUFFIX;
389 
390     /* compute the file_prefix from the user provided output_file_name */
391     if (output_file_name != 0)
392     {
393 	if (!(prefix = strstr(output_file_name, ".tab.c"))
394 	    && (prefix = strstr(output_file_name, ".c")))
395 	{
396 	    defines_suffix = ".h";
397 	    externs_suffix = ".i";
398 	}
399     }
400 
401     if (prefix != NULL)
402     {
403 	len = (size_t) (prefix - output_file_name);
404 	file_prefix = TMALLOC(char, len + 1);
405 	NO_SPACE(file_prefix);
406 	strncpy(file_prefix, output_file_name, len)[len] = 0;
407     }
408     else
409 	len = strlen(file_prefix);
410 
411     /* if "-o filename" was not given */
412     if (output_file_name == 0)
413     {
414 	oflag = 1;
415 	CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX);
416     }
417 
418     if (rflag)
419     {
420 	CREATE_FILE_NAME(code_file_name, CODE_SUFFIX);
421     }
422     else
423 	code_file_name = output_file_name;
424 
425     if (dflag)
426     {
427 	if (explicit_file_name)
428 	{
429 	    char *suffix;
430 	    defines_file_name = strdup(output_file_name);
431 	    if (defines_file_name == 0)
432 		no_space();
433 	    /* does the output_file_name have a known suffix */
434             suffix = strrchr(output_file_name, '.');
435             if (suffix != 0 &&
436 		(!strcmp(suffix, ".c") ||   /* good, old-fashioned C */
437                  !strcmp(suffix, ".C") ||   /* C++, or C on Windows */
438                  !strcmp(suffix, ".cc") ||  /* C++ */
439                  !strcmp(suffix, ".cxx") || /* C++ */
440                  !strcmp(suffix, ".cpp")))  /* C++ (Windows) */
441             {
442                 strncpy(defines_file_name, output_file_name,
443                         suffix - output_file_name + 1);
444                 defines_file_name[suffix - output_file_name + 1] = 'h';
445                 defines_file_name[suffix - output_file_name + 2] = 0;
446             } else {
447                 fprintf(stderr,"%s: suffix of output file name %s"
448                                " not recognized, no -d file generated.\n",
449                         myname, output_file_name);
450                 dflag = 0;
451                 free(defines_file_name);
452                 defines_file_name = 0;
453             }
454 	} else {
455 	    CREATE_FILE_NAME(defines_file_name, defines_suffix);
456 	}
457     }
458 
459     if (iflag)
460     {
461 	CREATE_FILE_NAME(externs_file_name, externs_suffix);
462     }
463 
464     if (vflag)
465     {
466 	CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX);
467     }
468 
469     if (gflag)
470     {
471 	CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX);
472     }
473 
474     if (prefix != NULL)
475     {
476 	FREE(file_prefix);
477     }
478 }
479 
480 #if USE_MKSTEMP
481 static void
482 close_tmpfiles(void)
483 {
484     while (my_tmpfiles != 0)
485     {
486 	MY_TMPFILES *next = my_tmpfiles->next;
487 
488 	chmod(my_tmpfiles->name, 0644);
489 	unlink(my_tmpfiles->name);
490 
491 	free(my_tmpfiles->name);
492 	free(my_tmpfiles);
493 
494 	my_tmpfiles = next;
495     }
496 }
497 
498 #ifndef HAVE_MKSTEMP
499 static int
500 my_mkstemp(char *temp)
501 {
502     int fd;
503     char *dname;
504     char *fname;
505     char *name;
506 
507     /*
508      * Split-up to use tempnam, rather than tmpnam; the latter (like
509      * mkstemp) is unusable on Windows.
510      */
511     if ((fname = strrchr(temp, '/')) != 0)
512     {
513 	dname = strdup(temp);
514 	dname[++fname - temp] = '\0';
515     }
516     else
517     {
518 	dname = 0;
519 	fname = temp;
520     }
521     if ((name = tempnam(dname, fname)) != 0)
522     {
523 	fd = open(name, O_CREAT | O_EXCL | O_RDWR);
524 	strcpy(temp, name);
525     }
526     else
527     {
528 	fd = -1;
529     }
530 
531     if (dname != 0)
532 	free(dname);
533 
534     return fd;
535 }
536 #define mkstemp(s) my_mkstemp(s)
537 #endif
538 
539 #endif
540 
541 /*
542  * tmpfile() should be adequate, except that it may require special privileges
543  * to use, e.g., MinGW and Windows 7 where it tries to use the root directory.
544  */
545 static FILE *
546 open_tmpfile(const char *label)
547 {
548     FILE *result;
549 #if USE_MKSTEMP
550     int fd;
551     const char *tmpdir;
552     char *name;
553     const char *mark;
554 
555     if ((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0)
556     {
557 #ifdef P_tmpdir
558 	tmpdir = P_tmpdir;
559 #else
560 	tmpdir = "/tmp";
561 #endif
562 	if (access(tmpdir, W_OK) != 0)
563 	    tmpdir = ".";
564     }
565 
566     name = malloc(strlen(tmpdir) + 10 + strlen(label));
567 
568     result = 0;
569     if (name != 0)
570     {
571 	if ((mark = strrchr(label, '_')) == 0)
572 	    mark = label + strlen(label);
573 
574 	sprintf(name, "%s/%.*sXXXXXX", tmpdir, (int)(mark - label), label);
575 	fd = mkstemp(name);
576 	if (fd >= 0)
577 	{
578 	    result = fdopen(fd, "w+");
579 	    if (result != 0)
580 	    {
581 		MY_TMPFILES *item;
582 
583 		if (my_tmpfiles == 0)
584 		{
585 		    atexit(close_tmpfiles);
586 		}
587 
588 		item = NEW(MY_TMPFILES);
589 		NO_SPACE(item);
590 
591 		item->name = name;
592 		NO_SPACE(item->name);
593 
594 		item->next = my_tmpfiles;
595 		my_tmpfiles = item;
596 	    }
597 	}
598     }
599 #else
600     result = tmpfile();
601 #endif
602 
603     if (result == 0)
604 	open_error(label);
605     return result;
606 }
607 
608 static void
609 open_files(void)
610 {
611     create_file_names();
612 
613     if (input_file == 0)
614     {
615 	input_file = fopen(input_file_name, "r");
616 	if (input_file == 0)
617 	    open_error(input_file_name);
618     }
619 
620     action_file = open_tmpfile("action_file");
621     text_file = open_tmpfile("text_file");
622 
623     if (vflag)
624     {
625 	verbose_file = fopen(verbose_file_name, "w");
626 	if (verbose_file == 0)
627 	    open_error(verbose_file_name);
628     }
629 
630     if (gflag)
631     {
632 	graph_file = fopen(graph_file_name, "w");
633 	if (graph_file == 0)
634 	    open_error(graph_file_name);
635 	fprintf(graph_file, "digraph %s {\n", file_prefix);
636 	fprintf(graph_file, "\tedge [fontsize=10];\n");
637 	fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n");
638 	fprintf(graph_file, "\torientation=landscape;\n");
639 	fprintf(graph_file, "\trankdir=LR;\n");
640 	fprintf(graph_file, "\t/*\n");
641 	fprintf(graph_file, "\tmargin=0.2;\n");
642 	fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n");
643 	fprintf(graph_file, "\tratio=auto;\n");
644 	fprintf(graph_file, "\t*/\n");
645     }
646 
647     if (dflag)
648     {
649 	defines_file = fopen(defines_file_name, "w");
650 	if (defines_file == 0)
651 	    open_error(defines_file_name);
652 	union_file = open_tmpfile("union_file");
653     }
654 
655     if (iflag)
656     {
657 	externs_file = fopen(externs_file_name, "w");
658 	if (externs_file == 0)
659 	    open_error(externs_file_name);
660     }
661 
662     output_file = fopen(output_file_name, "w");
663     if (output_file == 0)
664 	open_error(output_file_name);
665 
666     if (rflag)
667     {
668 	code_file = fopen(code_file_name, "w");
669 	if (code_file == 0)
670 	    open_error(code_file_name);
671     }
672     else
673 	code_file = output_file;
674 }
675 
676 int
677 main(int argc, char *argv[])
678 {
679     SRexpect = -1;
680     RRexpect = -1;
681     exit_code = EXIT_SUCCESS;
682 
683     set_signals();
684     getargs(argc, argv);
685     open_files();
686     reader();
687     lr0();
688     lalr();
689     make_parser();
690     graph();
691     finalize_closure();
692     verbose();
693     output();
694     done(exit_code);
695     /*NOTREACHED */
696 }
697