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