]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/gengtype-parse.c
make -freg-struct-return visibly a negative alias of -fpcc-struct-return
[thirdparty/gcc.git] / gcc / gengtype-parse.c
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
deleted file mode 100644 (file)
index f6ad398..0000000
+++ /dev/null
@@ -1,1179 +0,0 @@
-/* Process source files and output type information.
-   Copyright (C) 2006-2017 Free Software Foundation, Inc.
-
-   This file is part of GCC.
-
-   GCC 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 3, or (at your option) any later
-   version.
-
-   GCC 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 GCC; see the file COPYING3.  If not see
-   <http://www.gnu.org/licenses/>.  */
-
-#ifdef HOST_GENERATOR_FILE
-#include "config.h"
-#define GENERATOR_FILE 1
-#else
-#include "bconfig.h"
-#endif
-#include "system.h"
-#include "gengtype.h"
-
-/* This is a simple recursive-descent parser which understands a subset of
-   the C type grammar.
-
-   Rule functions are suffixed _seq if they scan a sequence of items;
-   _opt if they may consume zero tokens; _seqopt if both are true.  The
-   "consume_" prefix indicates that a sequence of tokens is parsed for
-   syntactic correctness and then thrown away.  */
-
-/* Simple one-token lookahead mechanism.  */
-
-struct token
-{
-  const char *value;
-  int code;
-  bool valid;
-};
-static struct token T;
-
-/* Retrieve the code of the current token; if there is no current token,
-   get the next one from the lexer.  */
-static inline int
-token (void)
-{
-  if (!T.valid)
-    {
-      T.code = yylex (&T.value);
-      T.valid = true;
-    }
-  return T.code;
-}
-
-/* Retrieve the value of the current token (if any) and mark it consumed.
-   The next call to token() will get another token from the lexer.  */
-static inline const char *
-advance (void)
-{
-  T.valid = false;
-  return T.value;
-}
-
-/* Diagnostics.  */
-
-/* This array is indexed by the token code minus CHAR_TOKEN_OFFSET.  */
-static const char *const token_names[] = {
-  "GTY",
-  "typedef",
-  "extern",
-  "static",
-  "union",
-  "struct",
-  "enum",
-  "...",
-  "ptr_alias",
-  "nested_ptr",
-  "a param<N>_is option",
-  "a number",
-  "a scalar type",
-  "an identifier",
-  "a string constant",
-  "a character constant",
-  "an array declarator",
-  "a C++ keyword to ignore"
-};
-
-/* This array is indexed by token code minus FIRST_TOKEN_WITH_VALUE.  */
-static const char *const token_value_format[] = {
-  "%s",
-  "'%s'",
-  "'%s'",
-  "'%s'",
-  "'\"%s\"'",
-  "\"'%s'\"",
-  "'[%s]'",
-  "'%s'",
-};
-
-/* Produce a printable representation for a token defined by CODE and
-   VALUE.  This sometimes returns pointers into malloc memory and
-   sometimes not, therefore it is unsafe to free the pointer it
-   returns, so that memory is leaked.  This does not matter, as this
-   function is only used for diagnostics, and in a successful run of
-   the program there will be none.  */
-static const char *
-print_token (int code, const char *value)
-{
-  if (code < CHAR_TOKEN_OFFSET)
-    return xasprintf ("'%c'", code);
-  else if (code < FIRST_TOKEN_WITH_VALUE)
-    return xasprintf ("'%s'", token_names[code - CHAR_TOKEN_OFFSET]);
-  else if (!value)
-    return token_names[code - CHAR_TOKEN_OFFSET];      /* don't quote these */
-  else
-    return xasprintf (token_value_format[code - FIRST_TOKEN_WITH_VALUE],
-                     value);
-}
-
-/* Convenience wrapper around print_token which produces the printable
-   representation of the current token.  */
-static inline const char *
-print_cur_token (void)
-{
-  return print_token (T.code, T.value);
-}
-
-/* Report a parse error on the current line, with diagnostic MSG.
-   Behaves as standard printf with respect to additional arguments and
-   format escapes.  */
-static void ATTRIBUTE_PRINTF_1
-parse_error (const char *msg, ...)
-{
-  va_list ap;
-
-  fprintf (stderr, "%s:%d: parse error: ", 
-          get_input_file_name (lexer_line.file), lexer_line.line);
-
-  va_start (ap, msg);
-  vfprintf (stderr, msg, ap);
-  va_end (ap);
-
-  fputc ('\n', stderr);
-
-  hit_error = true;
-}
-
-/* If the next token does not have code T, report a parse error; otherwise
-   return the token's value.  */
-static const char *
-require (int t)
-{
-  int u = token ();
-  const char *v = advance ();
-  if (u != t)
-    {
-      parse_error ("expected %s, have %s",
-                  print_token (t, 0), print_token (u, v));
-      return 0;
-    }
-  return v;
-}
-
-/* As per require, but do not advance.  */
-static const char *
-require_without_advance (int t)
-{
-  int u = token ();
-  const char *v = T.value;
-  if (u != t)
-    {
-      parse_error ("expected %s, have %s",
-                  print_token (t, 0), print_token (u, v));
-      return 0;
-    }
-  return v;
-}
-
-/* If the next token does not have one of the codes T1 or T2, report a
-   parse error; otherwise return the token's value.  */
-static const char *
-require2 (int t1, int t2)
-{
-  int u = token ();
-  const char *v = advance ();
-  if (u != t1 && u != t2)
-    {
-      parse_error ("expected %s or %s, have %s",
-                  print_token (t1, 0), print_token (t2, 0),
-                  print_token (u, v));
-      return 0;
-    }
-  return v;
-}
-
-/* If the next token does not have one of the codes T1, T2, T3 or T4, report a
-   parse error; otherwise return the token's value.  */
-static const char *
-require4 (int t1, int t2, int t3, int t4)
-{
-  int u = token ();
-  const char *v = advance ();
-  if (u != t1 && u != t2 && u != t3 && u != t4)
-    {
-      parse_error ("expected %s, %s, %s or %s, have %s",
-                  print_token (t1, 0), print_token (t2, 0),
-                  print_token (t3, 0), print_token (t4, 0),
-                  print_token (u, v));
-      return 0;
-    }
-  return v;
-}
-
-/* Near-terminals.  */
-
-/* C-style string constant concatenation: STRING+
-   Bare STRING should appear nowhere else in this file.  */
-static const char *
-string_seq (void)
-{
-  const char *s1, *s2;
-  size_t l1, l2;
-  char *buf;
-
-  s1 = require (STRING);
-  if (s1 == 0)
-    return "";
-  while (token () == STRING)
-    {
-      s2 = advance ();
-
-      l1 = strlen (s1);
-      l2 = strlen (s2);
-      buf = XRESIZEVEC (char, CONST_CAST (char *, s1), l1 + l2 + 1);
-      memcpy (buf + l1, s2, l2 + 1);
-      XDELETE (CONST_CAST (char *, s2));
-      s1 = buf;
-    }
-  return s1;
-}
-
-
-/* The caller has detected a template declaration that starts
-   with TMPL_NAME.  Parse up to the closing '>'.  This recognizes
-   simple template declarations of the form ID<ID1,ID2,...,IDn>,
-   potentially with a single level of indirection e.g.
-     ID<ID1 *, ID2, ID3 *, ..., IDn>.
-   It does not try to parse anything more sophisticated than that.
-
-   Returns the template declaration string "ID<ID1,ID2,...,IDn>".  */
-
-static const char *
-require_template_declaration (const char *tmpl_name)
-{
-  char *str;
-  int num_indirections = 0;
-
-  /* Recognize the opening '<'.  */
-  require ('<');
-  str = concat (tmpl_name, "<", (char *) 0);
-
-  /* Read the comma-separated list of identifiers.  */
-  int depth = 1;
-  while (depth > 0)
-    {
-      if (token () == ENUM)
-       {
-         advance ();
-         str = concat (str, "enum ", (char *) 0);
-         continue;
-       }
-      if (token () == NUM
-         || token () == ':'
-         || token () == '+')
-       {
-         str = concat (str, advance (), (char *) 0);
-         continue;
-       }
-      if (token () == '<')
-       {
-         advance ();
-         str = concat (str, "<", (char *) 0);
-         depth += 1;
-         continue;
-       }
-      if (token () == '>')
-       {
-         advance ();
-         str = concat (str, ">", (char *) 0);
-         depth -= 1;
-         continue;
-       }
-      const char *id = require4 (SCALAR, ID, '*', ',');
-      if (id == NULL)
-       {
-         if (T.code == '*')
-           {
-             id = "*";
-             if (num_indirections++)
-               parse_error ("only one level of indirection is supported"
-                            " in template arguments");
-           }
-         else
-           id = ",";
-       }
-      else
-       num_indirections = 0;
-      str = concat (str, id, (char *) 0);
-    }
-  return str;
-}
-
-
-/* typedef_name: either an ID, or a template type
-   specification of the form ID<t1,t2,...,tn>.  */
-
-static const char *
-typedef_name (void)
-{
-  const char *id = require (ID);
-  if (token () == '<')
-    return require_template_declaration (id);
-  else
-    return id;
-}
-
-/* Absorb a sequence of tokens delimited by balanced ()[]{}.  */
-static void
-consume_balanced (int opener, int closer)
-{
-  require (opener);
-  for (;;)
-    switch (token ())
-      {
-      default:
-       advance ();
-       break;
-      case '(':
-       consume_balanced ('(', ')');
-       break;
-      case '[':
-       consume_balanced ('[', ']');
-       break;
-      case '{':
-       consume_balanced ('{', '}');
-       break;
-
-      case '}':
-      case ']':
-      case ')':
-       if (token () != closer)
-         parse_error ("unbalanced delimiters - expected '%c', have '%c'",
-                      closer, token ());
-      advance ();
-      return;
-
-      case EOF_TOKEN:
-       parse_error ("unexpected end of file within %c%c-delimited construct",
-                    opener, closer);
-       return;
-      }
-}
-
-/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
-   expressions, until we encounter an end-of-statement marker (a ';' or
-   a '}') outside any such delimiters; absorb that too.  */
-
-static void
-consume_until_eos (void)
-{
-  for (;;)
-    switch (token ())
-      {
-      case ';':
-       advance ();
-       return;
-
-      case '{':
-       consume_balanced ('{', '}');
-       return;
-
-      case '(':
-       consume_balanced ('(', ')');
-       break;
-
-      case '[':
-       consume_balanced ('[', ']');
-       break;
-
-      case '}':
-      case ']':
-      case ')':
-       parse_error ("unmatched '%c' while scanning for ';'", token ());
-       return;
-
-      case EOF_TOKEN:
-       parse_error ("unexpected end of file while scanning for ';'");
-       return;
-
-      default:
-       advance ();
-       break;
-      }
-}
-
-/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
-   expressions, until we encounter a comma or semicolon outside any
-   such delimiters; absorb that too.  Returns true if the loop ended
-   with a comma.  */
-
-static bool
-consume_until_comma_or_eos ()
-{
-  for (;;)
-    switch (token ())
-      {
-      case ',':
-       advance ();
-       return true;
-
-      case ';':
-       advance ();
-       return false;
-
-      case '{':
-       consume_balanced ('{', '}');
-       return false;
-
-      case '(':
-       consume_balanced ('(', ')');
-       break;
-
-      case '[':
-       consume_balanced ('[', ']');
-       break;
-
-      case '}':
-      case ']':
-      case ')':
-       parse_error ("unmatched '%s' while scanning for ',' or ';'",
-                    print_cur_token ());
-      return false;
-
-      case EOF_TOKEN:
-       parse_error ("unexpected end of file while scanning for ',' or ';'");
-       return false;
-
-      default:
-       advance ();
-       break;
-      }
-}
-\f
-
-/* GTY(()) option handling.  */
-static type_p type (options_p *optsp, bool nested);
-
-/* Optional parenthesized string: ('(' string_seq ')')? */
-static options_p
-str_optvalue_opt (options_p prev)
-{
-  const char *name = advance ();
-  const char *value = "";
-  if (token () == '(')
-    {
-      advance ();
-      value = string_seq ();
-      require (')');
-    }
-  return create_string_option (prev, name, value);
-}
-
-/* absdecl: type '*'*
-   -- a vague approximation to what the C standard calls an abstract
-   declarator.  The only kinds that are actually used are those that
-   are just a bare type and those that have trailing pointer-stars.
-   Further kinds should be implemented if and when they become
-   necessary.  Used only within GTY(()) option values, therefore
-   further GTY(()) tags within the type are invalid.  Note that the
-   return value has already been run through adjust_field_type.  */
-static type_p
-absdecl (void)
-{
-  type_p ty;
-  options_p opts;
-
-  ty = type (&opts, true);
-  while (token () == '*')
-    {
-      ty = create_pointer (ty);
-      advance ();
-    }
-
-  if (opts)
-    parse_error ("nested GTY(()) options are invalid");
-
-  return adjust_field_type (ty, 0);
-}
-
-/* Type-option: '(' absdecl ')' */
-static options_p
-type_optvalue (options_p prev, const char *name)
-{
-  type_p ty;
-  require ('(');
-  ty = absdecl ();
-  require (')');
-  return create_type_option (prev, name, ty);
-}
-
-/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
-static options_p
-nestedptr_optvalue (options_p prev)
-{
-  type_p ty;
-  const char *from, *to;
-
-  require ('(');
-  ty = absdecl ();
-  require (',');
-  to = string_seq ();
-  require (',');
-  from = string_seq ();
-  require (')');
-
-  return create_nested_ptr_option (prev, ty, to, from);
-}
-
-/* One GTY(()) option:
-   ID str_optvalue_opt
-   | PTR_ALIAS type_optvalue
-   | NESTED_PTR nestedptr_optvalue
-*/
-static options_p
-option (options_p prev)
-{
-  switch (token ())
-    {
-    case ID:
-      return str_optvalue_opt (prev);
-
-    case PTR_ALIAS:
-      advance ();
-      return type_optvalue (prev, "ptr_alias");
-
-    case NESTED_PTR:
-      advance ();
-      return nestedptr_optvalue (prev);
-
-    case USER_GTY:
-      advance ();
-      return create_string_option (prev, "user", "");
-
-    default:
-      parse_error ("expected an option keyword, have %s", print_cur_token ());
-      advance ();
-      return create_string_option (prev, "", "");
-    }
-}
-
-/* One comma-separated list of options.  */
-static options_p
-option_seq (void)
-{
-  options_p o;
-
-  o = option (0);
-  while (token () == ',')
-    {
-      advance ();
-      o = option (o);
-    }
-  return o;
-}
-
-/* GTY marker: 'GTY' '(' '(' option_seq? ')' ')' */
-static options_p
-gtymarker (void)
-{
-  options_p result = 0;
-  require (GTY_TOKEN);
-  require ('(');
-  require ('(');
-  if (token () != ')')
-    result = option_seq ();
-  require (')');
-  require (')');
-  return result;
-}
-
-/* Optional GTY marker.  */
-static options_p
-gtymarker_opt (void)
-{
-  if (token () != GTY_TOKEN)
-    return 0;
-  return gtymarker ();
-}
-
-
-\f
-/* Declarators. The logic here is largely lifted from c-parser.c.
-   Note that we do not have to process abstract declarators, which can
-   appear only in parameter type lists or casts (but see absdecl,
-   above).  Also, type qualifiers are thrown out in gengtype-lex.l so
-   we don't have to do it.  */
-
-/* array_and_function_declarators_opt:
-   \epsilon
-   array_and_function_declarators_opt ARRAY
-   array_and_function_declarators_opt '(' ... ')'
-
-   where '...' indicates stuff we ignore except insofar as grouping
-   symbols ()[]{} must balance.
-
-   Subroutine of direct_declarator - do not use elsewhere. */
-
-static type_p
-array_and_function_declarators_opt (type_p ty)
-{
-  if (token () == ARRAY)
-    {
-      const char *array = advance ();
-      return create_array (array_and_function_declarators_opt (ty), array);
-    }
-  else if (token () == '(')
-    {
-      /* We don't need exact types for functions.  */
-      consume_balanced ('(', ')');
-      array_and_function_declarators_opt (ty);
-      return create_scalar_type ("function type");
-    }
-  else
-    return ty;
-}
-
-static type_p inner_declarator (type_p, const char **, options_p *, bool);
-
-/* direct_declarator:
-   '(' inner_declarator ')'
-   '(' \epsilon ')'    <-- C++ ctors/dtors
-   gtymarker_opt ID array_and_function_declarators_opt
-
-   Subroutine of declarator, mutually recursive with inner_declarator;
-   do not use elsewhere.
-
-   IN_STRUCT is true if we are called while parsing structures or classes.  */
-
-static type_p
-direct_declarator (type_p ty, const char **namep, options_p *optsp,
-                  bool in_struct)
-{
-  /* The first token in a direct-declarator must be an ID, a
-     GTY marker, or an open parenthesis.  */
-  switch (token ())
-    {
-    case GTY_TOKEN:
-      *optsp = gtymarker ();
-      /* fall through */
-
-    case ID:
-      *namep = require (ID);
-      /* If the next token is '(', we are parsing a function declaration.
-        Functions are ignored by gengtype, so we return NULL.  */
-      if (token () == '(')
-       return NULL;
-      break;
-
-    case '(':
-      /* If the declarator starts with a '(', we have three options.  We
-        are either parsing 'TYPE (*ID)' (i.e., a function pointer)
-        or 'TYPE(...)'.
-
-        The latter will be a constructor iff we are inside a
-        structure or class.  Otherwise, it could be a typedef, but
-        since we explicitly reject typedefs inside structures, we can
-        assume that we found a ctor and return NULL.  */
-      advance ();
-      if (in_struct && token () != '*')
-       {
-         /* Found a constructor.  Find and consume the closing ')'.  */
-         while (token () != ')')
-           advance ();
-         advance ();
-         /* Tell the caller to ignore this.  */
-         return NULL;
-       }
-      ty = inner_declarator (ty, namep, optsp, in_struct);
-      require (')');
-      break;
-
-    case IGNORABLE_CXX_KEYWORD:
-      /* Any C++ keyword like 'operator' means that we are not looking
-        at a regular data declarator.  */
-      return NULL;
-
-    default:
-      parse_error ("expected '(', ')', 'GTY', or an identifier, have %s",
-                  print_cur_token ());
-      /* Do _not_ advance if what we have is a close squiggle brace, as
-        we will get much better error recovery that way.  */
-      if (token () != '}')
-       advance ();
-      return 0;
-    }
-  return array_and_function_declarators_opt (ty);
-}
-
-/* The difference between inner_declarator and declarator is in the
-   handling of stars.  Consider this declaration:
-
-   char * (*pfc) (void)
-
-   It declares a pointer to a function that takes no arguments and
-   returns a char*.  To construct the correct type for this
-   declaration, the star outside the parentheses must be processed
-   _before_ the function type, the star inside the parentheses must
-   be processed _after_ the function type.  To accomplish this,
-   declarator() creates pointers before recursing (it is actually
-   coded as a while loop), whereas inner_declarator() recurses before
-   creating pointers.  */
-
-/* inner_declarator:
-   '*' inner_declarator
-   direct_declarator
-
-   Mutually recursive subroutine of direct_declarator; do not use
-   elsewhere.
-
-   IN_STRUCT is true if we are called while parsing structures or classes.  */
-
-static type_p
-inner_declarator (type_p ty, const char **namep, options_p *optsp,
-                 bool in_struct)
-{
-  if (token () == '*')
-    {
-      type_p inner;
-      advance ();
-      inner = inner_declarator (ty, namep, optsp, in_struct);
-      if (inner == 0)
-       return 0;
-      else
-       return create_pointer (ty);
-    }
-  else
-    return direct_declarator (ty, namep, optsp, in_struct);
-}
-
-/* declarator: '*'+ direct_declarator
-
-   This is the sole public interface to this part of the grammar.
-   Arguments are the type known so far, a pointer to where the name
-   may be stored, and a pointer to where GTY options may be stored.
-
-   IN_STRUCT is true when we are called to parse declarators inside
-   a structure or class.
-
-   Returns the final type.  */
-
-static type_p
-declarator (type_p ty, const char **namep, options_p *optsp,
-           bool in_struct = false)
-{
-  *namep = 0;
-  *optsp = 0;
-  while (token () == '*')
-    {
-      advance ();
-      ty = create_pointer (ty);
-    }
-  return direct_declarator (ty, namep, optsp, in_struct);
-}
-\f
-/* Types and declarations.  */
-
-/* Structure field(s) declaration:
-   (
-   type bitfield ';'
-   | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
-   )*
-
-   Knows that such declarations must end with a close brace (or,
-   erroneously, at EOF).
-*/
-static pair_p
-struct_field_seq (void)
-{
-  pair_p f = 0;
-  type_p ty, dty;
-  options_p opts, dopts;
-  const char *name;
-  bool another;
-
-  while (token () != '}' && token () != EOF_TOKEN)
-    {
-      ty = type (&opts, true);
-
-      /* Ignore access-control keywords ("public:" etc).  */
-      while (!ty && token () == IGNORABLE_CXX_KEYWORD)
-       {
-         const char *keyword = advance ();
-         if (strcmp (keyword, "public:") != 0
-             && strcmp (keyword, "private:") != 0
-             && strcmp (keyword, "protected:") != 0)
-           break;
-         ty = type (&opts, true);
-       }
-
-      if (!ty || token () == ':')
-       {
-         consume_until_eos ();
-         continue;
-       }
-
-      do
-       {
-         dty = declarator (ty, &name, &dopts, true);
-
-         /* There could be any number of weird things after the declarator,
-            notably bitfield declarations and __attribute__s.  If this
-            function returns true, the last thing was a comma, so we have
-            more than one declarator paired with the current type.  */
-         another = consume_until_comma_or_eos ();
-
-         if (!dty)
-           continue;
-
-         if (opts && dopts)
-           parse_error ("two GTY(()) options for field %s", name);
-         if (opts && !dopts)
-           dopts = opts;
-
-         f = create_field_at (f, dty, name, dopts, &lexer_line);
-       }
-      while (another);
-    }
-  return nreverse_pairs (f);
-}
-
-/* Return true if OPTS contain the option named STR.  */
-
-bool
-opts_have (options_p opts, const char *str)
-{
-  for (options_p opt = opts; opt; opt = opt->next)
-    if (strcmp (opt->name, str) == 0)
-      return true;
-  return false;
-}
-
-
-/* This is called type(), but what it parses (sort of) is what C calls
-   declaration-specifiers and specifier-qualifier-list:
-
-   SCALAR
-   | ID     // typedef
-   | (STRUCT|UNION) ID? gtymarker? ( '{' gtymarker? struct_field_seq '}' )?
-   | ENUM ID ( '{' ... '}' )?
-
-   Returns a partial type; under some conditions (notably
-   "struct foo GTY((...)) thing;") it may write an options
-   structure to *OPTSP.
-
-   NESTED is true when parsing a declaration already known to have a
-   GTY marker. In these cases, typedef and enum declarations are not
-   allowed because gengtype only understands types at the global
-   scope.  */
-
-static type_p
-type (options_p *optsp, bool nested)
-{
-  const char *s;
-  *optsp = 0;
-  switch (token ())
-    {
-    case SCALAR:
-      s = advance ();
-      return create_scalar_type (s);
-
-    case ID:
-      s = typedef_name ();
-      return resolve_typedef (s, &lexer_line);
-
-    case IGNORABLE_CXX_KEYWORD:
-      /* By returning NULL here, we indicate to the caller that they
-        should ignore everything following this keyword up to the
-        next ';' or '}'.  */
-      return NULL;
-
-    case STRUCT:
-    case UNION:
-      {
-       type_p base_class = NULL;
-       options_p opts = 0;
-       /* GTY annotations follow attribute syntax
-          GTY_BEFORE_ID is for union/struct declarations
-          GTY_AFTER_ID is for variable declarations.  */
-       enum
-       {
-         NO_GTY,
-         GTY_BEFORE_ID,
-         GTY_AFTER_ID
-       } is_gty = NO_GTY;
-       enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT;
-       advance ();
-
-       /* Top-level structures that are not explicitly tagged GTY(())
-          are treated as mere forward declarations.  This is because
-          there are a lot of structures that we don't need to know
-          about, and some of those have C++ and macro constructs that
-          we cannot handle.  */
-       if (nested || token () == GTY_TOKEN)
-         {
-           is_gty = GTY_BEFORE_ID;
-           opts = gtymarker_opt ();
-         }
-
-       if (token () == ID)
-         s = advance ();
-       else
-         s = xasprintf ("anonymous:%s:%d",
-                        get_input_file_name (lexer_line.file),
-                        lexer_line.line);
-
-       /* Unfortunately above GTY_TOKEN check does not capture the
-          typedef struct_type GTY case.  */
-       if (token () == GTY_TOKEN)
-         {
-           is_gty = GTY_AFTER_ID;
-           opts = gtymarker_opt ();
-         }
-
-       bool is_user_gty = opts_have (opts, "user");
-
-       if (token () == ':')
-         {
-           if (is_gty && !is_user_gty)
-             {
-               /* For GTY-marked types that are not "user", parse some C++
-                  inheritance specifications.
-                  We require single-inheritance from a non-template type.  */
-               advance ();
-               const char *basename = require (ID);
-               /* This may be either an access specifier, or the base name.  */
-               if (0 == strcmp (basename, "public")
-                   || 0 == strcmp (basename, "protected")
-                   || 0 == strcmp (basename, "private"))
-                 basename = require (ID);
-               base_class = find_structure (basename, TYPE_STRUCT);
-               if (!base_class)
-                 parse_error ("unrecognized base class: %s", basename);
-               require_without_advance ('{');
-             }
-           else
-             {
-               /* For types lacking GTY-markings, skip over C++ inheritance
-                  specification (and thus avoid having to parse e.g. template
-                  types).  */
-               while (token () != '{')
-                 advance ();
-             }
-         }
-
-       if (is_gty)
-         {
-           if (token () == '{')
-             {
-               pair_p fields;
-
-               if (is_gty == GTY_AFTER_ID)
-                 parse_error ("GTY must be specified before identifier");
-
-               if (!is_user_gty)
-                 {
-                   advance ();
-                   fields = struct_field_seq ();
-                   require ('}');
-                 }
-               else
-                 {
-                   /* Do not look inside user defined structures.  */
-                   fields = NULL;
-                   kind = TYPE_USER_STRUCT;
-                   consume_balanced ('{', '}');
-                   return create_user_defined_type (s, &lexer_line);
-                 }
-
-               return new_structure (s, kind, &lexer_line, fields, opts,
-                                     base_class);
-             }
-         }
-       else if (token () == '{')
-         consume_balanced ('{', '}');
-       if (opts)
-         *optsp = opts;
-       return find_structure (s, kind);
-      }
-
-    case TYPEDEF:
-      /* In C++, a typedef inside a struct/class/union defines a new
-        type for that inner scope.  We cannot support this in
-        gengtype because we have no concept of scoping.
-
-        We handle typedefs in the global scope separately (see
-        parse_file), so if we find a 'typedef', we must be inside
-        a struct.  */
-      gcc_assert (nested);
-      parse_error ("typedefs not supported in structures marked with "
-                  "automatic GTY markers.  Use GTY((user)) to mark "
-                  "this structure.");
-      advance ();
-      return NULL;
-
-    case ENUM:
-      advance ();
-      if (token () == ID)
-       s = advance ();
-      else
-       s = xasprintf ("anonymous:%s:%d",
-                      get_input_file_name (lexer_line.file),
-                      lexer_line.line);
-
-      if (token () == '{')
-       consume_balanced ('{', '}');
-
-      /* If after parsing the enum we are at the end of the statement,
-        and we are currently inside a structure, then this was an
-        enum declaration inside this scope.
-
-        We cannot support this for the same reason we cannot support
-        'typedef' inside structures (see the TYPEDEF handler above).
-        If this happens, emit an error and return NULL.  */
-      if (nested && token () == ';')
-       {
-         parse_error ("enum definitions not supported in structures marked "
-                      "with automatic GTY markers.  Use GTY((user)) to mark "
-                      "this structure.");
-         advance ();
-         return NULL;
-       }
-
-      return create_scalar_type (s);
-
-    default:
-      parse_error ("expected a type specifier, have %s", print_cur_token ());
-      advance ();
-      return create_scalar_type ("erroneous type");
-    }
-}
-\f
-/* Top level constructs.  */
-
-/* Dispatch declarations beginning with 'typedef'.  */
-
-static void
-typedef_decl (void)
-{
-  type_p ty, dty;
-  const char *name;
-  options_p opts;
-  bool another;
-
-  gcc_assert (token () == TYPEDEF);
-  advance ();
-
-  ty = type (&opts, false);
-  if (!ty)
-    return;
-  if (opts)
-    parse_error ("GTY((...)) cannot be applied to a typedef");
-  do
-    {
-      dty = declarator (ty, &name, &opts);
-      if (opts)
-       parse_error ("GTY((...)) cannot be applied to a typedef");
-
-      /* Yet another place where we could have junk (notably attributes)
-        after the declarator.  */
-      another = consume_until_comma_or_eos ();
-      if (dty)
-       do_typedef (name, dty, &lexer_line);
-    }
-  while (another);
-}
-
-/* Structure definition: type() does all the work.  */
-
-static void
-struct_or_union (void)
-{
-  options_p dummy;
-  type (&dummy, false);
-  /* There may be junk after the type: notably, we cannot currently
-     distinguish 'struct foo *function(prototype);' from 'struct foo;'
-     ...  we could call declarator(), but it's a waste of time at
-     present.  Instead, just eat whatever token is currently lookahead
-     and go back to lexical skipping mode. */
-  advance ();
-}
-
-/* GC root declaration:
-   (extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
-   If the gtymarker is not present, we ignore the rest of the declaration.  */
-static void
-extern_or_static (void)
-{
-  options_p opts, opts2, dopts;
-  type_p ty, dty;
-  const char *name;
-  require2 (EXTERN, STATIC);
-
-  if (token () != GTY_TOKEN)
-    {
-      advance ();
-      return;
-    }
-
-  opts = gtymarker ();
-  ty = type (&opts2, true);    /* if we get here, it's got a GTY(()) */
-  dty = declarator (ty, &name, &dopts);
-
-  if ((opts && dopts) || (opts && opts2) || (opts2 && dopts))
-    parse_error ("GTY((...)) specified more than once for %s", name);
-  else if (opts2)
-    opts = opts2;
-  else if (dopts)
-    opts = dopts;
-
-  if (dty)
-    {
-      note_variable (name, adjust_field_type (dty, opts), opts, &lexer_line);
-      require2 (';', '=');
-    }
-}
-
-/* Parse the file FNAME for GC-relevant declarations and definitions.
-   This is the only entry point to this file.  */
-void
-parse_file (const char *fname)
-{
-  yybegin (fname);
-  for (;;)
-    {
-      switch (token ())
-       {
-       case EXTERN:
-       case STATIC:
-         extern_or_static ();
-         break;
-
-       case STRUCT:
-       case UNION:
-         struct_or_union ();
-         break;
-
-       case TYPEDEF:
-         typedef_decl ();
-         break;
-
-       case EOF_TOKEN:
-         goto eof;
-
-       default:
-         parse_error ("unexpected top level token, %s", print_cur_token ());
-         goto eof;
-       }
-      lexer_toplevel_done = 1;
-    }
-
- eof:
-  advance ();
-  yyend ();
-}