2012-03-27 23:13:14 +00:00
|
|
|
|
/* Gengtype persistent state serialization & de-serialization.
|
|
|
|
|
Useful for gengtype in plugin mode.
|
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
Copyright (C) 2010-2022 Free Software Foundation, Inc.
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
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>
|
|
|
|
|
*/
|
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
|
#ifdef HOST_GENERATOR_FILE
|
2012-03-27 23:13:14 +00:00
|
|
|
|
#include "config.h"
|
2015-08-28 15:33:40 +00:00
|
|
|
|
#define GENERATOR_FILE 1
|
|
|
|
|
#else
|
|
|
|
|
#include "bconfig.h"
|
2012-03-27 23:13:14 +00:00
|
|
|
|
#endif
|
|
|
|
|
#include "system.h"
|
|
|
|
|
#include "errors.h" /* For fatal. */
|
|
|
|
|
#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:
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case TYPE_USER_STRUCT:
|
|
|
|
|
case TYPE_UNDEFINED:
|
2012-03-27 23:13:14 +00:00
|
|
|
|
return CONST_CAST (struct fileloc*, &ty->u.s.line);
|
|
|
|
|
case TYPE_SCALAR:
|
|
|
|
|
case TYPE_STRING:
|
|
|
|
|
case TYPE_POINTER:
|
|
|
|
|
case TYPE_ARRAY:
|
2022-10-27 18:55:19 +00:00
|
|
|
|
case TYPE_CALLBACK:
|
2012-03-27 23:13:14 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
default:
|
|
|
|
|
gcc_unreachable ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The state file has simplistic lispy lexical tokens. Its lexer gives
|
2014-09-21 17:33:12 +00:00
|
|
|
|
a linked list of struct state_token_st, through the peek_state_token
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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 */
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* A class for writing out s-expressions, keeping track of newlines and
|
|
|
|
|
nested indentation. */
|
|
|
|
|
class s_expr_writer
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
s_expr_writer ();
|
|
|
|
|
|
|
|
|
|
void write_new_line ();
|
|
|
|
|
void write_any_indent (int leading_spaces);
|
|
|
|
|
|
|
|
|
|
void begin_s_expr (const char *tag);
|
|
|
|
|
void end_s_expr ();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
int m_indent_amount;
|
|
|
|
|
int m_had_recent_newline;
|
|
|
|
|
}; // class s_expr_writer
|
|
|
|
|
|
|
|
|
|
/* A class for writing out "gtype.state". */
|
|
|
|
|
class state_writer : public s_expr_writer
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
state_writer ();
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
void write_state_fileloc (struct fileloc *floc);
|
|
|
|
|
void write_state_fields (pair_p fields);
|
|
|
|
|
void write_state_a_string (const char *s);
|
|
|
|
|
void write_state_string_option (options_p current);
|
|
|
|
|
void write_state_type_option (options_p current);
|
|
|
|
|
void write_state_nested_option (options_p current);
|
|
|
|
|
void write_state_option (options_p current);
|
|
|
|
|
void write_state_options (options_p opt);
|
|
|
|
|
void write_state_lang_bitmap (lang_bitmap bitmap);
|
|
|
|
|
void write_state_version (const char *version);
|
|
|
|
|
void write_state_scalar_type (type_p current);
|
|
|
|
|
void write_state_string_type (type_p current);
|
2022-10-27 18:55:19 +00:00
|
|
|
|
void write_state_callback_type (type_p current);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void write_state_undefined_type (type_p current);
|
|
|
|
|
void write_state_struct_union_type (type_p current, const char *kindstr);
|
|
|
|
|
void write_state_struct_type (type_p current);
|
|
|
|
|
void write_state_user_struct_type (type_p current);
|
|
|
|
|
void write_state_union_type (type_p current);
|
|
|
|
|
void write_state_lang_struct_type (type_p current);
|
|
|
|
|
void write_state_pointer_type (type_p current);
|
|
|
|
|
void write_state_array_type (type_p current);
|
|
|
|
|
void write_state_gc_used (enum gc_used_enum gus);
|
|
|
|
|
void write_state_common_type_content (type_p current);
|
|
|
|
|
void write_state_type (type_p current);
|
|
|
|
|
void write_state_pair (pair_p current);
|
|
|
|
|
int write_state_pair_list (pair_p list);
|
|
|
|
|
void write_state_typedefs (void);
|
|
|
|
|
void write_state_structures (void);
|
|
|
|
|
void write_state_variables (void);
|
|
|
|
|
void write_state_srcdir (void);
|
|
|
|
|
void write_state_files_list (void);
|
|
|
|
|
void write_state_languages (void);
|
|
|
|
|
|
|
|
|
|
friend void write_state (const char *state_path);
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
/* Counter of written types. */
|
|
|
|
|
int m_state_written_type_count;
|
|
|
|
|
}; // class state_writer
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* class s_expr_writer's trivial constructor. */
|
|
|
|
|
s_expr_writer::s_expr_writer ()
|
|
|
|
|
: m_indent_amount (0),
|
|
|
|
|
m_had_recent_newline (0)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a newline to the output file, merging adjacent newlines. */
|
|
|
|
|
void
|
|
|
|
|
s_expr_writer::write_new_line (void)
|
|
|
|
|
{
|
|
|
|
|
/* Don't add a newline if we've just had one. */
|
|
|
|
|
if (!m_had_recent_newline)
|
|
|
|
|
{
|
|
|
|
|
fprintf (state_file, "\n");
|
|
|
|
|
m_had_recent_newline = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If we've just had a newline, write the indentation amount, potentially
|
|
|
|
|
omitting some spaces.
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
LEADING_SPACES exists to support code that writes strings with leading
|
|
|
|
|
spaces (e.g " foo") which might occur within a line, or could be the first
|
|
|
|
|
thing on a line. By passing leading_spaces == 1, when such a string is the
|
|
|
|
|
first thing on a line, write_any_indent () swallows the successive
|
|
|
|
|
leading spaces into the indentation so that the "foo" begins at the expected
|
|
|
|
|
column. */
|
|
|
|
|
void
|
|
|
|
|
s_expr_writer::write_any_indent (int leading_spaces)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
int amount = m_indent_amount - leading_spaces;
|
|
|
|
|
if (m_had_recent_newline)
|
|
|
|
|
for (i = 0; i < amount; i++)
|
|
|
|
|
fprintf (state_file, " ");
|
|
|
|
|
m_had_recent_newline = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write the beginning of a new s-expresion e.g. "(!foo "
|
|
|
|
|
The writer automatically adds whitespace to show the hierarchical
|
|
|
|
|
structure of the expressions, so each one starts on a new line,
|
|
|
|
|
and any within it will be at an increased indentation level. */
|
|
|
|
|
void
|
|
|
|
|
s_expr_writer::begin_s_expr (const char *tag)
|
|
|
|
|
{
|
|
|
|
|
write_new_line ();
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "(!%s ", tag);
|
|
|
|
|
m_indent_amount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write out the end of an s-expression: any necssessary indentation,
|
|
|
|
|
a closing parenthesis, and a new line. */
|
|
|
|
|
void
|
|
|
|
|
s_expr_writer::end_s_expr (void)
|
|
|
|
|
{
|
|
|
|
|
m_indent_amount--;
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, ")");
|
|
|
|
|
write_new_line ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* class state_writer's trivial constructor. */
|
|
|
|
|
state_writer::state_writer ()
|
|
|
|
|
: s_expr_writer (),
|
|
|
|
|
m_state_written_type_count (0)
|
|
|
|
|
{
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fatal error messages when reading the state. They are extremely
|
2022-10-27 18:55:19 +00:00
|
|
|
|
unlikely, and only appear when this gengtype-state.cc file is buggy,
|
2012-03-27 23:13:14 +00:00
|
|
|
|
or when reading a gengtype state which was not generated by the
|
|
|
|
|
same version of gengtype or GCC. */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Fatal message while reading state. */
|
2015-08-28 15:33:40 +00:00
|
|
|
|
static void
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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__); \
|
2014-09-21 17:33:12 +00:00
|
|
|
|
} while (0)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Find or allocate an identifier in our name hash table. */
|
|
|
|
|
static struct state_ident_st *
|
|
|
|
|
state_ident_by_name (const char *name, enum insert_option optins)
|
|
|
|
|
{
|
|
|
|
|
PTR *slot = NULL;
|
|
|
|
|
int namlen = 0;
|
|
|
|
|
struct state_ident_st *stid = NULL;
|
|
|
|
|
|
|
|
|
|
if (!name || !name[0])
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
slot = htab_find_slot (state_ident_tab, name, optins);
|
|
|
|
|
if (!slot)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
namlen = strlen (name);
|
|
|
|
|
stid =
|
|
|
|
|
(struct state_ident_st *) xmalloc (sizeof (struct state_ident_st) +
|
|
|
|
|
namlen);
|
|
|
|
|
memset (stid, 0, sizeof (struct state_ident_st) + namlen);
|
|
|
|
|
strcpy (stid->stid_name, name);
|
|
|
|
|
*slot = stid;
|
|
|
|
|
|
|
|
|
|
return stid;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Our token lexer is heavily inspired by MELT's lexer, and share some
|
|
|
|
|
code with the file gcc/melt-runtime.c of the GCC MELT branch! We
|
|
|
|
|
really want the gengtype state to be easily parsable by MELT. This
|
|
|
|
|
is a usual lispy lexing routine, dealing with spaces and comments,
|
|
|
|
|
numbers, parenthesis, names, strings. */
|
|
|
|
|
static struct state_token_st *
|
|
|
|
|
read_a_state_token (void)
|
|
|
|
|
{
|
|
|
|
|
int c = 0;
|
|
|
|
|
long curoff = 0;
|
|
|
|
|
struct state_token_st *tk = NULL;
|
|
|
|
|
|
|
|
|
|
again: /* Read again, e.g. after a comment or spaces. */
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
if (c == EOF)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
/* Handle spaces, count lines. */
|
|
|
|
|
if (c == '\n')
|
|
|
|
|
{
|
|
|
|
|
state_line++;
|
|
|
|
|
state_bol = curoff = ftell (state_file);
|
|
|
|
|
goto again;
|
|
|
|
|
};
|
|
|
|
|
if (ISSPACE (c))
|
|
|
|
|
goto again;
|
|
|
|
|
/* Skip comments starting with semi-colon. */
|
|
|
|
|
if (c == ';')
|
|
|
|
|
{
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
}
|
|
|
|
|
while (c > 0 && c != '\n');
|
|
|
|
|
if (c == '\n')
|
|
|
|
|
{
|
|
|
|
|
state_line++;
|
|
|
|
|
state_bol = curoff = ftell (state_file);
|
|
|
|
|
}
|
|
|
|
|
goto again;
|
|
|
|
|
};
|
|
|
|
|
/* Read signed numbers. */
|
|
|
|
|
if (ISDIGIT (c) || c == '-' || c == '+')
|
|
|
|
|
{ /* number */
|
|
|
|
|
int n = 0;
|
|
|
|
|
ungetc (c, state_file);
|
|
|
|
|
curoff = ftell (state_file);
|
|
|
|
|
if (fscanf (state_file, "%d", &n) <= 0)
|
|
|
|
|
fatal_reading_state (NULL_STATE_TOKEN, "Lexical error in number");
|
|
|
|
|
tk = XCNEW (struct state_token_st);
|
|
|
|
|
tk->stok_kind = STOK_INTEGER;
|
|
|
|
|
tk->stok_line = state_line;
|
|
|
|
|
tk->stok_col = curoff - state_bol;
|
|
|
|
|
tk->stok_file = state_path;
|
|
|
|
|
tk->stok_next = NULL;
|
|
|
|
|
tk->stok_un.stok_num = n;
|
|
|
|
|
|
|
|
|
|
return tk;
|
|
|
|
|
}
|
|
|
|
|
/* Read an opening left parenthesis. */
|
|
|
|
|
else if (c == '(')
|
|
|
|
|
{
|
|
|
|
|
curoff = ftell (state_file);
|
|
|
|
|
tk = XCNEW (struct state_token_st);
|
|
|
|
|
tk->stok_kind = STOK_LEFTPAR;
|
|
|
|
|
tk->stok_line = state_line;
|
|
|
|
|
tk->stok_col = curoff - state_bol;
|
|
|
|
|
tk->stok_file = state_path;
|
|
|
|
|
tk->stok_next = NULL;
|
|
|
|
|
|
|
|
|
|
return tk;
|
|
|
|
|
}
|
|
|
|
|
/* Read an closing right parenthesis. */
|
|
|
|
|
else if (c == ')')
|
|
|
|
|
{
|
|
|
|
|
curoff = ftell (state_file);
|
|
|
|
|
tk = XCNEW (struct state_token_st);
|
|
|
|
|
tk->stok_kind = STOK_RIGHTPAR;
|
|
|
|
|
tk->stok_line = state_line;
|
|
|
|
|
tk->stok_col = curoff - state_bol;
|
|
|
|
|
tk->stok_file = state_path;
|
|
|
|
|
tk->stok_next = NULL;
|
|
|
|
|
|
|
|
|
|
return tk;
|
|
|
|
|
}
|
|
|
|
|
/* Read identifiers, using an obstack. */
|
|
|
|
|
else if (ISALPHA (c) || c == '_' || c == '$' || c == '!' || c == '#')
|
|
|
|
|
{
|
|
|
|
|
struct obstack id_obstack;
|
|
|
|
|
struct state_ident_st *sid = NULL;
|
|
|
|
|
char *ids = NULL;
|
|
|
|
|
obstack_init (&id_obstack);
|
|
|
|
|
curoff = ftell (state_file);
|
|
|
|
|
while (ISALNUM (c) || c == '_' || c == '$' || c == '!' || c == '#')
|
|
|
|
|
{
|
|
|
|
|
obstack_1grow (&id_obstack, c);
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
if (c < 0)
|
|
|
|
|
break;
|
|
|
|
|
};
|
|
|
|
|
if (c >= 0)
|
|
|
|
|
ungetc (c, state_file);
|
|
|
|
|
obstack_1grow (&id_obstack, (char) 0);
|
|
|
|
|
ids = XOBFINISH (&id_obstack, char *);
|
|
|
|
|
sid = state_ident_by_name (ids, INSERT);
|
|
|
|
|
obstack_free (&id_obstack, NULL);
|
|
|
|
|
ids = NULL;
|
|
|
|
|
tk = XCNEW (struct state_token_st);
|
|
|
|
|
tk->stok_kind = STOK_NAME;
|
|
|
|
|
tk->stok_line = state_line;
|
|
|
|
|
tk->stok_col = curoff - state_bol;
|
|
|
|
|
tk->stok_file = state_path;
|
|
|
|
|
tk->stok_next = NULL;
|
|
|
|
|
tk->stok_un.stok_ident = sid;
|
|
|
|
|
|
|
|
|
|
return tk;
|
|
|
|
|
}
|
|
|
|
|
/* Read a string, dealing with escape sequences a la C! */
|
|
|
|
|
else if (c == '"')
|
|
|
|
|
{
|
|
|
|
|
char *cstr = NULL;
|
|
|
|
|
int cslen = 0;
|
|
|
|
|
struct obstack bstring_obstack;
|
|
|
|
|
obstack_init (&bstring_obstack);
|
|
|
|
|
curoff = ftell (state_file);
|
|
|
|
|
while ((c = getc (state_file)) != '"' && c >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (ISPRINT (c) && c != '\\')
|
|
|
|
|
obstack_1grow (&bstring_obstack, (char) c);
|
|
|
|
|
else if (ISSPACE (c) && c != '\n')
|
|
|
|
|
obstack_1grow (&bstring_obstack, (char) c);
|
|
|
|
|
else if (c == '\\')
|
|
|
|
|
{
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
switch (c)
|
|
|
|
|
{
|
|
|
|
|
case 'a':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\a');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\b');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 't':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\t');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'n':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\n');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'v':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\v');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'f':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\f');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'r':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\r');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case '"':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\"');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case '\\':
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\\');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case ' ':
|
|
|
|
|
obstack_1grow (&bstring_obstack, ' ');
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
case 'x':
|
|
|
|
|
{
|
|
|
|
|
unsigned int cx = 0;
|
|
|
|
|
if (fscanf (state_file, "%02x", &cx) > 0 && cx > 0)
|
|
|
|
|
obstack_1grow (&bstring_obstack, cx);
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state
|
|
|
|
|
(NULL_STATE_TOKEN,
|
|
|
|
|
"Lexical error in string hex escape");
|
|
|
|
|
c = getc (state_file);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
fatal_reading_state
|
|
|
|
|
(NULL_STATE_TOKEN,
|
|
|
|
|
"Lexical error - unknown string escape");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (NULL_STATE_TOKEN, "Lexical error...");
|
|
|
|
|
};
|
|
|
|
|
if (c != '"')
|
|
|
|
|
fatal_reading_state (NULL_STATE_TOKEN, "Unterminated string");
|
|
|
|
|
obstack_1grow (&bstring_obstack, '\0');
|
|
|
|
|
cstr = XOBFINISH (&bstring_obstack, char *);
|
|
|
|
|
cslen = strlen (cstr);
|
|
|
|
|
tk = (struct state_token_st *)
|
|
|
|
|
xcalloc (sizeof (struct state_token_st) + cslen, 1);
|
|
|
|
|
tk->stok_kind = STOK_STRING;
|
|
|
|
|
tk->stok_line = state_line;
|
|
|
|
|
tk->stok_col = curoff - state_bol;
|
|
|
|
|
tk->stok_file = state_path;
|
|
|
|
|
tk->stok_next = NULL;
|
|
|
|
|
strcpy (tk->stok_un.stok_string, cstr);
|
|
|
|
|
obstack_free (&bstring_obstack, NULL);
|
|
|
|
|
|
|
|
|
|
return tk;
|
|
|
|
|
}
|
|
|
|
|
/* Got an unexpected character. */
|
|
|
|
|
fatal_reading_state_printf
|
|
|
|
|
(NULL_STATE_TOKEN,
|
|
|
|
|
"Lexical error at offset %ld - bad character \\%03o = '%c'",
|
|
|
|
|
ftell (state_file), c, c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Used for lexical look-ahead. Retrieves the lexical token of rank
|
|
|
|
|
DEPTH, starting with 0 when reading the state file. Gives null on
|
|
|
|
|
end of file. */
|
|
|
|
|
static struct state_token_st *
|
|
|
|
|
peek_state_token (int depth)
|
|
|
|
|
{
|
|
|
|
|
int remdepth = depth;
|
|
|
|
|
struct state_token_st **ptoken = &state_token;
|
|
|
|
|
struct state_token_st *tok = NULL;
|
|
|
|
|
|
|
|
|
|
while (remdepth >= 0)
|
|
|
|
|
{
|
|
|
|
|
if (*ptoken == NULL)
|
|
|
|
|
{
|
|
|
|
|
*ptoken = tok = read_a_state_token ();
|
|
|
|
|
if (tok == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
tok = *ptoken;
|
|
|
|
|
ptoken = &((*ptoken)->stok_next);
|
|
|
|
|
remdepth--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tok;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Consume the next DEPTH tokens and free them. */
|
|
|
|
|
static void
|
|
|
|
|
next_state_tokens (int depth)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *n;
|
|
|
|
|
|
|
|
|
|
while (depth > 0)
|
|
|
|
|
{
|
|
|
|
|
if (state_token != NULL)
|
|
|
|
|
{
|
|
|
|
|
n = state_token->stok_next;
|
|
|
|
|
free (state_token);
|
|
|
|
|
state_token = n;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (NULL_STATE_TOKEN, "Tokens stack empty");
|
|
|
|
|
|
|
|
|
|
depth--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Safely retrieve the lexical kind of a token. */
|
|
|
|
|
static inline enum state_token_en
|
|
|
|
|
state_token_kind (struct state_token_st *p)
|
|
|
|
|
{
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return STOK_NONE;
|
|
|
|
|
else
|
|
|
|
|
return p->stok_kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Test if a token is a given name i.e. an identifier. */
|
|
|
|
|
static inline bool
|
|
|
|
|
state_token_is_name (struct state_token_st *p, const char *name)
|
|
|
|
|
{
|
|
|
|
|
if (p == NULL)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
if (p->stok_kind != STOK_NAME)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
return !strcmp (p->stok_un.stok_ident->stid_name, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Following routines are useful for serializing datas.
|
|
|
|
|
*
|
|
|
|
|
* We want to serialize :
|
|
|
|
|
* - typedefs list
|
|
|
|
|
* - structures list
|
|
|
|
|
* - variables list
|
|
|
|
|
*
|
|
|
|
|
* So, we have one routine for each kind of data. The main writing
|
|
|
|
|
* routine is write_state. The main reading routine is
|
|
|
|
|
* read_state. Most writing routines write_state_FOO have a
|
|
|
|
|
* corresponding reading routine read_state_FOO. Reading is done in a
|
|
|
|
|
* recursive descending way, and any read error is fatal.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* When reading the state, we need to remember the previously seen
|
|
|
|
|
types by their state_number, since GTY-ed types are usually
|
|
|
|
|
shared. */
|
|
|
|
|
static htab_t state_seen_types;
|
|
|
|
|
|
|
|
|
|
/* Return the length of a linked list made of pairs. */
|
|
|
|
|
static int pair_list_length (pair_p list);
|
|
|
|
|
|
|
|
|
|
/* Compute the length of a list of pairs, starting from the first
|
|
|
|
|
one. */
|
|
|
|
|
static int
|
|
|
|
|
pair_list_length (pair_p list)
|
|
|
|
|
{
|
|
|
|
|
int nbpair = 0;
|
|
|
|
|
pair_p l = NULL;
|
|
|
|
|
for (l = list; l; l = l->next)
|
|
|
|
|
nbpair++;
|
|
|
|
|
return nbpair;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a file location. Files relative to $(srcdir) are quite
|
|
|
|
|
frequent and are handled specially. This ensures that two gengtype
|
|
|
|
|
state file-s produced by gengtype on the same GCC source tree are
|
|
|
|
|
very similar and can be reasonably compared with diff, even if the
|
|
|
|
|
two GCC source trees have different absolute paths. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_fileloc (struct fileloc *floc)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("srcfileloc");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (srcrelpath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("fileloc");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (get_input_file_name (floc->file));
|
|
|
|
|
}
|
|
|
|
|
fprintf (state_file, " %d", floc->line);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fprintf (state_file, "nil ");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a list of fields. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_fields (pair_p fields)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbfields = pair_list_length (fields);
|
|
|
|
|
int nbpairs = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("fields");
|
|
|
|
|
fprintf (state_file, "%d ", nbfields);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
nbpairs = write_state_pair_list (fields);
|
|
|
|
|
gcc_assert (nbpairs == nbfields);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a null-terminated string in our lexical convention, very
|
|
|
|
|
similar to the convention of C. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_a_string (const char *s)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
char c;
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (1);
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_string_option (options_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "string ");
|
|
|
|
|
if (current->info.string != NULL)
|
|
|
|
|
write_state_a_string (current->info.string);
|
|
|
|
|
else
|
|
|
|
|
fprintf (state_file, " nil ");
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_type_option (options_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "type ");
|
|
|
|
|
write_state_type (current->info.type);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_nested_option (options_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_any_indent (1);
|
|
|
|
|
fprintf (state_file, " nil ");
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
if (current->info.nested->convert_to != NULL)
|
|
|
|
|
write_state_a_string (current->info.nested->convert_to);
|
|
|
|
|
else
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_any_indent (1);
|
|
|
|
|
fprintf (state_file, " nil ");
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_option (options_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("option");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the "option" s-expression. */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Write a list of GTY options. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_options (options_p opt)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
options_p current;
|
|
|
|
|
|
|
|
|
|
if (opt == NULL)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "nil ");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("options");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
for (current = opt; current != NULL; current = current->next)
|
|
|
|
|
write_state_option (current);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Write a bitmap representing a set of GCC front-end languages. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_lang_bitmap (lang_bitmap bitmap)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "%d ", (int) bitmap);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write version information. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_version (const char *version)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("version");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (version);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a scalar type. We have only two of these. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_scalar_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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! */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_string_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
if (current == &string_type)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "string ");
|
|
|
|
|
write_state_common_type_content (current);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal ("Unexpected type in write_state_string_type");
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
/* Write the callback type. There is only one such thing! */
|
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_callback_type (type_p current)
|
|
|
|
|
{
|
|
|
|
|
if (current == &callback_type)
|
|
|
|
|
{
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "callback ");
|
|
|
|
|
write_state_common_type_content (current);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal ("Unexpected type in write_state_callback_type");
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Write an undefined type. */
|
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_undefined_type (type_p current)
|
|
|
|
|
{
|
|
|
|
|
DBGPRINTF ("undefined type @ %p #%d '%s'", (void *) current,
|
|
|
|
|
current->state_number, current->u.s.tag);
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "undefined ");
|
|
|
|
|
gcc_assert (current->gc_used == GC_UNUSED);
|
|
|
|
|
write_state_common_type_content (current);
|
|
|
|
|
if (current->u.s.tag != NULL)
|
|
|
|
|
write_state_a_string (current->u.s.tag);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "nil");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
write_state_fileloc (type_lineloc (current));
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
/* Common code to write structure like types. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_struct_union_type (type_p current,
|
|
|
|
|
const char *kindstr)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
DBGPRINTF ("%s type @ %p #%d '%s'", kindstr, (void *) current,
|
|
|
|
|
current->state_number, current->u.s.tag);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "nil");
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_struct_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
write_state_struct_union_type (current, "struct");
|
|
|
|
|
write_state_type (current->u.s.lang_struct);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_state_type (current->u.s.base_class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a GTY user-defined struct type. */
|
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_user_struct_type (type_p current)
|
|
|
|
|
{
|
|
|
|
|
DBGPRINTF ("user_struct type @ %p #%d '%s'", (void *) current,
|
|
|
|
|
current->state_number, current->u.s.tag);
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "user_struct ");
|
|
|
|
|
write_state_common_type_content (current);
|
|
|
|
|
if (current->u.s.tag != NULL)
|
|
|
|
|
write_state_a_string (current->u.s.tag);
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "nil");
|
|
|
|
|
}
|
|
|
|
|
write_state_fileloc (type_lineloc (current));
|
|
|
|
|
write_state_fields (current->u.s.fields);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* write a GTY union type. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_union_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_lang_struct_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbhomontype = 0;
|
|
|
|
|
type_p hty = NULL;
|
|
|
|
|
const char *homoname = 0;
|
|
|
|
|
write_state_struct_union_type (current, "lang_struct");
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* lang_struct-ures are particularly tricky, since their
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
gcc_assert (union_or_struct_p (hty));
|
2012-03-27 23:13:14 +00:00
|
|
|
|
gcc_assert (hty->u.s.lang_struct == current);
|
|
|
|
|
if (!homoname)
|
|
|
|
|
homoname = hty->u.s.tag;
|
|
|
|
|
gcc_assert (strcmp (homoname, hty->u.s.tag) == 0);
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("homotypes");
|
|
|
|
|
fprintf (state_file, "%d", nbhomontype);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
for (hty = current->u.s.lang_struct; hty != NULL; hty = hty->next)
|
|
|
|
|
write_state_type (hty);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a pointer type. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_pointer_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "pointer ");
|
|
|
|
|
write_state_common_type_content (current);
|
|
|
|
|
write_state_type (current->u.p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write an array type. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_array_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_any_indent (1);
|
|
|
|
|
fprintf (state_file, " nil");
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (1);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, " ");
|
|
|
|
|
write_state_type (current->u.a.p);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write the gc_used information. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_gc_used (enum gc_used_enum gus)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (1);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_common_type_content (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_type (type_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (current == NULL)
|
|
|
|
|
{
|
|
|
|
|
fprintf (state_file, "nil ");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("type");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
if (current->state_number > 0)
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_any_indent (0);
|
|
|
|
|
fprintf (state_file, "already_seen %d", current->state_number);
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
m_state_written_type_count++;
|
|
|
|
|
DBGPRINTF ("writing type #%d @%p old number %d", m_state_written_type_count,
|
2012-03-27 23:13:14 +00:00
|
|
|
|
(void *) current, current->state_number);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
current->state_number = m_state_written_type_count;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
switch (current->kind)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case TYPE_NONE:
|
|
|
|
|
gcc_unreachable ();
|
|
|
|
|
case TYPE_UNDEFINED:
|
|
|
|
|
write_state_undefined_type (current);
|
|
|
|
|
break;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case TYPE_STRUCT:
|
|
|
|
|
write_state_struct_type (current);
|
|
|
|
|
break;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case TYPE_USER_STRUCT:
|
|
|
|
|
write_state_user_struct_type (current);
|
|
|
|
|
break;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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_SCALAR:
|
|
|
|
|
write_state_scalar_type (current);
|
|
|
|
|
break;
|
|
|
|
|
case TYPE_STRING:
|
|
|
|
|
write_state_string_type (current);
|
|
|
|
|
break;
|
2022-10-27 18:55:19 +00:00
|
|
|
|
case TYPE_CALLBACK:
|
|
|
|
|
write_state_callback_type (current);
|
|
|
|
|
break;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the "type" s-expression. */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Write a pair. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_pair (pair_p current)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
if (current == NULL)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
write_any_indent (0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fprintf (state_file, "nil)");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("pair");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the "pair" s-expression. */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write a pair list and return the number of pairs written. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
int
|
|
|
|
|
state_writer::write_state_pair_list (pair_p list)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbpair = 0;
|
|
|
|
|
pair_p current;
|
|
|
|
|
|
|
|
|
|
for (current = list; current != NULL; current = current->next)
|
|
|
|
|
{
|
|
|
|
|
write_state_pair (current);
|
|
|
|
|
nbpair++;
|
|
|
|
|
}
|
|
|
|
|
return nbpair;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
|
/* When writing imported linked lists, like typedefs, structures, ... we count
|
|
|
|
|
their length first and write it. This eases the reading, and enables an
|
|
|
|
|
extra verification on the number of actually read items. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
/* Write our typedefs. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_typedefs (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbtypedefs = pair_list_length (typedefs);
|
|
|
|
|
int nbpairs = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("typedefs");
|
|
|
|
|
fprintf (state_file, "%d", nbtypedefs);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
nbpairs = write_state_pair_list (typedefs);
|
|
|
|
|
gcc_assert (nbpairs == nbtypedefs);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (verbosity_level >= 2)
|
|
|
|
|
printf ("%s wrote %d typedefs\n", progname, nbtypedefs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write our structures. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_structures (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbstruct = 0;
|
|
|
|
|
type_p current;
|
|
|
|
|
|
|
|
|
|
for (current = structures; current != NULL; current = current->next)
|
|
|
|
|
nbstruct++;
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("structures");
|
|
|
|
|
fprintf (state_file, "%d", nbstruct);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
for (current = structures; current != NULL; current = current->next)
|
2014-09-21 17:33:12 +00:00
|
|
|
|
{
|
|
|
|
|
write_new_line ();
|
|
|
|
|
write_state_type (current);
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the "structures" s-expression. */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (verbosity_level >= 2)
|
|
|
|
|
printf ("%s wrote %d structures in state\n", progname, nbstruct);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write our variables. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_variables (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int nbvars = pair_list_length (variables);
|
|
|
|
|
int nbpairs = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("variables");
|
|
|
|
|
fprintf (state_file, "%d", nbvars);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
nbpairs = write_state_pair_list (variables);
|
|
|
|
|
gcc_assert (nbpairs == nbvars);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_srcdir (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("srcdir");
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (srcdir);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Count and write the list of our files. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_files_list (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
/* Write the list of files with their lang_bitmap. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("fileslist");
|
2022-10-27 18:55:19 +00:00
|
|
|
|
fprintf (state_file, "%d %d", (int) num_gt_files, (int) num_build_headers);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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)
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("srcfile");
|
|
|
|
|
fprintf (state_file, "%d ", get_lang_bitmap (curfil));
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (cursrcrelpath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("file");
|
|
|
|
|
fprintf (state_file, "%d ", get_lang_bitmap (curfil));
|
2012-03-27 23:13:14 +00:00
|
|
|
|
write_state_a_string (get_input_file_name (curfil));
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the inner s-expression (either "srcfile" or "file"). */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Terminate the "fileslist" s-expression. */
|
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write the list of GCC front-end languages. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
void
|
|
|
|
|
state_writer::write_state_languages (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
begin_s_expr ("languages");
|
|
|
|
|
fprintf (state_file, "%d", (int) num_lang_dirs);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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]);
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
end_s_expr ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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
|
2022-10-27 18:55:19 +00:00
|
|
|
|
in gengtype.cc. To avoid messing the state if gengtype is
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
state_writer sw;
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* The first non-comment significant line gives the version string. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
sw.write_state_version (version_string);
|
|
|
|
|
sw.write_state_srcdir ();
|
|
|
|
|
sw.write_state_languages ();
|
|
|
|
|
sw.write_state_files_list ();
|
|
|
|
|
sw.write_state_structures ();
|
|
|
|
|
sw.write_state_typedefs ();
|
|
|
|
|
sw.write_state_variables ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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",
|
2014-09-21 17:33:12 +00:00
|
|
|
|
progname, state_path, statelen, sw.m_state_written_type_count);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
/* Read the callback_type. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_callback_type (type_p *type)
|
|
|
|
|
{
|
|
|
|
|
*type = &callback_type;
|
|
|
|
|
read_state_common_type_content (*type);
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
/* 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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Read an undefined type. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_undefined_type (type_p type)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0;
|
|
|
|
|
|
|
|
|
|
type->kind = TYPE_UNDEFINED;
|
|
|
|
|
read_state_common_type_content (type);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING)
|
|
|
|
|
{
|
|
|
|
|
if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
type->u.s.tag = NULL;
|
|
|
|
|
DBGPRINTF ("read anonymous undefined type @%p #%d",
|
|
|
|
|
(void *) type, type->state_number);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
type->u.s.tag = xstrdup (t0->stok_un.stok_string);
|
|
|
|
|
DBGPRINTF ("read undefined type @%p #%d '%s'",
|
|
|
|
|
(void *) type, type->state_number, type->u.s.tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_fileloc (&(type->u.s.line));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fatal_reading_state (t0, "Bad tag in undefined type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* 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));
|
2014-09-21 17:33:12 +00:00
|
|
|
|
read_state_type (&(type->u.s.base_class));
|
|
|
|
|
if (type->u.s.base_class)
|
|
|
|
|
add_subclass (type->u.s.base_class, type);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fatal_reading_state (t0, "Bad tag in struct type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Read a GTY-ed user-provided struct TYPE. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
read_state_user_struct_type (type_p type)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0;
|
|
|
|
|
|
|
|
|
|
type->kind = TYPE_USER_STRUCT;
|
|
|
|
|
read_state_common_type_content (type);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING)
|
|
|
|
|
{
|
|
|
|
|
if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
type->u.s.tag = NULL;
|
|
|
|
|
DBGPRINTF ("read anonymous struct type @%p #%d",
|
|
|
|
|
(void *) type, type->state_number);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
type->u.s.tag = xstrdup (t0->stok_un.stok_string);
|
|
|
|
|
DBGPRINTF ("read struct type @%p #%d '%s'",
|
|
|
|
|
(void *) type, type->state_number, type->u.s.tag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_fileloc (&(type->u.s.line));
|
|
|
|
|
read_state_fields (&(type->u.s.fields));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fatal_reading_state (t0, "Bad tag in user-struct type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* 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 the gc used information. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_gc_used (enum gc_used_enum *pgus)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_is_name (t0, "gc_unused"))
|
|
|
|
|
*pgus = GC_UNUSED;
|
|
|
|
|
else if (state_token_is_name (t0, "gc_used"))
|
|
|
|
|
*pgus = GC_USED;
|
|
|
|
|
else if (state_token_is_name (t0, "gc_maybe_pointed_to"))
|
|
|
|
|
*pgus = GC_MAYBE_POINTED_TO;
|
|
|
|
|
else if (state_token_is_name (t0, "gc_pointed_to"))
|
|
|
|
|
*pgus = GC_POINTED_TO;
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "invalid gc_used information");
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Utility function to read the common content of types. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_common_type_content (type_p current)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
current->state_number = t0->stok_un.stok_num;
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
record_type (current);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state_printf (t0,
|
|
|
|
|
"Expected integer for state_number line %d",
|
|
|
|
|
state_line);
|
|
|
|
|
/* We don't read the next field of the type. */
|
|
|
|
|
read_state_type (¤t->pointer_to);
|
|
|
|
|
read_state_gc_used (¤t->gc_used);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a GTY-ed type. */
|
|
|
|
|
void
|
|
|
|
|
read_state_type (type_p *current)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR &&
|
|
|
|
|
state_token_is_name (t1, "!type"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (2);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_is_name (t0, "already_seen"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_already_seen_type (current);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
|
|
|
|
|
if (state_token_is_name (t0, "scalar_nonchar"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_scalar_nonchar_type (current);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "scalar_char"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_scalar_char_type (current);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "string"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_string_type (current);
|
|
|
|
|
}
|
2022-10-27 18:55:19 +00:00
|
|
|
|
else if (state_token_is_name (t0, "callback"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_callback_type (current);
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
else if (state_token_is_name (t0, "undefined"))
|
|
|
|
|
{
|
|
|
|
|
*current = XCNEW (struct type);
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_undefined_type (*current);
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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, "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);
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
else if (state_token_is_name (t0, "user_struct"))
|
|
|
|
|
{
|
|
|
|
|
*current = XCNEW (struct type);
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_user_struct_type (*current);
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "bad type in (!type");
|
|
|
|
|
}
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
fatal_reading_state (t0, "missing ) in type");
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
*current = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "bad type syntax");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a file location. Files within the source directory are dealt
|
|
|
|
|
with specifically. */
|
|
|
|
|
void
|
|
|
|
|
read_state_fileloc (struct fileloc *floc)
|
|
|
|
|
{
|
|
|
|
|
bool issrcfile = false;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
|
|
|
|
|
gcc_assert (floc != NULL);
|
|
|
|
|
gcc_assert (srcdir != NULL);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR &&
|
|
|
|
|
(state_token_is_name (t1, "!fileloc")
|
|
|
|
|
|| (issrcfile = state_token_is_name (t1, "!srcfileloc"))))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (2);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
t1 = peek_state_token (1);
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING &&
|
|
|
|
|
state_token_kind (t1) == STOK_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
char *path = t0->stok_un.stok_string;
|
|
|
|
|
if (issrcfile)
|
|
|
|
|
{
|
|
|
|
|
static const char dirsepstr[2] = { DIR_SEPARATOR, (char) 0 };
|
|
|
|
|
char *fullpath = concat (srcdir, dirsepstr, path, NULL);
|
|
|
|
|
floc->file = input_file_by_name (fullpath);
|
|
|
|
|
free (fullpath);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
floc->file = input_file_by_name (path);
|
|
|
|
|
floc->line = t1->stok_un.stok_num;
|
|
|
|
|
next_state_tokens (2);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0,
|
|
|
|
|
"Bad fileloc syntax, expected path string and line");
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
fatal_reading_state (t0, "Bad fileloc syntax, expected )");
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
floc->file = NULL;
|
|
|
|
|
floc->line = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad fileloc syntax");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the fields of a GTY-ed type. */
|
|
|
|
|
void
|
|
|
|
|
read_state_fields (pair_p *fields)
|
|
|
|
|
{
|
|
|
|
|
pair_p tmp = NULL;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
struct state_token_st *t2 = peek_state_token (2);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR
|
|
|
|
|
&& state_token_is_name (t1, "!fields")
|
|
|
|
|
&& state_token_kind (t2) == STOK_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
int nbfields = t2->stok_un.stok_num;
|
|
|
|
|
int nbpairs = 0;
|
|
|
|
|
next_state_tokens (3);
|
|
|
|
|
nbpairs = read_state_pair_list (&tmp);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (nbpairs != nbfields)
|
|
|
|
|
fatal_reading_state_printf
|
|
|
|
|
(t0,
|
|
|
|
|
"Mismatched fields number, expected %d got %d", nbpairs, nbfields);
|
|
|
|
|
if (state_token_kind (t0) == STOK_RIGHTPAR)
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad fields expecting )");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*fields = tmp;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a string option. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_string_option (options_p opt)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
opt->kind = OPTION_STRING;
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING)
|
|
|
|
|
{
|
|
|
|
|
opt->info.string = xstrdup (t0->stok_un.stok_string);
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
opt->info.string = NULL;
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Missing name in string option");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a type option. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_type_option (options_p opt)
|
|
|
|
|
{
|
|
|
|
|
opt->kind = OPTION_TYPE;
|
|
|
|
|
read_state_type (&(opt->info.type));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a nested option. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_nested_option (options_p opt)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0;
|
|
|
|
|
|
|
|
|
|
opt->info.nested = XCNEW (struct nested_ptr_data);
|
|
|
|
|
opt->kind = OPTION_NESTED;
|
|
|
|
|
read_state_type (&(opt->info.nested->type));
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING)
|
|
|
|
|
{
|
|
|
|
|
opt->info.nested->convert_from = xstrdup (t0->stok_un.stok_string);
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
opt->info.nested->convert_from = NULL;
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad nested convert_from option");
|
|
|
|
|
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_STRING)
|
|
|
|
|
{
|
|
|
|
|
opt->info.nested->convert_to = xstrdup (t0->stok_un.stok_string);
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
opt->info.nested->convert_to = NULL;
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad nested convert_from option");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read an GTY option. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_option (options_p *opt)
|
|
|
|
|
{
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR &&
|
|
|
|
|
state_token_is_name (t1, "!option"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (2);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_NAME)
|
|
|
|
|
{
|
|
|
|
|
*opt = XCNEW (struct options);
|
|
|
|
|
if (state_token_is_name (t0, "nil"))
|
|
|
|
|
(*opt)->name = NULL;
|
|
|
|
|
else
|
|
|
|
|
(*opt)->name = t0->stok_un.stok_ident->stid_name;
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_NAME)
|
|
|
|
|
{
|
|
|
|
|
if (state_token_is_name (t0, "string"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_string_option (*opt);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "type"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_type_option (*opt);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nested"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
read_state_nested_option (*opt);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad option type");
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
fatal_reading_state (t0, "Bad syntax in option, expecting )");
|
|
|
|
|
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Missing option type");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad name for option");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad option, waiting for )");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read a list of options. */
|
|
|
|
|
void
|
|
|
|
|
read_state_options (options_p *opt)
|
|
|
|
|
{
|
|
|
|
|
options_p head = NULL;
|
|
|
|
|
options_p previous = NULL;
|
|
|
|
|
options_p current_option = NULL;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR &&
|
|
|
|
|
state_token_is_name (t1, "!options"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (2);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
while (state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
{
|
|
|
|
|
read_state_option (¤t_option);
|
|
|
|
|
if (head == NULL)
|
|
|
|
|
{
|
|
|
|
|
head = current_option;
|
|
|
|
|
previous = head;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
previous->next = current_option;
|
|
|
|
|
previous = current_option;
|
|
|
|
|
}
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
}
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad options syntax");
|
|
|
|
|
|
|
|
|
|
*opt = head;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read a version, and check against the version of the gengtype. */
|
|
|
|
|
static void
|
2022-10-27 18:55:19 +00:00
|
|
|
|
read_state_version (const char *ver_string)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
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. */
|
2022-10-27 18:55:19 +00:00
|
|
|
|
if (strcmp (ver_string, t0->stok_un.stok_string))
|
2012-03-27 23:13:14 +00:00
|
|
|
|
fatal_reading_state_printf (t0,
|
|
|
|
|
"version string mismatch; expecting %s but got %s",
|
2022-10-27 18:55:19 +00:00
|
|
|
|
ver_string,
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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));
|
2018-12-28 15:30:48 +00:00
|
|
|
|
read_state_options (&((*current)->opt));
|
2012-03-27 23:13:14 +00:00
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (state_token_kind (t0) == STOK_RIGHTPAR)
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fatal_reading_state (t0, "Bad syntax for pair, )");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
fatal_reading_state (t0, "Bad name for pair");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (state_token_kind (t0) == STOK_NAME &&
|
|
|
|
|
state_token_is_name (t0, "nil"))
|
|
|
|
|
{
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
*current = NULL;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state_printf (t0, "Bad syntax for pair, (!pair %d",
|
|
|
|
|
state_token->stok_kind);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Return the number of pairs actually read. */
|
|
|
|
|
int
|
|
|
|
|
read_state_pair_list (pair_p *list)
|
|
|
|
|
{
|
|
|
|
|
int nbpair = 0;
|
|
|
|
|
pair_p head = NULL;
|
|
|
|
|
pair_p previous = NULL;
|
|
|
|
|
pair_p tmp = NULL;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
{
|
|
|
|
|
read_state_pair (&tmp);
|
|
|
|
|
if (head == NULL)
|
|
|
|
|
{
|
|
|
|
|
head = tmp;
|
|
|
|
|
previous = head;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
previous->next = tmp;
|
|
|
|
|
previous = tmp;
|
|
|
|
|
}
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
nbpair++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* don't consume the ); the caller will eat it. */
|
|
|
|
|
*list = head;
|
|
|
|
|
return nbpair;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the typedefs. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_typedefs (pair_p *typedefs)
|
|
|
|
|
{
|
|
|
|
|
int nbtypedefs = 0;
|
|
|
|
|
pair_p list = NULL;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
struct state_token_st *t2 = peek_state_token (2);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR
|
|
|
|
|
&& state_token_is_name (t1, "!typedefs")
|
|
|
|
|
&& state_token_kind (t2) == STOK_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
int nbpairs = 0;
|
|
|
|
|
nbtypedefs = t2->stok_un.stok_num;
|
|
|
|
|
next_state_tokens (3);
|
|
|
|
|
nbpairs = read_state_pair_list (&list);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
if (nbpairs != nbtypedefs)
|
|
|
|
|
fatal_reading_state_printf
|
|
|
|
|
(t0,
|
|
|
|
|
"invalid number of typedefs, expected %d but got %d",
|
|
|
|
|
nbtypedefs, nbpairs);
|
|
|
|
|
if (state_token_kind (t0) == STOK_RIGHTPAR)
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad typedefs syntax )");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad typedefs syntax (!typedefs");
|
|
|
|
|
|
|
|
|
|
if (verbosity_level >= 2)
|
|
|
|
|
printf ("%s read %d typedefs from state\n", progname, nbtypedefs);
|
|
|
|
|
*typedefs = list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the structures. */
|
|
|
|
|
static void
|
|
|
|
|
read_state_structures (type_p *structures)
|
|
|
|
|
{
|
|
|
|
|
type_p head = NULL;
|
|
|
|
|
type_p previous = NULL;
|
|
|
|
|
type_p tmp;
|
|
|
|
|
int nbstruct = 0, countstruct = 0;
|
|
|
|
|
struct state_token_st *t0 = peek_state_token (0);
|
|
|
|
|
struct state_token_st *t1 = peek_state_token (1);
|
|
|
|
|
struct state_token_st *t2 = peek_state_token (2);
|
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR
|
|
|
|
|
&& state_token_is_name (t1, "!structures")
|
|
|
|
|
&& state_token_kind (t2) == STOK_INTEGER)
|
|
|
|
|
{
|
|
|
|
|
nbstruct = t2->stok_un.stok_num;
|
|
|
|
|
next_state_tokens (3);
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
while (t0 && state_token_kind (t0) != STOK_RIGHTPAR)
|
|
|
|
|
{
|
|
|
|
|
tmp = NULL;
|
|
|
|
|
read_state_type (&tmp);
|
|
|
|
|
countstruct++;
|
|
|
|
|
if (head == NULL)
|
|
|
|
|
{
|
|
|
|
|
head = tmp;
|
|
|
|
|
previous = head;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
previous->next = tmp;
|
|
|
|
|
previous = tmp;
|
|
|
|
|
}
|
|
|
|
|
t0 = peek_state_token (0);
|
|
|
|
|
}
|
|
|
|
|
next_state_tokens (1);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
fatal_reading_state (t0, "Bad structures syntax");
|
|
|
|
|
if (countstruct != nbstruct)
|
|
|
|
|
fatal_reading_state_printf (NULL_STATE_TOKEN,
|
|
|
|
|
"expected %d structures but got %d",
|
|
|
|
|
nbstruct, countstruct);
|
|
|
|
|
if (verbosity_level >= 2)
|
|
|
|
|
printf ("%s read %d structures from state\n", progname, nbstruct);
|
|
|
|
|
*structures = head;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Read the 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);
|
2022-10-27 18:55:19 +00:00
|
|
|
|
struct state_token_st *t3 = peek_state_token (3);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
if (state_token_kind (t0) == STOK_LEFTPAR
|
|
|
|
|
&& state_token_is_name (t1, "!fileslist")
|
2022-10-27 18:55:19 +00:00
|
|
|
|
&& state_token_kind (t2) == STOK_INTEGER
|
|
|
|
|
&& state_token_kind (t3) == STOK_INTEGER)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2022-10-27 18:55:19 +00:00
|
|
|
|
int i = 0, j = 0;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
num_gt_files = t2->stok_un.stok_num;
|
2022-10-27 18:55:19 +00:00
|
|
|
|
num_build_headers = t3->stok_un.stok_num;
|
|
|
|
|
next_state_tokens (4);
|
|
|
|
|
t0 = t1 = t2 = t3 = NULL;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
gt_files = XCNEWVEC (const input_file *, num_gt_files);
|
2022-10-27 18:55:19 +00:00
|
|
|
|
build_headers = XCNEWVEC (const char *, num_build_headers);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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
|
2022-10-27 18:55:19 +00:00
|
|
|
|
{
|
|
|
|
|
curgt = input_file_by_name (fnam);
|
|
|
|
|
/* Look for a header file created during the build,
|
|
|
|
|
which looks like "./<filename>.h". */
|
|
|
|
|
int len = strlen (fnam);
|
|
|
|
|
if (len >= 5
|
|
|
|
|
&& fnam[0] == '.'
|
|
|
|
|
&& IS_DIR_SEPARATOR (fnam[1])
|
|
|
|
|
&& fnam[len-2] == '.'
|
|
|
|
|
&& fnam[len-1] == 'h')
|
|
|
|
|
{
|
|
|
|
|
char *buf = (char *) xmalloc (len - 1);
|
|
|
|
|
/* Strip the leading "./" from the filename. */
|
|
|
|
|
strcpy (buf, &fnam[2]);
|
|
|
|
|
build_headers[j++] = buf;
|
|
|
|
|
}
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
if (state_token_kind (t0) != STOK_RIGHTPAR)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
/* The function reading the state, called by main from gengtype.cc. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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 =
|
2022-10-27 18:55:19 +00:00
|
|
|
|
htab_create (4027, htab_hash_string, htab_eq_string, NULL);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
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_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;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
/* End of file gengtype-state.cc. */
|