]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/gengtype-parse.c
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / gengtype-parse.c
diff --git a/gcc/gengtype-parse.c b/gcc/gengtype-parse.c
new file mode 100644 (file)
index 0000000..357981a
--- /dev/null
@@ -0,0 +1,928 @@
+/* Process source files and output type information.
+   Copyright (C) 2006, 2007 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/>.  */
+
+#include "bconfig.h"
+#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",
+  "VEC",
+  "DEF_VEC_[OP]",
+  "DEF_VEC_I",
+  "DEF_VEC_ALLOC_[IOP]",
+  "...",
+  "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",
+};
+
+/* 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]'",
+};
+
+/* 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: ", lexer_line.file, lexer_line.line);
+
+  va_start (ap, msg);
+  vfprintf (stderr, msg, ap);
+  va_end (ap);
+
+  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;
+}
+
+/* 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;
+}
+
+/* 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;
+}
+
+/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y.
+   Use only where VEC(x,y) is legitimate, i.e. in positions where a
+   typedef name may appear.  */
+static const char *
+typedef_name (void)
+{
+  if (token () == VEC_TOKEN)
+    {
+      const char *c1, *c2, *r;
+      advance ();
+      require ('(');
+      c1 = require2 (ID, SCALAR);
+      require (',');
+      c2 = require (ID);
+      require (')');
+      r = concat ("VEC_", c1, "_", c2, (char *)0);
+      free (CONST_CAST (char *, c1));
+      free (CONST_CAST (char *, c2));
+      return r;
+    }
+  else
+    return require (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 a semicolon outside any such
+   delimiters; absorb that too.  If IMMEDIATE is true, it is an error
+   if the semicolon is not the first token encountered.  */
+static void
+consume_until_semi (bool immediate)
+{
+  if (immediate && token () != ';')
+    require (';');
+  for (;;)
+    switch (token ())
+      {
+      case ';':        advance (); return;
+      default: advance (); break;
+
+      case '(':        consume_balanced ('(',')'); break;
+      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;
+      }
+}
+
+/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
+   expressions, until we encounter a comma or semicolon outside any
+   such delimiters; absorb that too.  If IMMEDIATE is true, it is an
+   error if the comma or semicolon is not the first token encountered.
+   Returns true if the loop ended with a comma.  */
+static bool
+consume_until_comma_or_semi (bool immediate)
+{
+  if (immediate && token () != ',' && token () != ';')
+    require2 (',', ';');
+  for (;;)
+    switch (token ())
+      {
+      case ',':        advance (); return true;
+      case ';':        advance (); return false;
+      default: advance (); break;
+
+      case '(':        consume_balanced ('(',')'); break;
+      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;
+      }
+}
+
+\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_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_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
+       | PARAM_IS 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 PARAM_IS:
+      return type_optvalue (prev, advance ());
+
+    case NESTED_PTR:
+      advance ();
+      return nestedptr_optvalue (prev);
+
+    default:
+      parse_error ("expected an option keyword, have %s",
+                  print_cur_token ());
+      advance ();
+      return create_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 *);
+
+/* direct_declarator:
+      '(' inner_declarator ')'
+      gtymarker_opt ID array_and_function_declarators_opt
+
+   Subroutine of declarator, mutually recursive with inner_declarator;
+   do not use elsewhere.  */
+static type_p
+direct_declarator (type_p ty, const char **namep, options_p *optsp)
+{
+  /* 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);
+      break;
+
+    case '(':
+      advance ();
+      ty = inner_declarator (ty, namep, optsp);
+      require (')');
+      break;
+
+    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.  */
+
+static type_p
+inner_declarator (type_p ty, const char **namep, options_p *optsp)
+{
+  if (token () == '*')
+    {
+      type_p inner;
+      advance ();
+      inner = inner_declarator (ty, namep, optsp);
+      if (inner == 0)
+       return 0;
+      else
+       return create_pointer (ty);
+    }
+  else
+    return direct_declarator (ty, namep, optsp);
+}
+
+/* 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.
+   Returns the final type. */
+
+static type_p
+declarator (type_p ty, const char **namep, options_p *optsp)
+{
+  *namep = 0;
+  *optsp = 0;
+  while (token () == '*')
+    {
+      advance ();
+      ty = create_pointer (ty);
+    }
+  return direct_declarator (ty, namep, optsp);
+}
+\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;
+
+  do
+    {
+      ty = type (&opts, true);
+      /* Another piece of the IFCVT_EXTRA_FIELDS special case, see type().  */
+      if (!ty && token () == '}')
+       break;
+
+      if (!ty || token () == ':')
+       {
+         consume_until_semi (false);
+         continue;
+       }
+
+      do
+       {
+         dty = declarator (ty, &name, &dopts);
+         /* 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_semi (false);
+
+         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);
+    }
+  while (token () != '}' && token () != EOF_TOKEN);
+  return nreverse_pairs (f);
+}
+
+/* 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.
+ */
+static type_p
+type (options_p *optsp, bool nested)
+{
+  const char *s;
+  bool is_union;
+  *optsp = 0;
+  switch (token ())
+    {
+    case SCALAR:
+      s = advance ();
+      return create_scalar_type (s);
+
+    case ID:
+    case VEC_TOKEN:
+      s = typedef_name ();
+      return resolve_typedef (s, &lexer_line);
+
+    case STRUCT:
+    case UNION:
+      {
+       options_p opts = 0;
+
+       is_union = (token() == UNION);
+       advance ();
+
+       if (token () == ID)
+         s = advance ();
+       else
+         s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
+
+       /* 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 weird macro stuff in them
+          that we can't handle.  */
+       if (nested || token () == GTY_TOKEN)
+         {
+           opts = gtymarker_opt ();
+           if (token () == '{')
+             {
+               pair_p fields;
+               advance ();
+               fields = struct_field_seq ();
+               require ('}');
+               return new_structure (s, is_union, &lexer_line, fields, opts);
+             }
+         }
+       else if (token () == '{')
+         consume_balanced ('{', '}');
+       if (opts)
+         *optsp = opts;
+       return find_structure (s, is_union);
+      }
+
+    case ENUM:
+      advance ();
+       if (token () == ID)
+         s = advance ();
+       else
+         s = xasprintf ("anonymous:%s:%d", lexer_line.file, lexer_line.line);
+
+      if (token () == '{')
+       consume_balanced ('{','}');
+      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_semi (false);
+      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 (';', '=');
+    }
+}
+
+/* Definition of a generic VEC structure:
+
+   'DEF_VEC_[IPO]' '(' id ')' ';'
+
+   Scalar VECs require slightly different treatment than otherwise -
+   that's handled in note_def_vec, we just pass it along.*/
+static void
+def_vec (void)
+{
+  bool is_scalar = (token() == DEFVEC_I);
+  const char *type;
+
+  require2 (DEFVEC_OP, DEFVEC_I);
+  require ('(');
+  type = require2 (ID, SCALAR);
+  require (')');
+  require (';');
+
+  if (!type)
+    return;
+
+  note_def_vec (type, is_scalar, &lexer_line);
+  note_def_vec_alloc (type, "none", &lexer_line);
+}
+
+/* Definition of an allocation strategy for a VEC structure:
+
+   'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';'
+
+   For purposes of gengtype, this just declares a wrapper structure.  */
+static void
+def_vec_alloc (void)
+{
+  const char *type, *astrat;
+
+  require (DEFVEC_ALLOC);
+  require ('(');
+  type = require2 (ID, SCALAR);
+  require (',');
+  astrat = require (ID);
+  require (')');
+  require (';');
+
+  if (!type || !astrat)
+    return;
+
+  note_def_vec_alloc (type, astrat, &lexer_line);
+}
+
+/* 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 DEFVEC_OP:
+       case DEFVEC_I:
+         def_vec ();
+         break;
+
+       case DEFVEC_ALLOC:
+         def_vec_alloc ();
+         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 ();
+}