From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- gcc/gengtype-state.c | 2439 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2439 insertions(+) create mode 100644 gcc/gengtype-state.c (limited to 'gcc/gengtype-state.c') diff --git a/gcc/gengtype-state.c b/gcc/gengtype-state.c new file mode 100644 index 000000000..07c880258 --- /dev/null +++ b/gcc/gengtype-state.c @@ -0,0 +1,2439 @@ +/* Gengtype persistent state serialization & de-serialization. + Useful for gengtype in plugin mode. + + Copyright (C) 2010 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 + . + + Contributed by Jeremie Salvucci + and Basile Starynkevitch +*/ + +#include "bconfig.h" +#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: + 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, thru 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 */ + + +/* Counter of written types. */ +static int 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, ids); + 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, cstr); + + 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); + +/* 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 +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. */ +static void +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) + { + fprintf (state_file, "\n(!srcfileloc "); + write_state_a_string (srcrelpath); + } + else + { + fprintf (state_file, "\n(!fileloc "); + write_state_a_string (get_input_file_name (floc->file)); + } + fprintf (state_file, " %d", floc->line); + fprintf (state_file, ")\n"); + } + else + fprintf (state_file, "nil "); +} + +/* Write a list of fields. */ +static void +write_state_fields (pair_p fields) +{ + int nbfields = pair_list_length (fields); + int nbpairs = 0; + fprintf (state_file, "\n(!fields %d ", nbfields); + nbpairs = write_state_pair_list (fields); + gcc_assert (nbpairs == nbfields); + fprintf (state_file, ")\n"); +} + +/* 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) +{ + char c; + + 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. */ +static void +write_state_string_option (options_p current) +{ + fprintf (state_file, "string "); + if (current->info.string != NULL) + write_state_a_string (current->info.string); + else + fprintf (state_file, " nil "); +} + +static void +write_state_type_option (options_p current) +{ + fprintf (state_file, "type "); + write_state_type (current->info.type); +} + +static void +write_state_nested_option (options_p current) +{ + 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 "); + + if (current->info.nested->convert_to != NULL) + write_state_a_string (current->info.nested->convert_to); + else + fprintf (state_file, " nil "); +} + +static void +write_state_option (options_p current) +{ + fprintf (state_file, "\n(!option "); + + 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"); + } + + fprintf (state_file, ")\n"); +} + + + +/* Write a list of GTY options. */ +static void +write_state_options (options_p opt) +{ + options_p current; + + if (opt == NULL) + { + fprintf (state_file, "nil "); + return; + } + + fprintf (state_file, "\n(!options "); + for (current = opt; current != NULL; current = current->next) + write_state_option (current); + fprintf (state_file, ")\n"); +} + + +/* Write a bitmap representing a set of GCC front-end languages. */ +static void +write_state_lang_bitmap (lang_bitmap bitmap) +{ + fprintf (state_file, "%d ", (int) bitmap); +} + +/* Write version information. */ +static void +write_state_version (const char *version) +{ + fprintf (state_file, "\n(!version "); + write_state_a_string (version); + fprintf (state_file, ")\n"); +} + +/* 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) +{ + 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! */ +static void +write_state_string_type (type_p current) +{ + if (current == &string_type) + { + fprintf (state_file, "string "); + write_state_common_type_content (current); + } + else + fatal ("Unexpected type in write_state_string_type"); +} + + +/* Common code to write structure like types. */ +static void +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); + 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_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. */ +static void +write_state_struct_type (type_p current) +{ + write_state_struct_union_type (current, "struct"); + write_state_type (current->u.s.lang_struct); +} + +/* write a GTY union type. */ +static void +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. */ +static void +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 + 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); + } + fprintf (state_file, "(!homotypes %d\n", 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 (¤t->u.param_struct.line); +} + +/* Write a pointer type. */ +static void +write_state_pointer_type (type_p current) +{ + 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) +{ + 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"); + + 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) +{ + 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. */ +static void +write_state_common_type_content (type_p current) +{ + 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. */ +static void +write_state_type (type_p current) +{ + if (current == NULL) + { + fprintf (state_file, "nil "); + return; + } + + fprintf (state_file, "\n(!type "); + + if (current->state_number > 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, + (void *) current, current->state_number); + current->state_number = state_written_type_count; + switch (current->kind) + { + case TYPE_STRUCT: + write_state_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; + + default: + fatal ("Unexpected type..."); + } + } + + fprintf (state_file, ")\n"); +} + + +/* Write a pair. */ +static void +write_state_pair (pair_p current) +{ + if (current == NULL) + { + fprintf (state_file, "nil)"); + return; + } + + fprintf (state_file, "\n(!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); + + fprintf (state_file, ")"); +} + +/* Write a pair list and return the number of pairs written. */ +static int +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. */ +static void +write_state_typedefs (void) +{ + int nbtypedefs = pair_list_length (typedefs); + int nbpairs = 0; + fprintf (state_file, "\n(!typedefs %d\n", nbtypedefs); + nbpairs = write_state_pair_list (typedefs); + gcc_assert (nbpairs == nbtypedefs); + fprintf (state_file, ")\n"); + if (verbosity_level >= 2) + printf ("%s wrote %d typedefs\n", progname, nbtypedefs); +} + +/* Write our structures. */ +static void +write_state_structures (void) +{ + int nbstruct = 0; + type_p current; + + for (current = structures; current != NULL; current = current->next) + nbstruct++; + + fprintf (state_file, "\n(!structures %d\n", nbstruct); + + for (current = structures; current != NULL; current = current->next) + write_state_type (current); + + fprintf (state_file, ")\n"); + 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) +{ + int nbvars = pair_list_length (variables); + int nbpairs = 0; + fprintf (state_file, "\n(!variables %d\n", nbvars); + nbpairs = write_state_pair_list (variables); + gcc_assert (nbpairs == nbvars); + fprintf (state_file, ")\n"); + 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) +{ + fprintf (state_file, "\n(!srcdir "); + write_state_a_string (srcdir); + fprintf (state_file, ")\n"); +} + +/* Count and write the list of our files. */ +static void +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); + 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) + { + fprintf (state_file, "(!srcfile %d ", get_lang_bitmap (curfil)); + write_state_a_string (cursrcrelpath); + } + else + { + fprintf (state_file, "(!file %d ", get_lang_bitmap (curfil)); + write_state_a_string (get_input_file_name (curfil)); + } + fprintf (state_file, ")\n"); + } + fprintf (state_file, ")\n"); +} + +/* Write the list of GCC front-end languages. */ +static void +write_state_languages (void) +{ + int i = 0; + fprintf (state_file, "\n(!languages %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]); + } + fprintf (state_file, ")\n"); +} + +/* 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); + fprintf (state_file, ";;; file %s generated on %s\n", state_path, + ctime (&now)); + /* 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 (); + 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, 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 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)); + } + else + { + fatal_reading_state (t0, "Bad tag in 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 .... ) */ + 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 (¤t->pointer_to); + read_state_gc_used (¤t->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, "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 + 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 (¤t_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; + 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; +} + + +/* 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, (htab_eq) strcmp, 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 (¶m_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. */ -- cgit v1.2.3