/* Output the generated parsing program for Bison.
- Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ Copyright (C) 1984, 1986, 1989, 1992, 2000-2012 Free Software
+ Foundation, Inc.
This file is part of Bison, the GNU Compiler Compiler.
#include <config.h>
#include "system.h"
+#include <concat-filename.h>
#include <configmake.h>
-#include <error.h>
+#include <filename.h>
#include <get-errno.h>
#include <quotearg.h>
-#include <subpipe.h>
+#include <spawn-pipe.h>
#include <timevar.h>
+#include <wait-process.h>
#include "complain.h"
#include "files.h"
#include "getargs.h"
#include "gram.h"
-#include "muscle_tab.h"
+#include "muscle-tab.h"
#include "output.h"
#include "reader.h"
#include "scan-code.h" /* max_left_semantic_context */
#include "symtab.h"
#include "tables.h"
+# define ARRAY_CARDINALITY(Array) (sizeof (Array) / sizeof *(Array))
static struct obstack format_obstack;
`-------------------------------------------------------------------*/
-#define GENERATE_MUSCLE_INSERT_TABLE(Name, Type) \
- \
-static void \
-Name (char const *name, \
- Type *table_data, \
- Type first, \
- int begin, \
- int end) \
-{ \
- Type min = first; \
- Type max = first; \
- long int lmin; \
- long int lmax; \
- int i; \
- int j = 1; \
- \
- obstack_fgrow1 (&format_obstack, "%6d", first); \
- for (i = begin; i < end; ++i) \
- { \
- obstack_1grow (&format_obstack, ','); \
- if (j >= 10) \
- { \
- obstack_sgrow (&format_obstack, "\n "); \
- j = 1; \
- } \
- else \
- ++j; \
- obstack_fgrow1 (&format_obstack, "%6d", table_data[i]); \
- if (table_data[i] < min) \
- min = table_data[i]; \
- if (max < table_data[i]) \
- max = table_data[i]; \
- } \
- obstack_1grow (&format_obstack, 0); \
- muscle_insert (name, obstack_finish (&format_obstack)); \
- \
- lmin = min; \
- lmax = max; \
- /* Build `NAME_min' and `NAME_max' in the obstack. */ \
- obstack_fgrow1 (&format_obstack, "%s_min", name); \
- obstack_1grow (&format_obstack, 0); \
- MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin); \
- obstack_fgrow1 (&format_obstack, "%s_max", name); \
- obstack_1grow (&format_obstack, 0); \
- MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax); \
+#define GENERATE_MUSCLE_INSERT_TABLE(Name, Type) \
+ \
+static void \
+Name (char const *name, \
+ Type *table_data, \
+ Type first, \
+ int begin, \
+ int end) \
+{ \
+ Type min = first; \
+ Type max = first; \
+ long int lmin; \
+ long int lmax; \
+ int i; \
+ int j = 1; \
+ \
+ obstack_fgrow1 (&format_obstack, "%6d", first); \
+ for (i = begin; i < end; ++i) \
+ { \
+ obstack_1grow (&format_obstack, ','); \
+ if (j >= 10) \
+ { \
+ obstack_sgrow (&format_obstack, "\n "); \
+ j = 1; \
+ } \
+ else \
+ ++j; \
+ obstack_fgrow1 (&format_obstack, "%6d", table_data[i]); \
+ if (table_data[i] < min) \
+ min = table_data[i]; \
+ if (max < table_data[i]) \
+ max = table_data[i]; \
+ } \
+ obstack_1grow (&format_obstack, 0); \
+ muscle_insert (name, obstack_finish (&format_obstack)); \
+ \
+ lmin = min; \
+ lmax = max; \
+ /* Build `NAME_min' and `NAME_max' in the obstack. */ \
+ obstack_fgrow1 (&format_obstack, "%s_min", name); \
+ obstack_1grow (&format_obstack, 0); \
+ MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmin); \
+ obstack_fgrow1 (&format_obstack, "%s_max", name); \
+ obstack_1grow (&format_obstack, 0); \
+ MUSCLE_INSERT_LONG_INT (obstack_finish (&format_obstack), lmax); \
}
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_unsigned_int_table, unsigned int)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_base_table, base_number)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_rule_number_table, rule_number)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_symbol_number_table, symbol_number)
-GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_item_number_table, item_number)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number)
MUSCLE_INSERT_INT ("user_token_number_max", max_user_token_number);
muscle_insert_symbol_number_table ("translate",
- token_translations,
- token_translations[0],
- 1, max_user_token_number + 1);
+ token_translations,
+ token_translations[0],
+ 1, max_user_token_number + 1);
/* tname -- token names. */
{
set_quoting_flags (qo, QA_SPLIT_TRIGRAPHS);
for (i = 0; i < nsyms; i++)
{
- char *cp = quotearg_alloc (symbols[i]->tag, -1, qo);
- /* Width of the next token, including the two quotes, the
- comma and the space. */
- int width = strlen (cp) + 2;
-
- if (j + width > 75)
- {
- obstack_sgrow (&format_obstack, "\n ");
- j = 1;
- }
-
- if (i)
- obstack_1grow (&format_obstack, ' ');
- MUSCLE_OBSTACK_SGROW (&format_obstack, cp);
+ char *cp = quotearg_alloc (symbols[i]->tag, -1, qo);
+ /* Width of the next token, including the two quotes, the
+ comma and the space. */
+ int width = strlen (cp) + 2;
+
+ if (j + width > 75)
+ {
+ obstack_sgrow (&format_obstack, "\n ");
+ j = 1;
+ }
+
+ if (i)
+ obstack_1grow (&format_obstack, ' ');
+ MUSCLE_OBSTACK_SGROW (&format_obstack, cp);
free (cp);
- obstack_1grow (&format_obstack, ',');
- j += width;
+ obstack_1grow (&format_obstack, ',');
+ j += width;
}
free (qo);
obstack_sgrow (&format_obstack, " ]b4_null[");
for (i = 0; i < ntokens; ++i)
values[i] = symbols[i]->user_token_number;
muscle_insert_int_table ("toknum", values,
- values[0], 1, ntokens);
+ values[0], 1, ntokens);
free (values);
}
}
/*----------------------------------------------------------------.
| Prepare the muscles related to the rules: r1, r2, rline, dprec, |
-| merger. |
+| merger, immediate. |
`----------------------------------------------------------------*/
static void
unsigned int *r2 = xnmalloc (nrules, sizeof *r2);
int *dprec = xnmalloc (nrules, sizeof *dprec);
int *merger = xnmalloc (nrules, sizeof *merger);
+ int *immediate = xnmalloc (nrules, sizeof *immediate);
rule_number r;
for (r = 0; r < nrules; ++r)
dprec[r] = rules[r].dprec;
/* Merger-function index (GLR). */
merger[r] = rules[r].merger;
+ /* Immediate reduction flags (GLR). */
+ immediate[r] = rules[r].is_predicate;
}
muscle_insert_unsigned_int_table ("rline", rline, 0, 0, nrules);
muscle_insert_unsigned_int_table ("r2", r2, 0, 0, nrules);
muscle_insert_int_table ("dprec", dprec, 0, 0, nrules);
muscle_insert_int_table ("merger", merger, 0, 0, nrules);
+ muscle_insert_int_table ("immediate", immediate, 0, 0, nrules);
MUSCLE_INSERT_INT ("rules_number", nrules);
MUSCLE_INSERT_INT ("max_left_semantic_context", max_left_semantic_context);
free (r2);
free (dprec);
free (merger);
+ free (immediate);
}
/*--------------------------------------------.
for (i = 0; i < nstates; ++i)
values[i] = states[i]->accessing_symbol;
muscle_insert_symbol_number_table ("stos", values,
- 0, 1, nstates);
+ 0, 1, nstates);
free (values);
MUSCLE_INSERT_INT ("last", high);
for (r = 0; r < nrules; ++r)
if (rules[r].action)
{
- fprintf (out, "b4_case(%d, [b4_syncline(%d, ", r + 1,
- rules[r].action_location.start.line);
- escaped_output (out, rules[r].action_location.start.file);
- fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
+ fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ",
+ rules[r].is_predicate ? "predicate_" : "",
+ r + 1, rules[r].action_location.start.line);
+ escaped_output (out, rules[r].action_location.start.file);
+ fprintf (out, ")\n[ %s]])\n\n", rules[r].action);
}
fputs ("])\n\n", out);
}
for (n = 1, p = merge_functions; p != NULL; n += 1, p = p->next)
{
if (p->type[0] == '\0')
- fprintf (out, " case %d: *yy0 = %s (*yy0, *yy1); break;\n",
- n, p->name);
+ fprintf (out, " case %d: *yy0 = %s (*yy0, *yy1); break;\n",
+ n, p->name);
else
- fprintf (out, " case %d: yy0->%s = %s (*yy0, *yy1); break;\n",
- n, p->type, p->name);
+ fprintf (out, " case %d: yy0->%s = %s (*yy0, *yy1); break;\n",
+ n, p->type, p->name);
}
fputs ("]])\n\n", out);
}
#define CODE_PROP(PropName) \
do { \
- code_props const *p = symbol_ ## PropName ## _get (sym); \
+ code_props const *p = symbol_code_props_get (sym, PropName); \
SET_KEY("has_" #PropName); \
MUSCLE_INSERT_INT (key, !!p->code); \
\
{
symbol *sym = symbols[i];
int number = sym->user_token_number;
-
- /* At this stage, if there are literal aliases, they are part of
- SYMBOLS, so we should not find symbols which are the aliases
- here. */
- aver (number != USER_NUMBER_ALIAS);
-
- /* Skip error token. */
- if (sym == errtoken)
- continue;
-
- /* If this string has an alias, then it is necessarily the alias
- which is to be output. */
- if (sym->alias)
- sym = sym->alias;
-
- /* Don't output literal chars or strings (when defined only as a
- string). Note that must be done after the alias resolution:
- think about `%token 'f' "f"'. */
- if (sym->tag[0] == '\'' || sym->tag[0] == '\"')
- continue;
-
- /* Don't #define nonliteral tokens whose names contain periods
- or '$' (as does the default value of the EOF token). */
- if (strchr (sym->tag, '.') || strchr (sym->tag, '$'))
- continue;
-
- fprintf (out, "%s[[[%s]], %d]",
- sep, sym->tag, number);
- sep = ",\n";
+ uniqstr id = symbol_id_get (sym);
+
+ /* At this stage, if there are literal string aliases, they are
+ part of SYMBOLS, so we should not find their aliased symbols
+ here. */
+ aver (number != USER_NUMBER_HAS_STRING_ALIAS);
+
+ /* Skip error token and tokens without identifier. */
+ if (sym != errtoken && id)
+ {
+ fprintf (out, "%s[[[%s]], %d]",
+ sep, id, number);
+ sep = ",\n";
+ }
}
fputs ("])\n\n", out);
}
lookahead token type. */
muscle_insert_rule_number_table ("defact", yydefact,
- yydefact[0], 1, nstates);
+ yydefact[0], 1, nstates);
/* Figure out what to do after reducing with each rule, depending on
the saved state from before the beginning of parsing the data
that matched this rule. */
muscle_insert_state_number_table ("defgoto", yydefgoto,
- yydefgoto[0], 1, nsyms - ntokens);
+ yydefgoto[0], 1, nsyms - ntokens);
/* Output PACT. */
muscle_insert_base_table ("pact", base,
- base[0], 1, nstates);
+ base[0], 1, nstates);
MUSCLE_INSERT_INT ("pact_ninf", base_ninf);
/* Output PGOTO. */
muscle_insert_base_table ("pgoto", base,
- base[nstates], nstates + 1, nvectors);
+ base[nstates], nstates + 1, nvectors);
muscle_insert_base_table ("table", table,
- table[0], 1, high + 1);
+ table[0], 1, high + 1);
MUSCLE_INSERT_INT ("table_ninf", table_ninf);
muscle_insert_base_table ("check", check,
- check[0], 1, high + 1);
+ check[0], 1, high + 1);
/* GLR parsing slightly modifies YYTABLE and YYCHECK (and thus
YYPACT) so that in states with unresolved conflicts, the default
that case. Nevertheless, it seems even better to be able to use
the GLR skeletons even without the non-deterministic tables. */
muscle_insert_unsigned_int_table ("conflict_list_heads", conflict_table,
- conflict_table[0], 1, high + 1);
+ conflict_table[0], 1, high + 1);
muscle_insert_unsigned_int_table ("conflicting_rules", conflict_list,
- 0, 1, conflict_list_cnt);
+ 0, 1, conflict_list_cnt);
}
static void
output_skeleton (void)
{
- FILE *in;
int filter_fd[2];
- char const *argv[9];
pid_t pid;
/* Compute the names of the package data dir and skeleton files. */
- char const m4sugar[] = "m4sugar/m4sugar.m4";
- char const m4bison[] = "bison.m4";
- char *full_m4sugar;
- char *full_m4bison;
- char *full_skeleton;
- char const *p;
- char const *m4 = (p = getenv ("M4")) ? p : M4;
- char const *pkgdatadir = compute_pkgdatadir ();
- size_t skeleton_size = strlen (skeleton) + 1;
- size_t pkgdatadirlen = strlen (pkgdatadir);
- while (pkgdatadirlen && pkgdatadir[pkgdatadirlen - 1] == '/')
- pkgdatadirlen--;
- full_skeleton = xmalloc (pkgdatadirlen + 1
- + (skeleton_size < sizeof m4sugar
- ? sizeof m4sugar : skeleton_size));
- strncpy (full_skeleton, pkgdatadir, pkgdatadirlen);
- full_skeleton[pkgdatadirlen] = '/';
- strcpy (full_skeleton + pkgdatadirlen + 1, m4sugar);
- full_m4sugar = xstrdup (full_skeleton);
- strcpy (full_skeleton + pkgdatadirlen + 1, m4bison);
- full_m4bison = xstrdup (full_skeleton);
- if (strchr (skeleton, '/'))
- strcpy (full_skeleton, skeleton);
- else
- strcpy (full_skeleton + pkgdatadirlen + 1, skeleton);
+ char const *m4 = (m4 = getenv ("M4")) ? m4 : M4;
+ char const *datadir = pkgdatadir ();
+ char *m4sugar = xconcatenated_filename (datadir, "m4sugar/m4sugar.m4", NULL);
+ char *m4bison = xconcatenated_filename (datadir, "bison.m4", NULL);
+ char *skel = (IS_PATH_WITH_DIR (skeleton)
+ ? xstrdup (skeleton)
+ : xconcatenated_filename (datadir, skeleton, NULL));
/* Test whether m4sugar.m4 is readable, to check for proper
installation. A faulty installation can cause deadlock, so a
cheap sanity check is worthwhile. */
- xfclose (xfopen (full_m4sugar, "r"));
+ xfclose (xfopen (m4sugar, "r"));
/* Create an m4 subprocess connected to us via two pipes. */
if (trace_flag & trace_tools)
fprintf (stderr, "running: %s %s - %s %s\n",
- m4, full_m4sugar, full_m4bison, full_skeleton);
+ m4, m4sugar, m4bison, skel);
/* Some future version of GNU M4 (most likely 1.6) may treat the -dV in a
position-dependent manner. Keep it as the first argument so that all
<http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
for details. */
{
+ char const *argv[10];
int i = 0;
argv[i++] = m4;
+
+ /* When POSIXLY_CORRECT is set, GNU M4 1.6 and later disable GNU
+ extensions, which Bison's skeletons depend on. With older M4,
+ it has no effect. M4 1.4.12 added a -g/--gnu command-line
+ option to make it explicit that a program wants GNU M4
+ extensions even when POSIXLY_CORRECT is set.
+
+ See the thread starting at
+ <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
+ for details. */
+ if (*M4_GNU_OPTION)
+ argv[i++] = M4_GNU_OPTION;
+
argv[i++] = "-I";
- argv[i++] = pkgdatadir;
+ argv[i++] = datadir;
if (trace_flag & trace_m4)
argv[i++] = "-dV";
- argv[i++] = full_m4sugar;
+ argv[i++] = m4sugar;
argv[i++] = "-";
- argv[i++] = full_m4bison;
- argv[i++] = full_skeleton;
+ argv[i++] = m4bison;
+ argv[i++] = skel;
argv[i++] = NULL;
+ aver (i <= ARRAY_CARDINALITY (argv));
+
+ /* The ugly cast is because gnulib gets the const-ness wrong. */
+ pid = create_pipe_bidi ("m4", m4, (char **)(void*)argv, false, true,
+ true, filter_fd);
}
- /* When POSIXLY_CORRECT is set, some future versions of GNU M4 (most likely
- 2.0) may drop some of the GNU extensions that Bison's skeletons depend
- upon. So that the next release of Bison is forward compatible with those
- future versions of GNU M4, we unset POSIXLY_CORRECT here.
-
- FIXME: A user might set POSIXLY_CORRECT to affect processes run from
- macros like m4_syscmd in a custom skeleton. For now, Bison makes no
- promises about the behavior of custom skeletons, so this scenario is not a
- concern. However, we eventually want to eliminate this shortcoming. The
- next release of GNU M4 (1.4.12 or 1.6) will accept the -g command-line
- option as a no-op, and later releases will accept it to indicate that
- POSIXLY_CORRECT should be ignored. Once the GNU M4 versions that accept
- -g are pervasive, Bison should use -g instead of unsetting
- POSIXLY_CORRECT.
- See the thread starting at
- <http://lists.gnu.org/archive/html/bug-bison/2008-07/msg00000.html>
- for details. */
- unsetenv ("POSIXLY_CORRECT");
- init_subpipe ();
- pid = create_subpipe (argv, filter_fd);
- free (full_m4sugar);
- free (full_m4bison);
- free (full_skeleton);
+ free (m4sugar);
+ free (m4bison);
+ free (skel);
if (trace_flag & trace_muscles)
muscles_output (stderr);
{
- FILE *out = fdopen (filter_fd[0], "w");
- if (! out)
- error (EXIT_FAILURE, get_errno (),
- "fdopen");
+ FILE *out = xfdopen (filter_fd[1], "w");
muscles_output (out);
xfclose (out);
}
/* Read and process m4's output. */
timevar_push (TV_M4);
- end_of_output_subpipe (pid, filter_fd);
- in = fdopen (filter_fd[1], "r");
- if (! in)
- error (EXIT_FAILURE, get_errno (),
- "fdopen");
- scan_skel (in);
- xfclose (in);
- reap_subpipe (pid, m4);
+ {
+ FILE *in = xfdopen (filter_fd[0], "r");
+ scan_skel (in);
+ /* scan_skel should have read all of M4's output. Otherwise, when we
+ close the pipe, we risk letting M4 report a broken-pipe to the
+ Bison user. */
+ aver (feof (in));
+ xfclose (in);
+ }
+ wait_subprocess (pid, "m4", false, false, true, true, NULL);
timevar_pop (TV_M4);
}
static void
prepare (void)
{
- /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be documented
- for the user. */
- char const *use_push_for_pull_env = getenv ("BISON_USE_PUSH_FOR_PULL");
- bool use_push_for_pull_flag = false;
- if (use_push_for_pull_env != NULL
- && use_push_for_pull_env[0] != '\0'
- && 0 != strcmp (use_push_for_pull_env, "0"))
- use_push_for_pull_flag = true;
+ /* BISON_USE_PUSH_FOR_PULL is for the test suite and should not be
+ documented for the user. */
+ char const *cp = getenv ("BISON_USE_PUSH_FOR_PULL");
+ bool use_push_for_pull_flag = cp && *cp && strtol (cp, 0, 10);
/* Flags. */
- MUSCLE_INSERT_BOOL ("debug_flag", debug_flag);
MUSCLE_INSERT_BOOL ("defines_flag", defines_flag);
- MUSCLE_INSERT_BOOL ("error_verbose_flag", error_verbose);
MUSCLE_INSERT_BOOL ("glr_flag", glr_parser);
- MUSCLE_INSERT_BOOL ("locations_flag", locations_flag);
MUSCLE_INSERT_BOOL ("nondeterministic_flag", nondeterministic_parser);
MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag);
MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen);
/* b4_pkgdatadir is used inside m4_include in the skeletons, so digraphs
would never be expanded. Hopefully no one has M4-special characters in
his Bison installation path. */
- MUSCLE_INSERT_STRING_RAW ("pkgdatadir", compute_pkgdatadir ());
+ MUSCLE_INSERT_STRING_RAW ("pkgdatadir", pkgdatadir ());
}
}
}
char const *
-compute_pkgdatadir (void)
+pkgdatadir (void)
{
- char const *pkgdatadir = getenv ("BISON_PKGDATADIR");
- return pkgdatadir ? pkgdatadir : PKGDATADIR;
+ char const *cp = getenv ("BISON_PKGDATADIR");
+ return cp ? cp : PKGDATADIR;
}