/* Output the generated parsing program for Bison.
- Copyright (C) 1984, 1986, 1989, 1992, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006, 2007, 2008, 2009, 2010 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 <pipe.h>
#include <quotearg.h>
+#include <spawn-pipe.h>
#include <timevar.h>
#include <wait-process.h>
#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_printf (&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_printf (&format_obstack, "%6d", table_data[i]); \
+ if (table_data[i] < min) \
+ min = table_data[i]; \
+ if (max < table_data[i]) \
+ max = table_data[i]; \
+ } \
+ muscle_insert (name, obstack_finish0 (&format_obstack)); \
+ \
+ lmin = min; \
+ lmax = max; \
+ /* Build `NAME_min' and `NAME_max' in the obstack. */ \
+ obstack_printf (&format_obstack, "%s_min", name); \
+ MUSCLE_INSERT_LONG_INT (obstack_finish0 (&format_obstack), lmin); \
+ obstack_printf (&format_obstack, "%s_max", name); \
+ MUSCLE_INSERT_LONG_INT (obstack_finish0 (&format_obstack), lmax); \
}
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_unsigned_int_table, unsigned int)
GENERATE_MUSCLE_INSERT_TABLE(muscle_insert_state_number_table, state_number)
-/*--------------------------------------------------------------------.
-| Print to OUT a representation of STRING escaped both for C and M4. |
-`--------------------------------------------------------------------*/
+/*----------------------------------------------------------------.
+| Print to OUT a representation of CP quoted and escaped for M4. |
+`----------------------------------------------------------------*/
static void
-escaped_output (FILE *out, char const *string)
+quoted_output (FILE *out, char const *cp)
{
- char const *p;
fprintf (out, "[[");
- for (p = quotearg_style (c_quoting_style, string); *p; p++)
- switch (*p)
+ for (; *cp; cp++)
+ switch (*cp)
{
case '$': fputs ("$][", out); break;
case '@': fputs ("@@", out); break;
case '[': fputs ("@{", out); break;
case ']': fputs ("@}", out); break;
- default: fputc (*p, out); break;
+ default: fputc (*cp, out); break;
}
fprintf (out, "]]");
}
+/*----------------------------------------------------------------.
+| Print to OUT a representation of STRING quoted and escaped both |
+| for C and M4. |
+`----------------------------------------------------------------*/
+
+static void
+string_output (FILE *out, char const *string)
+{
+ quoted_output (out, quotearg_style (c_quoting_style, string));
+}
+
/*------------------------------------------------------------------.
| Prepare the muscles related to the symbols: translate, tname, and |
static void
prepare_symbols (void)
{
- MUSCLE_INSERT_BOOL ("token_table", token_table_flag);
MUSCLE_INSERT_INT ("tokens_number", ntokens);
MUSCLE_INSERT_INT ("nterms_number", nvars);
MUSCLE_INSERT_INT ("symbols_number", nsyms);
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, ' ');
+ obstack_escape (&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[");
/* Finish table and store. */
- obstack_1grow (&format_obstack, 0);
- muscle_insert ("tname", obstack_finish (&format_obstack));
+ muscle_insert ("tname", obstack_finish0 (&format_obstack));
}
/* Output YYTOKNUM. */
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);
}
}
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_%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);
+ fprintf (out, "b4_%scase(%d, [b4_syncline(%d, ",
+ rules[r].is_predicate ? "predicate_" : "",
+ r + 1, rules[r].action_location.start.line);
+ string_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);
}
const char *key;
const char *value;
-#define SET_KEY(Entry) \
- obstack_fgrow2 (&format_obstack, "symbol(%d, %s)", i, Entry); \
- obstack_1grow (&format_obstack, 0); \
- key = obstack_finish (&format_obstack);
+#define SET_KEY(Entry) \
+ obstack_printf (&format_obstack, "symbol(%d, %s)", \
+ i, Entry); \
+ key = obstack_finish0 (&format_obstack);
+
+#define SET_KEY2(Entry, Suffix) \
+ obstack_printf (&format_obstack, "symbol(%d, %s_%s)", \
+ i, Entry, Suffix); \
+ key = obstack_finish0 (&format_obstack);
// Whether the symbol has an identifier.
value = symbol_id_get (sym);
SET_KEY("type");
MUSCLE_INSERT_STRING (key, sym->type_name ? sym->type_name : "");
-#define CODE_PROP(PropName) \
- do { \
- code_props const *p = symbol_ ## PropName ## _get (sym); \
- SET_KEY("has_" #PropName); \
- MUSCLE_INSERT_INT (key, !!p->code); \
- \
- if (p->code) \
- { \
- SET_KEY(#PropName "_file"); \
- MUSCLE_INSERT_STRING (key, p->location.start.file); \
- \
- SET_KEY(#PropName "_line"); \
- MUSCLE_INSERT_INT (key, p->location.start.line); \
- \
- SET_KEY(#PropName); \
- MUSCLE_INSERT_STRING_RAW (key, p->code); \
- } \
- } while (0)
-
- CODE_PROP(destructor);
- CODE_PROP(printer);
-#undef CODE_PROP
+ {
+ int j;
+ for (j = 0; j < CODE_PROPS_SIZE; ++j)
+ {
+ /* "printer", not "%printer". */
+ char const *pname = code_props_type_string (j) + 1;
+ code_props const *p = symbol_code_props_get (sym, j);
+ SET_KEY2("has", pname);
+ MUSCLE_INSERT_INT (key, !!p->code);
+
+ if (p->code)
+ {
+ SET_KEY2(pname, "file");
+ MUSCLE_INSERT_STRING (key, p->location.start.file);
+
+ SET_KEY2(pname, "line");
+ MUSCLE_INSERT_INT (key, p->location.start.line);
+
+ SET_KEY(pname);
+ MUSCLE_INSERT_STRING_RAW (key, p->code);
+ }
+ }
+ }
+#undef SET_KEY2
#undef SET_KEY
}
}
-/*--------------------------------------.
-| Output the tokens definition to OUT. |
-`--------------------------------------*/
-
-static void
-token_definitions_output (FILE *out)
-{
- int i;
- char const *sep = "";
-
- fputs ("m4_define([b4_tokens], \n[", out);
- for (i = 0; i < ntokens; ++i)
- {
- symbol *sym = symbols[i];
- int number = sym->user_token_number;
- 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);
-}
-
-
static void
prepare_actions (void)
{
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);
}
fputs ("m4_init()\n", out);
merger_output (out);
symbol_numbers_output (out);
- token_definitions_output (out);
type_names_output (out);
user_actions_output (out);
// Must be last.
static void
output_skeleton (void)
{
- FILE *in;
int filter_fd[2];
- char const *argv[10];
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;
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);
}
- /* 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);
- 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[1], "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);
- in = fdopen (filter_fd[0], "r");
- if (! in)
- error (EXIT_FAILURE, get_errno (),
- "fdopen");
- 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);
+ {
+ 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 ("defines_flag", defines_flag);
MUSCLE_INSERT_BOOL ("nondeterministic_flag", nondeterministic_parser);
MUSCLE_INSERT_BOOL ("synclines_flag", !no_lines_flag);
MUSCLE_INSERT_BOOL ("tag_seen_flag", tag_seen);
+ MUSCLE_INSERT_BOOL ("token_table_flag", token_table_flag);
MUSCLE_INSERT_BOOL ("use_push_for_pull_flag", use_push_for_pull_flag);
MUSCLE_INSERT_BOOL ("yacc_flag", yacc_flag);
/* 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;
}