- This file is part of Bison, the GNU Compiler Compiler.
-
- Bison is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Bison is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Bison; see the file COPYING. If not, write to
- the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
-
-
-#include "system.h"
-#include "obstack.h"
-#include "quotearg.h"
-#include "quote.h"
-#include "getargs.h"
-#include "files.h"
-#include "symtab.h"
-#include "options.h"
-#include "lex.h"
-#include "gram.h"
-#include "complain.h"
-#include "output.h"
-#include "reader.h"
-#include "conflicts.h"
-#include "muscle_tab.h"
-
-typedef struct symbol_list
-{
- struct symbol_list *next;
- bucket *sym;
- int line;
- bucket *ruleprec;
-}
-symbol_list;
-
-int lineno;
-char **tags;
-short *user_toknums;
-static symbol_list *grammar;
-static int start_flag;
-static bucket *startval;
-
-/* Nonzero if components of semantic values are used, implying
- they must be unions. */
-static int value_components_used;
-
-/* Nonzero if %union has been seen. */
-static int typed;
-
-/* Incremented for each %left, %right or %nonassoc seen */
-static int lastprec;
-
-static bucket *errtoken;
-static bucket *undeftoken;
-
-
-static symbol_list *
-symbol_list_new (bucket *sym)
-{
- symbol_list *res = XMALLOC (symbol_list, 1);
- res->next = NULL;
- res->sym = sym;
- res->line = lineno;
- res->ruleprec = NULL;
- return res;
-}
-
-\f
-
-/*===================\
-| Low level lexing. |
-\===================*/
-
-static void
-skip_to_char (int target)
-{
- int c;
- if (target == '\n')
- complain (_(" Skipping to next \\n"));
- else
- complain (_(" Skipping to next %c"), target);
-
- do
- c = skip_white_space ();
- while (c != target && c != EOF);
- if (c != EOF)
- ungetc (c, finput);
-}
-
-
-/*---------------------------------------------------------.
-| Read a signed integer from STREAM and return its value. |
-`---------------------------------------------------------*/
-
-static inline int
-read_signed_integer (FILE *stream)
-{
- int c = getc (stream);
- int sign = 1;
- int n = 0;
-
- if (c == '-')
- {
- c = getc (stream);
- sign = -1;
- }
-
- while (isdigit (c))
- {
- n = 10 * n + (c - '0');
- c = getc (stream);
- }
-
- ungetc (c, stream);
-
- return sign * n;
-}
-\f
-/*--------------------------------------------------------------.
-| Get the data type (alternative in the union) of the value for |
-| symbol N in rule RULE. |
-`--------------------------------------------------------------*/
-
-static char *
-get_type_name (int n, symbol_list *rule)
-{
- int i;
- symbol_list *rp;
-
- if (n < 0)
- {
- complain (_("invalid $ value"));
- return NULL;
- }
-
- rp = rule;
- i = 0;
-
- while (i < n)
- {
- rp = rp->next;
- if (rp == NULL || rp->sym == NULL)
- {
- complain (_("invalid $ value"));
- return NULL;
- }
- i++;
- }
-
- return rp->sym->type_name;
-}
-\f
-/*------------------------------------------------------------.
-| Dump the string from FIN to OOUT if non null. MATCH is the |
-| delimiter of the string (either ' or "). |
-`------------------------------------------------------------*/
-
-static inline void
-copy_string2 (FILE *fin, struct obstack *oout, int match, int store)
-{
- int c;
-
- if (store)
- obstack_1grow (oout, match);
-
- c = getc (fin);
-
- while (c != match)
- {
- if (c == EOF)
- fatal (_("unterminated string at end of file"));
- if (c == '\n')
- {
- complain (_("unterminated string"));
- ungetc (c, fin);
- c = match; /* invent terminator */
- continue;
- }
-
- obstack_1grow (oout, c);
-
- if (c == '\\')
- {
- c = getc (fin);
- if (c == EOF)
- fatal (_("unterminated string at end of file"));
- obstack_1grow (oout, c);
-
- if (c == '\n')
- lineno++;
- }
-
- c = getc (fin);
- }
-
- if (store)
- obstack_1grow (oout, c);
-}
-
-/* FIXME. */
-
-static inline void
-copy_string (FILE *fin, struct obstack *oout, int match)
-{
- copy_string2 (fin, oout, match, 1);
-}
-
-/* FIXME. */
-
-static inline void
-copy_identifier (FILE *fin, struct obstack *oout)
-{
- int c;
-
- while (isalnum (c = getc (fin)) || c == '_')
- obstack_1grow (oout, c);
-
- ungetc (c, fin);
-}
-
-/*-----------------------------------------------------------------.
-| Dump the wannabee comment from IN to OUT1 and OUT2 (which can be |
-| NULL). In fact we just saw a `/', which might or might not be a |
-| comment. In any case, copy what we saw. |
-| |
-| OUT2 might be NULL. |
-`-----------------------------------------------------------------*/
-
-static inline void
-copy_comment2 (FILE *fin, struct obstack *oout1, struct obstack *oout2)
-{
- int cplus_comment;
- int ended;
- int c;
-
- /* We read a `/', output it. */
- obstack_1grow (oout1, '/');
- if (oout2)
- obstack_1grow (oout2, '/');
-
- switch ((c = getc (fin)))
- {
- case '/':
- cplus_comment = 1;
- break;
- case '*':
- cplus_comment = 0;
- break;
- default:
- ungetc (c, fin);
- return;
- }
-
- obstack_1grow (oout1, c);
- if (oout2)
- obstack_1grow (oout2, c);
- c = getc (fin);
-
- ended = 0;
- while (!ended)
- {
- if (!cplus_comment && c == '*')
- {
- while (c == '*')
- {
- obstack_1grow (oout1, c);
- if (oout2)
- obstack_1grow (oout2, c);
- c = getc (fin);
- }
-
- if (c == '/')
- {
- obstack_1grow (oout1, c);
- if (oout2)
- obstack_1grow (oout2, c);
- ended = 1;
- }
- }
- else if (c == '\n')
- {
- lineno++;
- obstack_1grow (oout1, c);
- if (oout2)
- obstack_1grow (oout2, c);
- if (cplus_comment)
- ended = 1;
- else
- c = getc (fin);
- }
- else if (c == EOF)
- fatal (_("unterminated comment"));
- else
- {
- obstack_1grow (oout1, c);
- if (oout2)
- obstack_1grow (oout2, c);
- c = getc (fin);
- }
- }
-}
-
-
-/*-------------------------------------------------------------------.
-| Dump the comment (actually the current string starting with a `/') |
-| from FIN to OOUT. |
-`-------------------------------------------------------------------*/
-
-static inline void
-copy_comment (FILE *fin, struct obstack *oout)
-{
- copy_comment2 (fin, oout, NULL);
-}
-
-
-/*-----------------------------------------------------------------.
-| FIN is pointing to a location (i.e., a `@'). Output to OOUT a |
-| reference to this location. STACK_OFFSET is the number of values |
-| in the current rule so far, which says where to find `$0' with |
-| respect to the top of the stack. |
-`-----------------------------------------------------------------*/
-
-static inline void
-copy_at (FILE *fin, struct obstack *oout, int stack_offset)
-{
- int c;
-
- c = getc (fin);
- if (c == '$')
- {
- obstack_sgrow (oout, "yyloc");
- locations_flag = 1;
- }
- else if (isdigit (c) || c == '-')
- {
- int n;
-
- ungetc (c, fin);
- n = read_signed_integer (fin);
-
- obstack_fgrow1 (oout, "yylsp[%d]", n - stack_offset);
- locations_flag = 1;
- }
- else
- {
- char buf[] = "@c";
- buf[1] = c;
- complain (_("%s is invalid"), quote (buf));
- }
-}
-
-
-/*-------------------------------------------------------------------.
-| FIN is pointing to a wannabee semantic value (i.e., a `$'). |
-| |
-| Possible inputs: $[<TYPENAME>]($|integer) |
-| |
-| Output to OOUT a reference to this semantic value. STACK_OFFSET is |
-| the number of values in the current rule so far, which says where |
-| to find `$0' with respect to the top of the stack. |
-`-------------------------------------------------------------------*/
-
-static inline void
-copy_dollar (FILE *fin, struct obstack *oout,
- symbol_list *rule, int stack_offset)
-{
- int c = getc (fin);
- const char *type_name = NULL;
-
- /* Get the type name if explicit. */
- if (c == '<')
- {
- read_type_name (fin);
- type_name = token_buffer;
- value_components_used = 1;
- c = getc (fin);
- }
-
- if (c == '$')
- {
- obstack_sgrow (oout, "yyval");
-
- if (!type_name)
- type_name = get_type_name (0, rule);
- if (type_name)
- obstack_fgrow1 (oout, ".%s", type_name);
- if (!type_name && typed)
- complain (_("$$ of `%s' has no declared type"),
- rule->sym->tag);
- }
- else if (isdigit (c) || c == '-')
- {
- int n;
- ungetc (c, fin);
- n = read_signed_integer (fin);
-
- if (!type_name && n > 0)
- type_name = get_type_name (n, rule);
-
- obstack_fgrow1 (oout, "yyvsp[%d]", n - stack_offset);
-
- if (type_name)
- obstack_fgrow1 (oout, ".%s", type_name);
- if (!type_name && typed)
- complain (_("$%d of `%s' has no declared type"),
- n, rule->sym->tag);
- }
- else
- {
- char buf[] = "$c";
- buf[1] = c;
- complain (_("%s is invalid"), quote (buf));
- }
-}
-\f
-/*-------------------------------------------------------------------.
-| Copy the contents of a `%{ ... %}' into the definitions file. The |
-| `%{' has already been read. Return after reading the `%}'. |
-`-------------------------------------------------------------------*/
-
-static void
-copy_definition (void)
-{
- int c;
- /* -1 while reading a character if prev char was %. */
- int after_percent;
-
-#if 0
- if (!no_lines_flag)
- {
- obstack_fgrow2 (&attrs_obstack, muscle_find ("linef"),
- lineno, quotearg_style (c_quoting_style,
- muscle_find("filename")));
- }
-#endif
-
- after_percent = 0;
-
- c = getc (finput);
-
- for (;;)
- {
- switch (c)
- {
- case '\n':
- obstack_1grow (&attrs_obstack, c);
- lineno++;
- break;
-
- case '%':
- after_percent = -1;
- break;
-
- case '\'':
- case '"':
- copy_string (finput, &attrs_obstack, c);
- break;
-
- case '/':
- copy_comment (finput, &attrs_obstack);
- break;
-
- case EOF:
- fatal ("%s", _("unterminated `%{' definition"));
-
- default:
- obstack_1grow (&attrs_obstack, c);
- }
-
- c = getc (finput);
-
- if (after_percent)
- {
- if (c == '}')
- return;
- obstack_1grow (&attrs_obstack, '%');
- }
- after_percent = 0;
- }
-}
-
-
-/*-------------------------------------------------------------------.
-| Parse what comes after %token or %nterm. For %token, WHAT_IS is |
-| token_sym and WHAT_IS_NOT is nterm_sym. For %nterm, the arguments |
-| are reversed. |
-`-------------------------------------------------------------------*/
-
-static void
-parse_token_decl (symbol_class what_is, symbol_class what_is_not)
-{
- token_t token = tok_undef;
- char *typename = NULL;
-
- /* The symbol being defined. */
- struct bucket *symbol = NULL;
-
- /* After `%token' and `%nterm', any number of symbols maybe be
- defined. */
- for (;;)
- {
- int tmp_char = ungetc (skip_white_space (), finput);
-
- /* `%' (for instance from `%token', or from `%%' etc.) is the
- only valid means to end this declaration. */
- if (tmp_char == '%')
- return;
- if (tmp_char == EOF)
- fatal (_("Premature EOF after %s"), token_buffer);
-
- token = lex ();
- if (token == tok_comma)
- {
- symbol = NULL;
- continue;
- }
- if (token == tok_typename)
- {
- typename = xstrdup (token_buffer);
- value_components_used = 1;
- symbol = NULL;
- }
- else if (token == tok_identifier && *symval->tag == '\"' && symbol)
- {
- if (symval->alias)
- warn (_("symbol `%s' used more than once as a literal string"),
- symval->tag);
- else if (symbol->alias)
- warn (_("symbol `%s' given more than one literal string"),
- symbol->tag);
- else
- {
- symval->class = token_sym;
- symval->type_name = typename;
- symval->user_token_number = symbol->user_token_number;
- symbol->user_token_number = SALIAS;
- symval->alias = symbol;
- symbol->alias = symval;
- /* symbol and symval combined are only one symbol */
- nsyms--;
- }
- symbol = NULL;
- }
- else if (token == tok_identifier)
- {
- int oldclass = symval->class;
- symbol = symval;
-
- if (symbol->class == what_is_not)
- complain (_("symbol %s redefined"), symbol->tag);
- symbol->class = what_is;
- if (what_is == nterm_sym && oldclass != nterm_sym)
- symbol->value = nvars++;
-
- if (typename)
- {
- if (symbol->type_name == NULL)
- symbol->type_name = typename;
- else if (strcmp (typename, symbol->type_name) != 0)
- complain (_("type redeclaration for %s"), symbol->tag);
- }
- }
- else if (symbol && token == tok_number)
- {
- symbol->user_token_number = numval;
- }
- else
- {
- complain (_("`%s' is invalid in %s"),
- token_buffer,
- (what_is == token_sym) ? "%token" : "%nterm");
- skip_to_char ('%');
- }
- }
-
-}
-
-
-/*------------------------------.
-| Parse what comes after %start |
-`------------------------------*/
-
-static void
-parse_start_decl (void)
-{
- if (start_flag)
- complain (_("multiple %s declarations"), "%start");
- if (lex () != tok_identifier)
- complain (_("invalid %s declaration"), "%start");
- else
- {
- start_flag = 1;
- startval = symval;
- }
-}
-
-/*-----------------------------------------------------------.
-| read in a %type declaration and record its information for |
-| get_type_name to access |
-`-----------------------------------------------------------*/
-
-static void
-parse_type_decl (void)
-{
- char *name;
-
- if (lex () != tok_typename)
- {
- complain ("%s", _("%type declaration has no <typename>"));
- skip_to_char ('%');
- return;
- }
-
- name = xstrdup (token_buffer);
-
- for (;;)
- {
- token_t t;
- int tmp_char = ungetc (skip_white_space (), finput);
-
- if (tmp_char == '%')
- return;
- if (tmp_char == EOF)
- fatal (_("Premature EOF after %s"), token_buffer);
-
- t = lex ();
-
- switch (t)
- {
-
- case tok_comma:
- case tok_semicolon:
- break;
-
- case tok_identifier:
- if (symval->type_name == NULL)
- symval->type_name = name;
- else if (strcmp (name, symval->type_name) != 0)
- complain (_("type redeclaration for %s"), symval->tag);
-
- break;
-
- default:
- complain (_("invalid %%type declaration due to item: %s"),
- token_buffer);
- skip_to_char ('%');
- }
- }
-}
-
-
-
-/*----------------------------------------------------------------.
-| Read in a %left, %right or %nonassoc declaration and record its |
-| information. |
-`----------------------------------------------------------------*/
-
-static void
-parse_assoc_decl (associativity assoc)
-{
- char *name = NULL;
- int prev = 0;
-
- lastprec++; /* Assign a new precedence level, never 0. */
-
- for (;;)
- {
- token_t t;
- int tmp_char = ungetc (skip_white_space (), finput);
-
- if (tmp_char == '%')
- return;
- if (tmp_char == EOF)
- fatal (_("Premature EOF after %s"), token_buffer);
-
- t = lex ();
-
- switch (t)
- {
- case tok_typename:
- name = xstrdup (token_buffer);
- break;
-
- case tok_comma:
- break;
-
- case tok_identifier:
- if (symval->prec != 0)
- complain (_("redefining precedence of %s"), symval->tag);
- symval->prec = lastprec;
- symval->assoc = assoc;
- if (symval->class == nterm_sym)
- complain (_("symbol %s redefined"), symval->tag);
- symval->class = token_sym;
- if (name)
- { /* record the type, if one is specified */
- if (symval->type_name == NULL)
- symval->type_name = name;
- else if (strcmp (name, symval->type_name) != 0)
- complain (_("type redeclaration for %s"), symval->tag);
- }
- break;
-
- case tok_number:
- if (prev == tok_identifier)
- {
- symval->user_token_number = numval;
- }
- else
- {
- complain (_
- ("invalid text (%s) - number should be after identifier"),
-token_buffer);
- skip_to_char ('%');
- }
- break;
-
- case tok_semicolon:
- return;
-
- default:
- complain (_("unexpected item: %s"), token_buffer);
- skip_to_char ('%');
- }
-
- prev = t;
- }
-}
-
-
-
-/*--------------------------------------------------------------.
-| Copy the union declaration into the stype muscle |
-| (and fdefines), where it is made into the definition of |
-| YYSTYPE, the type of elements of the parser value stack. |
-`--------------------------------------------------------------*/
-
-static void
-parse_union_decl (void)
-{
- int c;
- int count = 0;
- struct obstack union_obstack;
- const char *prologue = "\
-#ifndef YYSTYPE\n\
-typedef union";
- const char *epilogue = "\
- yystype;\n\
-# define YYSTYPE yystype\n\
-#endif\n";
-
- if (typed)
- complain (_("multiple %s declarations"), "%union");
-
- typed = 1;
-
- /* FIXME: I'm worried: are you sure attrs_obstack is properly
- filled? */
- /* I don't see any reasons to keep this line, because we should
- create a special skeleton for this option. */
- if (no_lines_flag)
- obstack_1grow (&attrs_obstack, '\n');
-
- obstack_init (&union_obstack);
- obstack_sgrow (&union_obstack, "union");
- if (defines_flag)
- obstack_sgrow (&defines_obstack, prologue);
-
- c = getc (finput);
-
- while (c != EOF)
- {
- /* If C contains '/', it is output by copy_comment (). */
- if (c != '/')
- {
- obstack_1grow (&union_obstack, c);
- if (defines_flag)
- obstack_1grow (&defines_obstack, c);
- }
-
- switch (c)
- {
- case '\n':
- lineno++;
- break;
-
- case '/':
- copy_comment2 (finput, &defines_obstack, &union_obstack);
- break;
-
- case '{':
- count++;
- break;
-
- case '}':
- if (count == 0)
- complain (_("unmatched %s"), "`}'");
- count--;
- if (count <= 0)
- {
- if (defines_flag)
- obstack_sgrow (&defines_obstack, epilogue);
- /* JF don't choke on trailing semi */
- c = skip_white_space ();
- if (c != ';')
- ungetc (c, finput);
- obstack_1grow (&union_obstack, 0);
- muscle_insert ("stype", obstack_finish (&union_obstack));
- return;
- }
- }
-
- c = getc (finput);
- }
-
-}
-
-
-/*-------------------------------------------------------.
-| Parse the declaration %expect N which says to expect N |
-| shift-reduce conflicts. |
-`-------------------------------------------------------*/
-
-static void
-parse_expect_decl (void)
-{
- int c = skip_white_space ();
- ungetc (c, finput);
-
- if (!isdigit (c))
- complain (_("argument of %%expect is not an integer"));
- else
- expected_conflicts = read_signed_integer (finput);
-}
-
-
-/*-------------------------------------------------------------------.
-| Parse what comes after %thong. the full syntax is |
-| |
-| %thong <type> token number literal |
-| |
-| the <type> or number may be omitted. The number specifies the |
-| user_token_number. |
-| |
-| Two symbols are entered in the table, one for the token symbol and |
-| one for the literal. Both are given the <type>, if any, from the |
-| declaration. The ->user_token_number of the first is SALIAS and |
-| the ->user_token_number of the second is set to the number, if |
-| any, from the declaration. The two symbols are linked via |
-| pointers in their ->alias fields. |
-| |
-| During OUTPUT_DEFINES_TABLE, the symbol is reported thereafter, |
-| only the literal string is retained it is the literal string that |
-| is output to yytname |
-`-------------------------------------------------------------------*/
-
-static void
-parse_thong_decl (void)
-{
- token_t token;
- struct bucket *symbol;
- char *typename = 0;
- int usrtoknum = SUNDEF;
-
- token = lex (); /* fetch typename or first token */
- if (token == tok_typename)
- {
- typename = xstrdup (token_buffer);
- value_components_used = 1;
- token = lex (); /* fetch first token */
- }
-
- /* process first token */
-
- if (token != tok_identifier)
- {
- complain (_("unrecognized item %s, expected an identifier"),
- token_buffer);
- skip_to_char ('%');
- return;
- }
- symval->class = token_sym;
- symval->type_name = typename;
- symval->user_token_number = SALIAS;
- symbol = symval;
-
- token = lex (); /* get number or literal string */
-
- if (token == tok_number)
- {
- usrtoknum = numval;
- token = lex (); /* okay, did number, now get literal */
- }