diff options
author | Baptiste Daroussin <bapt@FreeBSD.org> | 2012-05-21 13:31:26 +0000 |
---|---|---|
committer | Baptiste Daroussin <bapt@FreeBSD.org> | 2012-05-21 13:31:26 +0000 |
commit | 98e903e7a0e26ebb7bec65bfe7f9a6b0d19dd966 (patch) | |
tree | c752c1d24d195a334247f36888203a7e2bce0837 /contrib/byacc/main.c | |
parent | c7e5232438a12e0798143b73dbae712a06ed0dee (diff) | |
parent | aec86590e4a004278acba93b5e6df2aee860b36d (diff) | |
download | src-98e903e7a0e26ebb7bec65bfe7f9a6b0d19dd966.tar.gz src-98e903e7a0e26ebb7bec65bfe7f9a6b0d19dd966.zip |
Import byacc from invisible island, it brings us lots of compatibilities with
bison, keeping full compatibility with our previous yacc implementation.
Also bring the ability to create reentrant parser
This fix bin/140309 [1]
PR: bin/140309 [1]
Submitted by: Philippe Pepiot <ksh@philpep.org> [1]
Approved by: des (mentor)
MFC after: 1 month
Notes
Notes:
svn path=/head/; revision=235723
Diffstat (limited to 'contrib/byacc/main.c')
-rw-r--r-- | contrib/byacc/main.c | 664 |
1 files changed, 664 insertions, 0 deletions
diff --git a/contrib/byacc/main.c b/contrib/byacc/main.c new file mode 100644 index 000000000000..0405a99b4bff --- /dev/null +++ b/contrib/byacc/main.c @@ -0,0 +1,664 @@ +/* $Id: main.c,v 1.38 2012/01/14 01:01:15 tom Exp $ */ + +#include <signal.h> +#include <unistd.h> /* for _exit() */ + +#include "defs.h" + +#if defined(HAVE_ATEXIT) +# ifdef HAVE_MKSTEMP +# define USE_MKSTEMP 1 +# elif defined(HAVE_FCNTL_H) +# define USE_MKSTEMP 1 +# include <fcntl.h> /* for open(), O_EXCL, etc. */ +# else +# define USE_MKSTEMP 0 +# endif +#else +# define USE_MKSTEMP 0 +#endif + +#if USE_MKSTEMP +#include <sys/types.h> +#include <sys/stat.h> + +typedef struct _my_tmpfiles +{ + struct _my_tmpfiles *next; + char *name; +} +MY_TMPFILES; + +static MY_TMPFILES *my_tmpfiles; +#endif /* USE_MKSTEMP */ + +char dflag; +char gflag; +char iflag; +char lflag; +static char oflag; +char rflag; +char sflag; +char tflag; +char vflag; + +const char *symbol_prefix; +const char *myname = "yacc"; + +int lineno; +int outline; + +static char empty_string[] = ""; +static char default_file_prefix[] = "y"; + +static char *file_prefix = default_file_prefix; + +char *code_file_name; +char *input_file_name = empty_string; +char *defines_file_name; +char *externs_file_name; + +static char *graph_file_name; +static char *output_file_name; +static char *verbose_file_name; + +FILE *action_file; /* a temp file, used to save actions associated */ + /* with rules until the parser is written */ +FILE *code_file; /* y.code.c (used when the -r option is specified) */ +FILE *defines_file; /* y.tab.h */ +FILE *externs_file; /* y.tab.i */ +FILE *input_file; /* the input file */ +FILE *output_file; /* y.tab.c */ +FILE *text_file; /* a temp file, used to save text until all */ + /* symbols have been defined */ +FILE *union_file; /* a temp file, used to save the union */ + /* definition until all symbol have been */ + /* defined */ +FILE *verbose_file; /* y.output */ +FILE *graph_file; /* y.dot */ + +int nitems; +int nrules; +int nsyms; +int ntokens; +int nvars; + +Value_t start_symbol; +char **symbol_name; +char **symbol_pname; +Value_t *symbol_value; +short *symbol_prec; +char *symbol_assoc; + +int pure_parser; +int exit_code; + +Value_t *ritem; +Value_t *rlhs; +Value_t *rrhs; +Value_t *rprec; +Assoc_t *rassoc; +Value_t **derives; +char *nullable; + +/* + * Since fclose() is called via the signal handler, it might die. Don't loop + * if there is a problem closing a file. + */ +#define DO_CLOSE(fp) \ + if (fp != 0) { \ + FILE *use = fp; \ + fp = 0; \ + fclose(use); \ + } + +static int got_intr = 0; + +void +done(int k) +{ + DO_CLOSE(input_file); + DO_CLOSE(output_file); + + DO_CLOSE(action_file); + DO_CLOSE(defines_file); + DO_CLOSE(graph_file); + DO_CLOSE(text_file); + DO_CLOSE(union_file); + DO_CLOSE(verbose_file); + + if (got_intr) + _exit(EXIT_FAILURE); + +#ifdef NO_LEAKS + if (rflag) + DO_FREE(code_file_name); + + if (dflag) + DO_FREE(defines_file_name); + + if (iflag) + DO_FREE(externs_file_name); + + if (oflag) + DO_FREE(output_file_name); + + if (vflag) + DO_FREE(verbose_file_name); + + if (gflag) + DO_FREE(graph_file_name); + + lr0_leaks(); + lalr_leaks(); + mkpar_leaks(); + output_leaks(); + reader_leaks(); +#endif + + if (rflag) + DO_CLOSE(code_file); + + exit(k); +} + +static void +onintr(__unused int sig) +{ + got_intr = 1; + done(EXIT_FAILURE); +} + +static void +set_signals(void) +{ +#ifdef SIGINT + if (signal(SIGINT, SIG_IGN) != SIG_IGN) + signal(SIGINT, onintr); +#endif +#ifdef SIGTERM + if (signal(SIGTERM, SIG_IGN) != SIG_IGN) + signal(SIGTERM, onintr); +#endif +#ifdef SIGHUP + if (signal(SIGHUP, SIG_IGN) != SIG_IGN) + signal(SIGHUP, onintr); +#endif +} + +static void +usage(void) +{ + static const char *msg[] = + { + "" + ,"Options:" + ," -b file_prefix set filename prefix (default \"y.\")" + ," -d write definitions (y.tab.h)" + ," -i write interface (y.tab.i)" + ," -g write a graphical description" + ," -l suppress #line directives" + ," -o output_file (default \"y.tab.c\")" + ," -p symbol_prefix set symbol prefix (default \"yy\")" + ," -P create a reentrant parser, e.g., \"%pure-parser\"" + ," -r produce separate code and table files (y.code.c)" + ," -s suppress #define's for quoted names in %token lines" + ," -t add debugging support" + ," -v write description (y.output)" + ," -V show version information and exit" + }; + unsigned n; + + fflush(stdout); + fprintf(stderr, "Usage: %s [options] filename\n", myname); + for (n = 0; n < sizeof(msg) / sizeof(msg[0]); ++n) + fprintf(stderr, "%s\n", msg[n]); + + exit(1); +} + +static void +setflag(int ch) +{ + switch (ch) + { + case 'd': + dflag = 1; + break; + + case 'g': + gflag = 1; + break; + + case 'i': + iflag = 1; + break; + + case 'l': + lflag = 1; + break; + + case 'P': + pure_parser = 1; + break; + + case 'r': + rflag = 1; + break; + + case 's': + sflag = 1; + break; + + case 't': + tflag = 1; + break; + + case 'v': + vflag = 1; + break; + + case 'V': + printf("%s - %s\n", myname, VERSION); + exit(EXIT_SUCCESS); + + case 'y': + /* noop for bison compatibility. byacc is already designed to be posix + * yacc compatible. */ + break; + + default: + usage(); + } +} + +static void +getargs(int argc, char *argv[]) +{ + int i; + char *s; + int ch; + + if (argc > 0) + myname = argv[0]; + + for (i = 1; i < argc; ++i) + { + s = argv[i]; + if (*s != '-') + break; + switch (ch = *++s) + { + case '\0': + input_file = stdin; + if (i + 1 < argc) + usage(); + return; + + case '-': + ++i; + goto no_more_options; + + case 'b': + if (*++s) + file_prefix = s; + else if (++i < argc) + file_prefix = argv[i]; + else + usage(); + continue; + + case 'o': + if (*++s) + output_file_name = s; + else if (++i < argc) + output_file_name = argv[i]; + else + usage(); + continue; + + case 'p': + if (*++s) + symbol_prefix = s; + else if (++i < argc) + symbol_prefix = argv[i]; + else + usage(); + continue; + + default: + setflag(ch); + break; + } + + for (;;) + { + switch (ch = *++s) + { + case '\0': + goto end_of_option; + + default: + setflag(ch); + break; + } + } + end_of_option:; + } + + no_more_options:; + if (i + 1 != argc) + usage(); + input_file_name = argv[i]; +} + +void * +allocate(size_t n) +{ + void *p; + + p = NULL; + if (n) + { + p = CALLOC(1, n); + NO_SPACE(p); + } + return (p); +} + +#define CREATE_FILE_NAME(dest, suffix) \ + dest = MALLOC(len + strlen(suffix) + 1); \ + NO_SPACE(dest); \ + strcpy(dest, file_prefix); \ + strcpy(dest + len, suffix) + +static void +create_file_names(void) +{ + size_t len; + const char *defines_suffix; + const char *externs_suffix; + char *prefix; + + prefix = NULL; + defines_suffix = DEFINES_SUFFIX; + externs_suffix = EXTERNS_SUFFIX; + + /* compute the file_prefix from the user provided output_file_name */ + if (output_file_name != 0) + { + if (!(prefix = strstr(output_file_name, ".tab.c")) + && (prefix = strstr(output_file_name, ".c"))) + { + defines_suffix = ".h"; + externs_suffix = ".i"; + } + } + + if (prefix != NULL) + { + len = (size_t) (prefix - output_file_name); + file_prefix = (char *)MALLOC(len + 1); + NO_SPACE(file_prefix); + strncpy(file_prefix, output_file_name, len)[len] = 0; + } + else + len = strlen(file_prefix); + + /* if "-o filename" was not given */ + if (output_file_name == 0) + { + oflag = 1; + CREATE_FILE_NAME(output_file_name, OUTPUT_SUFFIX); + } + + if (rflag) + { + CREATE_FILE_NAME(code_file_name, CODE_SUFFIX); + } + else + code_file_name = output_file_name; + + if (dflag) + { + CREATE_FILE_NAME(defines_file_name, defines_suffix); + } + + if (iflag) + { + CREATE_FILE_NAME(externs_file_name, externs_suffix); + } + + if (vflag) + { + CREATE_FILE_NAME(verbose_file_name, VERBOSE_SUFFIX); + } + + if (gflag) + { + CREATE_FILE_NAME(graph_file_name, GRAPH_SUFFIX); + } + + if (prefix != NULL) + { + FREE(file_prefix); + } +} + +#if USE_MKSTEMP +static void +close_tmpfiles(void) +{ + while (my_tmpfiles != 0) + { + MY_TMPFILES *next = my_tmpfiles->next; + + chmod(my_tmpfiles->name, 0644); + unlink(my_tmpfiles->name); + + free(my_tmpfiles->name); + free(my_tmpfiles); + + my_tmpfiles = next; + } +} + +#ifndef HAVE_MKSTEMP +static int +my_mkstemp(char *temp) +{ + int fd; + char *dname; + char *fname; + char *name; + + /* + * Split-up to use tempnam, rather than tmpnam; the latter (like + * mkstemp) is unusable on Windows. + */ + if ((fname = strrchr(temp, '/')) != 0) + { + dname = strdup(temp); + dname[++fname - temp] = '\0'; + } + else + { + dname = 0; + fname = temp; + } + if ((name = tempnam(dname, fname)) != 0) + { + fd = open(name, O_CREAT | O_EXCL | O_RDWR); + strcpy(temp, name); + } + else + { + fd = -1; + } + + if (dname != 0) + free(dname); + + return fd; +} +#define mkstemp(s) my_mkstemp(s) +#endif + +#endif + +/* + * tmpfile() should be adequate, except that it may require special privileges + * to use, e.g., MinGW and Windows 7 where it tries to use the root directory. + */ +static FILE * +open_tmpfile(const char *label) +{ + FILE *result; +#if USE_MKSTEMP + int fd; + const char *tmpdir; + char *name; + const char *mark; + + if ((tmpdir = getenv("TMPDIR")) == 0 || access(tmpdir, W_OK) != 0) + { +#ifdef P_tmpdir + tmpdir = P_tmpdir; +#else + tmpdir = "/tmp"; +#endif + if (access(tmpdir, W_OK) != 0) + tmpdir = "."; + } + + name = malloc(strlen(tmpdir) + 10 + strlen(label)); + + result = 0; + if (name != 0) + { + if ((mark = strrchr(label, '_')) == 0) + mark = label + strlen(label); + + sprintf(name, "%s/%.*sXXXXXX", tmpdir, (int)(mark - label), label); + fd = mkstemp(name); + if (fd >= 0) + { + result = fdopen(fd, "w+"); + if (result != 0) + { + MY_TMPFILES *item; + + if (my_tmpfiles == 0) + { + atexit(close_tmpfiles); + } + + item = NEW(MY_TMPFILES); + NO_SPACE(item); + + item->name = name; + NO_SPACE(item->name); + + item->next = my_tmpfiles; + my_tmpfiles = item; + } + } + } +#else + result = tmpfile(); +#endif + + if (result == 0) + open_error(label); + return result; +} + +static void +open_files(void) +{ + create_file_names(); + + if (input_file == 0) + { + input_file = fopen(input_file_name, "r"); + if (input_file == 0) + open_error(input_file_name); + } + + action_file = open_tmpfile("action_file"); + text_file = open_tmpfile("text_file"); + + if (vflag) + { + verbose_file = fopen(verbose_file_name, "w"); + if (verbose_file == 0) + open_error(verbose_file_name); + } + + if (gflag) + { + graph_file = fopen(graph_file_name, "w"); + if (graph_file == 0) + open_error(graph_file_name); + fprintf(graph_file, "digraph %s {\n", file_prefix); + fprintf(graph_file, "\tedge [fontsize=10];\n"); + fprintf(graph_file, "\tnode [shape=box,fontsize=10];\n"); + fprintf(graph_file, "\torientation=landscape;\n"); + fprintf(graph_file, "\trankdir=LR;\n"); + fprintf(graph_file, "\t/*\n"); + fprintf(graph_file, "\tmargin=0.2;\n"); + fprintf(graph_file, "\tpage=\"8.27,11.69\"; // for A4 printing\n"); + fprintf(graph_file, "\tratio=auto;\n"); + fprintf(graph_file, "\t*/\n"); + } + + if (dflag) + { + defines_file = fopen(defines_file_name, "w"); + if (defines_file == 0) + open_error(defines_file_name); + union_file = open_tmpfile("union_file"); + } + + if (iflag) + { + externs_file = fopen(externs_file_name, "w"); + if (externs_file == 0) + open_error(externs_file_name); + } + + output_file = fopen(output_file_name, "w"); + if (output_file == 0) + open_error(output_file_name); + + if (rflag) + { + code_file = fopen(code_file_name, "w"); + if (code_file == 0) + open_error(code_file_name); + } + else + code_file = output_file; +} + +int +main(int argc, char *argv[]) +{ + SRexpect = -1; + RRexpect = -1; + exit_code = EXIT_SUCCESS; + + set_signals(); + getargs(argc, argv); + open_files(); + reader(); + lr0(); + lalr(); + make_parser(); + graph(); + finalize_closure(); + verbose(); + output(); + done(exit_code); + /*NOTREACHED */ +} |