mkfs: move directory entry manipulation
[minix.git] / external / bsd / byacc / dist / main.c
blobeef4ac0264df513b98f573e47b325dfea01fdff2
1 /* $NetBSD: main.c,v 1.7 2011/09/10 21:29:04 christos Exp $ */
2 /* Id: main.c,v 1.36 2011/09/06 22:44:45 tom Exp */
4 #include "defs.h"
6 #include <sys/cdefs.h>
7 __RCSID("$NetBSD: main.c,v 1.7 2011/09/10 21:29:04 christos Exp $");
9 #include <signal.h>
10 #include <unistd.h> /* for _exit() */
13 #if defined(HAVE_ATEXIT)
14 # ifdef HAVE_MKSTEMP
15 # define USE_MKSTEMP 1
16 # elif defined(HAVE_FCNTL_H)
17 # define USE_MKSTEMP 1
18 # include <fcntl.h> /* for open(), O_EXCL, etc. */
19 # else
20 # define USE_MKSTEMP 0
21 # endif
22 #else
23 # define USE_MKSTEMP 0
24 #endif
26 #if USE_MKSTEMP
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 typedef struct _my_tmpfiles
32 struct _my_tmpfiles *next;
33 char *name;
35 MY_TMPFILES;
37 static MY_TMPFILES *my_tmpfiles;
38 #endif /* USE_MKSTEMP */
40 char dflag;
41 char gflag;
42 char iflag;
43 char lflag;
44 static char oflag;
45 char rflag;
46 char tflag;
47 char vflag;
49 const char *symbol_prefix;
50 const char *myname = "yacc";
52 int lineno;
53 int outline;
55 static char empty_string[] = "";
56 static char default_file_prefix[] = "y";
57 static int explicit_file_name;
59 static char *file_prefix = default_file_prefix;
61 char *code_file_name;
62 char *input_file_name = empty_string;
63 char *defines_file_name;
64 char *externs_file_name;
66 static char *graph_file_name;
67 static char *output_file_name;
68 static char *verbose_file_name;
70 FILE *action_file; /* a temp file, used to save actions associated */
71 /* with rules until the parser is written */
72 FILE *code_file; /* y.code.c (used when the -r option is specified) */
73 FILE *defines_file; /* y.tab.h */
74 FILE *externs_file; /* y.tab.i */
75 FILE *input_file; /* the input file */
76 FILE *output_file; /* y.tab.c */
77 FILE *text_file; /* a temp file, used to save text until all */
78 /* symbols have been defined */
79 FILE *union_file; /* a temp file, used to save the union */
80 /* definition until all symbol have been */
81 /* defined */
82 FILE *verbose_file; /* y.output */
83 FILE *graph_file; /* y.dot */
85 int nitems;
86 int nrules;
87 int nsyms;
88 int ntokens;
89 int nvars;
91 Value_t start_symbol;
92 char **symbol_name;
93 char **symbol_pname;
94 Value_t *symbol_value;
95 short *symbol_prec;
96 char *symbol_assoc;
98 int pure_parser;
99 int exit_code;
101 Value_t *ritem;
102 Value_t *rlhs;
103 Value_t *rrhs;
104 Value_t *rprec;
105 Assoc_t *rassoc;
106 Value_t **derives;
107 char *nullable;
110 * Since fclose() is called via the signal handler, it might die. Don't loop
111 * if there is a problem closing a file.
113 #define DO_CLOSE(fp) \
114 if (fp != 0) { \
115 FILE *use = fp; \
116 fp = 0; \
117 fclose(use); \
120 static int got_intr = 0;
122 void
123 done(int k)
125 DO_CLOSE(input_file);
126 DO_CLOSE(output_file);
128 DO_CLOSE(action_file);
129 DO_CLOSE(defines_file);
130 DO_CLOSE(graph_file);
131 DO_CLOSE(text_file);
132 DO_CLOSE(union_file);
133 DO_CLOSE(verbose_file);
135 if (got_intr)
136 _exit(EXIT_FAILURE);
138 #ifdef NO_LEAKS
139 if (rflag)
140 DO_FREE(code_file_name);
142 if (dflag)
143 DO_FREE(defines_file_name);
145 if (iflag)
146 DO_FREE(externs_file_name);
148 if (oflag)
149 DO_FREE(output_file_name);
151 if (vflag)
152 DO_FREE(verbose_file_name);
154 if (gflag)
155 DO_FREE(graph_file_name);
157 lr0_leaks();
158 lalr_leaks();
159 mkpar_leaks();
160 output_leaks();
161 reader_leaks();
162 #endif
164 if (rflag)
165 DO_CLOSE(code_file);
167 exit(k);
170 static void
171 onintr(int sig GCC_UNUSED)
173 got_intr = 1;
174 done(EXIT_FAILURE);
177 static void
178 set_signals(void)
180 #ifdef SIGINT
181 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
182 signal(SIGINT, onintr);
183 #endif
184 #ifdef SIGTERM
185 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
186 signal(SIGTERM, onintr);
187 #endif
188 #ifdef SIGHUP
189 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
190 signal(SIGHUP, onintr);
191 #endif
194 static void
195 usage(void)
197 static const char *msg[] =
200 ,"Options:"
201 ," -b file_prefix set filename prefix (default \"y.\")"
202 ," -d write definitions (y.tab.h)"
203 ," -i write interface (y.tab.i)"
204 ," -g write a graphical description"
205 ," -l suppress #line directives"
206 ," -o output_file (default \"y.tab.c\")"
207 ," -p symbol_prefix set symbol prefix (default \"yy\")"
208 ," -P create a reentrant parser, e.g., \"%pure-parser\""
209 ," -r produce separate code and table files (y.code.c)"
210 ," -t add debugging support"
211 ," -v write description (y.output)"
212 ," -V show version information and exit"
214 unsigned n;
216 fflush(stdout);
217 fprintf(stderr, "Usage: %s [options] filename\n", myname);
218 for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n)
219 fprintf(stderr, "%s\n", msg[n]);
221 exit(1);
224 static void
225 setflag(int ch)
227 switch (ch)
229 case 'd':
230 dflag = 1;
231 break;
233 case 'g':
234 gflag = 1;
235 break;
237 case 'i':
238 iflag = 1;
239 break;
241 case 'l':
242 lflag = 1;
243 break;
245 case 'P':
246 pure_parser = 1;
247 break;
249 case 'r':
250 rflag = 1;
251 break;
253 case 't':
254 tflag = 1;
255 break;
257 case 'v':
258 vflag = 1;
259 break;
261 case 'V':
262 printf("%s - %s\n", myname, VERSION);
263 exit(EXIT_SUCCESS);
265 case 'y':
266 /* noop for bison compatibility. byacc is already designed to be posix
267 * yacc compatible. */
268 break;
270 default:
271 usage();
275 static void
276 getargs(int argc, char *argv[])
278 int i;
279 char *s;
280 int ch;
282 if (argc > 0)
283 myname = argv[0];
285 for (i = 1; i < argc; ++i)
287 s = argv[i];
288 if (*s != '-')
289 break;
290 switch (ch = *++s)
292 case '\0':
293 input_file = stdin;
294 if (i + 1 < argc)
295 usage();
296 return;
298 case '-':
299 ++i;
300 goto no_more_options;
302 case 'b':
303 if (*++s)
304 file_prefix = s;
305 else if (++i < argc)
306 file_prefix = argv[i];
307 else
308 usage();
309 continue;
311 case 'o':
312 if (*++s)
313 output_file_name = s;
314 else if (++i < argc)
315 output_file_name = argv[i];
316 else
317 usage();
318 explicit_file_name = 1;
319 continue;
321 case 'p':
322 if (*++s)
323 symbol_prefix = s;
324 else if (++i < argc)
325 symbol_prefix = argv[i];
326 else
327 usage();
328 continue;
330 default:
331 setflag(ch);
332 break;
335 for (;;)
337 switch (ch = *++s)
339 case '\0':
340 goto end_of_option;
342 default:
343 setflag(ch);
344 break;
347 end_of_option:;
350 no_more_options:;
351 if (i + 1 != argc)
352 usage();
353 input_file_name = argv[i];
356 void *
357 allocate(size_t n)
359 void *p;
361 p = NULL;
362 if (n)
364 p = CALLOC(1, n);
365 NO_SPACE(p);
367 return (p);
370 #define CREATE_FILE_NAME(dest, suffix) \
371 dest = MALLOC(len + strlen(suffix) + 1); \
372 NO_SPACE(dest); \
373 strcpy(dest, file_prefix); \
374 strcpy(dest + len, suffix)
376 static void
377 create_file_names(void)
379 size_t len;
380 const char *defines_suffix;
381 const char *externs_suffix;
382 char *prefix;
384 prefix = NULL;
385 defines_suffix = DEFINES_SUFFIX;
386 externs_suffix = EXTERNS_SUFFIX;
388 /* compute the file_prefix from the user provided output_file_name */
389 if (output_file_name != 0)
391 if (!(prefix = strstr(output_file_name, ".tab.c"))
392 && (prefix = strstr(output_file_name, ".c")))
394 defines_suffix = ".h";
395 externs_suffix = ".i";
399 if (prefix != NULL)
401 len = (size_t) (prefix - output_file_name);
402 file_prefix = MALLOC(len + 1);
403 NO_SPACE(file_prefix);
404 strncpy(file_prefix, output_file_name, len)[len] = 0;
406 else
407 len = strlen(file_prefix);
409 /* if "-o filename" was not given */
410 if (output_file_name == 0)
412 oflag = 1;
413 CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX);
416 if (rflag)
418 CREATE_FILE_NAME(code_file_name, CODE_SUFFIX);
420 else
421 code_file_name = output_file_name;
423 if (dflag)
425 if (explicit_file_name)
427 char *suffix;
428 defines_file_name = strdup(output_file_name);
429 if (defines_file_name == 0)
430 no_space();
431 /* does the output_file_name have a known suffix */
432 suffix = strrchr(output_file_name, '.');
433 if (suffix != 0 &&
434 (!strcmp(suffix, ".c") || /* good, old-fashioned C */
435 !strcmp(suffix, ".C") || /* C++, or C on Windows */
436 !strcmp(suffix, ".cc") || /* C++ */
437 !strcmp(suffix, ".cxx") || /* C++ */
438 !strcmp(suffix, ".cpp"))) /* C++ (Windows) */
440 strncpy(defines_file_name, output_file_name,
441 suffix - output_file_name + 1);
442 defines_file_name[suffix - output_file_name + 1] = 'h';
443 defines_file_name[suffix - output_file_name + 2] = 0;
444 } else {
445 fprintf(stderr,"%s: suffix of output file name %s"
446 " not recognized, no -d file generated.\n",
447 myname, output_file_name);
448 dflag = 0;
449 free(defines_file_name);
450 defines_file_name = 0;
452 } else {
453 CREATE_FILE_NAME(defines_file_name, defines_suffix);
457 if (iflag)
459 CREATE_FILE_NAME(externs_file_name, externs_suffix);
462 if (vflag)
464 CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX);
467 if (gflag)
469 CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX);
472 if (prefix != NULL)
474 FREE(file_prefix);
478 #if USE_MKSTEMP
479 static void
480 close_tmpfiles(void)
482 while (my_tmpfiles != 0)
484 MY_TMPFILES *next = my_tmpfiles->next;
486 chmod(my_tmpfiles->name, 0644);
487 unlink(my_tmpfiles->name);
489 free(my_tmpfiles->name);
490 free(my_tmpfiles);
492 my_tmpfiles = next;
496 #ifndef HAVE_MKSTEMP
497 static int
498 my_mkstemp(char *temp)
500 int fd;
501 char *dname;
502 char *fname;
503 char *name;
506 * Split-up to use tempnam, rather than tmpnam; the latter (like
507 * mkstemp) is unusable on Windows.
509 if ((fname = strrchr(temp, '/')) != 0)
511 dname = strdup(temp);
512 dname[++fname - temp] = '\0';
514 else
516 dname = 0;
517 fname = temp;
519 if ((name = tempnam(dname, fname)) != 0)
521 fd = open(name, O_CREAT | O_EXCL | O_RDWR);
522 strcpy(temp, name);
524 else
526 fd = -1;
529 if (dname != 0)
530 free(dname);
532 return fd;
534 #define mkstemp(s) my_mkstemp(s)
535 #endif
537 #endif
540 * tmpfile() should be adequate, except that it may require special privileges
541 * to use, e.g., MinGW and Windows 7 where it tries to use the root directory.
543 static FILE *
544 open_tmpfile(const char *label)
546 FILE *result;
547 #if USE_MKSTEMP
548 int fd;
549 const char *tmpdir;
550 char *name;
551 const char *mark;
553 if ((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0)
555 #ifdef P_tmpdir
556 tmpdir = P_tmpdir;
557 #else
558 tmpdir = "/tmp";
559 #endif
560 if (access(tmpdir, W_OK) != 0)
561 tmpdir = ".";
564 name = malloc(strlen(tmpdir) + 10 + strlen(label));
566 result = 0;
567 if (name != 0)
569 if ((mark = strrchr(label, '_')) == 0)
570 mark = label + strlen(label);
572 sprintf(name, "%s/%.*sXXXXXX", tmpdir, (int)(mark - label), label);
573 fd = mkstemp(name);
574 if (fd >= 0)
576 result = fdopen(fd, "w+");
577 if (result != 0)
579 MY_TMPFILES *item;
581 if (my_tmpfiles == 0)
583 atexit(close_tmpfiles);
586 item = NEW(MY_TMPFILES);
587 NO_SPACE(item);
589 item->name = name;
590 NO_SPACE(item->name);
592 item->next = my_tmpfiles;
593 my_tmpfiles = item;
597 #else
598 result = tmpfile();
599 #endif
601 if (result == 0)
602 open_error(label);
603 return result;
606 static void
607 open_files(void)
609 create_file_names();
611 if (input_file == 0)
613 input_file = fopen(input_file_name, "r");
614 if (input_file == 0)
615 open_error(input_file_name);
618 action_file = open_tmpfile("action_file");
619 text_file = open_tmpfile("text_file");
621 if (vflag)
623 verbose_file = fopen(verbose_file_name, "w");
624 if (verbose_file == 0)
625 open_error(verbose_file_name);
628 if (gflag)
630 graph_file = fopen(graph_file_name, "w");
631 if (graph_file == 0)
632 open_error(graph_file_name);
633 fprintf(graph_file, "digraph %s {\n", file_prefix);
634 fprintf(graph_file, "\tedge [fontsize=10];\n");
635 fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n");
636 fprintf(graph_file, "\torientation=landscape;\n");
637 fprintf(graph_file, "\trankdir=LR;\n");
638 fprintf(graph_file, "\t/*\n");
639 fprintf(graph_file, "\tmargin=0.2;\n");
640 fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n");
641 fprintf(graph_file, "\tratio=auto;\n");
642 fprintf(graph_file, "\t*/\n");
645 if (dflag)
647 defines_file = fopen(defines_file_name, "w");
648 if (defines_file == 0)
649 open_error(defines_file_name);
650 union_file = open_tmpfile("union_file");
653 if (iflag)
655 externs_file = fopen(externs_file_name, "w");
656 if (externs_file == 0)
657 open_error(externs_file_name);
660 output_file = fopen(output_file_name, "w");
661 if (output_file == 0)
662 open_error(output_file_name);
664 if (rflag)
666 code_file = fopen(code_file_name, "w");
667 if (code_file == 0)
668 open_error(code_file_name);
670 else
671 code_file = output_file;
675 main(int argc, char *argv[])
677 SRexpect = -1;
678 RRexpect = -1;
679 exit_code = EXIT_SUCCESS;
681 set_signals();
682 getargs(argc, argv);
683 open_files();
684 reader();
685 lr0();
686 lalr();
687 make_parser();
688 graph();
689 finalize_closure();
690 verbose();
691 output();
692 done(exit_code);
693 /*NOTREACHED */