Commit 92724e1d by Basile Starynkevitch Committed by Basile Starynkevitch

gentype-state.c: Add new file.

2010-11-25  Basile Starynkevitch  <basile@starynkevitch.net>
	    Jeremie Salvucci  <jeremie.salvucci@free.fr>

	* gentype-state.c: Add new file.

	* gengtype.c (type count): New variable.
	(new_structure, find_param_structure, create_pointer)
	(create_array): Use it to set state_number in types.
	(dump_everything): Improve comment.
	(main): Call read_state and write_state. Print type_count.

	* gengtype.h (type_lineloc): New function.
	(read_state, write_state): New declarations.

	* Makefile.in (GENGTYPE_FLAGS): New variable.
	(s-gtype): Run gengtype twice and generate gtype.state.
	(build/gengtype-state.o): New rule.
	(build/gengtype$(build_exeext)): Link gengtype-state.o.
	(mostlyclean): Update comment.  Remove gtype.state.


Co-Authored-By: Jeremie Salvucci <jeremie.salvucci@free.fr>

From-SVN: r167150
parent f7598845
2010-11-25 Basile Starynkevitch <basile@starynkevitch.net>
Jeremie Salvucci <jeremie.salvucci@free.fr>
* gentype-state.c: Add new file.
* gengtype.c (type count): New variable.
(new_structure, find_param_structure, create_pointer)
(create_array): Use it to set state_number in types.
(dump_everything): Improve comment.
(main): Call read_state and write_state. Print type_count.
* gengtype.h (type_lineloc): New function.
(read_state, write_state): New declarations.
* Makefile.in (GENGTYPE_FLAGS): New variable.
(s-gtype): Run gengtype twice and generate gtype.state.
(build/gengtype-state.o): New rule.
(build/gengtype$(build_exeext)): Link gengtype-state.o.
(mostlyclean): Update comment. Remove gtype.state.
2010-11-25 Jakub Jelinek <jakub@redhat.com>
PR middle-end/46637
......@@ -3819,6 +3819,9 @@ ALL_GTFILES_H := $(sort $(GTFILES_H) $(GTFILES_LANG_H))
$(ALL_GTFILES_H) gtype-desc.c gtype-desc.h : s-gtype ; @true
### Common flags to gengtype [e.g. -v or -B backupdir]
GENGTYPE_FLAGS=
gtyp-input.list: s-gtyp-input ; @true
s-gtyp-input: Makefile
@: $(call write_entries_to_file,$(GTFILES),tmp-gi.list)
......@@ -3827,7 +3830,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 \
......@@ -3923,6 +3932,8 @@ build/gengenrtl.o : gengenrtl.c $(BCONFIG_H) $(SYSTEM_H) rtl.def
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) \
$(OBSTACK_H) $(XREGEX_H)
......@@ -3968,7 +3979,7 @@ build/genautomata$(build_exeext) : BUILD_LIBS += -lm
# 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
# Rule for the generator programs:
$(genprog:%=build/gen%$(build_exeext)): build/gen%$(build_exeext): build/gen%.o $(BUILD_LIBDEPS)
......@@ -4441,9 +4452,10 @@ mostlyclean: lang.mostlyclean
-rm -f core */core
# Delete file generated for gengtype
-rm -f gtyp-input.list
# Delete files generated by gengtype.c
# Delete files generated by gengtype
-rm -f gtype-*
-rm -f gt-*
-rm -f gtype.state
# Delete genchecksum outputs
-rm -f *-checksum.c
......
/* 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 "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 (&current->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 <number-types> <type-1> .... <type-n>) */
if (state_token_kind (t0) == STOK_LEFTPAR
&& state_token_is_name (t1, "!homotypes")
&& state_token_kind (t2) == STOK_INTEGER)
{
type_p *prevty = &type->u.s.lang_struct;
int nbhomotype = t2->stok_un.stok_num;
int i = 0;
t0 = t1 = t2 = NULL;
next_state_tokens (3);
for (i = 0; i < nbhomotype; i++)
{
read_state_type (prevty);
t0 = peek_state_token (0);
if (*prevty)
prevty = &(*prevty)->next;
else
fatal_reading_state (t0,
"expecting type in homotype list for lang_struct");
};
if (state_token_kind (t0) != STOK_RIGHTPAR)
fatal_reading_state (t0,
"expecting ) in homotype list for lang_struct");
next_state_tokens (1);
}
else
fatal_reading_state (t0, "expecting !homotypes for lang_struct");
}
/* Read a param_struct type for GTY parametrized structures. */
static void
read_state_param_struct_type (type_p type)
{
int i;
struct state_token_st *t0;
type->kind = TYPE_PARAM_STRUCT;
read_state_common_type_content (type);
DBGPRINTF ("read param_struct type @%p #%d",
(void *) type, type->state_number);
read_state_type (&(type->u.param_struct.stru));
for (i = 0; i < NUM_PARAM; i++)
{
t0 = peek_state_token (0);
if (state_token_is_name (t0, "nil"))
{
type->u.param_struct.param[i] = NULL;
next_state_tokens (1);
}
else
read_state_type (&(type->u.param_struct.param[i]));
}
read_state_fileloc (&(type->u.param_struct.line));
}
/* Read the gc used information. */
static void
read_state_gc_used (enum gc_used_enum *pgus)
{
struct state_token_st *t0 = peek_state_token (0);
if (state_token_is_name (t0, "gc_unused"))
*pgus = GC_UNUSED;
else if (state_token_is_name (t0, "gc_used"))
*pgus = GC_USED;
else if (state_token_is_name (t0, "gc_maybe_pointed_to"))
*pgus = GC_MAYBE_POINTED_TO;
else if (state_token_is_name (t0, "gc_pointed_to"))
*pgus = GC_POINTED_TO;
else
fatal_reading_state (t0, "invalid gc_used information");
next_state_tokens (1);
}
/* Utility function to read the common content of types. */
static void
read_state_common_type_content (type_p current)
{
struct state_token_st *t0 = peek_state_token (0);
if (state_token_kind (t0) == STOK_INTEGER)
{
current->state_number = t0->stok_un.stok_num;
next_state_tokens (1);
record_type (current);
}
else
fatal_reading_state_printf (t0,
"Expected integer for state_number line %d",
state_line);
/* We don't read the next field of the type. */
read_state_type (&current->pointer_to);
read_state_gc_used (&current->gc_used);
}
/* Read a GTY-ed type. */
void
read_state_type (type_p *current)
{
struct state_token_st *t0 = peek_state_token (0);
struct state_token_st *t1 = peek_state_token (1);
if (state_token_kind (t0) == STOK_LEFTPAR &&
state_token_is_name (t1, "!type"))
{
next_state_tokens (2);
t0 = peek_state_token (0);
if (state_token_is_name (t0, "already_seen"))
{
next_state_tokens (1);
read_state_already_seen_type (current);
}
else
{
t0 = peek_state_token (0);
if (state_token_is_name (t0, "scalar_nonchar"))
{
next_state_tokens (1);
read_state_scalar_nonchar_type (current);
}
else if (state_token_is_name (t0, "scalar_char"))
{
next_state_tokens (1);
read_state_scalar_char_type (current);
}
else if (state_token_is_name (t0, "string"))
{
next_state_tokens (1);
read_state_string_type (current);
}
else if (state_token_is_name (t0, "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 (&current_option);
if (head == NULL)
{
head = current_option;
previous = head;
}
else
{
previous->next = current_option;
previous = current_option;
}
t0 = peek_state_token (0);
}
next_state_tokens (1);
}
else if (state_token_is_name (t0, "nil"))
{
next_state_tokens (1);
}
else
fatal_reading_state (t0, "Bad options syntax");
*opt = head;
}
/* Read a version, and check against the version of the gengtype. */
static void
read_state_version (const char *version_string)
{
struct state_token_st *t0 = peek_state_token (0);
struct state_token_st *t1 = peek_state_token (1);
if (state_token_kind (t0) == STOK_LEFTPAR &&
state_token_is_name (t1, "!version"))
{
next_state_tokens (2);
t0 = peek_state_token (0);
t1 = peek_state_token (1);
if (state_token_kind (t0) == STOK_STRING &&
state_token_kind (t1) == STOK_RIGHTPAR)
{
/* Check that the read version string is the same as current
version. */
if (strcmp (version_string, t0->stok_un.stok_string))
fatal_reading_state_printf (t0,
"version string mismatch; expecting %s but got %s",
version_string,
t0->stok_un.stok_string);
next_state_tokens (2);
}
else
fatal_reading_state (t0, "Missing version or right parenthesis");
}
else
fatal_reading_state (t0, "Bad version syntax");
}
/* Read a pair. */
void
read_state_pair (pair_p *current)
{
struct state_token_st *t0 = peek_state_token (0);
struct state_token_st *t1 = peek_state_token (1);
if (state_token_kind (t0) == STOK_LEFTPAR &&
state_token_is_name (t1, "!pair"))
{
*current = XCNEW (struct pair);
next_state_tokens (2);
t0 = peek_state_token (0);
if (state_token_kind (t0) == STOK_STRING)
{
if (strcmp (t0->stok_un.stok_string, "nil") == 0)
{
(*current)->name = NULL;
}
else
{
(*current)->name = xstrdup (t0->stok_un.stok_string);
}
next_state_tokens (1);
read_state_type (&((*current)->type));
read_state_fileloc (&((*current)->line));
read_state_options (&((*current)->opt));;
t0 = peek_state_token (0);
if (state_token_kind (t0) == STOK_RIGHTPAR)
{
next_state_tokens (1);
}
else
{
fatal_reading_state (t0, "Bad syntax for pair, )");
}
}
else
{
fatal_reading_state (t0, "Bad name for pair");
}
}
else if (state_token_kind (t0) == STOK_NAME &&
state_token_is_name (t0, "nil"))
{
next_state_tokens (1);
*current = NULL;
}
else
fatal_reading_state_printf (t0, "Bad syntax for pair, (!pair %d",
state_token->stok_kind);
}
/* Return the number of pairs actually read. */
int
read_state_pair_list (pair_p *list)
{
int nbpair = 0;
pair_p head = NULL;
pair_p previous = NULL;
pair_p tmp = NULL;
struct state_token_st *t0 = peek_state_token (0);
while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
{
read_state_pair (&tmp);
if (head == NULL)
{
head = tmp;
previous = head;
}
else
{
previous->next = tmp;
previous = tmp;
}
t0 = peek_state_token (0);
nbpair++;
}
/* don't consume the ); the caller will eat it. */
*list = head;
return nbpair;
}
/* Read the typedefs. */
static void
read_state_typedefs (pair_p *typedefs)
{
int nbtypedefs = 0;
pair_p list = NULL;
struct state_token_st *t0 = peek_state_token (0);
struct state_token_st *t1 = peek_state_token (1);
struct state_token_st *t2 = peek_state_token (2);
if (state_token_kind (t0) == STOK_LEFTPAR
&& state_token_is_name (t1, "!typedefs")
&& state_token_kind (t2) == STOK_INTEGER)
{
int nbpairs = 0;
nbtypedefs = t2->stok_un.stok_num;
next_state_tokens (3);
nbpairs = read_state_pair_list (&list);
t0 = peek_state_token (0);
if (nbpairs != nbtypedefs)
fatal_reading_state_printf
(t0,
"invalid number of typedefs, expected %d but got %d",
nbtypedefs, nbpairs);
if (state_token_kind (t0) == STOK_RIGHTPAR)
next_state_tokens (1);
else
fatal_reading_state (t0, "Bad typedefs syntax )");
}
else
fatal_reading_state (t0, "Bad typedefs syntax (!typedefs");
if (verbosity_level >= 2)
printf ("%s read %d typedefs from state\n", progname, nbtypedefs);
*typedefs = list;
}
/* Read the structures. */
static void
read_state_structures (type_p *structures)
{
type_p head = NULL;
type_p previous;
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 (&param_structs);
read_state_variables (&variables);
read_state_trailer ();
if (verbosity_level >= 1)
{
printf ("%s read %ld bytes.\n", progname, ftell (state_file));
fflush (stdout);
};
if (fclose (state_file))
fatal ("failed to close read state file %s [%s]",
path, xstrerror (errno));
state_file = NULL;
state_path = NULL;
}
/* End of file gengtype-state.c. */
......@@ -67,6 +67,10 @@ int do_debug;
/* Level for verbose messages. */
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. */
......@@ -563,12 +567,14 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
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;
}
......@@ -577,7 +583,9 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
if (ls != NULL && s == NULL)
{
type_count++;
s = XCNEW (struct type);
s->state_number = -type_count;
s->next = ls->u.s.lang_struct;
ls->u.s.lang_struct = s;
s->u.s.lang_struct = ls;
......@@ -587,7 +595,9 @@ new_structure (const char *name, int isunion, struct fileloc *pos,
if (s == NULL)
{
type_count++;
s = XCNEW (struct type);
s->state_number = -type_count;
s->next = structures;
structures = s;
}
......@@ -625,8 +635,10 @@ find_structure (const char *name, int isunion)
if (strcmp (name, s->u.s.tag) == 0 && UNION_P (s) == isunion)
return s;
type_count++;
s = XCNEW (struct type);
s->next = structures;
s->state_number = -type_count;
structures = s;
s->kind = isunion ? TYPE_UNION : TYPE_STRUCT;
s->u.s.tag = name;
......@@ -650,9 +662,11 @@ find_param_structure (type_p t, type_p param[NUM_PARAM])
break;
if (res == NULL)
{
type_count++;
res = XCNEW (struct type);
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);
......@@ -679,6 +693,8 @@ create_pointer (type_p t)
if (!t->pointer_to)
{
type_p r = XCNEW (struct type);
type_count++;
r->state_number = -type_count;
r->kind = TYPE_POINTER;
r->u.p = t;
t->pointer_to = r;
......@@ -693,8 +709,10 @@ create_array (type_p t, const char *len)
{
type_p v;
type_count++;
v = XCNEW (struct type);
v->kind = TYPE_ARRAY;
v->state_number = -type_count;
v->u.a.p = t;
v->u.a.len = len;
return v;
......@@ -4600,7 +4618,9 @@ dump_structures (const char *name, type_p structures)
printf ("End of %s\n\n", name);
}
/* Dumps the internal structures of gengtype. */
/* Dumps the internal structures of gengtype. This is useful to debug
gengtype itself, or to understand what it does, e.g. for plugin
developers. */
static void
dump_everything (void)
......@@ -4836,8 +4856,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)
{
......@@ -4867,7 +4891,8 @@ main (int argc, char **argv)
(int) i, get_input_file_name (gt_files[i]));
}
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);
DBGPRINT_COUNT_TYPE ("structures after parsing", structures);
DBGPRINT_COUNT_TYPE ("param_structs after parsing", param_structs);
......@@ -4892,7 +4917,7 @@ main (int argc, char **argv)
fatal ("No plugin files given in plugin mode for %s",
plugin_output_filename);
/* Parse our plugin files. */
/* Parse our plugin files and augment the state. */
for (ix = 0; ix < nb_plugin_files; ix++)
parse_file (get_input_file_name (plugin_files[ix]));
......@@ -4917,11 +4942,30 @@ main (int argc, char **argv)
hence enlarge the param_structs list of types. */
set_gc_used (variables);
/* We should write the state here, but it is not yet implemented. */
/* The state at this point is read from the state input file or by
parsing source files and optionally augmented by parsing plugin
source files. Write it now. */
if (write_state_filename)
{
fatal ("write state %s in not yet implemented", write_state_filename);
/* TODO: implement write state. */
DBGPRINT_COUNT_TYPE ("structures before write_state", structures);
DBGPRINT_COUNT_TYPE ("param_structs before write_state", param_structs);
if (hit_error)
fatal ("didn't write state file %s after errors",
write_state_filename);
DBGPRINTF ("before write_state %s", 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;
}
......
......@@ -374,6 +374,13 @@ extern size_t srcdir_len;
extern const char *read_state_filename; /* (-r) program argument. */
extern const char *write_state_filename; /* (-w) program argument. */
/* 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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment