aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/gengtype-state.c
diff options
context:
space:
mode:
authorBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
committerBen Cheng <bccheng@google.com>2014-03-25 22:37:19 -0700
commit1bc5aee63eb72b341f506ad058502cd0361f0d10 (patch)
treec607e8252f3405424ff15bc2d00aa38dadbb2518 /gcc-4.9/gcc/gengtype-state.c
parent283a0bf58fcf333c58a2a92c3ebbc41fb9eb1fdb (diff)
downloadtoolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.gz
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.tar.bz2
toolchain_gcc-1bc5aee63eb72b341f506ad058502cd0361f0d10.zip
Initial checkin of GCC 4.9.0 from trunk (r208799).
Change-Id: I48a3c08bb98542aa215912a75f03c0890e497dba
Diffstat (limited to 'gcc-4.9/gcc/gengtype-state.c')
-rw-r--r--gcc-4.9/gcc/gengtype-state.c2758
1 files changed, 2758 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/gengtype-state.c b/gcc-4.9/gcc/gengtype-state.c
new file mode 100644
index 000000000..0b925b539
--- /dev/null
+++ b/gcc-4.9/gcc/gengtype-state.c
@@ -0,0 +1,2758 @@
+/* Gengtype persistent state serialization & de-serialization.
+ Useful for gengtype in plugin mode.
+
+ Copyright (C) 2010-2014 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/>.
+
+ Contributed by Jeremie Salvucci <jeremie.salvucci@free.fr>
+ and Basile Starynkevitch <basile@starynkevitch.net>
+*/
+
+#ifdef GENERATOR_FILE
+#include "bconfig.h"
+#else
+#include "config.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"
+
+
+
+/* Gives the file location of a type, if any. */
+static inline struct fileloc*
+type_lineloc (const_type_p ty)
+{
+ if (!ty)
+ return NULL;
+ switch (ty->kind)
+ {
+ case TYPE_NONE:
+ gcc_unreachable ();
+ 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:
+ case TYPE_ARRAY:
+ return NULL;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* The state file has simplistic lispy lexical tokens. Its lexer gives
+ a linked list of struct state_token_st, through the peek_state_token
+ function. Lexical tokens are consumed with next_state_tokens. */
+
+
+/* The lexical kind of each lispy token. */
+enum state_token_en
+{
+ STOK_NONE, /* Never used. */
+ STOK_INTEGER, /* Integer token. */
+ STOK_STRING, /* String token. */
+ STOK_LEFTPAR, /* Left opening parenthesis. */
+ STOK_RIGHTPAR, /* Right closing parenthesis. */
+ STOK_NAME /* hash-consed name or identifier. */
+};
+
+
+/* Structure and hash-table used to share identifiers or names. */
+struct state_ident_st
+{
+ /* TODO: We could improve the parser by reserving identifiers for
+ state keywords and adding a keyword number for them. That would
+ mean adding another field in this state_ident_st struct. */
+ char stid_name[1]; /* actually bigger & null terminated */
+};
+static htab_t state_ident_tab;
+
+
+/* The state_token_st structure is for lexical tokens in the read
+ state file. The stok_kind field discriminates the union. Tokens
+ are allocated by peek_state_token which calls read_a_state_token
+ which allocate them. Tokens are freed by calls to
+ next_state_tokens. Token are organized in a FIFO look-ahead queue
+ filled by peek_state_token. */
+struct state_token_st
+{
+ enum state_token_en stok_kind; /* the lexical kind
+ discriminates the stok_un
+ union */
+ int stok_line; /* the line number */
+ int stok_col; /* the column number */
+ const char *stok_file; /* the file path */
+ struct state_token_st *stok_next; /* the next token in the
+ queue, when peeked */
+ union /* discriminated by stok_kind! */
+ {
+ int stok_num; /* when STOK_INTEGER */
+ char stok_string[1]; /* when STOK_STRING, actual size is
+ bigger and null terminated */
+ struct state_ident_st *stok_ident; /* when STOK_IDENT */
+ void *stok_ptr; /* null otherwise */
+ }
+ stok_un;
+};
+
+
+
+
+#define NULL_STATE_TOKEN (struct state_token_st*)0
+
+/* the state_token pointer contains the leftmost current token. The
+ tokens are organized in a linked queue, using stok_next, for token
+ look-ahead. */
+struct state_token_st *state_token = NULL_STATE_TOKEN;
+
+/* Used by the reading lexer. */
+static FILE *state_file;
+static const char *state_path = NULL;
+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 ();
+
+ 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_param_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_param_structs (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
+ unlikely, and only appear when this gengtype-state.c file is buggy,
+ or when reading a gengtype state which was not generated by the
+ same version of gengtype or GCC. */
+
+
+/* Fatal message while reading state. */
+static inline void
+fatal_reading_state (struct state_token_st* tok, const char*msg)
+{
+ if (tok)
+ fatal ("%s:%d:%d: Invalid state file; %s",
+ tok->stok_file, tok->stok_line, tok->stok_col,
+ msg);
+ else
+ fatal ("%s:%d: Invalid state file; %s",
+ state_path, state_line, msg);
+}
+
+
+/* Fatal printf-like message while reading state. This can't be a
+ function, because there is no way to pass a va_arg to a variant of
+ fatal. */
+#define fatal_reading_state_printf(Tok,Fmt,...) do { \
+ struct state_token_st* badtok = Tok; \
+ if (badtok) \
+ fatal ("%s:%d:%d: Invalid state file; " Fmt, \
+ badtok->stok_file, \
+ badtok->stok_line, \
+ badtok->stok_col, __VA_ARGS__); \
+ else \
+ fatal ("%s:%d: Invalid state file; " Fmt, \
+ state_path, state_line, __VA_ARGS__); \
+ } while (0)
+
+
+/* Find or allocate an identifier in our name hash table. */
+static struct state_ident_st *
+state_ident_by_name (const char *name, enum insert_option optins)
+{
+ PTR *slot = NULL;
+ int namlen = 0;
+ struct state_ident_st *stid = NULL;
+
+ if (!name || !name[0])
+ return NULL;
+
+ slot = htab_find_slot (state_ident_tab, name, optins);
+ if (!slot)
+ return NULL;
+
+ namlen = strlen (name);
+ stid =
+ (struct state_ident_st *) xmalloc (sizeof (struct state_ident_st) +
+ namlen);
+ memset (stid, 0, sizeof (struct state_ident_st) + namlen);
+ strcpy (stid->stid_name, name);
+ *slot = stid;
+
+ return stid;
+}
+
+/* Our token lexer is heavily inspired by MELT's lexer, and share some
+ code with the file gcc/melt-runtime.c of the GCC MELT branch! We
+ really want the gengtype state to be easily parsable by MELT. This
+ is a usual lispy lexing routine, dealing with spaces and comments,
+ numbers, parenthesis, names, strings. */
+static struct state_token_st *
+read_a_state_token (void)
+{
+ int c = 0;
+ long curoff = 0;
+ struct state_token_st *tk = NULL;
+
+ again: /* Read again, e.g. after a comment or spaces. */
+ c = getc (state_file);
+ if (c == EOF)
+ return NULL;
+
+ /* Handle spaces, count lines. */
+ if (c == '\n')
+ {
+ state_line++;
+ state_bol = curoff = ftell (state_file);
+ goto again;
+ };
+ if (ISSPACE (c))
+ goto again;
+ /* Skip comments starting with semi-colon. */
+ if (c == ';')
+ {
+ do
+ {
+ c = getc (state_file);
+ }
+ while (c > 0 && c != '\n');
+ if (c == '\n')
+ {
+ state_line++;
+ state_bol = curoff = ftell (state_file);
+ }
+ goto again;
+ };
+ /* Read signed numbers. */
+ if (ISDIGIT (c) || c == '-' || c == '+')
+ { /* number */
+ int n = 0;
+ ungetc (c, state_file);
+ curoff = ftell (state_file);
+ if (fscanf (state_file, "%d", &n) <= 0)
+ fatal_reading_state (NULL_STATE_TOKEN, "Lexical error in number");
+ tk = XCNEW (struct state_token_st);
+ tk->stok_kind = STOK_INTEGER;
+ tk->stok_line = state_line;
+ tk->stok_col = curoff - state_bol;
+ tk->stok_file = state_path;
+ tk->stok_next = NULL;
+ tk->stok_un.stok_num = n;
+
+ return tk;
+ }
+ /* Read an opening left parenthesis. */
+ else if (c == '(')
+ {
+ curoff = ftell (state_file);
+ tk = XCNEW (struct state_token_st);
+ tk->stok_kind = STOK_LEFTPAR;
+ tk->stok_line = state_line;
+ tk->stok_col = curoff - state_bol;
+ tk->stok_file = state_path;
+ tk->stok_next = NULL;
+
+ return tk;
+ }
+ /* Read an closing right parenthesis. */
+ else if (c == ')')
+ {
+ curoff = ftell (state_file);
+ tk = XCNEW (struct state_token_st);
+ tk->stok_kind = STOK_RIGHTPAR;
+ tk->stok_line = state_line;
+ tk->stok_col = curoff - state_bol;
+ tk->stok_file = state_path;
+ tk->stok_next = NULL;
+
+ return tk;
+ }
+ /* Read identifiers, using an obstack. */
+ else if (ISALPHA (c) || c == '_' || c == '$' || c == '!' || c == '#')
+ {
+ struct obstack id_obstack;
+ struct state_ident_st *sid = NULL;
+ char *ids = NULL;
+ obstack_init (&id_obstack);
+ curoff = ftell (state_file);
+ while (ISALNUM (c) || c == '_' || c == '$' || c == '!' || c == '#')
+ {
+ obstack_1grow (&id_obstack, c);
+ c = getc (state_file);
+ if (c < 0)
+ break;
+ };
+ if (c >= 0)
+ ungetc (c, state_file);
+ obstack_1grow (&id_obstack, (char) 0);
+ ids = XOBFINISH (&id_obstack, char *);
+ sid = state_ident_by_name (ids, INSERT);
+ obstack_free (&id_obstack, NULL);
+ ids = NULL;
+ tk = XCNEW (struct state_token_st);
+ tk->stok_kind = STOK_NAME;
+ tk->stok_line = state_line;
+ tk->stok_col = curoff - state_bol;
+ tk->stok_file = state_path;
+ tk->stok_next = NULL;
+ tk->stok_un.stok_ident = sid;
+
+ return tk;
+ }
+ /* Read a string, dealing with escape sequences a la C! */
+ else if (c == '"')
+ {
+ char *cstr = NULL;
+ int cslen = 0;
+ struct obstack bstring_obstack;
+ obstack_init (&bstring_obstack);
+ curoff = ftell (state_file);
+ while ((c = getc (state_file)) != '"' && c >= 0)
+ {
+ if (ISPRINT (c) && c != '\\')
+ obstack_1grow (&bstring_obstack, (char) c);
+ else if (ISSPACE (c) && c != '\n')
+ obstack_1grow (&bstring_obstack, (char) c);
+ else if (c == '\\')
+ {
+ c = getc (state_file);
+ switch (c)
+ {
+ case 'a':
+ obstack_1grow (&bstring_obstack, '\a');
+ c = getc (state_file);
+ break;
+ case 'b':
+ obstack_1grow (&bstring_obstack, '\b');
+ c = getc (state_file);
+ break;
+ case 't':
+ obstack_1grow (&bstring_obstack, '\t');
+ c = getc (state_file);
+ break;
+ case 'n':
+ obstack_1grow (&bstring_obstack, '\n');
+ c = getc (state_file);
+ break;
+ case 'v':
+ obstack_1grow (&bstring_obstack, '\v');
+ c = getc (state_file);
+ break;
+ case 'f':
+ obstack_1grow (&bstring_obstack, '\f');
+ c = getc (state_file);
+ break;
+ case 'r':
+ obstack_1grow (&bstring_obstack, '\r');
+ c = getc (state_file);
+ break;
+ case '"':
+ obstack_1grow (&bstring_obstack, '\"');
+ c = getc (state_file);
+ break;
+ case '\\':
+ obstack_1grow (&bstring_obstack, '\\');
+ c = getc (state_file);
+ break;
+ case ' ':
+ obstack_1grow (&bstring_obstack, ' ');
+ c = getc (state_file);
+ break;
+ case 'x':
+ {
+ unsigned int cx = 0;
+ if (fscanf (state_file, "%02x", &cx) > 0 && cx > 0)
+ obstack_1grow (&bstring_obstack, cx);
+ else
+ fatal_reading_state
+ (NULL_STATE_TOKEN,
+ "Lexical error in string hex escape");
+ c = getc (state_file);
+ break;
+ }
+ default:
+ fatal_reading_state
+ (NULL_STATE_TOKEN,
+ "Lexical error - unknown string escape");
+ }
+ }
+ else
+ fatal_reading_state (NULL_STATE_TOKEN, "Lexical error...");
+ };
+ if (c != '"')
+ fatal_reading_state (NULL_STATE_TOKEN, "Unterminated string");
+ obstack_1grow (&bstring_obstack, '\0');
+ cstr = XOBFINISH (&bstring_obstack, char *);
+ cslen = strlen (cstr);
+ tk = (struct state_token_st *)
+ xcalloc (sizeof (struct state_token_st) + cslen, 1);
+ tk->stok_kind = STOK_STRING;
+ tk->stok_line = state_line;
+ tk->stok_col = curoff - state_bol;
+ tk->stok_file = state_path;
+ tk->stok_next = NULL;
+ strcpy (tk->stok_un.stok_string, cstr);
+ obstack_free (&bstring_obstack, NULL);
+
+ return tk;
+ }
+ /* Got an unexpected character. */
+ fatal_reading_state_printf
+ (NULL_STATE_TOKEN,
+ "Lexical error at offset %ld - bad character \\%03o = '%c'",
+ ftell (state_file), c, c);
+}
+
+/* Used for lexical look-ahead. Retrieves the lexical token of rank
+ DEPTH, starting with 0 when reading the state file. Gives null on
+ end of file. */
+static struct state_token_st *
+peek_state_token (int depth)
+{
+ int remdepth = depth;
+ struct state_token_st **ptoken = &state_token;
+ struct state_token_st *tok = NULL;
+
+ while (remdepth >= 0)
+ {
+ if (*ptoken == NULL)
+ {
+ *ptoken = tok = read_a_state_token ();
+ if (tok == NULL)
+ return NULL;
+ }
+ tok = *ptoken;
+ ptoken = &((*ptoken)->stok_next);
+ remdepth--;
+ }
+
+ return tok;
+}
+
+/* Consume the next DEPTH tokens and free them. */
+static void
+next_state_tokens (int depth)
+{
+ struct state_token_st *n;
+
+ while (depth > 0)
+ {
+ if (state_token != NULL)
+ {
+ n = state_token->stok_next;
+ free (state_token);
+ state_token = n;
+ }
+ else
+ fatal_reading_state (NULL_STATE_TOKEN, "Tokens stack empty");
+
+ depth--;
+ }
+}
+
+/* Safely retrieve the lexical kind of a token. */
+static inline enum state_token_en
+state_token_kind (struct state_token_st *p)
+{
+ if (p == NULL)
+ return STOK_NONE;
+ else
+ return p->stok_kind;
+}
+
+/* Test if a token is a given name i.e. an identifier. */
+static inline bool
+state_token_is_name (struct state_token_st *p, const char *name)
+{
+ if (p == NULL)
+ return false;
+
+ if (p->stok_kind != STOK_NAME)
+ return false;
+
+ return !strcmp (p->stok_un.stok_ident->stid_name, name);
+}
+
+
+/* Following routines are useful for serializing datas.
+ *
+ * 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
+ * routine is write_state. The main reading routine is
+ * read_state. Most writing routines write_state_FOO have a
+ * corresponding reading routine read_state_FOO. Reading is done in a
+ * recursive descending way, and any read error is fatal.
+ */
+
+/* When reading the state, we need to remember the previously seen
+ types by their state_number, since GTY-ed types are usually
+ shared. */
+static htab_t state_seen_types;
+
+/* Return the length of a linked list made of pairs. */
+static int pair_list_length (pair_p list);
+
+/* Compute the length of a list of pairs, starting from the first
+ one. */
+static int
+pair_list_length (pair_p list)
+{
+ int nbpair = 0;
+ pair_p l = NULL;
+ for (l = list; l; l = l->next)
+ nbpair++;
+ return nbpair;
+}
+
+/* Write a file location. Files relative to $(srcdir) are quite
+ frequent and are handled specially. This ensures that two gengtype
+ 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. */
+void
+state_writer::write_state_fileloc (struct fileloc *floc)
+{
+
+ if (floc != NULL && floc->line > 0)
+ {
+ const char *srcrelpath = NULL;
+ gcc_assert (floc->file != NULL);
+ /* Most of the files are inside $(srcdir) so it is worth to
+ handle them specially. */
+ srcrelpath = get_file_srcdir_relative_path (floc->file);
+ if (srcrelpath != NULL)
+ {
+ begin_s_expr ("srcfileloc");
+ write_state_a_string (srcrelpath);
+ }
+ else
+ {
+ begin_s_expr ("fileloc");
+ write_state_a_string (get_input_file_name (floc->file));
+ }
+ fprintf (state_file, " %d", floc->line);
+ end_s_expr ();
+ }
+ else
+ fprintf (state_file, "nil ");
+}
+
+/* Write a list of fields. */
+void
+state_writer::write_state_fields (pair_p fields)
+{
+ int nbfields = pair_list_length (fields);
+ int nbpairs = 0;
+ begin_s_expr ("fields");
+ fprintf (state_file, "%d ", nbfields);
+ nbpairs = write_state_pair_list (fields);
+ gcc_assert (nbpairs == nbfields);
+ end_s_expr ();
+}
+
+/* Write a null-terminated string in our lexical convention, very
+ similar to the convention of C. */
+void
+state_writer::write_state_a_string (const char *s)
+{
+ char c;
+
+ write_any_indent (1);
+
+ fputs (" \"", state_file);
+ for (; *s != 0; s++)
+ {
+ c = *s;
+ switch (c)
+ {
+ case '\a':
+ fputs ("\\a", state_file);
+ break;
+ case '\b':
+ fputs ("\\b", state_file);
+ break;
+ case '\t':
+ fputs ("\\t", state_file);
+ break;
+ case '\n':
+ fputs ("\\n", state_file);
+ break;
+ case '\v':
+ fputs ("\\v", state_file);
+ break;
+ case '\f':
+ fputs ("\\f", state_file);
+ break;
+ case '\r':
+ fputs ("\\r", state_file);
+ break;
+ case '\"':
+ fputs ("\\\"", state_file);
+ break;
+ case '\\':
+ fputs ("\\\\", state_file);
+ break;
+ default:
+ if (ISPRINT (c))
+ putc (c, state_file);
+ else
+ fprintf (state_file, "\\x%02x", (unsigned) c);
+ }
+ }
+ fputs ("\"", state_file);
+}
+
+/* Our option-s have three kinds, each with its writer. */
+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);
+ else
+ fprintf (state_file, " nil ");
+}
+
+void
+state_writer::write_state_type_option (options_p current)
+{
+ write_any_indent (0);
+ fprintf (state_file, "type ");
+ write_state_type (current->info.type);
+}
+
+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
+ {
+ 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
+ {
+ write_any_indent (1);
+ fprintf (state_file, " nil ");
+ }
+}
+
+void
+state_writer::write_state_option (options_p current)
+{
+ begin_s_expr ("option");
+
+ write_any_indent (0);
+ if (current->name != NULL)
+ fprintf (state_file, "%s ", current->name);
+ else
+ fprintf (state_file, "nil ");
+
+ switch (current->kind)
+ {
+ case OPTION_STRING:
+ write_state_string_option (current);
+ break;
+ case OPTION_TYPE:
+ write_state_type_option (current);
+ break;
+ case OPTION_NESTED:
+ write_state_nested_option (current);
+ break;
+ default:
+ fatal ("Option tag unknown");
+ }
+
+ /* Terminate the "option" s-expression. */
+ end_s_expr ();
+}
+
+
+
+/* Write a list of GTY options. */
+void
+state_writer::write_state_options (options_p opt)
+{
+ options_p current;
+
+ if (opt == NULL)
+ {
+ write_any_indent (0);
+ fprintf (state_file, "nil ");
+ return;
+ }
+
+ begin_s_expr ("options");
+ for (current = opt; current != NULL; current = current->next)
+ write_state_option (current);
+ end_s_expr ();
+}
+
+
+/* Write a bitmap representing a set of GCC front-end languages. */
+void
+state_writer::write_state_lang_bitmap (lang_bitmap bitmap)
+{
+ write_any_indent (0);
+ fprintf (state_file, "%d ", (int) bitmap);
+}
+
+/* Write version information. */
+void
+state_writer::write_state_version (const char *version)
+{
+ begin_s_expr ("version");
+ write_state_a_string (version);
+ end_s_expr ();
+}
+
+/* Write a scalar type. We have only two of these. */
+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)
+ fprintf (state_file, "scalar_char ");
+ else
+ fatal ("Unexpected type in write_state_scalar_type");
+
+ write_state_common_type_content (current);
+}
+
+/* Write the string type. There is only one such thing! */
+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);
+ }
+ else
+ 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. */
+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
+ {
+ write_any_indent (0);
+ fprintf (state_file, "nil");
+ }
+
+ write_state_fileloc (type_lineloc (current));
+ write_state_fields (current->u.s.fields);
+ write_state_options (current->u.s.opt);
+ write_state_lang_bitmap (current->u.s.bitmap);
+}
+
+
+/* Write a GTY struct type. */
+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. */
+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);
+}
+
+/* Write a lang_struct type. This is tricky and was painful to debug,
+ we deal with the next field specifically within their lang_struct
+ subfield, which points to a linked list of homonumous types.
+ Change this function with extreme care, see also
+ read_state_lang_struct_type. */
+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 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);
+ for (hty = current->u.s.lang_struct; hty != NULL; hty = hty->next)
+ {
+ nbhomontype++;
+ 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 (hty->u.s.lang_struct == current);
+ if (!homoname)
+ homoname = hty->u.s.tag;
+ gcc_assert (strcmp (homoname, hty->u.s.tag) == 0);
+ }
+ 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);
+ end_s_expr ();
+}
+
+/* Write a parametrized structure GTY type. */
+void
+state_writer::write_state_param_struct_type (type_p current)
+{
+ int i;
+
+ write_any_indent (0);
+ 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
+ {
+ write_any_indent (0);
+ fprintf (state_file, "nil ");
+ }
+ }
+ write_state_fileloc (&current->u.param_struct.line);
+}
+
+/* Write a pointer type. */
+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. */
+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
+ {
+ 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. */
+void
+state_writer::write_state_gc_used (enum gc_used_enum gus)
+{
+ write_any_indent (1);
+ switch (gus)
+ {
+ case GC_UNUSED:
+ fprintf (state_file, " gc_unused");
+ break;
+ case GC_USED:
+ fprintf (state_file, " gc_used");
+ break;
+ case GC_MAYBE_POINTED_TO:
+ fprintf (state_file, " gc_maybe_pointed_to");
+ break;
+ case GC_POINTED_TO:
+ fprintf (state_file, " gc_pointed_to");
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+
+/* Utility routine to write the common content of all types. Notice
+ that the next field is *not* written on purpose. */
+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
+ respect. See function write_state_lang_struct_type for more. */
+ write_state_type (current->pointer_to);
+ write_state_gc_used (current->gc_used);
+}
+
+
+/* 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. */
+void
+state_writer::write_state_type (type_p current)
+{
+ write_any_indent (0);
+ if (current == NULL)
+ {
+ fprintf (state_file, "nil ");
+ return;
+ }
+
+ begin_s_expr ("type");
+
+ if (current->state_number > 0)
+ {
+ write_any_indent (0);
+ fprintf (state_file, "already_seen %d", current->state_number);
+ }
+ else
+ {
+ 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 = 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;
+ case TYPE_POINTER:
+ write_state_pointer_type (current);
+ break;
+ case TYPE_ARRAY:
+ write_state_array_type (current);
+ break;
+ 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;
+ }
+ }
+
+ /* Terminate the "type" s-expression. */
+ end_s_expr ();
+}
+
+
+/* Write a pair. */
+void
+state_writer::write_state_pair (pair_p current)
+{
+ if (current == NULL)
+ {
+ write_any_indent (0);
+ fprintf (state_file, "nil)");
+ return;
+ }
+
+ begin_s_expr ("pair");
+
+ if (current->name != NULL)
+ write_state_a_string (current->name);
+ else
+ write_state_a_string ("nil");
+
+ write_state_type (current->type);
+ write_state_fileloc (&(current->line));
+ write_state_options (current->opt);
+
+ /* Terminate the "pair" s-expression. */
+ end_s_expr ();
+}
+
+/* Write a pair list and return the number of pairs written. */
+int
+state_writer::write_state_pair_list (pair_p list)
+{
+ int nbpair = 0;
+ pair_p current;
+
+ for (current = list; current != NULL; current = current->next)
+ {
+ write_state_pair (current);
+ nbpair++;
+ }
+ return nbpair;
+
+}
+
+/* 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. */
+
+/* Write our typedefs. */
+void
+state_writer::write_state_typedefs (void)
+{
+ int nbtypedefs = pair_list_length (typedefs);
+ int nbpairs = 0;
+ begin_s_expr ("typedefs");
+ fprintf (state_file, "%d", nbtypedefs);
+ nbpairs = write_state_pair_list (typedefs);
+ gcc_assert (nbpairs == nbtypedefs);
+ end_s_expr ();
+ if (verbosity_level >= 2)
+ printf ("%s wrote %d typedefs\n", progname, nbtypedefs);
+}
+
+/* Write our structures. */
+void
+state_writer::write_state_structures (void)
+{
+ int nbstruct = 0;
+ type_p current;
+
+ for (current = structures; current != NULL; current = current->next)
+ nbstruct++;
+
+ begin_s_expr ("structures");
+ fprintf (state_file, "%d", nbstruct);
+
+ for (current = structures; current != NULL; current = current->next)
+ {
+ write_new_line ();
+ write_state_type (current);
+ }
+
+ /* 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. */
+void
+state_writer::write_state_param_structs (void)
+{
+ int nbparamstruct = 0;
+ type_p current;
+
+ for (current = param_structs; current != NULL; current = current->next)
+ nbparamstruct++;
+
+ begin_s_expr ("param_structs");
+ fprintf (state_file, "%d", nbparamstruct);
+
+ for (current = param_structs; current != NULL; current = current->next)
+ write_state_type (current);
+
+ end_s_expr ();
+}
+
+/* Write our variables. */
+void
+state_writer::write_state_variables (void)
+{
+ int nbvars = pair_list_length (variables);
+ int nbpairs = 0;
+ begin_s_expr ("variables");
+ fprintf (state_file, "%d", nbvars);
+ nbpairs = write_state_pair_list (variables);
+ gcc_assert (nbpairs == nbvars);
+ 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. */
+void
+state_writer::write_state_srcdir (void)
+{
+ begin_s_expr ("srcdir");
+ write_state_a_string (srcdir);
+ end_s_expr ();
+}
+
+/* Count and write the list of our files. */
+void
+state_writer::write_state_files_list (void)
+{
+ int i = 0;
+ /* Write the list of files with their lang_bitmap. */
+ 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;
+ const input_file *curfil = gt_files[i];
+ /* Most of the files are inside $(srcdir) so it is worth to
+ handle them specially. */
+ cursrcrelpath = get_file_srcdir_relative_path (curfil);
+ if (cursrcrelpath)
+ {
+ begin_s_expr ("srcfile");
+ fprintf (state_file, "%d ", get_lang_bitmap (curfil));
+ write_state_a_string (cursrcrelpath);
+ }
+ else
+ {
+ begin_s_expr ("file");
+ fprintf (state_file, "%d ", get_lang_bitmap (curfil));
+ write_state_a_string (get_input_file_name (curfil));
+ }
+ /* Terminate the inner s-expression (either "srcfile" or "file"). */
+ end_s_expr ();
+ }
+ /* Terminate the "fileslist" s-expression. */
+ end_s_expr ();
+}
+
+/* Write the list of GCC front-end languages. */
+void
+state_writer::write_state_languages (void)
+{
+ int i = 0;
+ 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
+ underscores or digits in them. In particular, C++ is not a
+ valid language name, but cp is valid. */
+ fprintf (state_file, " %s", lang_dir_names[i]);
+ }
+ end_s_expr ();
+}
+
+/* Write the trailer. */
+static void
+write_state_trailer (void)
+{
+ /* This test should probably catch IO errors like disk full... */
+ if (fputs ("\n(!endfile)\n", state_file) == EOF)
+ fatal ("failed to write state trailer [%s]", xstrerror (errno));
+}
+
+/* The write_state routine is the only writing routine called by main
+ in gengtype.c. To avoid messing the state if gengtype is
+ interrupted or aborted, we write a temporary file and rename it
+ after having written it in totality. */
+void
+write_state (const char *state_path)
+{
+ long statelen = 0;
+ time_t now = 0;
+ char *temp_state_path = NULL;
+ char tempsuffix[40];
+ time (&now);
+
+ /* We write a unique temporary file which is renamed when complete
+ * only. So even if gengtype is interrupted, the written state file
+ * won't be partially written, since the temporary file is not yet
+ * renamed in that case. */
+ memset (tempsuffix, 0, sizeof (tempsuffix));
+ snprintf (tempsuffix, sizeof (tempsuffix) - 1, "-%ld-%d.tmp", (long) now,
+ (int) getpid ());
+ temp_state_path = concat (state_path, tempsuffix, NULL);
+ state_file = fopen (temp_state_path, "w");
+ if (state_file == NULL)
+ fatal ("Failed to open file %s for writing state: %s",
+ temp_state_path, xstrerror (errno));
+ if (verbosity_level >= 3)
+ printf ("%s writing state file %s temporarily in %s\n",
+ progname, state_path, temp_state_path);
+ /* This is the first line of the state. Perhaps the file utility
+ could know about that, so don't change it often. */
+ fprintf (state_file, ";;;;@@@@ GCC gengtype state\n");
+ /* Output a few comments for humans. */
+ fprintf (state_file,
+ ";;; DON'T EDIT THIS FILE, since generated by GCC's gengtype\n");
+ fprintf (state_file,
+ ";;; The format of this file is tied to a particular version of GCC.\n");
+ fprintf (state_file,
+ ";;; Don't parse this file wihout knowing GCC gengtype internals.\n");
+ fprintf (state_file,
+ ";;; This file should be parsed by the same %s which wrote it.\n",
+ progname);
+
+ state_writer sw;
+
+ /* The first non-comment significant line gives the version string. */
+ 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_param_structs ();
+ sw.write_state_variables ();
+ write_state_trailer ();
+ statelen = ftell (state_file);
+ if (ferror (state_file))
+ fatal ("output error when writing state file %s [%s]",
+ temp_state_path, xstrerror (errno));
+ if (fclose (state_file))
+ fatal ("failed to close state file %s [%s]",
+ temp_state_path, xstrerror (errno));
+ if (rename (temp_state_path, state_path))
+ fatal ("failed to rename %s to state file %s [%s]", temp_state_path,
+ state_path, xstrerror (errno));
+ free (temp_state_path);
+
+ if (verbosity_level >= 1)
+ printf ("%s wrote state file %s of %ld bytes with %d GTY-ed types\n",
+ progname, state_path, statelen, sw.m_state_written_type_count);
+
+}
+
+/** End of writing routines! The corresponding reading routines follow. **/
+
+
+
+/* Forward declarations, since some read_state_* functions are
+ recursive! */
+static void read_state_fileloc (struct fileloc *line);
+static void read_state_options (options_p *opt);
+static void read_state_type (type_p *current);
+static void read_state_pair (pair_p *pair);
+/* Return the number of pairs actually read. */
+static int read_state_pair_list (pair_p *list);
+static void read_state_fields (pair_p *fields);
+static void read_state_common_type_content (type_p current);
+
+
+
+
+/* Record into the state_seen_types hash-table a type which we are
+ reading, to enable recursive or circular references to it. */
+static void
+record_type (type_p type)
+{
+ PTR *slot;
+
+ slot = htab_find_slot (state_seen_types, type, INSERT);
+ gcc_assert (slot);
+
+ *slot = type;
+}
+
+/* Read an already seen type. */
+static void
+read_state_already_seen_type (type_p *type)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+
+ if (state_token_kind (t0) == STOK_INTEGER)
+ {
+ PTR *slot = NULL;
+ struct type loctype = { TYPE_SCALAR, 0, 0, 0, GC_UNUSED, {0} };
+
+ loctype.state_number = t0->stok_un.stok_num;
+ slot = htab_find_slot (state_seen_types, &loctype, NO_INSERT);
+ if (slot == NULL)
+ {
+ fatal_reading_state (t0, "Unknown type");
+ }
+
+ next_state_tokens (1);
+ *type = (type_p) *slot;
+ }
+ else
+ {
+ fatal_reading_state (t0, "Bad seen type");
+ }
+}
+
+
+/* Read the scalar_nonchar type. */
+static void
+read_state_scalar_nonchar_type (type_p *type)
+{
+ *type = &scalar_nonchar;
+ read_state_common_type_content (*type);
+}
+
+
+/* Read the scalar_char type. */
+static void
+read_state_scalar_char_type (type_p *type)
+{
+ *type = &scalar_char;
+ read_state_common_type_content (*type);
+}
+
+/* Read the string_type. */
+static void
+read_state_string_type (type_p *type)
+{
+ *type = &string_type;
+ read_state_common_type_content (*type);
+}
+
+
+/* Read a lang_bitmap representing a set of GCC front-end languages. */
+static void
+read_state_lang_bitmap (lang_bitmap *bitmap)
+{
+ struct state_token_st *t;
+
+ t = peek_state_token (0);
+ if (state_token_kind (t) == STOK_INTEGER)
+ {
+ *bitmap = t->stok_un.stok_num;
+ next_state_tokens (1);
+ }
+ else
+ {
+ fatal_reading_state (t, "Bad syntax for bitmap");
+ }
+}
+
+
+/* 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)
+{
+ struct state_token_st *t0;
+
+ type->kind = TYPE_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));
+ 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
+ {
+ fatal_reading_state (t0, "Bad tag in struct type");
+ }
+}
+
+
+/* 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)
+{
+ struct state_token_st *t0;
+
+ type->kind = TYPE_UNION;
+ 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 union type @%p #%d",
+ (void *) type, type->state_number);
+ }
+ else
+ {
+ type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+ DBGPRINTF ("read union 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));
+ read_state_options (&(type->u.s.opt));
+ read_state_lang_bitmap (&(type->u.s.bitmap));
+ read_state_type (&(type->u.s.lang_struct));
+ }
+ else
+ fatal_reading_state (t0, "Bad tag in union type");
+}
+
+
+/* Read a GTY-ed pointer type. */
+static void
+read_state_pointer_type (type_p type)
+{
+ type->kind = TYPE_POINTER;
+ read_state_common_type_content (type);
+ DBGPRINTF ("read pointer type @%p #%d", (void *) type, type->state_number);
+ read_state_type (&(type->u.p));
+}
+
+
+/* Read a GTY-ed array type. */
+static void
+read_state_array_type (type_p type)
+{
+ struct state_token_st *t0;
+
+ type->kind = TYPE_ARRAY;
+ read_state_common_type_content (type);
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_STRING)
+ {
+ type->u.a.len = xstrdup (t0->stok_un.stok_string);
+ DBGPRINTF ("read array type @%p #%d length '%s'",
+ (void *) type, type->state_number, type->u.a.len);
+ next_state_tokens (1);
+ }
+
+ else if (state_token_is_name (t0, "nil"))
+ {
+ type->u.a.len = NULL;
+ DBGPRINTF ("read array type @%p #%d without length",
+ (void *) type, type->state_number);
+ next_state_tokens (1);
+ }
+
+ else
+ fatal_reading_state (t0, "Bad array name type");
+ read_state_type (&(type->u.a.p));
+}
+
+
+
+/* Read a lang_struct type for GTY-ed struct-s which depends upon GCC
+ front-end languages. This is a tricky function and it was painful
+ to debug. Change it with extreme care. See also
+ write_state_lang_struct_type. */
+static void
+read_state_lang_struct_type (type_p type)
+{
+ struct state_token_st *t0 = NULL;
+ struct state_token_st *t1 = NULL;
+ struct state_token_st *t2 = NULL;
+
+ type->kind = TYPE_LANG_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"))
+ {
+ DBGPRINTF ("read anonymous lang_struct type @%p #%d",
+ (void *) type, type->state_number);
+ type->u.s.tag = NULL;
+ }
+ else
+ {
+ type->u.s.tag = xstrdup (t0->stok_un.stok_string);
+ DBGPRINTF ("read lang_struct type @%p #%d '%s'",
+ (void *) type, type->state_number, type->u.s.tag);
+ }
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Bad tag in lang struct type");
+ read_state_fileloc (&(type->u.s.line));
+ read_state_fields (&(type->u.s.fields));
+ read_state_options (&(type->u.s.opt));
+ read_state_lang_bitmap (&(type->u.s.bitmap));
+ /* Within lang_struct-ures, the lang_struct field is a linked list
+ of homonymous types! */
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ t2 = peek_state_token (2);
+ /* Parse (!homotypes <number-types> <type-1> .... <type-n>) */
+ if (state_token_kind (t0) == STOK_LEFTPAR
+ && state_token_is_name (t1, "!homotypes")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ type_p *prevty = &type->u.s.lang_struct;
+ int nbhomotype = t2->stok_un.stok_num;
+ int i = 0;
+ t0 = t1 = t2 = NULL;
+ next_state_tokens (3);
+ for (i = 0; i < nbhomotype; i++)
+ {
+ read_state_type (prevty);
+ t0 = peek_state_token (0);
+ if (*prevty)
+ prevty = &(*prevty)->next;
+ else
+ fatal_reading_state (t0,
+ "expecting type in homotype list for lang_struct");
+ };
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0,
+ "expecting ) in homotype list for lang_struct");
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "expecting !homotypes for lang_struct");
+}
+
+
+/* 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)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ if (state_token_is_name (t0, "gc_unused"))
+ *pgus = GC_UNUSED;
+ else if (state_token_is_name (t0, "gc_used"))
+ *pgus = GC_USED;
+ else if (state_token_is_name (t0, "gc_maybe_pointed_to"))
+ *pgus = GC_MAYBE_POINTED_TO;
+ else if (state_token_is_name (t0, "gc_pointed_to"))
+ *pgus = GC_POINTED_TO;
+ else
+ fatal_reading_state (t0, "invalid gc_used information");
+ next_state_tokens (1);
+}
+
+
+/* Utility function to read the common content of types. */
+static void
+read_state_common_type_content (type_p current)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+
+ if (state_token_kind (t0) == STOK_INTEGER)
+ {
+ current->state_number = t0->stok_un.stok_num;
+ next_state_tokens (1);
+ record_type (current);
+ }
+ else
+ fatal_reading_state_printf (t0,
+ "Expected integer for state_number line %d",
+ state_line);
+ /* We don't read the next field of the type. */
+ read_state_type (&current->pointer_to);
+ read_state_gc_used (&current->gc_used);
+}
+
+
+/* Read a GTY-ed type. */
+void
+read_state_type (type_p *current)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!type"))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ if (state_token_is_name (t0, "already_seen"))
+ {
+ next_state_tokens (1);
+ read_state_already_seen_type (current);
+ }
+ else
+ {
+ t0 = peek_state_token (0);
+
+ if (state_token_is_name (t0, "scalar_nonchar"))
+ {
+ next_state_tokens (1);
+ read_state_scalar_nonchar_type (current);
+ }
+ else if (state_token_is_name (t0, "scalar_char"))
+ {
+ next_state_tokens (1);
+ read_state_scalar_char_type (current);
+ }
+ else if (state_token_is_name (t0, "string"))
+ {
+ 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);
+ next_state_tokens (1);
+ read_state_struct_type (*current);
+ }
+ else if (state_token_is_name (t0, "union"))
+ {
+ *current = XCNEW (struct type);
+ next_state_tokens (1);
+ read_state_union_type (*current);
+ }
+ else if (state_token_is_name (t0, "lang_struct"))
+ {
+ *current = XCNEW (struct type);
+ 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);
+ next_state_tokens (1);
+ read_state_pointer_type (*current);
+ }
+ else if (state_token_is_name (t0, "array"))
+ {
+ *current = XCNEW (struct type);
+ 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");
+ }
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0, "missing ) in type");
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ next_state_tokens (1);
+ *current = NULL;
+ }
+ else
+ fatal_reading_state (t0, "bad type syntax");
+}
+
+
+/* Read a file location. Files within the source directory are dealt
+ with specifically. */
+void
+read_state_fileloc (struct fileloc *floc)
+{
+ bool issrcfile = false;
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+
+ gcc_assert (floc != NULL);
+ gcc_assert (srcdir != NULL);
+
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ (state_token_is_name (t1, "!fileloc")
+ || (issrcfile = state_token_is_name (t1, "!srcfileloc"))))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_STRING &&
+ state_token_kind (t1) == STOK_INTEGER)
+ {
+ char *path = t0->stok_un.stok_string;
+ if (issrcfile)
+ {
+ static const char dirsepstr[2] = { DIR_SEPARATOR, (char) 0 };
+ char *fullpath = concat (srcdir, dirsepstr, path, NULL);
+ floc->file = input_file_by_name (fullpath);
+ free (fullpath);
+ }
+ else
+ floc->file = input_file_by_name (path);
+ floc->line = t1->stok_un.stok_num;
+ next_state_tokens (2);
+ }
+ else
+ fatal_reading_state (t0,
+ "Bad fileloc syntax, expected path string and line");
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0, "Bad fileloc syntax, expected )");
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ next_state_tokens (1);
+ floc->file = NULL;
+ floc->line = 0;
+ }
+ else
+ fatal_reading_state (t0, "Bad fileloc syntax");
+}
+
+
+/* Read the fields of a GTY-ed type. */
+void
+read_state_fields (pair_p *fields)
+{
+ pair_p tmp = NULL;
+ 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, "!fields")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ int nbfields = t2->stok_un.stok_num;
+ int nbpairs = 0;
+ next_state_tokens (3);
+ nbpairs = read_state_pair_list (&tmp);
+ t0 = peek_state_token (0);
+ if (nbpairs != nbfields)
+ fatal_reading_state_printf
+ (t0,
+ "Mismatched fields number, expected %d got %d", nbpairs, nbfields);
+ if (state_token_kind (t0) == STOK_RIGHTPAR)
+ next_state_tokens (1);
+ else
+ fatal_reading_state (t0, "Bad fields expecting )");
+ }
+
+ *fields = tmp;
+}
+
+
+/* Read a string option. */
+static void
+read_state_string_option (options_p opt)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ opt->kind = OPTION_STRING;
+ if (state_token_kind (t0) == STOK_STRING)
+ {
+ opt->info.string = xstrdup (t0->stok_un.stok_string);
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ opt->info.string = NULL;
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Missing name in string option");
+}
+
+
+/* Read a type option. */
+static void
+read_state_type_option (options_p opt)
+{
+ opt->kind = OPTION_TYPE;
+ read_state_type (&(opt->info.type));
+}
+
+
+/* Read a nested option. */
+static void
+read_state_nested_option (options_p opt)
+{
+ struct state_token_st *t0;
+
+ opt->info.nested = XCNEW (struct nested_ptr_data);
+ opt->kind = OPTION_NESTED;
+ read_state_type (&(opt->info.nested->type));
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_STRING)
+ {
+ opt->info.nested->convert_from = xstrdup (t0->stok_un.stok_string);
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ opt->info.nested->convert_from = NULL;
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Bad nested convert_from option");
+
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_STRING)
+ {
+ opt->info.nested->convert_to = xstrdup (t0->stok_un.stok_string);
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ opt->info.nested->convert_to = NULL;
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Bad nested convert_from option");
+}
+
+
+/* Read an GTY option. */
+static void
+read_state_option (options_p *opt)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!option"))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_NAME)
+ {
+ *opt = XCNEW (struct options);
+ if (state_token_is_name (t0, "nil"))
+ (*opt)->name = NULL;
+ else
+ (*opt)->name = t0->stok_un.stok_ident->stid_name;
+ next_state_tokens (1);
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_NAME)
+ {
+ if (state_token_is_name (t0, "string"))
+ {
+ next_state_tokens (1);
+ read_state_string_option (*opt);
+ }
+ else if (state_token_is_name (t0, "type"))
+ {
+ next_state_tokens (1);
+ read_state_type_option (*opt);
+ }
+ else if (state_token_is_name (t0, "nested"))
+ {
+ next_state_tokens (1);
+ read_state_nested_option (*opt);
+ }
+ else
+ fatal_reading_state (t0, "Bad option type");
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0, "Bad syntax in option, expecting )");
+
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Missing option type");
+ }
+ else
+ fatal_reading_state (t0, "Bad name for option");
+ }
+ else
+ fatal_reading_state (t0, "Bad option, waiting for )");
+}
+
+/* Read a list of options. */
+void
+read_state_options (options_p *opt)
+{
+ options_p head = NULL;
+ options_p previous = NULL;
+ options_p current_option = NULL;
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!options"))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ while (state_token_kind (t0) != STOK_RIGHTPAR)
+ {
+ read_state_option (&current_option);
+ if (head == NULL)
+ {
+ head = current_option;
+ previous = head;
+ }
+ else
+ {
+ previous->next = current_option;
+ previous = current_option;
+ }
+ t0 = peek_state_token (0);
+ }
+ next_state_tokens (1);
+ }
+ else if (state_token_is_name (t0, "nil"))
+ {
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Bad options syntax");
+
+ *opt = head;
+}
+
+
+/* Read a version, and check against the version of the gengtype. */
+static void
+read_state_version (const char *version_string)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!version"))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_STRING &&
+ state_token_kind (t1) == STOK_RIGHTPAR)
+ {
+ /* Check that the read version string is the same as current
+ version. */
+ if (strcmp (version_string, t0->stok_un.stok_string))
+ fatal_reading_state_printf (t0,
+ "version string mismatch; expecting %s but got %s",
+ version_string,
+ t0->stok_un.stok_string);
+ next_state_tokens (2);
+ }
+ else
+ fatal_reading_state (t0, "Missing version or right parenthesis");
+ }
+ else
+ fatal_reading_state (t0, "Bad version syntax");
+}
+
+
+/* Read a pair. */
+void
+read_state_pair (pair_p *current)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!pair"))
+ {
+ *current = XCNEW (struct pair);
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_STRING)
+ {
+ if (strcmp (t0->stok_un.stok_string, "nil") == 0)
+ {
+ (*current)->name = NULL;
+ }
+ else
+ {
+ (*current)->name = xstrdup (t0->stok_un.stok_string);
+ }
+ next_state_tokens (1);
+ read_state_type (&((*current)->type));
+ read_state_fileloc (&((*current)->line));
+ read_state_options (&((*current)->opt));;
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) == STOK_RIGHTPAR)
+ {
+ next_state_tokens (1);
+ }
+ else
+ {
+ fatal_reading_state (t0, "Bad syntax for pair, )");
+ }
+ }
+ else
+ {
+ fatal_reading_state (t0, "Bad name for pair");
+ }
+ }
+ else if (state_token_kind (t0) == STOK_NAME &&
+ state_token_is_name (t0, "nil"))
+ {
+ next_state_tokens (1);
+ *current = NULL;
+ }
+ else
+ fatal_reading_state_printf (t0, "Bad syntax for pair, (!pair %d",
+ state_token->stok_kind);
+}
+
+
+/* Return the number of pairs actually read. */
+int
+read_state_pair_list (pair_p *list)
+{
+ int nbpair = 0;
+ pair_p head = NULL;
+ pair_p previous = NULL;
+ pair_p tmp = NULL;
+ struct state_token_st *t0 = peek_state_token (0);
+ while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
+ {
+ read_state_pair (&tmp);
+ if (head == NULL)
+ {
+ head = tmp;
+ previous = head;
+ }
+ else
+ {
+ previous->next = tmp;
+ previous = tmp;
+ }
+ t0 = peek_state_token (0);
+ nbpair++;
+ }
+
+ /* don't consume the ); the caller will eat it. */
+ *list = head;
+ return nbpair;
+}
+
+/* Read the typedefs. */
+static void
+read_state_typedefs (pair_p *typedefs)
+{
+ int nbtypedefs = 0;
+ pair_p list = NULL;
+ 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, "!typedefs")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ int nbpairs = 0;
+ nbtypedefs = t2->stok_un.stok_num;
+ next_state_tokens (3);
+ nbpairs = read_state_pair_list (&list);
+ t0 = peek_state_token (0);
+ if (nbpairs != nbtypedefs)
+ fatal_reading_state_printf
+ (t0,
+ "invalid number of typedefs, expected %d but got %d",
+ nbtypedefs, nbpairs);
+ if (state_token_kind (t0) == STOK_RIGHTPAR)
+ next_state_tokens (1);
+ else
+ fatal_reading_state (t0, "Bad typedefs syntax )");
+ }
+ else
+ fatal_reading_state (t0, "Bad typedefs syntax (!typedefs");
+
+ if (verbosity_level >= 2)
+ printf ("%s read %d typedefs from state\n", progname, nbtypedefs);
+ *typedefs = list;
+}
+
+
+/* Read the structures. */
+static void
+read_state_structures (type_p *structures)
+{
+ type_p head = NULL;
+ type_p previous = NULL;
+ type_p tmp;
+ int nbstruct = 0, countstruct = 0;
+ 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, "!structures")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ nbstruct = t2->stok_un.stok_num;
+ next_state_tokens (3);
+ t0 = peek_state_token (0);
+ while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
+ {
+ tmp = NULL;
+ read_state_type (&tmp);
+ countstruct++;
+ if (head == NULL)
+ {
+ head = tmp;
+ previous = head;
+ }
+ else
+ {
+ previous->next = tmp;
+ previous = tmp;
+ }
+ t0 = peek_state_token (0);
+ }
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "Bad structures syntax");
+ if (countstruct != nbstruct)
+ fatal_reading_state_printf (NULL_STATE_TOKEN,
+ "expected %d structures but got %d",
+ nbstruct, countstruct);
+ if (verbosity_level >= 2)
+ printf ("%s read %d structures from state\n", progname, nbstruct);
+ *structures = head;
+}
+
+
+/* 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 = NULL;
+ 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)
+{
+ pair_p list = NULL;
+ int nbvars = 0;
+ 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, "!variables")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ int nbpairs = 0;
+ nbvars = t2->stok_un.stok_num;
+ next_state_tokens (3);
+ nbpairs = read_state_pair_list (&list);
+ t0 = peek_state_token (0);
+ if (nbpairs != nbvars)
+ fatal_reading_state_printf
+ (t0, "Invalid number of variables, expected %d but got %d",
+ nbvars, nbpairs);
+ if (state_token_kind (t0) == STOK_RIGHTPAR)
+ next_state_tokens (1);
+ else
+ fatal_reading_state (t0, "Waiting for ) in variables");
+ }
+ else
+ fatal_reading_state (t0, "Bad variables syntax");
+ *variables = list;
+ if (verbosity_level >= 2)
+ printf ("%s read %d variables from state\n", progname, nbvars);
+}
+
+
+/* Read the source directory. */
+static void
+read_state_srcdir (void)
+{
+ struct state_token_st *t0 = peek_state_token (0);
+ struct state_token_st *t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_LEFTPAR &&
+ state_token_is_name (t1, "!srcdir"))
+ {
+ next_state_tokens (2);
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_STRING &&
+ state_token_kind (t1) == STOK_RIGHTPAR)
+ {
+ srcdir = xstrdup (t0->stok_un.stok_string);
+ srcdir_len = strlen (srcdir);
+ next_state_tokens (2);
+ return;
+ }
+ }
+
+ fatal_reading_state (t0, "Bad srcdir in state_file");
+}
+
+
+/* Read the sequence of GCC front-end languages. */
+static void
+read_state_languages (void)
+{
+ 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, "!languages")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ int i = 0;
+ num_lang_dirs = t2->stok_un.stok_num;
+ lang_dir_names = XCNEWVEC (const char *, num_lang_dirs);
+ next_state_tokens (3);
+ t0 = t1 = t2 = NULL;
+ for (i = 0; i < (int) num_lang_dirs; i++)
+ {
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_NAME)
+ fatal_reading_state (t0, "expecting language name in state file");
+ lang_dir_names[i] = t0->stok_un.stok_ident->stid_name;
+ next_state_tokens (1);
+ }
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0, "missing ) in languages list of state file");
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "expecting languages list in state file");
+
+}
+
+/* Read the sequence of files. */
+static void
+read_state_files_list (void)
+{
+ 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, "!fileslist")
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ int i = 0;
+ num_gt_files = t2->stok_un.stok_num;
+ next_state_tokens (3);
+ t0 = t1 = t2 = NULL;
+ gt_files = XCNEWVEC (const input_file *, num_gt_files);
+ for (i = 0; i < (int) num_gt_files; i++)
+ {
+ bool issrcfile = FALSE;
+ t0 = t1 = t2 = NULL;
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ t2 = peek_state_token (2);
+ if (state_token_kind (t0) == STOK_LEFTPAR
+ && (state_token_is_name (t1, "!file")
+ || (issrcfile = state_token_is_name (t1, "!srcfile")))
+ && state_token_kind (t2) == STOK_INTEGER)
+ {
+ lang_bitmap bmap = t2->stok_un.stok_num;
+ next_state_tokens (3);
+ t0 = t1 = t2 = NULL;
+ t0 = peek_state_token (0);
+ t1 = peek_state_token (1);
+ if (state_token_kind (t0) == STOK_STRING
+ && state_token_kind (t1) == STOK_RIGHTPAR)
+ {
+ const char *fnam = t0->stok_un.stok_string;
+ /* Allocate & fill a gt_file entry with space for the lang_bitmap before! */
+ input_file *curgt = NULL;
+ if (issrcfile)
+ {
+ static const char dirsepstr[2] =
+ { DIR_SEPARATOR, (char) 0 };
+ char *fullpath = concat (srcdir, dirsepstr, fnam, NULL);
+ curgt = input_file_by_name (fullpath);
+ free (fullpath);
+ }
+ else
+ curgt = input_file_by_name (fnam);
+ set_lang_bitmap (curgt, bmap);
+ gt_files[i] = curgt;
+ next_state_tokens (2);
+ }
+ else
+ fatal_reading_state (t0,
+ "bad file in !fileslist of state file");
+ }
+ else
+ fatal_reading_state (t0,
+ "expecting file in !fileslist of state file");
+ };
+ t0 = peek_state_token (0);
+ if (state_token_kind (t0) != STOK_RIGHTPAR)
+ fatal_reading_state (t0, "missing ) for !fileslist in state file");
+ next_state_tokens (1);
+ }
+ else
+ fatal_reading_state (t0, "missing !fileslist in state file");
+}
+
+
+/* Read the trailer. */
+static void
+read_state_trailer (void)
+{
+ 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, "!endfile")
+ && state_token_kind (t2) == STOK_RIGHTPAR)
+ next_state_tokens (3);
+ else
+ fatal_reading_state (t0, "missing !endfile in state file");
+}
+
+
+/* Utility functions for the state_seen_types hash table. */
+static unsigned
+hash_type_number (const void *ty)
+{
+ const struct type *type = (const struct type *) ty;
+
+ return type->state_number;
+}
+
+static int
+equals_type_number (const void *ty1, const void *ty2)
+{
+ const struct type *type1 = (const struct type *) ty1;
+ const struct type *type2 = (const struct type *) ty2;
+
+ 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
+read_state (const char *path)
+{
+ state_file = fopen (path, "r");
+ if (state_file == NULL)
+ fatal ("Failed to open state file %s for reading [%s]", path,
+ xstrerror (errno));
+ state_path = path;
+ state_line = 1;
+
+ if (verbosity_level >= 1)
+ {
+ printf ("%s reading state file %s;", progname, state_path);
+ if (verbosity_level >= 2)
+ putchar ('\n');
+ fflush (stdout);
+ }
+
+ state_seen_types =
+ htab_create (2017, hash_type_number, equals_type_number, NULL);
+ state_ident_tab =
+ htab_create (4027, htab_hash_string, string_eq, NULL);
+ read_state_version (version_string);
+ read_state_srcdir ();
+ read_state_languages ();
+ read_state_files_list ();
+ read_state_structures (&structures);
+ if (ferror (state_file))
+ fatal_reading_state_printf
+ (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 ();
+
+ if (verbosity_level >= 1)
+ {
+ printf ("%s read %ld bytes.\n", progname, ftell (state_file));
+ fflush (stdout);
+ };
+
+ if (fclose (state_file))
+ fatal ("failed to close read state file %s [%s]",
+ path, xstrerror (errno));
+ state_file = NULL;
+ state_path = NULL;
+}
+
+/* End of file gengtype-state.c. */