main.c revision 1.1.1.2 1 /* $NetBSD: main.c,v 1.1.1.2 2010/12/23 23:36:26 christos Exp $ */
2
3 /* Id: main.c,v 1.30 2010/11/24 15:13:39 tom Exp */
4
5 #include <signal.h>
6 #include <unistd.h> /* for _exit() */
7
8 #include "defs.h"
9
10 char dflag;
11 char gflag;
12 char lflag;
13 static char oflag;
14 char rflag;
15 char tflag;
16 char vflag;
17
18 const char *symbol_prefix;
19 const char *myname = "yacc";
20
21 int lineno;
22 int outline;
23
24 static char empty_string[] = "";
25 static char default_file_prefix[] = "y";
26
27 static char *file_prefix = default_file_prefix;
28
29 char *code_file_name;
30 char *input_file_name = empty_string;
31 static char *defines_file_name;
32 static char *graph_file_name;
33 static char *output_file_name;
34 static char *verbose_file_name;
35
36 FILE *action_file; /* a temp file, used to save actions associated */
37 /* with rules until the parser is written */
38 FILE *code_file; /* y.code.c (used when the -r option is specified) */
39 FILE *defines_file; /* y.tab.h */
40 FILE *input_file; /* the input file */
41 FILE *output_file; /* y.tab.c */
42 FILE *text_file; /* a temp file, used to save text until all */
43 /* symbols have been defined */
44 FILE *union_file; /* a temp file, used to save the union */
45 /* definition until all symbol have been */
46 /* defined */
47 FILE *verbose_file; /* y.output */
48 FILE *graph_file; /* y.dot */
49
50 int nitems;
51 int nrules;
52 int nsyms;
53 int ntokens;
54 int nvars;
55
56 Value_t start_symbol;
57 char **symbol_name;
58 char **symbol_pname;
59 Value_t *symbol_value;
60 short *symbol_prec;
61 char *symbol_assoc;
62
63 int pure_parser;
64 int exit_code;
65
66 Value_t *ritem;
67 Value_t *rlhs;
68 Value_t *rrhs;
69 Value_t *rprec;
70 Assoc_t *rassoc;
71 Value_t **derives;
72 char *nullable;
73
74 /*
75 * Since fclose() is called via the signal handler, it might die. Don't loop
76 * if there is a problem closing a file.
77 */
78 #define DO_CLOSE(fp) \
79 if (fp != 0) { \
80 FILE *use = fp; \
81 fp = 0; \
82 fclose(use); \
83 }
84
85 static int got_intr = 0;
86
87 void
88 done(int k)
89 {
90 DO_CLOSE(input_file);
91 DO_CLOSE(output_file);
92
93 DO_CLOSE(action_file);
94 DO_CLOSE(defines_file);
95 DO_CLOSE(graph_file);
96 DO_CLOSE(text_file);
97 DO_CLOSE(union_file);
98 DO_CLOSE(verbose_file);
99
100 if (got_intr)
101 _exit(EXIT_FAILURE);
102
103 #ifdef NO_LEAKS
104 if (rflag)
105 DO_FREE(code_file_name);
106
107 if (dflag)
108 DO_FREE(defines_file_name);
109
110 if (oflag)
111 DO_FREE(output_file_name);
112
113 if (vflag)
114 DO_FREE(verbose_file_name);
115
116 if (gflag)
117 DO_FREE(graph_file_name);
118
119 lr0_leaks();
120 lalr_leaks();
121 mkpar_leaks();
122 output_leaks();
123 reader_leaks();
124 #endif
125
126 if (rflag)
127 DO_CLOSE(code_file);
128
129 exit(k);
130 }
131
132 static void
133 onintr(int sig GCC_UNUSED)
134 {
135 got_intr = 1;
136 done(EXIT_FAILURE);
137 }
138
139 static void
140 set_signals(void)
141 {
142 #ifdef SIGINT
143 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
144 signal(SIGINT, onintr);
145 #endif
146 #ifdef SIGTERM
147 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
148 signal(SIGTERM, onintr);
149 #endif
150 #ifdef SIGHUP
151 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
152 signal(SIGHUP, onintr);
153 #endif
154 }
155
156 static void
157 usage(void)
158 {
159 static const char *msg[] =
160 {
161 ""
162 ,"Options:"
163 ," -b file_prefix set filename prefix (default \"y.\")"
164 ," -d write definitions (y.tab.h)"
165 ," -g write a graphical description"
166 ," -l suppress #line directives"
167 ," -o output_file (default \"y.tab.c\")"
168 ," -p symbol_prefix set symbol prefix (default \"yy\")"
169 ," -P create a reentrant parser, e.g., \"%pure-parser\""
170 ," -r produce separate code and table files (y.code.c)"
171 ," -t add debugging support"
172 ," -v write description (y.output)"
173 ," -V show version information and exit"
174 };
175 unsigned n;
176
177 fflush(stdout);
178 fprintf(stderr, "Usage: %s [options] filename\n", myname);
179 for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n)
180 fprintf(stderr, "%s\n", msg[n]);
181
182 exit(1);
183 }
184
185 static void
186 setflag(int ch)
187 {
188 switch (ch)
189 {
190 case 'd':
191 dflag = 1;
192 break;
193
194 case 'g':
195 gflag = 1;
196 break;
197
198 case 'l':
199 lflag = 1;
200 break;
201
202 case 'P':
203 pure_parser = 1;
204 break;
205
206 case 'r':
207 rflag = 1;
208 break;
209
210 case 't':
211 tflag = 1;
212 break;
213
214 case 'v':
215 vflag = 1;
216 break;
217
218 case 'V':
219 printf("%s - %s\n", myname, VERSION);
220 exit(EXIT_SUCCESS);
221
222 case 'y':
223 /* noop for bison compatibility. byacc is already designed to be posix
224 * yacc compatible. */
225 break;
226
227 default:
228 usage();
229 }
230 }
231
232 static void
233 getargs(int argc, char *argv[])
234 {
235 int i;
236 char *s;
237 int ch;
238
239 if (argc > 0)
240 myname = argv[0];
241
242 for (i = 1; i < argc; ++i)
243 {
244 s = argv[i];
245 if (*s != '-')
246 break;
247 switch (ch = *++s)
248 {
249 case '\0':
250 input_file = stdin;
251 if (i + 1 < argc)
252 usage();
253 return;
254
255 case '-':
256 ++i;
257 goto no_more_options;
258
259 case 'b':
260 if (*++s)
261 file_prefix = s;
262 else if (++i < argc)
263 file_prefix = argv[i];
264 else
265 usage();
266 continue;
267
268 case 'o':
269 if (*++s)
270 output_file_name = s;
271 else if (++i < argc)
272 output_file_name = argv[i];
273 else
274 usage();
275 continue;
276
277 case 'p':
278 if (*++s)
279 symbol_prefix = s;
280 else if (++i < argc)
281 symbol_prefix = argv[i];
282 else
283 usage();
284 continue;
285
286 default:
287 setflag(ch);
288 break;
289 }
290
291 for (;;)
292 {
293 switch (ch = *++s)
294 {
295 case '\0':
296 goto end_of_option;
297
298 default:
299 setflag(ch);
300 break;
301 }
302 }
303 end_of_option:;
304 }
305
306 no_more_options:;
307 if (i + 1 != argc)
308 usage();
309 input_file_name = argv[i];
310 }
311
312 char *
313 allocate(size_t n)
314 {
315 char *p;
316
317 p = NULL;
318 if (n)
319 {
320 p = CALLOC(1, n);
321 NO_SPACE(p);
322 }
323 return (p);
324 }
325
326 #define CREATE_FILE_NAME(dest, suffix) \
327 dest = MALLOC(len + strlen(suffix) + 1); \
328 NO_SPACE(dest); \
329 strcpy(dest, file_prefix); \
330 strcpy(dest + len, suffix)
331
332 static void
333 create_file_names(void)
334 {
335 size_t len;
336 const char *defines_suffix;
337 char *prefix;
338
339 prefix = NULL;
340 defines_suffix = DEFINES_SUFFIX;
341
342 /* compute the file_prefix from the user provided output_file_name */
343 if (output_file_name != 0)
344 {
345 if (!(prefix = strstr(output_file_name, ".tab.c"))
346 && (prefix = strstr(output_file_name, ".c")))
347 defines_suffix = ".h";
348 }
349
350 if (prefix != NULL)
351 {
352 len = (size_t) (prefix - output_file_name);
353 file_prefix = (char *)MALLOC(len + 1);
354 NO_SPACE(file_prefix);
355 strncpy(file_prefix, output_file_name, len)[len] = 0;
356 }
357 else
358 len = strlen(file_prefix);
359
360 /* if "-o filename" was not given */
361 if (output_file_name == 0)
362 {
363 oflag = 1;
364 CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX);
365 }
366
367 if (rflag)
368 {
369 CREATE_FILE_NAME(code_file_name, CODE_SUFFIX);
370 }
371 else
372 code_file_name = output_file_name;
373
374 if (dflag)
375 {
376 CREATE_FILE_NAME(defines_file_name, defines_suffix);
377 }
378
379 if (vflag)
380 {
381 CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX);
382 }
383
384 if (gflag)
385 {
386 CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX);
387 }
388
389 if (prefix != NULL)
390 {
391 FREE(file_prefix);
392 }
393 }
394
395 static void
396 open_files(void)
397 {
398 create_file_names();
399
400 if (input_file == 0)
401 {
402 input_file = fopen(input_file_name, "r");
403 if (input_file == 0)
404 open_error(input_file_name);
405 }
406
407 action_file = tmpfile();
408 if (action_file == 0)
409 open_error("action_file");
410
411 text_file = tmpfile();
412 if (text_file == 0)
413 open_error("text_file");
414
415 if (vflag)
416 {
417 verbose_file = fopen(verbose_file_name, "w");
418 if (verbose_file == 0)
419 open_error(verbose_file_name);
420 }
421
422 if (gflag)
423 {
424 graph_file = fopen(graph_file_name, "w");
425 if (graph_file == 0)
426 open_error(graph_file_name);
427 fprintf(graph_file, "digraph %s {\n", file_prefix);
428 fprintf(graph_file, "\tedge [fontsize=10];\n");
429 fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n");
430 fprintf(graph_file, "\torientation=landscape;\n");
431 fprintf(graph_file, "\trankdir=LR;\n");
432 fprintf(graph_file, "\t/*\n");
433 fprintf(graph_file, "\tmargin=0.2;\n");
434 fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n");
435 fprintf(graph_file, "\tratio=auto;\n");
436 fprintf(graph_file, "\t*/\n");
437 }
438
439 if (dflag)
440 {
441 defines_file = fopen(defines_file_name, "w");
442 if (defines_file == 0)
443 open_error(defines_file_name);
444 union_file = tmpfile();
445 if (union_file == 0)
446 open_error("union_file");
447 }
448
449 output_file = fopen(output_file_name, "w");
450 if (output_file == 0)
451 open_error(output_file_name);
452
453 if (rflag)
454 {
455 code_file = fopen(code_file_name, "w");
456 if (code_file == 0)
457 open_error(code_file_name);
458 }
459 else
460 code_file = output_file;
461 }
462
463 int
464 main(int argc, char *argv[])
465 {
466 SRexpect = -1;
467 RRexpect = -1;
468 exit_code = EXIT_SUCCESS;
469
470 set_signals();
471 getargs(argc, argv);
472 open_files();
473 reader();
474 lr0();
475 lalr();
476 make_parser();
477 graph();
478 finalize_closure();
479 verbose();
480 output();
481 done(exit_code);
482 /*NOTREACHED */
483 }
484