diff gcc/gengtype-state.c @ 111:04ced10e8804

gcc 7
author kono
date Fri, 27 Oct 2017 22:46:09 +0900
parents 561a7518be6b
children 84e7813d76e9
line wrap: on
line diff
--- a/gcc/gengtype-state.c	Sun Aug 21 07:07:55 2011 +0900
+++ b/gcc/gengtype-state.c	Fri Oct 27 22:46:09 2017 +0900
@@ -1,7 +1,7 @@
 /* Gengtype persistent state serialization & de-serialization.
    Useful for gengtype in plugin mode.
 
-   Copyright (C) 2010  Free Software Foundation, Inc.
+   Copyright (C) 2010-2017 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -23,11 +23,14 @@
    and Basile Starynkevitch <basile@starynkevitch.net>
 */
 
+#ifdef HOST_GENERATOR_FILE
+#include "config.h"
+#define GENERATOR_FILE 1
+#else
 #include "bconfig.h"
+#endif
 #include "system.h"
 #include "errors.h"	/* For fatal.  */
-#include "double-int.h"
-#include "hashtab.h"
 #include "version.h"	/* For version_string & pkgversion_string.  */
 #include "obstack.h"
 #include "gengtype.h"
@@ -47,9 +50,9 @@
     case TYPE_STRUCT:
     case TYPE_UNION:
     case TYPE_LANG_STRUCT:
+    case TYPE_USER_STRUCT:
+    case TYPE_UNDEFINED:
       return CONST_CAST (struct fileloc*, &ty->u.s.line);
-    case TYPE_PARAM_STRUCT:
-      return CONST_CAST (struct fileloc*, &ty->u.param_struct.line);
     case TYPE_SCALAR:
     case TYPE_STRING:
     case TYPE_POINTER:
@@ -61,7 +64,7 @@
 }
 
 /* The state file has simplistic lispy lexical tokens.  Its lexer gives
-   a linked list of struct state_token_st, thru the peek_state_token
+   a linked list of struct state_token_st, through the peek_state_token
    function.  Lexical tokens are consumed with next_state_tokens.  */
 
 
@@ -131,9 +134,141 @@
 static int state_line = 0;
 static long state_bol = 0;	/* offset of beginning of line */
 
+/* A class for writing out s-expressions, keeping track of newlines and
+   nested indentation.  */
+class s_expr_writer
+{
+public:
+  s_expr_writer ();
 
-/* Counter of written types.  */
-static int state_written_type_count = 0;
+  void write_new_line ();
+  void write_any_indent (int leading_spaces);
+
+  void begin_s_expr (const char *tag);
+  void end_s_expr ();
+
+private:
+  int m_indent_amount;
+  int m_had_recent_newline;
+}; // class s_expr_writer
+
+/* A class for writing out "gtype.state".  */
+class state_writer : public s_expr_writer
+{
+public:
+  state_writer ();
+
+private:
+  void write_state_fileloc (struct fileloc *floc);
+  void write_state_fields (pair_p fields);
+  void write_state_a_string (const char *s);
+  void write_state_string_option (options_p current);
+  void write_state_type_option (options_p current);
+  void write_state_nested_option (options_p current);
+  void write_state_option (options_p current);
+  void write_state_options (options_p opt);
+  void write_state_lang_bitmap (lang_bitmap bitmap);
+  void write_state_version (const char *version);
+  void write_state_scalar_type (type_p current);
+  void write_state_string_type (type_p current);
+  void write_state_undefined_type (type_p current);
+  void write_state_struct_union_type (type_p current, const char *kindstr);
+  void write_state_struct_type (type_p current);
+  void write_state_user_struct_type (type_p current);
+  void write_state_union_type (type_p current);
+  void write_state_lang_struct_type (type_p current);
+  void write_state_pointer_type (type_p current);
+  void write_state_array_type (type_p current);
+  void write_state_gc_used (enum gc_used_enum gus);
+  void write_state_common_type_content (type_p current);
+  void write_state_type (type_p current);
+  void write_state_pair (pair_p current);
+  int write_state_pair_list (pair_p list);
+  void write_state_typedefs (void);
+  void write_state_structures (void);
+  void write_state_variables (void);
+  void write_state_srcdir (void);
+  void write_state_files_list (void);
+  void write_state_languages (void);
+
+  friend void write_state (const char *state_path);
+
+private:
+  /* Counter of written types.  */
+  int m_state_written_type_count;
+}; // class state_writer
+
+
+/* class s_expr_writer's trivial constructor.  */
+s_expr_writer::s_expr_writer ()
+  : m_indent_amount (0),
+    m_had_recent_newline (0)
+{
+}
+
+/* Write a newline to the output file, merging adjacent newlines.  */
+void
+s_expr_writer::write_new_line (void)
+{
+  /* Don't add a newline if we've just had one.  */
+  if (!m_had_recent_newline)
+    {
+      fprintf (state_file, "\n");
+      m_had_recent_newline = 1;
+    }
+}
+
+/* If we've just had a newline, write the indentation amount, potentially
+   omitting some spaces.
+
+   LEADING_SPACES exists to support code that writes strings with leading
+   spaces (e.g " foo") which might occur within a line, or could be the first
+   thing on a line.  By passing leading_spaces == 1, when such a string is the
+   first thing on a line, write_any_indent () swallows the successive
+   leading spaces into the indentation so that the "foo" begins at the expected
+   column.  */
+void
+s_expr_writer::write_any_indent (int leading_spaces)
+{
+  int i;
+  int amount = m_indent_amount - leading_spaces;
+  if (m_had_recent_newline)
+    for (i = 0; i < amount; i++)
+      fprintf (state_file, " ");
+  m_had_recent_newline = 0;
+}
+
+/* Write the beginning of a new s-expresion e.g. "(!foo "
+   The writer automatically adds whitespace to show the hierarchical
+   structure of the expressions, so each one starts on a new line,
+   and any within it will be at an increased indentation level.  */
+void
+s_expr_writer::begin_s_expr (const char *tag)
+{
+  write_new_line ();
+  write_any_indent (0);
+  fprintf (state_file, "(!%s ", tag);
+  m_indent_amount++;
+}
+
+/* Write out the end of an s-expression: any necssessary indentation,
+   a closing parenthesis, and a new line.  */
+void
+s_expr_writer::end_s_expr (void)
+{
+  m_indent_amount--;
+  write_any_indent (0);
+  fprintf (state_file, ")");
+  write_new_line ();
+}
+
+
+/* class state_writer's trivial constructor.  */
+state_writer::state_writer ()
+  : s_expr_writer (),
+    m_state_written_type_count (0)
+{
+}
 
 
 /* Fatal error messages when reading the state.  They are extremely
@@ -143,7 +278,7 @@
 
 
 /* Fatal message while reading state.  */
-static inline void 
+static void 
 fatal_reading_state (struct state_token_st* tok, const char*msg)
 {
   if (tok)
@@ -169,7 +304,7 @@
     else						\
       fatal ("%s:%d: Invalid state file; " Fmt,		\
 	     state_path, state_line, __VA_ARGS__);	\
-  } while(0)
+  } while (0)
 
 
 /* Find or allocate an identifier in our name hash table.  */
@@ -303,7 +438,7 @@
       obstack_1grow (&id_obstack, (char) 0);
       ids = XOBFINISH (&id_obstack, char *);
       sid = state_ident_by_name (ids, INSERT);
-      obstack_free (&id_obstack, ids);
+      obstack_free (&id_obstack, NULL);
       ids = NULL;
       tk = XCNEW (struct state_token_st);
       tk->stok_kind = STOK_NAME;
@@ -408,7 +543,7 @@
       tk->stok_file = state_path;
       tk->stok_next = NULL;
       strcpy (tk->stok_un.stok_string, cstr);
-      obstack_free (&bstring_obstack, cstr);
+      obstack_free (&bstring_obstack, NULL);
 
       return tk;
     }
@@ -495,7 +630,6 @@
  * We want to serialize :
  *          - typedefs list
  *          - structures list
- *          - param_structs list
  *          - variables list
  *
  * So, we have one routine for each kind of data.  The main writing
@@ -513,22 +647,6 @@
 /* Return the length of a linked list made of pairs.  */
 static int pair_list_length (pair_p list);
 
-/* Write a pair */
-static void write_state_pair (pair_p);
-
-/* return the number of pairs written.  Should match the length given
-   by pair_list_length.  */
-static int write_state_pair_list (pair_p list);
-
-/* Write a type.  When a type is written, its state_number is updated,
-   to ensure that a "reference" to a seen type is written on next
-   occurrences.  */
-static void write_state_type (type_p);
-
-/* Write a null-terminatel string using our Lispy lexical conventions,
-   similar to those of C or MELT.  */
-static void write_state_a_string (const char *s);
-
 /* Compute the length of a list of pairs, starting from the first
    one.  */
 static int
@@ -546,8 +664,8 @@
    state file-s produced by gengtype on the same GCC source tree are
    very similar and can be reasonably compared with diff, even if the
    two GCC source trees have different absolute paths.  */
-static void
-write_state_fileloc (struct fileloc *floc)
+void
+state_writer::write_state_fileloc (struct fileloc *floc)
 {
 
   if (floc != NULL && floc->line > 0)
@@ -559,40 +677,43 @@
       srcrelpath = get_file_srcdir_relative_path (floc->file);
       if (srcrelpath != NULL)
 	{
-	  fprintf (state_file, "\n(!srcfileloc ");
+	  begin_s_expr ("srcfileloc");
 	  write_state_a_string (srcrelpath);
 	}
       else
 	{
-	  fprintf (state_file, "\n(!fileloc ");
+	  begin_s_expr ("fileloc");
 	  write_state_a_string (get_input_file_name (floc->file));
 	}
       fprintf (state_file, " %d", floc->line);
-      fprintf (state_file, ")\n");
+      end_s_expr ();
     }
   else
     fprintf (state_file, "nil ");
 }
 
 /* Write a list of fields.  */
-static void
-write_state_fields (pair_p fields)
+void
+state_writer::write_state_fields (pair_p fields)
 {
   int nbfields = pair_list_length (fields);
   int nbpairs = 0;
-  fprintf (state_file, "\n(!fields %d ", nbfields);
+  begin_s_expr ("fields");
+  fprintf (state_file, "%d ", nbfields);
   nbpairs = write_state_pair_list (fields);
   gcc_assert (nbpairs == nbfields);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
 }
 
 /* Write a null-terminated string in our lexical convention, very
    similar to the convention of C.  */
-static void
-write_state_a_string (const char *s)
+void
+state_writer::write_state_a_string (const char *s)
 {
   char c;
 
+  write_any_indent (1);
+
   fputs (" \"", state_file);
   for (; *s != 0; s++)
     {
@@ -637,9 +758,10 @@
 }
 
 /* Our option-s have three kinds, each with its writer.  */
-static void
-write_state_string_option (options_p current)
+void
+state_writer::write_state_string_option (options_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "string ");
   if (current->info.string != NULL)
     write_state_a_string (current->info.string);
@@ -647,34 +769,43 @@
     fprintf (state_file, " nil ");
 }
 
-static void
-write_state_type_option (options_p current)
+void
+state_writer::write_state_type_option (options_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "type ");
   write_state_type (current->info.type);
 }
 
-static void
-write_state_nested_option (options_p current)
+void
+state_writer::write_state_nested_option (options_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "nested ");
   write_state_type (current->info.nested->type);
   if (current->info.nested->convert_from != NULL)
     write_state_a_string (current->info.nested->convert_from);
   else
-    fprintf (state_file, " nil ");
+    {
+      write_any_indent (1);
+      fprintf (state_file, " nil ");
+    }
 
   if (current->info.nested->convert_to != NULL)
     write_state_a_string (current->info.nested->convert_to);
   else
-    fprintf (state_file, " nil ");
+    {
+      write_any_indent (1);
+      fprintf (state_file, " nil ");
+    }
 }
 
-static void
-write_state_option (options_p current)
+void
+state_writer::write_state_option (options_p current)
 {
-  fprintf (state_file, "\n(!option ");
+  begin_s_expr ("option");
 
+  write_any_indent (0);
   if (current->name != NULL)
     fprintf (state_file, "%s ", current->name);
   else
@@ -695,53 +826,54 @@
       fatal ("Option tag unknown");
     }
 
-  fprintf (state_file, ")\n");
+  /* Terminate the "option" s-expression.  */
+  end_s_expr ();
 }
 
 
 
 /* Write a list of GTY options.  */
-static void
-write_state_options (options_p opt)
+void
+state_writer::write_state_options (options_p opt)
 {
   options_p current;
 
   if (opt == NULL)
     {
-      fprintf (state_file, "nil ");
+	write_any_indent (0);
+	fprintf (state_file, "nil ");
       return;
     }
 
-  fprintf (state_file, "\n(!options ");
+  begin_s_expr ("options");
   for (current = opt; current != NULL; current = current->next)
       write_state_option (current);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
 }
 
 
 /* Write a bitmap representing a set of GCC front-end languages.  */
-static void
-write_state_lang_bitmap (lang_bitmap bitmap)
+void
+state_writer::write_state_lang_bitmap (lang_bitmap bitmap)
 {
+  write_any_indent (0);
   fprintf (state_file, "%d ", (int) bitmap);
 }
 
 /* Write version information.  */
-static void
-write_state_version (const char *version)
+void
+state_writer::write_state_version (const char *version)
 {
-  fprintf (state_file, "\n(!version ");
+  begin_s_expr ("version");
   write_state_a_string (version);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
 }
 
-/* Common routine to write the common content of all types.  */
-static void write_state_common_type_content (type_p current);
-
 /* Write a scalar type.  We have only two of these.  */
-static void
-write_state_scalar_type (type_p current)
+void
+state_writer::write_state_scalar_type (type_p current)
 {
+  write_any_indent (0);
   if (current == &scalar_nonchar)
     fprintf (state_file, "scalar_nonchar ");
   else if (current == &scalar_char)
@@ -753,11 +885,12 @@
 }
 
 /* Write the string type.  There is only one such thing! */
-static void
-write_state_string_type (type_p current)
+void
+state_writer::write_state_string_type (type_p current)
 {
   if (current == &string_type)
     {
+      write_any_indent (0);
       fprintf (state_file, "string ");
       write_state_common_type_content (current);
     }
@@ -765,19 +898,45 @@
     fatal ("Unexpected type in write_state_string_type");
 }
 
+/* Write an undefined type.  */
+void
+state_writer::write_state_undefined_type (type_p current)
+{
+  DBGPRINTF ("undefined type @ %p #%d '%s'", (void *) current,
+	     current->state_number, current->u.s.tag);
+  write_any_indent (0);
+  fprintf (state_file, "undefined ");
+  gcc_assert (current->gc_used == GC_UNUSED);
+  write_state_common_type_content (current);
+  if (current->u.s.tag != NULL)
+    write_state_a_string (current->u.s.tag);
+  else
+    {
+      write_any_indent (0);
+      fprintf (state_file, "nil");
+    }
+
+  write_state_fileloc (type_lineloc (current));
+}
+
 
 /* Common code to write structure like types.  */
-static void
-write_state_struct_union_type (type_p current, const char *kindstr)
+void
+state_writer::write_state_struct_union_type (type_p current,
+					     const char *kindstr)
 {
   DBGPRINTF ("%s type @ %p #%d '%s'", kindstr, (void *) current,
 	     current->state_number, current->u.s.tag);
+  write_any_indent (0);
   fprintf (state_file, "%s ", kindstr);
   write_state_common_type_content (current);
   if (current->u.s.tag != NULL)
     write_state_a_string (current->u.s.tag);
   else
-    fprintf (state_file, "nil");
+    {
+      write_any_indent (0);
+      fprintf (state_file, "nil");
+    }
 
   write_state_fileloc (type_lineloc (current));
   write_state_fields (current->u.s.fields);
@@ -787,16 +946,37 @@
 
 
 /* Write a GTY struct type.  */
-static void
-write_state_struct_type (type_p current)
+void
+state_writer::write_state_struct_type (type_p current)
 {
   write_state_struct_union_type (current, "struct");
   write_state_type (current->u.s.lang_struct);
+  write_state_type (current->u.s.base_class);
+}
+
+/* Write a GTY user-defined struct type.  */
+void
+state_writer::write_state_user_struct_type (type_p current)
+{
+  DBGPRINTF ("user_struct type @ %p #%d '%s'", (void *) current,
+	     current->state_number, current->u.s.tag);
+  write_any_indent (0);
+  fprintf (state_file, "user_struct ");
+  write_state_common_type_content (current);
+  if (current->u.s.tag != NULL)
+    write_state_a_string (current->u.s.tag);
+  else
+    {
+      write_any_indent (0);
+      fprintf (state_file, "nil");
+    }
+  write_state_fileloc (type_lineloc (current));
+  write_state_fields (current->u.s.fields);
 }
 
 /* write a GTY union type.  */
-static void
-write_state_union_type (type_p current)
+void
+state_writer::write_state_union_type (type_p current)
 {
   write_state_struct_union_type (current, "union");
   write_state_type (current->u.s.lang_struct);
@@ -807,14 +987,14 @@
    subfield, which points to a linked list of homonumous types.
    Change this function with extreme care, see also
    read_state_lang_struct_type.  */
-static void
-write_state_lang_struct_type (type_p current)
+void
+state_writer::write_state_lang_struct_type (type_p current)
 {
   int nbhomontype = 0;
   type_p hty = NULL;
   const char *homoname = 0;
   write_state_struct_union_type (current, "lang_struct");
-  /* lang_struct-ures are particularily tricky, since their
+  /* lang_struct-ures are particularly tricky, since their
      u.s.lang_struct field gives a list of homonymous struct-s or
      union-s! */
   DBGPRINTF ("lang_struct @ %p #%d", (void *) current, current->state_number);
@@ -824,65 +1004,54 @@
       DBGPRINTF ("homonymous #%d hty @ %p #%d '%s'", nbhomontype,
 		 (void *) hty, hty->state_number, hty->u.s.tag);
       /* Every member of the homonymous list should have the same tag.  */
-      gcc_assert (UNION_OR_STRUCT_P (hty));
+      gcc_assert (union_or_struct_p (hty));
       gcc_assert (hty->u.s.lang_struct == current);
       if (!homoname)
 	homoname = hty->u.s.tag;
       gcc_assert (strcmp (homoname, hty->u.s.tag) == 0);
     }
-  fprintf (state_file, "(!homotypes %d\n", nbhomontype);
+  begin_s_expr ("homotypes");
+  fprintf (state_file, "%d", nbhomontype);
   for (hty = current->u.s.lang_struct; hty != NULL; hty = hty->next)
     write_state_type (hty);
-  fprintf (state_file, ")\n");
-}
-
-/* Write a parametrized structure GTY type.  */
-static void
-write_state_param_struct_type (type_p current)
-{
-  int i;
-
-  fprintf (state_file, "param_struct ");
-  write_state_common_type_content (current);
-  write_state_type (current->u.param_struct.stru);
-  for (i = 0; i < NUM_PARAM; i++)
-    {
-      if (current->u.param_struct.param[i] != NULL)
-	write_state_type (current->u.param_struct.param[i]);
-      else
-	fprintf (state_file, "nil ");
-    }
-  write_state_fileloc (&current->u.param_struct.line);
+  end_s_expr ();
 }
 
 /* Write a pointer type.  */
-static void
-write_state_pointer_type (type_p current)
+void
+state_writer::write_state_pointer_type (type_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "pointer ");
   write_state_common_type_content (current);
   write_state_type (current->u.p);
 }
 
 /* Write an array type.  */
-static void
-write_state_array_type (type_p current)
+void
+state_writer::write_state_array_type (type_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "array ");
   write_state_common_type_content (current);
   if (current->u.a.len != NULL)
     write_state_a_string (current->u.a.len);
   else
-    fprintf (state_file, " nil");
+    {
+      write_any_indent (1);
+      fprintf (state_file, " nil");
+    }
 
+  write_any_indent (1);
   fprintf (state_file, " ");
   write_state_type (current->u.a.p);
 }
 
 /* Write the gc_used information.  */
-static void
-write_state_gc_used (enum gc_used_enum gus)
+void
+state_writer::write_state_gc_used (enum gc_used_enum gus)
 {
+  write_any_indent (1);
   switch (gus)
     {
     case GC_UNUSED:
@@ -904,9 +1073,10 @@
 
 /* Utility routine to write the common content of all types.  Notice
    that the next field is *not* written on purpose.  */
-static void
-write_state_common_type_content (type_p current)
+void
+state_writer::write_state_common_type_content (type_p current)
 {
+  write_any_indent (0);
   fprintf (state_file, "%d ", current->state_number);
   /* We do not write the next type, because list of types are
      explicitly written.  However, lang_struct are special in that
@@ -919,30 +1089,42 @@
 /* The important and recursive routine writing GTY types as understood
    by gengtype.  Types which have a positive state_number have already
    been seen and written.  */
-static void
-write_state_type (type_p current)
+void
+state_writer::write_state_type (type_p current)
 {
+  write_any_indent (0);
   if (current == NULL)
     {
       fprintf (state_file, "nil ");
       return;
     }
 
-  fprintf (state_file, "\n(!type ");
+  begin_s_expr ("type");
 
   if (current->state_number > 0)
-    fprintf (state_file, "already_seen %d", current->state_number);
+    {
+      write_any_indent (0);
+      fprintf (state_file, "already_seen %d", current->state_number);
+    }
   else
     {
-      state_written_type_count++;
-      DBGPRINTF ("writing type #%d @%p old number %d", state_written_type_count,
+      m_state_written_type_count++;
+      DBGPRINTF ("writing type #%d @%p old number %d", m_state_written_type_count,
 		 (void *) current, current->state_number);
-      current->state_number = state_written_type_count;
+      current->state_number = m_state_written_type_count;
       switch (current->kind)
 	{
+	case TYPE_NONE:
+	  gcc_unreachable ();
+	case TYPE_UNDEFINED:
+	  write_state_undefined_type (current);
+	  break;
 	case TYPE_STRUCT:
 	  write_state_struct_type (current);
 	  break;
+	case TYPE_USER_STRUCT:
+	  write_state_user_struct_type (current);
+	  break;
 	case TYPE_UNION:
 	  write_state_union_type (current);
 	  break;
@@ -955,36 +1137,32 @@
 	case TYPE_LANG_STRUCT:
 	  write_state_lang_struct_type (current);
 	  break;
-	case TYPE_PARAM_STRUCT:
-	  write_state_param_struct_type (current);
-	  break;
 	case TYPE_SCALAR:
 	  write_state_scalar_type (current);
 	  break;
 	case TYPE_STRING:
 	  write_state_string_type (current);
 	  break;
-
-	default:
-	  fatal ("Unexpected type...");
 	}
     }
 
-  fprintf (state_file, ")\n");
+  /* Terminate the "type" s-expression.  */
+  end_s_expr ();
 }
 
 
 /* Write a pair.  */
-static void
-write_state_pair (pair_p current)
+void
+state_writer::write_state_pair (pair_p current)
 {
   if (current == NULL)
     {
+      write_any_indent (0);
       fprintf (state_file, "nil)");
       return;
     }
 
-  fprintf (state_file, "\n(!pair ");
+  begin_s_expr ("pair");
 
   if (current->name != NULL)
     write_state_a_string (current->name);
@@ -995,12 +1173,13 @@
   write_state_fileloc (&(current->line));
   write_state_options (current->opt);
 
-  fprintf (state_file, ")");
+  /* Terminate the "pair" s-expression.  */
+  end_s_expr ();
 }
 
 /* Write a pair list and return the number of pairs written.  */
-static int
-write_state_pair_list (pair_p list)
+int
+state_writer::write_state_pair_list (pair_p list)
 {
   int nbpair = 0;
   pair_p current;
@@ -1014,28 +1193,28 @@
 
 }
 
-/* When writing imported linked lists, like typedefs, structures,
-   param_structs, ... we count their length first and write it.  These
-   eases the reading, and enables an extra verification on the number
-   of actually read items.  */
+/* When writing imported linked lists, like typedefs, structures, ... we count
+   their length first and write it.  This eases the reading, and enables an
+   extra verification on the number of actually read items.  */
 
 /* Write our typedefs.  */
-static void
-write_state_typedefs (void)
+void
+state_writer::write_state_typedefs (void)
 {
   int nbtypedefs = pair_list_length (typedefs);
   int nbpairs = 0;
-  fprintf (state_file, "\n(!typedefs %d\n", nbtypedefs);
+  begin_s_expr ("typedefs");
+  fprintf (state_file, "%d", nbtypedefs);
   nbpairs = write_state_pair_list (typedefs);
   gcc_assert (nbpairs == nbtypedefs);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
   if (verbosity_level >= 2)
     printf ("%s wrote %d typedefs\n", progname, nbtypedefs);
 }
 
 /* Write our structures.  */
-static void
-write_state_structures (void)
+void
+state_writer::write_state_structures (void)
 {
   int nbstruct = 0;
   type_p current;
@@ -1043,65 +1222,54 @@
   for (current = structures; current != NULL; current = current->next)
     nbstruct++;
 
-  fprintf (state_file, "\n(!structures %d\n", nbstruct);
+  begin_s_expr ("structures");
+  fprintf (state_file, "%d", nbstruct);
 
   for (current = structures; current != NULL; current = current->next)
-    write_state_type (current);
+    {
+      write_new_line ();
+      write_state_type (current);
+    }
 
-  fprintf (state_file, ")\n");
+  /* Terminate the "structures" s-expression.  */
+  end_s_expr ();
   if (verbosity_level >= 2)
     printf ("%s wrote %d structures in state\n", progname, nbstruct);
 }
 
-/* Write our param_struct-s.  */
-static void
-write_state_param_structs (void)
-{
-  int nbparamstruct = 0;
-  type_p current;
-
-  for (current = param_structs; current != NULL; current = current->next)
-    nbparamstruct++;
-
-  fprintf (state_file, "\n(!param_structs %d\n", nbparamstruct);
-
-  for (current = param_structs; current != NULL; current = current->next)
-    write_state_type (current);
-
-  fprintf (state_file, ")\n");
-}
-
 /* Write our variables.  */
-static void
-write_state_variables (void)
+void
+state_writer::write_state_variables (void)
 {
   int nbvars = pair_list_length (variables);
   int nbpairs = 0;
-  fprintf (state_file, "\n(!variables %d\n", nbvars);
+  begin_s_expr ("variables");
+  fprintf (state_file, "%d", nbvars);
   nbpairs = write_state_pair_list (variables);
   gcc_assert (nbpairs == nbvars);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
   if (verbosity_level >= 2)
     printf ("%s wrote %d variables.\n", progname, nbvars);
 }
 
 /* Write the source directory.  File locations within the source
    directory have been written specifically.  */
-static void
-write_state_srcdir (void)
+void
+state_writer::write_state_srcdir (void)
 {
-  fprintf (state_file, "\n(!srcdir ");
+  begin_s_expr ("srcdir");
   write_state_a_string (srcdir);
-  fprintf (state_file, ")\n");
+  end_s_expr ();
 }
 
 /* Count and write the list of our files.  */
-static void
-write_state_files_list (void)
+void
+state_writer::write_state_files_list (void)
 {
   int i = 0;
   /* Write the list of files with their lang_bitmap.  */
-  fprintf (state_file, "\n(!fileslist %d\n", (int) num_gt_files);
+  begin_s_expr ("fileslist");
+  fprintf (state_file, "%d", (int) num_gt_files);
   for (i = 0; i < (int) num_gt_files; i++)
     {
       const char *cursrcrelpath = NULL;
@@ -1111,25 +1279,30 @@
       cursrcrelpath = get_file_srcdir_relative_path (curfil);
       if (cursrcrelpath)
 	{
-	  fprintf (state_file, "(!srcfile %d ", get_lang_bitmap (curfil));
+	  begin_s_expr ("srcfile");
+	  fprintf (state_file, "%d ", get_lang_bitmap (curfil));
 	  write_state_a_string (cursrcrelpath);
 	}
       else
 	{
-	  fprintf (state_file, "(!file %d ", get_lang_bitmap (curfil));
+	  begin_s_expr ("file");
+	  fprintf (state_file, "%d ", get_lang_bitmap (curfil));
 	  write_state_a_string (get_input_file_name (curfil));
 	}
-      fprintf (state_file, ")\n");
+      /* Terminate the inner s-expression (either "srcfile" or "file").   */
+      end_s_expr ();
     }
-  fprintf (state_file, ")\n");
+  /* Terminate the "fileslist" s-expression.  */
+  end_s_expr ();
 }
 
 /* Write the list of GCC front-end languages.  */
-static void
-write_state_languages (void)
+void
+state_writer::write_state_languages (void)
 {
   int i = 0;
-  fprintf (state_file, "\n(!languages %d", (int) num_lang_dirs);
+  begin_s_expr ("languages");
+  fprintf (state_file, "%d", (int) num_lang_dirs);
   for (i = 0; i < (int) num_lang_dirs; i++)
     {
       /* Languages names are identifiers, we expect only letters or
@@ -1137,7 +1310,7 @@
          valid language name, but cp is valid.  */
       fprintf (state_file, " %s", lang_dir_names[i]);
     }
-  fprintf (state_file, ")\n");
+  end_s_expr ();
 }
 
 /* Write the trailer.  */
@@ -1190,17 +1363,17 @@
   fprintf (state_file,
 	   ";;; This file should be parsed by the same %s which wrote it.\n",
 	   progname);
-  fprintf (state_file, ";;; file %s generated on %s\n", state_path,
-	   ctime (&now));
+
+  state_writer sw;
+
   /* The first non-comment significant line gives the version string.  */
-  write_state_version (version_string);
-  write_state_srcdir ();
-  write_state_languages ();
-  write_state_files_list ();
-  write_state_structures ();
-  write_state_typedefs ();
-  write_state_param_structs ();
-  write_state_variables ();
+  sw.write_state_version (version_string);
+  sw.write_state_srcdir ();
+  sw.write_state_languages ();
+  sw.write_state_files_list ();
+  sw.write_state_structures ();
+  sw.write_state_typedefs ();
+  sw.write_state_variables ();
   write_state_trailer ();
   statelen = ftell (state_file);
   if (ferror (state_file))
@@ -1216,7 +1389,7 @@
 
   if (verbosity_level >= 1)
     printf ("%s wrote state file %s of %ld bytes with %d GTY-ed types\n",
-	    progname, state_path, statelen, state_written_type_count);
+	    progname, state_path, statelen, sw.m_state_written_type_count);
 
 }
 
@@ -1296,7 +1469,6 @@
   read_state_common_type_content (*type);
 }
 
-
 /* Read the string_type.  */
 static void
 read_state_string_type (type_p *type)
@@ -1325,6 +1497,40 @@
 }
 
 
+/* Read an undefined type.  */
+static void
+read_state_undefined_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_UNDEFINED;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.s.tag = NULL;
+	  DBGPRINTF ("read anonymous undefined type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read undefined type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad tag in undefined type");
+    }
+}
+
+
 /* Read a GTY-ed struct type.  */
 static void
 read_state_struct_type (type_p type)
@@ -1355,6 +1561,9 @@
       read_state_options (&(type->u.s.opt));
       read_state_lang_bitmap (&(type->u.s.bitmap));
       read_state_type (&(type->u.s.lang_struct));
+      read_state_type (&(type->u.s.base_class));
+      if (type->u.s.base_class)
+	add_subclass (type->u.s.base_class, type);
     }
   else
     {
@@ -1363,6 +1572,42 @@
 }
 
 
+/* Read a GTY-ed user-provided struct TYPE.  */
+
+static void
+read_state_user_struct_type (type_p type)
+{
+  struct state_token_st *t0;
+
+  type->kind = TYPE_USER_STRUCT;
+  read_state_common_type_content (type);
+  t0 = peek_state_token (0);
+  if (state_token_kind (t0) == STOK_STRING)
+    {
+      if (state_token_is_name (t0, "nil"))
+	{
+	  type->u.s.tag = NULL;
+	  DBGPRINTF ("read anonymous struct type @%p #%d",
+		     (void *) type, type->state_number);
+	}
+      else
+	{
+	  type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+	  DBGPRINTF ("read struct type @%p #%d '%s'",
+		     (void *) type, type->state_number, type->u.s.tag);
+	}
+
+      next_state_tokens (1);
+      read_state_fileloc (&(type->u.s.line));
+      read_state_fields (&(type->u.s.fields));
+    }
+  else
+    {
+      fatal_reading_state (t0, "Bad tag in user-struct type");
+    }
+}
+
+
 /* Read a GTY-ed union type.  */
 static void
 read_state_union_type (type_p type)
@@ -1512,34 +1757,6 @@
 }
 
 
-/* Read a param_struct type for GTY parametrized structures.  */
-static void
-read_state_param_struct_type (type_p type)
-{
-  int i;
-  struct state_token_st *t0;
-
-  type->kind = TYPE_PARAM_STRUCT;
-  read_state_common_type_content (type);
-  DBGPRINTF ("read param_struct type @%p #%d",
-	     (void *) type, type->state_number);
-  read_state_type (&(type->u.param_struct.stru));
-
-  for (i = 0; i < NUM_PARAM; i++)
-    {
-      t0 = peek_state_token (0);
-      if (state_token_is_name (t0, "nil"))
-	{
-	  type->u.param_struct.param[i] = NULL;
-	  next_state_tokens (1);
-	}
-      else
-	read_state_type (&(type->u.param_struct.param[i]));
-    }
-  read_state_fileloc (&(type->u.param_struct.line));
-}
-
-
 /* Read the gc used information.  */
 static void
 read_state_gc_used (enum gc_used_enum *pgus)
@@ -1617,6 +1834,12 @@
 	      next_state_tokens (1);
 	      read_state_string_type (current);
 	    }
+	  else if (state_token_is_name (t0, "undefined"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_undefined_type (*current);
+	    }
 	  else if (state_token_is_name (t0, "struct"))
 	    {
 	      *current = XCNEW (struct type);
@@ -1635,12 +1858,6 @@
 	      next_state_tokens (1);
 	      read_state_lang_struct_type (*current);
 	    }
-	  else if (state_token_is_name (t0, "param_struct"))
-	    {
-	      *current = XCNEW (struct type);
-	      next_state_tokens (1);
-	      read_state_param_struct_type (*current);
-	    }
 	  else if (state_token_is_name (t0, "pointer"))
 	    {
 	      *current = XCNEW (struct type);
@@ -1653,6 +1870,12 @@
 	      next_state_tokens (1);
 	      read_state_array_type (*current);
 	    }
+	  else if (state_token_is_name (t0, "user_struct"))
+	    {
+	      *current = XCNEW (struct type);
+	      next_state_tokens (1);
+	      read_state_user_struct_type (*current);
+	    }
 	  else
 	    fatal_reading_state (t0, "bad type in (!type");
 	}
@@ -2130,58 +2353,6 @@
 }
 
 
-/* Read the param_struct-s.  */
-static void
-read_state_param_structs (type_p *param_structs)
-{
-  int nbparamstructs = 0;
-  int countparamstructs = 0;
-  type_p head = NULL;
-  type_p previous;
-  type_p tmp;
-  struct state_token_st *t0 = peek_state_token (0);
-  struct state_token_st *t1 = peek_state_token (1);
-  struct state_token_st *t2 = peek_state_token (2);
-
-  if (state_token_kind (t0) == STOK_LEFTPAR
-      && state_token_is_name (t1, "!param_structs")
-      && state_token_kind (t2) == STOK_INTEGER)
-    {
-      nbparamstructs = t2->stok_un.stok_num;
-      next_state_tokens (3);
-      t0 = t1 = t2 = NULL;
-      t0 = peek_state_token (0);
-      while (state_token_kind (t0) != STOK_RIGHTPAR)
-	{
-	  tmp = NULL;
-	  read_state_type (&tmp);
-	  if (head == NULL)
-	    {
-	      head = tmp;
-	      previous = head;
-	    }
-	  else
-	    {
-	      previous->next = tmp;
-	      previous = tmp;
-	    }
-	  t0 = peek_state_token (0);
-	  countparamstructs++;
-	}
-      next_state_tokens (1);
-    }
-  else
-    fatal_reading_state (t0, "Bad param_structs syntax");
-  t0 = peek_state_token (0);
-  if (countparamstructs != nbparamstructs)
-    fatal_reading_state_printf
-      (t0,
-       "invalid number of param_structs expected %d got %d",
-       nbparamstructs, countparamstructs);
-  *param_structs = head;
-}
-
-
 /* Read the variables.  */
 static void
 read_state_variables (pair_p *variables)
@@ -2341,7 +2512,7 @@
 				 "expecting file in !fileslist of state file");
 	};
       t0 = peek_state_token (0);
-      if (!state_token_kind (t0) == STOK_RIGHTPAR)
+      if (state_token_kind (t0) != STOK_RIGHTPAR)
 	fatal_reading_state (t0, "missing ) for !fileslist in state file");
       next_state_tokens (1);
     }
@@ -2385,6 +2556,15 @@
   return type1->state_number == type2->state_number;
 }
 
+static int
+string_eq (const void *a, const void *b)
+{
+  const char *a0 = (const char *)a;
+  const char *b0 = (const char *)b;
+
+  return (strcmp (a0, b0) == 0);
+}
+
 
 /* The function reading the state, called by main from gengtype.c.  */
 void
@@ -2408,7 +2588,7 @@
   state_seen_types =
     htab_create (2017, hash_type_number, equals_type_number, NULL);
   state_ident_tab =
-    htab_create (4027, htab_hash_string, (htab_eq) strcmp, NULL);
+    htab_create (4027, htab_hash_string, string_eq, NULL);
   read_state_version (version_string);
   read_state_srcdir ();
   read_state_languages ();
@@ -2419,7 +2599,6 @@
       (NULL_STATE_TOKEN, "input error while reading state [%s]",
        xstrerror (errno));
   read_state_typedefs (&typedefs);
-  read_state_param_structs (&param_structs);
   read_state_variables (&variables);
   read_state_trailer ();