1319349Sjkim/* $Id: main.c,v 1.59 2017/02/02 00:44:38 tom Exp $ */
2234949Sbapt
3234949Sbapt#include <signal.h>
4264803Sbapt#ifndef _WIN32
5234949Sbapt#include <unistd.h>		/* for _exit() */
6264803Sbapt#else
7264803Sbapt#include <stdlib.h>		/* for _exit() */
8264803Sbapt#endif
9234949Sbapt
10234949Sbapt#include "defs.h"
11234949Sbapt
12251143Sbapt#ifdef HAVE_MKSTEMP
13251143Sbapt# define USE_MKSTEMP 1
14251143Sbapt#elif defined(HAVE_FCNTL_H)
15251143Sbapt# define USE_MKSTEMP 1
16251143Sbapt# include <fcntl.h>		/* for open(), O_EXCL, etc. */
17234949Sbapt#else
18234949Sbapt# define USE_MKSTEMP 0
19234949Sbapt#endif
20234949Sbapt
21234949Sbapt#if USE_MKSTEMP
22234949Sbapt#include <sys/types.h>
23234949Sbapt#include <sys/stat.h>
24234949Sbapt
25234949Sbapttypedef struct _my_tmpfiles
26234949Sbapt{
27234949Sbapt    struct _my_tmpfiles *next;
28234949Sbapt    char *name;
29234949Sbapt}
30234949SbaptMY_TMPFILES;
31234949Sbapt
32234949Sbaptstatic MY_TMPFILES *my_tmpfiles;
33234949Sbapt#endif /* USE_MKSTEMP */
34234949Sbapt
35234949Sbaptchar dflag;
36234949Sbaptchar gflag;
37234949Sbaptchar iflag;
38234949Sbaptchar lflag;
39234949Sbaptstatic char oflag;
40234949Sbaptchar rflag;
41234949Sbaptchar sflag;
42234949Sbaptchar tflag;
43234949Sbaptchar vflag;
44234949Sbapt
45234949Sbaptconst char *symbol_prefix;
46234949Sbaptconst char *myname = "yacc";
47234949Sbapt
48234949Sbaptint lineno;
49234949Sbaptint outline;
50234949Sbapt
51234949Sbaptstatic char default_file_prefix[] = "y";
52234949Sbapt
53234949Sbaptstatic char *file_prefix = default_file_prefix;
54234949Sbapt
55234949Sbaptchar *code_file_name;
56319349Sjkimchar *input_file_name;
57319349Sjkimsize_t input_file_name_len = 0;
58234949Sbaptchar *defines_file_name;
59234949Sbaptchar *externs_file_name;
60234949Sbapt
61234949Sbaptstatic char *graph_file_name;
62234949Sbaptstatic char *output_file_name;
63234949Sbaptstatic char *verbose_file_name;
64234949Sbapt
65234949SbaptFILE *action_file;	/*  a temp file, used to save actions associated    */
66234949Sbapt			/*  with rules until the parser is written          */
67234949SbaptFILE *code_file;	/*  y.code.c (used when the -r option is specified) */
68234949SbaptFILE *defines_file;	/*  y.tab.h                                         */
69234949SbaptFILE *externs_file;	/*  y.tab.i                                         */
70234949SbaptFILE *input_file;	/*  the input file                                  */
71234949SbaptFILE *output_file;	/*  y.tab.c                                         */
72234949SbaptFILE *text_file;	/*  a temp file, used to save text until all        */
73234949Sbapt			/*  symbols have been defined                       */
74234949SbaptFILE *union_file;	/*  a temp file, used to save the union             */
75234949Sbapt			/*  definition until all symbol have been           */
76234949Sbapt			/*  defined                                         */
77234949SbaptFILE *verbose_file;	/*  y.output                                        */
78234949SbaptFILE *graph_file;	/*  y.dot                                           */
79234949Sbapt
80264803SbaptValue_t nitems;
81264803SbaptValue_t nrules;
82264803SbaptValue_t nsyms;
83264803SbaptValue_t ntokens;
84264803SbaptValue_t nvars;
85234949Sbapt
86234949SbaptValue_t start_symbol;
87234949Sbaptchar **symbol_name;
88234949Sbaptchar **symbol_pname;
89234949SbaptValue_t *symbol_value;
90264803SbaptValue_t *symbol_prec;
91234949Sbaptchar *symbol_assoc;
92234949Sbapt
93234949Sbaptint pure_parser;
94260445Sbaptint token_table;
95319297Sdelphijint error_verbose;
96264803Sbapt
97264803Sbapt#if defined(YYBTYACC)
98264803SbaptValue_t *symbol_pval;
99264803Sbaptchar **symbol_destructor;
100264803Sbaptchar **symbol_type_tag;
101264803Sbaptint locations = 0;	/* default to no position processing */
102264803Sbaptint backtrack = 0;	/* default is no backtracking */
103319297Sdelphijchar *initial_action = NULL;
104264803Sbapt#endif
105264803Sbapt
106234949Sbaptint exit_code;
107234949Sbapt
108234949SbaptValue_t *ritem;
109234949SbaptValue_t *rlhs;
110234949SbaptValue_t *rrhs;
111234949SbaptValue_t *rprec;
112234949SbaptAssoc_t *rassoc;
113234949SbaptValue_t **derives;
114234949Sbaptchar *nullable;
115234949Sbapt
116234949Sbapt/*
117234949Sbapt * Since fclose() is called via the signal handler, it might die.  Don't loop
118234949Sbapt * if there is a problem closing a file.
119234949Sbapt */
120234949Sbapt#define DO_CLOSE(fp) \
121234949Sbapt	if (fp != 0) { \
122234949Sbapt	    FILE *use = fp; \
123234949Sbapt	    fp = 0; \
124234949Sbapt	    fclose(use); \
125234949Sbapt	}
126234949Sbapt
127234949Sbaptstatic int got_intr = 0;
128234949Sbapt
129234949Sbaptvoid
130234949Sbaptdone(int k)
131234949Sbapt{
132234949Sbapt    DO_CLOSE(input_file);
133234949Sbapt    DO_CLOSE(output_file);
134264803Sbapt    if (iflag)
135264803Sbapt	DO_CLOSE(externs_file);
136264803Sbapt    if (rflag)
137264803Sbapt	DO_CLOSE(code_file);
138234949Sbapt
139234949Sbapt    DO_CLOSE(action_file);
140234949Sbapt    DO_CLOSE(defines_file);
141234949Sbapt    DO_CLOSE(graph_file);
142234949Sbapt    DO_CLOSE(text_file);
143234949Sbapt    DO_CLOSE(union_file);
144234949Sbapt    DO_CLOSE(verbose_file);
145234949Sbapt
146234949Sbapt    if (got_intr)
147234949Sbapt	_exit(EXIT_FAILURE);
148234949Sbapt
149234949Sbapt#ifdef NO_LEAKS
150234949Sbapt    if (rflag)
151234949Sbapt	DO_FREE(code_file_name);
152234949Sbapt
153234949Sbapt    if (dflag)
154234949Sbapt	DO_FREE(defines_file_name);
155234949Sbapt
156234949Sbapt    if (iflag)
157234949Sbapt	DO_FREE(externs_file_name);
158234949Sbapt
159234949Sbapt    if (oflag)
160234949Sbapt	DO_FREE(output_file_name);
161234949Sbapt
162234949Sbapt    if (vflag)
163234949Sbapt	DO_FREE(verbose_file_name);
164234949Sbapt
165234949Sbapt    if (gflag)
166234949Sbapt	DO_FREE(graph_file_name);
167234949Sbapt
168234949Sbapt    lr0_leaks();
169234949Sbapt    lalr_leaks();
170234949Sbapt    mkpar_leaks();
171266639Sbapt    mstring_leaks();
172234949Sbapt    output_leaks();
173234949Sbapt    reader_leaks();
174234949Sbapt#endif
175234949Sbapt
176234949Sbapt    exit(k);
177234949Sbapt}
178234949Sbapt
179234949Sbaptstatic void
180240517Sbaptonintr(int sig GCC_UNUSED)
181234949Sbapt{
182234949Sbapt    got_intr = 1;
183234949Sbapt    done(EXIT_FAILURE);
184234949Sbapt}
185234949Sbapt
186234949Sbaptstatic void
187234949Sbaptset_signals(void)
188234949Sbapt{
189234949Sbapt#ifdef SIGINT
190234949Sbapt    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
191234949Sbapt	signal(SIGINT, onintr);
192234949Sbapt#endif
193234949Sbapt#ifdef SIGTERM
194234949Sbapt    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
195234949Sbapt	signal(SIGTERM, onintr);
196234949Sbapt#endif
197234949Sbapt#ifdef SIGHUP
198234949Sbapt    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
199234949Sbapt	signal(SIGHUP, onintr);
200234949Sbapt#endif
201234949Sbapt}
202234949Sbapt
203234949Sbaptstatic void
204234949Sbaptusage(void)
205234949Sbapt{
206234949Sbapt    static const char *msg[] =
207234949Sbapt    {
208234949Sbapt	""
209234949Sbapt	,"Options:"
210234949Sbapt	,"  -b file_prefix        set filename prefix (default \"y.\")"
211264803Sbapt	,"  -B                    create a backtracking parser"
212264803Sbapt	,"  -d                    write definitions (" DEFINES_SUFFIX ")"
213234949Sbapt	,"  -i                    write interface (y.tab.i)"
214234949Sbapt	,"  -g                    write a graphical description"
215234949Sbapt	,"  -l                    suppress #line directives"
216264803Sbapt	,"  -L                    enable position processing, e.g., \"%locations\""
217264803Sbapt	,"  -o output_file        (default \"" OUTPUT_SUFFIX "\")"
218234949Sbapt	,"  -p symbol_prefix      set symbol prefix (default \"yy\")"
219234949Sbapt	,"  -P                    create a reentrant parser, e.g., \"%pure-parser\""
220234949Sbapt	,"  -r                    produce separate code and table files (y.code.c)"
221234949Sbapt	,"  -s                    suppress #define's for quoted names in %token lines"
222234949Sbapt	,"  -t                    add debugging support"
223234949Sbapt	,"  -v                    write description (y.output)"
224234949Sbapt	,"  -V                    show version information and exit"
225234949Sbapt    };
226234949Sbapt    unsigned n;
227234949Sbapt
228234949Sbapt    fflush(stdout);
229234949Sbapt    fprintf(stderr, "Usage: %s [options] filename\n", myname);
230234949Sbapt    for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n)
231234949Sbapt	fprintf(stderr, "%s\n", msg[n]);
232234949Sbapt
233234949Sbapt    exit(1);
234234949Sbapt}
235234949Sbapt
236234949Sbaptstatic void
237234949Sbaptsetflag(int ch)
238234949Sbapt{
239234949Sbapt    switch (ch)
240234949Sbapt    {
241264803Sbapt    case 'B':
242264803Sbapt#if defined(YYBTYACC)
243264803Sbapt	backtrack = 1;
244264803Sbapt#else
245264803Sbapt	unsupported_flag_warning("-B", "reconfigure with --enable-btyacc");
246264803Sbapt#endif
247264803Sbapt	break;
248264803Sbapt
249234949Sbapt    case 'd':
250234949Sbapt	dflag = 1;
251234949Sbapt	break;
252234949Sbapt
253234949Sbapt    case 'g':
254234949Sbapt	gflag = 1;
255234949Sbapt	break;
256234949Sbapt
257234949Sbapt    case 'i':
258234949Sbapt	iflag = 1;
259234949Sbapt	break;
260234949Sbapt
261234949Sbapt    case 'l':
262234949Sbapt	lflag = 1;
263234949Sbapt	break;
264234949Sbapt
265264803Sbapt    case 'L':
266264803Sbapt#if defined(YYBTYACC)
267264803Sbapt	locations = 1;
268264803Sbapt#else
269264803Sbapt	unsupported_flag_warning("-B", "reconfigure with --enable-btyacc");
270264803Sbapt#endif
271264803Sbapt	break;
272264803Sbapt
273234949Sbapt    case 'P':
274234949Sbapt	pure_parser = 1;
275234949Sbapt	break;
276234949Sbapt
277234949Sbapt    case 'r':
278234949Sbapt	rflag = 1;
279234949Sbapt	break;
280234949Sbapt
281234949Sbapt    case 's':
282234949Sbapt	sflag = 1;
283234949Sbapt	break;
284234949Sbapt
285234949Sbapt    case 't':
286234949Sbapt	tflag = 1;
287234949Sbapt	break;
288234949Sbapt
289234949Sbapt    case 'v':
290234949Sbapt	vflag = 1;
291234949Sbapt	break;
292234949Sbapt
293234949Sbapt    case 'V':
294234949Sbapt	printf("%s - %s\n", myname, VERSION);
295234949Sbapt	exit(EXIT_SUCCESS);
296234949Sbapt
297234949Sbapt    case 'y':
298234949Sbapt	/* noop for bison compatibility. byacc is already designed to be posix
299234949Sbapt	 * yacc compatible. */
300234949Sbapt	break;
301234949Sbapt
302234949Sbapt    default:
303234949Sbapt	usage();
304234949Sbapt    }
305234949Sbapt}
306234949Sbapt
307234949Sbaptstatic void
308234949Sbaptgetargs(int argc, char *argv[])
309234949Sbapt{
310234949Sbapt    int i;
311234949Sbapt    char *s;
312234949Sbapt    int ch;
313234949Sbapt
314234949Sbapt    if (argc > 0)
315234949Sbapt	myname = argv[0];
316234949Sbapt
317234949Sbapt    for (i = 1; i < argc; ++i)
318234949Sbapt    {
319234949Sbapt	s = argv[i];
320234949Sbapt	if (*s != '-')
321234949Sbapt	    break;
322234949Sbapt	switch (ch = *++s)
323234949Sbapt	{
324234949Sbapt	case '\0':
325234949Sbapt	    input_file = stdin;
326234949Sbapt	    if (i + 1 < argc)
327234949Sbapt		usage();
328234949Sbapt	    return;
329234949Sbapt
330234949Sbapt	case '-':
331234949Sbapt	    ++i;
332234949Sbapt	    goto no_more_options;
333234949Sbapt
334234949Sbapt	case 'b':
335234949Sbapt	    if (*++s)
336234949Sbapt		file_prefix = s;
337234949Sbapt	    else if (++i < argc)
338234949Sbapt		file_prefix = argv[i];
339234949Sbapt	    else
340234949Sbapt		usage();
341234949Sbapt	    continue;
342234949Sbapt
343234949Sbapt	case 'o':
344234949Sbapt	    if (*++s)
345234949Sbapt		output_file_name = s;
346234949Sbapt	    else if (++i < argc)
347234949Sbapt		output_file_name = argv[i];
348234949Sbapt	    else
349234949Sbapt		usage();
350234949Sbapt	    continue;
351234949Sbapt
352234949Sbapt	case 'p':
353234949Sbapt	    if (*++s)
354234949Sbapt		symbol_prefix = s;
355234949Sbapt	    else if (++i < argc)
356234949Sbapt		symbol_prefix = argv[i];
357234949Sbapt	    else
358234949Sbapt		usage();
359234949Sbapt	    continue;
360234949Sbapt
361234949Sbapt	default:
362234949Sbapt	    setflag(ch);
363234949Sbapt	    break;
364234949Sbapt	}
365234949Sbapt
366234949Sbapt	for (;;)
367234949Sbapt	{
368234949Sbapt	    switch (ch = *++s)
369234949Sbapt	    {
370234949Sbapt	    case '\0':
371234949Sbapt		goto end_of_option;
372234949Sbapt
373234949Sbapt	    default:
374234949Sbapt		setflag(ch);
375234949Sbapt		break;
376234949Sbapt	    }
377234949Sbapt	}
378234949Sbapt      end_of_option:;
379234949Sbapt    }
380234949Sbapt
381234949Sbapt  no_more_options:;
382234949Sbapt    if (i + 1 != argc)
383234949Sbapt	usage();
384319349Sjkim    input_file_name_len = strlen(argv[i]);
385319349Sjkim    input_file_name = TMALLOC(char, input_file_name_len + 1);
386319349Sjkim    NO_SPACE(input_file_name);
387319349Sjkim    strcpy(input_file_name, argv[i]);
388234949Sbapt}
389234949Sbapt
390234949Sbaptvoid *
391234949Sbaptallocate(size_t n)
392234949Sbapt{
393234949Sbapt    void *p;
394234949Sbapt
395234949Sbapt    p = NULL;
396234949Sbapt    if (n)
397234949Sbapt    {
398234949Sbapt	p = CALLOC(1, n);
399234949Sbapt	NO_SPACE(p);
400234949Sbapt    }
401234949Sbapt    return (p);
402234949Sbapt}
403234949Sbapt
404234949Sbapt#define CREATE_FILE_NAME(dest, suffix) \
405264803Sbapt	dest = alloc_file_name(len, suffix)
406234949Sbapt
407264803Sbaptstatic char *
408264803Sbaptalloc_file_name(size_t len, const char *suffix)
409264803Sbapt{
410264803Sbapt    char *result = TMALLOC(char, len + strlen(suffix) + 1);
411264803Sbapt    if (result == 0)
412264803Sbapt	no_space();
413264803Sbapt    strcpy(result, file_prefix);
414264803Sbapt    strcpy(result + len, suffix);
415264803Sbapt    return result;
416264803Sbapt}
417264803Sbapt
418297276Sjkimstatic char *
419297276Sjkimfind_suffix(char *name, const char *suffix)
420297276Sjkim{
421297276Sjkim    size_t len = strlen(name);
422297276Sjkim    size_t slen = strlen(suffix);
423297276Sjkim    if (len >= slen)
424297276Sjkim    {
425297276Sjkim	name += len - slen;
426297276Sjkim	if (strcmp(name, suffix) == 0)
427297276Sjkim	    return name;
428297276Sjkim    }
429297276Sjkim    return NULL;
430297276Sjkim}
431297276Sjkim
432234949Sbaptstatic void
433234949Sbaptcreate_file_names(void)
434234949Sbapt{
435234949Sbapt    size_t len;
436234949Sbapt    const char *defines_suffix;
437234949Sbapt    const char *externs_suffix;
438297276Sjkim    char *suffix;
439234949Sbapt
440297276Sjkim    suffix = NULL;
441234949Sbapt    defines_suffix = DEFINES_SUFFIX;
442234949Sbapt    externs_suffix = EXTERNS_SUFFIX;
443234949Sbapt
444234949Sbapt    /* compute the file_prefix from the user provided output_file_name */
445234949Sbapt    if (output_file_name != 0)
446234949Sbapt    {
447297276Sjkim	if (!(suffix = find_suffix(output_file_name, OUTPUT_SUFFIX))
448297276Sjkim	    && (suffix = find_suffix(output_file_name, ".c")))
449234949Sbapt	{
450234949Sbapt	    defines_suffix = ".h";
451234949Sbapt	    externs_suffix = ".i";
452234949Sbapt	}
453234949Sbapt    }
454234949Sbapt
455297276Sjkim    if (suffix != NULL)
456234949Sbapt    {
457297276Sjkim	len = (size_t) (suffix - output_file_name);
458240517Sbapt	file_prefix = TMALLOC(char, len + 1);
459234949Sbapt	NO_SPACE(file_prefix);
460234949Sbapt	strncpy(file_prefix, output_file_name, len)[len] = 0;
461234949Sbapt    }
462234949Sbapt    else
463234949Sbapt	len = strlen(file_prefix);
464234949Sbapt
465234949Sbapt    /* if "-o filename" was not given */
466234949Sbapt    if (output_file_name == 0)
467234949Sbapt    {
468234949Sbapt	oflag = 1;
469234949Sbapt	CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX);
470234949Sbapt    }
471234949Sbapt
472234949Sbapt    if (rflag)
473234949Sbapt    {
474234949Sbapt	CREATE_FILE_NAME(code_file_name, CODE_SUFFIX);
475234949Sbapt    }
476234949Sbapt    else
477234949Sbapt	code_file_name = output_file_name;
478234949Sbapt
479234949Sbapt    if (dflag)
480234949Sbapt    {
481234949Sbapt	CREATE_FILE_NAME(defines_file_name, defines_suffix);
482234949Sbapt    }
483234949Sbapt
484234949Sbapt    if (iflag)
485234949Sbapt    {
486234949Sbapt	CREATE_FILE_NAME(externs_file_name, externs_suffix);
487234949Sbapt    }
488234949Sbapt
489234949Sbapt    if (vflag)
490234949Sbapt    {
491234949Sbapt	CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX);
492234949Sbapt    }
493234949Sbapt
494234949Sbapt    if (gflag)
495234949Sbapt    {
496234949Sbapt	CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX);
497234949Sbapt    }
498234949Sbapt
499297276Sjkim    if (suffix != NULL)
500234949Sbapt    {
501234949Sbapt	FREE(file_prefix);
502234949Sbapt    }
503234949Sbapt}
504234949Sbapt
505234949Sbapt#if USE_MKSTEMP
506234949Sbaptstatic void
507234949Sbaptclose_tmpfiles(void)
508234949Sbapt{
509234949Sbapt    while (my_tmpfiles != 0)
510234949Sbapt    {
511234949Sbapt	MY_TMPFILES *next = my_tmpfiles->next;
512234949Sbapt
513272655Sbapt	(void)chmod(my_tmpfiles->name, 0644);
514272655Sbapt	(void)unlink(my_tmpfiles->name);
515234949Sbapt
516234949Sbapt	free(my_tmpfiles->name);
517234949Sbapt	free(my_tmpfiles);
518234949Sbapt
519234949Sbapt	my_tmpfiles = next;
520234949Sbapt    }
521234949Sbapt}
522234949Sbapt
523234949Sbapt#ifndef HAVE_MKSTEMP
524234949Sbaptstatic int
525234949Sbaptmy_mkstemp(char *temp)
526234949Sbapt{
527234949Sbapt    int fd;
528234949Sbapt    char *dname;
529234949Sbapt    char *fname;
530234949Sbapt    char *name;
531234949Sbapt
532234949Sbapt    /*
533234949Sbapt     * Split-up to use tempnam, rather than tmpnam; the latter (like
534234949Sbapt     * mkstemp) is unusable on Windows.
535234949Sbapt     */
536234949Sbapt    if ((fname = strrchr(temp, '/')) != 0)
537234949Sbapt    {
538234949Sbapt	dname = strdup(temp);
539234949Sbapt	dname[++fname - temp] = '\0';
540234949Sbapt    }
541234949Sbapt    else
542234949Sbapt    {
543234949Sbapt	dname = 0;
544234949Sbapt	fname = temp;
545234949Sbapt    }
546234949Sbapt    if ((name = tempnam(dname, fname)) != 0)
547234949Sbapt    {
548234949Sbapt	fd = open(name, O_CREAT | O_EXCL | O_RDWR);
549234949Sbapt	strcpy(temp, name);
550234949Sbapt    }
551234949Sbapt    else
552234949Sbapt    {
553234949Sbapt	fd = -1;
554234949Sbapt    }
555234949Sbapt
556234949Sbapt    if (dname != 0)
557234949Sbapt	free(dname);
558234949Sbapt
559234949Sbapt    return fd;
560234949Sbapt}
561234949Sbapt#define mkstemp(s) my_mkstemp(s)
562234949Sbapt#endif
563234949Sbapt
564234949Sbapt#endif
565234949Sbapt
566234949Sbapt/*
567234949Sbapt * tmpfile() should be adequate, except that it may require special privileges
568234949Sbapt * to use, e.g., MinGW and Windows 7 where it tries to use the root directory.
569234949Sbapt */
570234949Sbaptstatic FILE *
571234949Sbaptopen_tmpfile(const char *label)
572234949Sbapt{
573296240Sjkim#define MY_FMT "%s/%.*sXXXXXX"
574234949Sbapt    FILE *result;
575234949Sbapt#if USE_MKSTEMP
576234949Sbapt    int fd;
577234949Sbapt    const char *tmpdir;
578234949Sbapt    char *name;
579234949Sbapt    const char *mark;
580234949Sbapt
581234949Sbapt    if ((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0)
582234949Sbapt    {
583234949Sbapt#ifdef P_tmpdir
584234949Sbapt	tmpdir = P_tmpdir;
585234949Sbapt#else
586234949Sbapt	tmpdir = "/tmp";
587234949Sbapt#endif
588234949Sbapt	if (access(tmpdir, W_OK) != 0)
589234949Sbapt	    tmpdir = ".";
590234949Sbapt    }
591234949Sbapt
592296240Sjkim    /* The size of the format is guaranteed to be longer than the result from
593296240Sjkim     * printing empty strings with it; this calculation accounts for the
594296240Sjkim     * string-lengths as well.
595296240Sjkim     */
596296240Sjkim    name = malloc(strlen(tmpdir) + sizeof(MY_FMT) + strlen(label));
597234949Sbapt
598234949Sbapt    result = 0;
599234949Sbapt    if (name != 0)
600234949Sbapt    {
601272769Sbapt	mode_t save_umask = umask(0177);
602272655Sbapt
603234949Sbapt	if ((mark = strrchr(label, '_')) == 0)
604234949Sbapt	    mark = label + strlen(label);
605234949Sbapt
606296240Sjkim	sprintf(name, MY_FMT, tmpdir, (int)(mark - label), label);
607234949Sbapt	fd = mkstemp(name);
608234949Sbapt	if (fd >= 0)
609234949Sbapt	{
610234949Sbapt	    result = fdopen(fd, "w+");
611234949Sbapt	    if (result != 0)
612234949Sbapt	    {
613234949Sbapt		MY_TMPFILES *item;
614234949Sbapt
615234949Sbapt		if (my_tmpfiles == 0)
616234949Sbapt		{
617234949Sbapt		    atexit(close_tmpfiles);
618234949Sbapt		}
619234949Sbapt
620234949Sbapt		item = NEW(MY_TMPFILES);
621234949Sbapt		NO_SPACE(item);
622234949Sbapt
623234949Sbapt		item->name = name;
624234949Sbapt		NO_SPACE(item->name);
625234949Sbapt
626234949Sbapt		item->next = my_tmpfiles;
627234949Sbapt		my_tmpfiles = item;
628234949Sbapt	    }
629234949Sbapt	}
630272655Sbapt	(void)umask(save_umask);
631234949Sbapt    }
632234949Sbapt#else
633234949Sbapt    result = tmpfile();
634234949Sbapt#endif
635234949Sbapt
636234949Sbapt    if (result == 0)
637234949Sbapt	open_error(label);
638234949Sbapt    return result;
639296240Sjkim#undef MY_FMT
640234949Sbapt}
641234949Sbapt
642234949Sbaptstatic void
643234949Sbaptopen_files(void)
644234949Sbapt{
645234949Sbapt    create_file_names();
646234949Sbapt
647234949Sbapt    if (input_file == 0)
648234949Sbapt    {
649234949Sbapt	input_file = fopen(input_file_name, "r");
650234949Sbapt	if (input_file == 0)
651234949Sbapt	    open_error(input_file_name);
652234949Sbapt    }
653234949Sbapt
654234949Sbapt    action_file = open_tmpfile("action_file");
655234949Sbapt    text_file = open_tmpfile("text_file");
656234949Sbapt
657234949Sbapt    if (vflag)
658234949Sbapt    {
659234949Sbapt	verbose_file = fopen(verbose_file_name, "w");
660234949Sbapt	if (verbose_file == 0)
661234949Sbapt	    open_error(verbose_file_name);
662234949Sbapt    }
663234949Sbapt
664234949Sbapt    if (gflag)
665234949Sbapt    {
666234949Sbapt	graph_file = fopen(graph_file_name, "w");
667234949Sbapt	if (graph_file == 0)
668234949Sbapt	    open_error(graph_file_name);
669234949Sbapt	fprintf(graph_file, "digraph %s {\n", file_prefix);
670234949Sbapt	fprintf(graph_file, "\tedge [fontsize=10];\n");
671234949Sbapt	fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n");
672234949Sbapt	fprintf(graph_file, "\torientation=landscape;\n");
673234949Sbapt	fprintf(graph_file, "\trankdir=LR;\n");
674234949Sbapt	fprintf(graph_file, "\t/*\n");
675234949Sbapt	fprintf(graph_file, "\tmargin=0.2;\n");
676234949Sbapt	fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n");
677234949Sbapt	fprintf(graph_file, "\tratio=auto;\n");
678234949Sbapt	fprintf(graph_file, "\t*/\n");
679234949Sbapt    }
680234949Sbapt
681234949Sbapt    if (dflag)
682234949Sbapt    {
683234949Sbapt	defines_file = fopen(defines_file_name, "w");
684234949Sbapt	if (defines_file == 0)
685234949Sbapt	    open_error(defines_file_name);
686234949Sbapt	union_file = open_tmpfile("union_file");
687234949Sbapt    }
688234949Sbapt
689234949Sbapt    if (iflag)
690234949Sbapt    {
691234949Sbapt	externs_file = fopen(externs_file_name, "w");
692234949Sbapt	if (externs_file == 0)
693234949Sbapt	    open_error(externs_file_name);
694234949Sbapt    }
695234949Sbapt
696234949Sbapt    output_file = fopen(output_file_name, "w");
697234949Sbapt    if (output_file == 0)
698234949Sbapt	open_error(output_file_name);
699234949Sbapt
700234949Sbapt    if (rflag)
701234949Sbapt    {
702234949Sbapt	code_file = fopen(code_file_name, "w");
703234949Sbapt	if (code_file == 0)
704234949Sbapt	    open_error(code_file_name);
705234949Sbapt    }
706234949Sbapt    else
707234949Sbapt	code_file = output_file;
708234949Sbapt}
709234949Sbapt
710234949Sbaptint
711234949Sbaptmain(int argc, char *argv[])
712234949Sbapt{
713234949Sbapt    SRexpect = -1;
714234949Sbapt    RRexpect = -1;
715234949Sbapt    exit_code = EXIT_SUCCESS;
716234949Sbapt
717234949Sbapt    set_signals();
718234949Sbapt    getargs(argc, argv);
719234949Sbapt    open_files();
720234949Sbapt    reader();
721234949Sbapt    lr0();
722234949Sbapt    lalr();
723234949Sbapt    make_parser();
724234949Sbapt    graph();
725234949Sbapt    finalize_closure();
726234949Sbapt    verbose();
727234949Sbapt    output();
728234949Sbapt    done(exit_code);
729234949Sbapt    /*NOTREACHED */
730234949Sbapt}
731