This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |
Other format: | [Raw text] |
On Tue, 21 Sep 2010 21:29:26 +0200 Basile Starynkevitch <basile@starynkevitch.net> wrote: > > Hello All, > > [join work by Basile Starynkevitch & Jeremie Salvucci] > > References: > http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02060.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00616.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00663.html > http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02063.html > http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02065.html > http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02068.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg00983.html > http://gcc.gnu.org/ml/gcc-patches/2010-08/msg02069.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01713.html > > The 6th part [wstate] of our patch series (thirdround) is a slightly > improved version of > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01150.html by adding > comments notably taking into account Laurynas remarks in > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01151.html & > http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01153.html > > diff -u -p -N $(svn stat . |awk '/[AM]/{print $2}') \ > --from-file ../thirdround_05_typedopt/ > \ > $HOME/Gengtype_Thirdround/patch6_wstate-relto05.diff > > #################### gcc/ChangeLog entry relative to patch piece 5 [typedopt] > 2010-09-21 Jeremie Salvucci <jeremie.salvucci@free.fr> > Basile Starynkevitch <basile@starynkevitch.net> > > * gengtype-state.c: Added new file. > > * gengtype.c: > (type_count): New static variable. > (new_structure, find_structure, find_param_structure) > (create_pointer, create_array): Use type_count for initializing > state_number field of types. > (main): Initialize state_number in predefined types. Call > read_state and write_state appropriately. Show the > type_count when verbose. > > * gengtype.h: Updated comment about per-language directories. > (read_state, write_state): New declarations. > > * Makefile.in (MOSTLYCLEANFILES): Added gtype.state. > (GENGTYPE_FLAGS): New variable. > (s-gtype): Runs gengtype twice, once to write the gtype.state, > once to read it. > (build/gengtype-state.o): New target. > (build/gengtype): Use it. > (mostlyclean): Remove gtype.state > ################################################################ > > > > Also, how should the gengtype program be installed? Perhaps it should > be named gcc-gengtype? I still need help on these minor issues, in > particular as ways to patch gcc/Makefile.in.... There has been some > discussions & suggestions, but I was not able to imagine a > gcc/Makefile.in patch from them. I confess that I don't understand all > of gcc/Makefile.in in particular the installations tricks. > > I am as usual attaching the cumulated patch w.r.t. trunk 164437. Sorry attachment in previous email was wrong. http://gcc.gnu.org/ml/gcc-patches/2010-09/msg01714.html I attached by mistake a draft version of the email, not the relative patch. Apologies! > > Ok for trunk? > > Cheers. > -- > Basile STARYNKEVITCH http://starynkevitch.net/Basile/ > email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359 > 8, rue de la Faiencerie, 92340 Bourg La Reine, France > *** opinions {are only mine, sont seulement les miennes} *** -- Basile STARYNKEVITCH http://starynkevitch.net/Basile/ email: basile<at>starynkevitch<dot>net mobile: +33 6 8501 2359 8, rue de la Faiencerie, 92340 Bourg La Reine, France *** opinions {are only mine, sont seulement les miennes} ***
--- ../thirdround_05_typedopt//gengtype-state.c 2010-09-21 19:56:44.000000000 +0200 +++ gcc/gengtype-state.c 2010-09-21 19:58:32.000000000 +0200 @@ -0,0 +1,2469 @@ +/* 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 + <http://www.gnu.org/licenses/>. + + Contributed by Jeremie Salvucci <jeremie.salvucci@free.fr> + and Basile Starynkevitch <basile@starynkevitch.net> +*/ + +#include "bconfig.h" +#include "system.h" +#include "getopt.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 "xregex.h" +#include "gengtype.h" + + +/* 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 parenthesis. */ + STOK_RIGHTPAR, /* Right 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. */ +#define fatal_reading_state(Tok,Msg) do { \ + struct state_token_st* badtok = Tok; \ + if (badtok) \ + fatal ("%s:%d:%d: Invalid state file; " Msg, \ + badtok->stok_file, \ + badtok->stok_line, \ + badtok->stok_col); \ + else \ + fatal ("%s:%d: Invalid state file; " Msg, \ + state_path, state_line); \ + } while(0) + +#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. */ + 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 escape"); + c = getc (state_file); + break; + } + default: + fatal_reading_state (NULL_STATE_TOKEN, + "Lexical error in 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, (char) 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", + ftell (state_file)); +} + +/* 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; + } +} + +/* 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 writting 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; + 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"); + 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 who 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 (); + /* The writing of structures probably wrote a lot, so we flush to + disk and check for errors, e.g. to catch disk full situations a + bit earlier. */ + if (fflush (state_file) || ferror (state_file)) + fatal ("output error when writing state file %s [%s]", + temp_state_path, xstrerror (errno)); + 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; + + 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 <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; + 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; + + 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; + struct state_token_st *t1; + + t0 = peek_state_token (0); + 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; + struct state_token_st *t1; + + gcc_assert (floc != NULL); + gcc_assert (srcdir != NULL); + + t0 = peek_state_token (0); + t1 = peek_state_token (1); + + 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; + struct state_token_st *t1; + struct state_token_st *t2; + + 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, "!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; + + 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; + struct state_token_st *t1; + + t0 = peek_state_token (0); + 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; + struct state_token_st *t1; + + t0 = peek_state_token (0); + 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; + struct state_token_st *t1; + + t0 = peek_state_token (0); + 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; + struct state_token_st *t1; + + t0 = peek_state_token (0); + 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; + 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; + struct state_token_st *t1; + struct state_token_st *t2; + + 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, "!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; + type_p tmp; + int nbstruct = 0, countstruct = 0; + struct state_token_st *t0; + struct state_token_st *t1; + struct state_token_st *t2; + + 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, "!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; + struct state_token_st *t1; + struct state_token_st *t2; + + 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, "!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; + struct state_token_st *t1; + struct state_token_st *t2; + + 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, "!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 = NULL; + struct state_token_st *t1 = NULL; + + t0 = peek_state_token (0); + 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 = NULL; + struct state_token_st *t1 = NULL; + struct state_token_st *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, "!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 sequences of files. */ +static void +read_state_files_list (void) +{ + struct state_token_st *t0 = NULL; + struct state_token_st *t1 = NULL; + struct state_token_st *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, "!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 (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 = NULL; + struct state_token_st *t1 = NULL; + struct state_token_st *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, "!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. */ --- ../thirdround_05_typedopt//gengtype.c 2010-09-21 16:16:19.000000000 +0200 +++ gcc/gengtype.c 2010-09-21 19:40:11.000000000 +0200 @@ -70,6 +70,10 @@ int do_debug; /* For verbose messages to the user. */ int verbosity_level; +/* We have a type count and use it to set the state_number of newly + allocated types to some unique negative number. */ +static int type_count; + /* The backup directory should be in the same file-system as the generated files, otherwise the rename(2) system call would fail. If NULL, no backup is made when overwriting a generated file. */ @@ -572,12 +576,14 @@ new_structure (const char *name, int isu else if (si->u.s.line.file != NULL && si->u.s.bitmap != bitmap) { ls = si; + type_count++; si = XCNEW (struct type); memcpy (si, ls, sizeof (struct type)); ls->kind = TYPE_LANG_STRUCT; ls->u.s.lang_struct = si; ls->u.s.fields = NULL; si->next = NULL; + si->state_number = -type_count; si->pointer_to = NULL; si->u.s.lang_struct = ls; } @@ -587,6 +593,8 @@ new_structure (const char *name, int isu if (ls != NULL && s == NULL) { s = XCNEW (struct type); + type_count++; + s->state_number = -type_count; s->next = ls->u.s.lang_struct; ls->u.s.lang_struct = s; s->u.s.lang_struct = ls; @@ -598,6 +606,8 @@ new_structure (const char *name, int isu { s = XCNEW (struct type); s->next = structures; + type_count++; + s->state_number = -type_count; structures = s; } @@ -634,11 +644,12 @@ find_structure (const char *name, int is if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion) return s; - - s = XCNEW (struct type); + s = XCNEW (struct type); + type_count++; s->next = structures; structures = s; s->kind = isunion ? TYPE_UNION : TYPE_STRUCT; + s->state_number = -type_count; s->u.s.tag = name; structures = s; return s; @@ -661,8 +672,10 @@ find_param_structure (type_p t, type_p p if (res == NULL) { res = XCNEW (struct type); + type_count++; res->kind = TYPE_PARAM_STRUCT; res->next = param_structs; + res->state_number = -type_count; param_structs = res; res->u.param_struct.stru = t; memcpy (res->u.param_struct.param, param, sizeof (type_p) * NUM_PARAM); @@ -689,7 +702,9 @@ create_pointer (type_p t) if (! t->pointer_to) { type_p r = XCNEW (struct type); + type_count++; r->kind = TYPE_POINTER; + r->state_number = -type_count; r->u.p = t; t->pointer_to = r; } @@ -703,8 +718,10 @@ create_array (type_p t, const char *len) { type_p v; - v = XCNEW (struct type); + v = XCNEW (struct type); v->kind = TYPE_ARRAY; + type_count++; + v->state_number = -type_count; v->u.a.p = t; v->u.a.len = len; return v; @@ -4571,8 +4588,10 @@ dump_structures (const char * name, type printf ("End of %s\n\n", name); } -/* Dumps the internal structures of gengtype. */ - +/* Dumps the internal structures of gengtype. This can be used to + debug gengtype itself, or perhaps to understand what is happenning, + e.g. the role of some difficult to grasp GTY-s. So it might be + useful for plugin or GCC developers. */ static void dump_everything (void) { @@ -4787,8 +4806,12 @@ main (int argc, char **argv) static struct fileloc pos = { NULL, 0 }; outf_p output_header; - /* Mandatory common initializations. */ + /* Mandatory common initializations. */ progname = "gengtype"; /* For fatal and messages. */ + /* Initialize the state number of statically predefined types. */ + string_type.state_number = - (++type_count); + scalar_nonchar.state_number = - (++type_count); + scalar_char.state_number = - (++type_count); /* Set the scalar_is_char union number for predefined scalar types. */ scalar_nonchar.u.scalar_is_char = FALSE; scalar_char.u.scalar_is_char = TRUE; @@ -4815,8 +4838,12 @@ main (int argc, char **argv) DBGPRINTF ("inputlist %s", inputlist); if (read_state_filename) { - fatal ("read state %s not implemented yet", read_state_filename); - /* TODO: implement read state. */ + if (inputlist) + fatal ("input list %s cannot be given with a read state file %s", + inputlist, read_state_filename); + read_state (read_state_filename); + DBGPRINT_COUNT_TYPE ("structures after read_state", structures); + DBGPRINT_COUNT_TYPE ("param_structs after read_state", param_structs); } else if (inputlist) { @@ -4844,9 +4871,9 @@ main (int argc, char **argv) DBGPRINT_COUNT_TYPE ("structures after parsing", structures); DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs); if (verbosity_level >= 1) - printf ("%s parsed %d files\n", progname, (int) num_gt_files); - - } + printf ("%s parsed %d files with %d GTY types\n", + progname, (int) num_gt_files, type_count); + } else fatal ("either an input list or a read state file should be given"); if (hit_error) @@ -4893,11 +4920,30 @@ main (int argc, char **argv) happen before writing the state. */ set_gc_used (variables); - /* We should write the state here, but it is not yet implemented. */ + + /* We write the state here. It could eventually happen that the + state file is written after some plugin files have been parsed, + perhaps to enlarge the state file for other plugins needs. But + this is an uncommon scenario. */ if (write_state_filename) { - fatal ("write state %s in not yet implemented", write_state_filename); - /* TODO: implement write state. */ + DBGPRINT_COUNT_TYPE ("structures before writestate", structures); + DBGPRINT_COUNT_TYPE ("param_structs before writestate", param_structs); + /* We definitely don't want to write a state file if some error + occurred while reading input files processed by gengtype, + because we only want to write sane state files! */ + if (hit_error) + fatal ("won't write state %s after errors", write_state_filename); + write_state (write_state_filename); + if (do_dump) + dump_everything (); + + /* After having written the state file we return immediately to + avoid generating any output file. */ + if (hit_error) + return 1; + else + return 0; } --- ../thirdround_05_typedopt//gengtype.h 2010-09-21 16:11:46.000000000 +0200 +++ gcc/gengtype.h 2010-09-21 19:40:29.000000000 +0200 @@ -434,6 +434,13 @@ extern size_t srcdir_len; extern const char *read_state_filename; extern const char *write_state_filename; +/* Functions reading and writing the entire gengtype state, called from + main, and implemented in file gengtype-state.c. */ +void read_state (const char* path); +/* Write the state, and update the state_number field in types. */ +void write_state (const char* path); + + /* Print an error message. */ extern void error_at_line (const struct fileloc *pos, const char *msg, ...) ATTRIBUTE_PRINTF_2; --- ../thirdround_05_typedopt//Makefile.in 2010-09-20 21:13:15.000000000 +0200 +++ gcc/Makefile.in 2010-09-21 19:41:05.000000000 +0200 @@ -1492,7 +1492,7 @@ MOSTLYCLEANFILES = insn-flags.h insn-con insn-attr.h insn-attrtab.c insn-opinit.c insn-preds.c insn-constants.h \ tm-preds.h tm-constrs.h \ tree-check.h min-insn-modes.c insn-modes.c insn-modes.h \ - genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list \ + genrtl.h gt-*.h gtype-*.h gtype-desc.c gtyp-input.list gtype.state \ xgcc$(exeext) cpp$(exeext) cc1$(exeext) cc1*-dummy$(exeext) $(EXTRA_PASSES) \ $(EXTRA_PARTS) $(EXTRA_PROGRAMS) gcc-cross$(exeext) \ $(SPECS) collect2$(exeext) lto-wrapper$(exeext) \ @@ -3798,6 +3798,9 @@ ALL_GTFILES_H := $(sort $(GTFILES_H) $(G $(ALL_GTFILES_H) gtype-desc.c gtype-desc.h : s-gtype ; @true +## Common flags to gengtype [e.g. -v for verbosity or -B . for backups]. +GENGTYPE_FLAGS = + gtyp-input.list: s-gtyp-input ; @true s-gtyp-input: Makefile @: $(call write_entries_to_file,$(GTFILES),tmp-gi.list) @@ -3806,7 +3809,13 @@ s-gtyp-input: Makefile s-gtype: build/gengtype$(build_exeext) $(filter-out [%], $(GTFILES)) \ gtyp-input.list - $(RUN_GEN) build/gengtype$(build_exeext) -S $(srcdir) -I gtyp-input.list +# First, parse all files and save a state file. + $(RUN_GEN) build/gengtype$(build_exeext) $(GENGTYPE_FLAGS) \ + -S $(srcdir) -I gtyp-input.list -w gtype.state +# Second, read the state file and generate all files. This ensure that +# gtype.state is correctly read: + $(RUN_GEN) build/gengtype$(build_exeext) $(GENGTYPE_FLAGS) \ + -r gtype.state $(STAMP) s-gtype generated_files = config.h tm.h $(TM_P_H) $(TM_H) multilib.h \ @@ -3902,6 +3911,8 @@ build/gengenrtl.o : gengenrtl.c $(BCONFI build/gengtype-lex.o : gengtype-lex.c gengtype.h $(BCONFIG_H) $(SYSTEM_H) build/gengtype-parse.o : gengtype-parse.c gengtype.h $(BCONFIG_H) \ $(SYSTEM_H) +build/gengtype-state.o : gengtype-state.c gengtype.h $(BCONFIG_H) \ + $(SYSTEM_H) errors.h build/gengtype.o : gengtype.c $(BCONFIG_H) $(SYSTEM_H) gengtype.h \ rtl.def insn-notes.def errors.h double-int.h $(HASHTAB_H) build/genmddeps.o: genmddeps.c $(BCONFIG_H) $(SYSTEM_H) coretypes.h \ @@ -3948,7 +3959,7 @@ build/genautomata$(build_exeext) : BUILD # These programs are not linked with the MD reader. build/gengtype$(build_exeext) : build/gengtype-lex.o build/gengtype-parse.o \ - build/version.o + build/gengtype-state.o build/version.o build/genhooks$(build_exeext) : $(BUILD_ERRORS) # Generated source files for gengtype. @@ -4404,6 +4415,7 @@ mostlyclean: lang.mostlyclean # Delete files generated by gengtype.c -rm -f gtype-* -rm -f gt-* + -rm gtype.state # Delete genchecksum outputs -rm -f *-checksum.c
Attachment:
cumulatedpatch6_wstate-gengtypethird-r164437.diff.gz
Description: Binary data
Index Nav: | [Date Index] [Subject Index] [Author Index] [Thread Index] | |
---|---|---|
Message Nav: | [Date Prev] [Date Next] | [Thread Prev] [Thread Next] |