main.c revision 93832
1/*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Robert Paul Corbett.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#if 0
38#ifndef lint
39static char sccsid[] = "@(#)main.c	5.5 (Berkeley) 5/24/93";
40#endif
41#endif
42
43#include <sys/cdefs.h>
44#ifdef __FBSDID
45__FBSDID("$FreeBSD: head/usr.bin/yacc/main.c 93832 2002-04-04 22:15:56Z obrien $");
46#endif
47
48#include <paths.h>
49#include <signal.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53#include "defs.h"
54
55char dflag;
56char lflag;
57char rflag;
58char tflag;
59char vflag;
60
61const char *symbol_prefix;
62const char *file_prefix = "y";
63char temp_form[] = "yacc.XXXXXXXXXXX";
64
65int lineno;
66int outline;
67
68char *action_file_name;
69char *code_file_name;
70char *defines_file_name;
71const char *input_file_name = "";
72char *output_file_name;
73char *text_file_name;
74char *union_file_name;
75char *verbose_file_name;
76
77FILE *action_file;	/*  a temp file, used to save actions associated    */
78			/*  with rules until the parser is written	    */
79FILE *code_file;	/*  y.code.c (used when the -r option is specified) */
80FILE *defines_file;	/*  y.tab.h					    */
81FILE *input_file;	/*  the input file				    */
82FILE *output_file;	/*  y.tab.c					    */
83FILE *text_file;	/*  a temp file, used to save text until all	    */
84			/*  symbols have been defined			    */
85FILE *union_file;	/*  a temp file, used to save the union		    */
86			/*  definition until all symbol have been	    */
87			/*  defined					    */
88FILE *verbose_file;	/*  y.output					    */
89
90int nitems;
91int nrules;
92int nsyms;
93int ntokens;
94int nvars;
95
96int   start_symbol;
97char  **symbol_name;
98short *symbol_value;
99short *symbol_prec;
100char  *symbol_assoc;
101
102short *ritem;
103short *rlhs;
104short *rrhs;
105short *rprec;
106char  *rassoc;
107short **derives;
108char *nullable;
109
110static void create_file_names(void);
111static void getargs(int, char **);
112static void onintr(int);
113static void open_files(void);
114static void set_signals(void);
115static void usage(void);
116
117volatile sig_atomic_t sigdie;
118
119__dead2 void
120done(k)
121int k;
122{
123    if (action_file) { fclose(action_file); unlink(action_file_name); }
124    if (text_file) { fclose(text_file); unlink(text_file_name); }
125    if (union_file) { fclose(union_file); unlink(union_file_name); }
126    if (sigdie) { _exit(k); }
127    exit(k);
128}
129
130
131static void
132onintr(signo)
133	int signo __unused;
134{
135    sigdie = 1;
136    done(1);
137}
138
139
140static void
141set_signals()
142{
143#ifdef SIGINT
144    if (signal(SIGINT, SIG_IGN) != SIG_IGN)
145	signal(SIGINT, onintr);
146#endif
147#ifdef SIGTERM
148    if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
149	signal(SIGTERM, onintr);
150#endif
151#ifdef SIGHUP
152    if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
153	signal(SIGHUP, onintr);
154#endif
155}
156
157
158static void
159usage()
160{
161    fprintf(stderr, "%s\n%s\n",
162		"usage: yacc [-dlrtv] [-b file_prefix] [-o output_filename]",
163		"            [-p symbol_prefix] filename");
164    exit(1);
165}
166
167
168static void
169getargs(argc, argv)
170int argc;
171char *argv[];
172{
173    int i;
174    char *s;
175
176    for (i = 1; i < argc; ++i)
177    {
178	s = argv[i];
179	if (*s != '-') break;
180	switch (*++s)
181	{
182	case '\0':
183	    input_file = stdin;
184	    if (i + 1 < argc) usage();
185	    return;
186
187	case '-':
188	    ++i;
189	    goto no_more_options;
190
191	case 'b':
192	    if (*++s)
193		 file_prefix = s;
194	    else if (++i < argc)
195		file_prefix = argv[i];
196	    else
197		usage();
198	    continue;
199
200	case 'd':
201	    dflag = 1;
202	    break;
203
204	case 'l':
205	    lflag = 1;
206	    break;
207
208	case 'o':
209	    if (*++s)
210		output_file_name = s;
211	    else if (++i < argc)
212		output_file_name = argv[i];
213	    else
214		usage();
215	    continue;
216
217	case 'p':
218	    if (*++s)
219		symbol_prefix = s;
220	    else if (++i < argc)
221		symbol_prefix = argv[i];
222	    else
223		usage();
224	    continue;
225
226	case 'r':
227	    rflag = 1;
228	    break;
229
230	case 't':
231	    tflag = 1;
232	    break;
233
234	case 'v':
235	    vflag = 1;
236	    break;
237
238	default:
239	    usage();
240	}
241
242	for (;;)
243	{
244	    switch (*++s)
245	    {
246	    case '\0':
247		goto end_of_option;
248
249	    case 'd':
250		dflag = 1;
251		break;
252
253	    case 'l':
254		lflag = 1;
255		break;
256
257	    case 'r':
258		rflag = 1;
259		break;
260
261	    case 't':
262		tflag = 1;
263		break;
264
265	    case 'v':
266		vflag = 1;
267		break;
268
269	    default:
270		usage();
271	    }
272	}
273end_of_option:;
274    }
275
276no_more_options:;
277    if (i + 1 != argc) usage();
278    input_file_name = argv[i];
279}
280
281
282char *
283allocate(n)
284unsigned n;
285{
286    char *p;
287
288    p = NULL;
289    if (n)
290    {
291	p = CALLOC(1, n);
292	if (!p) no_space();
293    }
294    return (p);
295}
296
297
298static void
299create_file_names()
300{
301    int i, len;
302    const char *tmpdir;
303
304    if (!(tmpdir = getenv("TMPDIR")))
305	tmpdir = _PATH_TMP;
306
307    len = strlen(tmpdir);
308    i = len + strlen(temp_form) + 1;
309    if (len && tmpdir[len-1] != '/')
310	++i;
311
312    action_file_name = MALLOC(i);
313    if (action_file_name == 0) no_space();
314    text_file_name = MALLOC(i);
315    if (text_file_name == 0) no_space();
316    union_file_name = MALLOC(i);
317    if (union_file_name == 0) no_space();
318
319    strcpy(action_file_name, tmpdir);
320    strcpy(text_file_name, tmpdir);
321    strcpy(union_file_name, tmpdir);
322
323    if (len && tmpdir[len - 1] != '/')
324    {
325	action_file_name[len] = '/';
326	text_file_name[len] = '/';
327	union_file_name[len] = '/';
328	++len;
329    }
330
331    strcpy(action_file_name + len, temp_form);
332    strcpy(text_file_name + len, temp_form);
333    strcpy(union_file_name + len, temp_form);
334
335    action_file_name[len + 5] = 'a';
336    text_file_name[len + 5] = 't';
337    union_file_name[len + 5] = 'u';
338
339    if (output_file_name != 0)
340    {
341	file_prefix = output_file_name;
342	len = strlen(file_prefix);
343    }
344    else
345    {
346	len = strlen(file_prefix);
347	output_file_name = MALLOC(len + 7);
348	if (output_file_name == 0)
349	    no_space();
350	strcpy(output_file_name, file_prefix);
351	strcpy(output_file_name + len, OUTPUT_SUFFIX);
352    }
353
354    if (rflag)
355    {
356	code_file_name = MALLOC(len + 8);
357	if (code_file_name == 0)
358	    no_space();
359	strcpy(code_file_name, file_prefix);
360	if (file_prefix == output_file_name)
361	{
362	    /*
363	     * XXX ".tab.c" here is OUTPUT_SUFFIX, but since its length is
364	     * in various magic numbers, don't bother using the macro.
365	     */
366	    if (len >= 6 && strcmp(code_file_name + len - 6, ".tab.c") == 0)
367		strcpy(code_file_name + len - 6, CODE_SUFFIX);
368	    else if (len >= 2 && strcmp(code_file_name + len - 2, ".c") == 0)
369		strcpy(code_file_name + len - 2, CODE_SUFFIX);
370	    else
371		strcpy(code_file_name + len, CODE_SUFFIX);
372	}
373	else
374	    strcpy(code_file_name + len, CODE_SUFFIX);
375    }
376    else
377	code_file_name = output_file_name;
378
379    if (dflag)
380    {
381	defines_file_name = MALLOC(len + 7);
382	if (defines_file_name == 0)
383	    no_space();
384	strcpy(defines_file_name, file_prefix);
385	if (file_prefix == output_file_name)
386	{
387#define BISON_DEFINES_SUFFIX  ".h"
388	    if (len >= 2 && strcmp(defines_file_name + len - 2, ".c") == 0)
389		strcpy(defines_file_name + len - 2, BISON_DEFINES_SUFFIX);
390	    else
391		strcpy(defines_file_name + len, BISON_DEFINES_SUFFIX);
392	}
393	else
394	    strcpy(defines_file_name + len, DEFINES_SUFFIX);
395    }
396
397    if (vflag)
398    {
399	verbose_file_name = MALLOC(len + 8);
400	if (verbose_file_name == 0)
401	    no_space();
402	strcpy(verbose_file_name, file_prefix);
403	if (file_prefix == output_file_name)
404	{
405	    if (len >= 6 && strcmp(verbose_file_name + len - 6, ".tab.c") == 0)
406		strcpy(verbose_file_name + len - 6, VERBOSE_SUFFIX);
407	    else if (len >= 2 && strcmp(verbose_file_name + len - 2, ".c") == 0)
408		strcpy(verbose_file_name + len - 2, VERBOSE_SUFFIX);
409	    else
410		strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
411	}
412	else
413	    strcpy(verbose_file_name + len, VERBOSE_SUFFIX);
414    }
415}
416
417
418static void
419open_files()
420{
421    int fd;
422
423    create_file_names();
424
425    if (input_file == 0)
426    {
427	input_file = fopen(input_file_name, "r");
428	if (input_file == 0)
429	    open_error(input_file_name);
430    }
431
432    fd = mkstemp(action_file_name);
433    if (fd < 0 || (action_file = fdopen(fd, "w")) == NULL) {
434        if (fd >= 0)
435	    close(fd);
436	open_error(action_file_name);
437    }
438    fd = mkstemp(text_file_name);
439    if (fd < 0 || (text_file = fdopen(fd, "w")) == NULL) {
440        if (fd >= 0)
441	    close(fd);
442	open_error(text_file_name);
443    }
444    fd = mkstemp(union_file_name);
445    if (fd < 0 || (union_file = fdopen(fd, "w")) == NULL) {
446        if (fd >= 0)
447	    close(fd);
448	open_error(union_file_name);
449    }
450
451    text_file = fopen(text_file_name, "w");
452    if (text_file == 0)
453	open_error(text_file_name);
454
455    if (vflag)
456    {
457	verbose_file = fopen(verbose_file_name, "w");
458	if (verbose_file == 0)
459	    open_error(verbose_file_name);
460    }
461
462    if (dflag)
463    {
464	defines_file = fopen(defines_file_name, "w");
465	if (defines_file == 0)
466	    open_error(defines_file_name);
467	union_file = fopen(union_file_name, "w");
468	if (union_file ==  0)
469	    open_error(union_file_name);
470    }
471
472    output_file = fopen(output_file_name, "w");
473    if (output_file == 0)
474	open_error(output_file_name);
475
476    if (rflag)
477    {
478	code_file = fopen(code_file_name, "w");
479	if (code_file == 0)
480	    open_error(code_file_name);
481    }
482    else
483	code_file = output_file;
484}
485
486
487int
488main(int argc, char *argv[])
489{
490    set_signals();
491    getargs(argc, argv);
492    open_files();
493    reader();
494    lr0();
495    lalr();
496    make_parser();
497    verbose();
498    output();
499    done(0);
500    /*NOTREACHED*/
501    return (0);
502}
503