2012-03-27 23:13:14 +00:00
|
|
|
|
/* Process source files and output type information.
|
2022-10-27 18:55:19 +00:00
|
|
|
|
Copyright (C) 2006-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/>. */
|
|
|
|
|
|
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 "gengtype.h"
|
|
|
|
|
|
|
|
|
|
/* This is a simple recursive-descent parser which understands a subset of
|
|
|
|
|
the C type grammar.
|
|
|
|
|
|
|
|
|
|
Rule functions are suffixed _seq if they scan a sequence of items;
|
|
|
|
|
_opt if they may consume zero tokens; _seqopt if both are true. The
|
|
|
|
|
"consume_" prefix indicates that a sequence of tokens is parsed for
|
|
|
|
|
syntactic correctness and then thrown away. */
|
|
|
|
|
|
|
|
|
|
/* Simple one-token lookahead mechanism. */
|
|
|
|
|
|
|
|
|
|
struct token
|
|
|
|
|
{
|
|
|
|
|
const char *value;
|
|
|
|
|
int code;
|
|
|
|
|
bool valid;
|
|
|
|
|
};
|
|
|
|
|
static struct token T;
|
|
|
|
|
|
|
|
|
|
/* Retrieve the code of the current token; if there is no current token,
|
|
|
|
|
get the next one from the lexer. */
|
|
|
|
|
static inline int
|
|
|
|
|
token (void)
|
|
|
|
|
{
|
|
|
|
|
if (!T.valid)
|
|
|
|
|
{
|
|
|
|
|
T.code = yylex (&T.value);
|
|
|
|
|
T.valid = true;
|
|
|
|
|
}
|
|
|
|
|
return T.code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Retrieve the value of the current token (if any) and mark it consumed.
|
|
|
|
|
The next call to token() will get another token from the lexer. */
|
|
|
|
|
static inline const char *
|
|
|
|
|
advance (void)
|
|
|
|
|
{
|
|
|
|
|
T.valid = false;
|
|
|
|
|
return T.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Diagnostics. */
|
|
|
|
|
|
|
|
|
|
/* This array is indexed by the token code minus CHAR_TOKEN_OFFSET. */
|
|
|
|
|
static const char *const token_names[] = {
|
|
|
|
|
"GTY",
|
|
|
|
|
"typedef",
|
|
|
|
|
"extern",
|
|
|
|
|
"static",
|
|
|
|
|
"union",
|
|
|
|
|
"struct",
|
|
|
|
|
"enum",
|
|
|
|
|
"...",
|
|
|
|
|
"ptr_alias",
|
|
|
|
|
"nested_ptr",
|
|
|
|
|
"a param<N>_is option",
|
|
|
|
|
"a number",
|
|
|
|
|
"a scalar type",
|
|
|
|
|
"an identifier",
|
|
|
|
|
"a string constant",
|
|
|
|
|
"a character constant",
|
|
|
|
|
"an array declarator",
|
2014-09-21 17:33:12 +00:00
|
|
|
|
"a C++ keyword to ignore"
|
2012-03-27 23:13:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* This array is indexed by token code minus FIRST_TOKEN_WITH_VALUE. */
|
|
|
|
|
static const char *const token_value_format[] = {
|
|
|
|
|
"%s",
|
|
|
|
|
"'%s'",
|
|
|
|
|
"'%s'",
|
|
|
|
|
"'%s'",
|
|
|
|
|
"'\"%s\"'",
|
|
|
|
|
"\"'%s'\"",
|
|
|
|
|
"'[%s]'",
|
2014-09-21 17:33:12 +00:00
|
|
|
|
"'%s'",
|
2012-03-27 23:13:14 +00:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Produce a printable representation for a token defined by CODE and
|
|
|
|
|
VALUE. This sometimes returns pointers into malloc memory and
|
|
|
|
|
sometimes not, therefore it is unsafe to free the pointer it
|
|
|
|
|
returns, so that memory is leaked. This does not matter, as this
|
|
|
|
|
function is only used for diagnostics, and in a successful run of
|
|
|
|
|
the program there will be none. */
|
|
|
|
|
static const char *
|
|
|
|
|
print_token (int code, const char *value)
|
|
|
|
|
{
|
|
|
|
|
if (code < CHAR_TOKEN_OFFSET)
|
|
|
|
|
return xasprintf ("'%c'", code);
|
|
|
|
|
else if (code < FIRST_TOKEN_WITH_VALUE)
|
|
|
|
|
return xasprintf ("'%s'", token_names[code - CHAR_TOKEN_OFFSET]);
|
|
|
|
|
else if (!value)
|
|
|
|
|
return token_names[code - CHAR_TOKEN_OFFSET]; /* don't quote these */
|
|
|
|
|
else
|
|
|
|
|
return xasprintf (token_value_format[code - FIRST_TOKEN_WITH_VALUE],
|
|
|
|
|
value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Convenience wrapper around print_token which produces the printable
|
|
|
|
|
representation of the current token. */
|
|
|
|
|
static inline const char *
|
|
|
|
|
print_cur_token (void)
|
|
|
|
|
{
|
|
|
|
|
return print_token (T.code, T.value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Report a parse error on the current line, with diagnostic MSG.
|
|
|
|
|
Behaves as standard printf with respect to additional arguments and
|
|
|
|
|
format escapes. */
|
|
|
|
|
static void ATTRIBUTE_PRINTF_1
|
|
|
|
|
parse_error (const char *msg, ...)
|
|
|
|
|
{
|
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
|
|
fprintf (stderr, "%s:%d: parse error: ",
|
|
|
|
|
get_input_file_name (lexer_line.file), lexer_line.line);
|
|
|
|
|
|
|
|
|
|
va_start (ap, msg);
|
|
|
|
|
vfprintf (stderr, msg, ap);
|
|
|
|
|
va_end (ap);
|
|
|
|
|
|
|
|
|
|
fputc ('\n', stderr);
|
|
|
|
|
|
|
|
|
|
hit_error = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* If the next token does not have code T, report a parse error; otherwise
|
|
|
|
|
return the token's value. */
|
|
|
|
|
static const char *
|
|
|
|
|
require (int t)
|
|
|
|
|
{
|
|
|
|
|
int u = token ();
|
|
|
|
|
const char *v = advance ();
|
|
|
|
|
if (u != t)
|
|
|
|
|
{
|
|
|
|
|
parse_error ("expected %s, have %s",
|
|
|
|
|
print_token (t, 0), print_token (u, v));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* As per require, but do not advance. */
|
|
|
|
|
static const char *
|
|
|
|
|
require_without_advance (int t)
|
|
|
|
|
{
|
|
|
|
|
int u = token ();
|
|
|
|
|
const char *v = T.value;
|
|
|
|
|
if (u != t)
|
|
|
|
|
{
|
|
|
|
|
parse_error ("expected %s, have %s",
|
|
|
|
|
print_token (t, 0), print_token (u, v));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* If the next token does not have one of the codes T1 or T2, report a
|
|
|
|
|
parse error; otherwise return the token's value. */
|
|
|
|
|
static const char *
|
|
|
|
|
require2 (int t1, int t2)
|
|
|
|
|
{
|
|
|
|
|
int u = token ();
|
|
|
|
|
const char *v = advance ();
|
|
|
|
|
if (u != t1 && u != t2)
|
|
|
|
|
{
|
|
|
|
|
parse_error ("expected %s or %s, have %s",
|
|
|
|
|
print_token (t1, 0), print_token (t2, 0),
|
|
|
|
|
print_token (u, v));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-28 15:33:40 +00:00
|
|
|
|
/* If the next token does not have one of the codes T1, T2, T3 or T4, report a
|
|
|
|
|
parse error; otherwise return the token's value. */
|
|
|
|
|
static const char *
|
|
|
|
|
require4 (int t1, int t2, int t3, int t4)
|
|
|
|
|
{
|
|
|
|
|
int u = token ();
|
|
|
|
|
const char *v = advance ();
|
|
|
|
|
if (u != t1 && u != t2 && u != t3 && u != t4)
|
|
|
|
|
{
|
|
|
|
|
parse_error ("expected %s, %s, %s or %s, have %s",
|
|
|
|
|
print_token (t1, 0), print_token (t2, 0),
|
|
|
|
|
print_token (t3, 0), print_token (t4, 0),
|
|
|
|
|
print_token (u, v));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* Near-terminals. */
|
|
|
|
|
|
|
|
|
|
/* C-style string constant concatenation: STRING+
|
|
|
|
|
Bare STRING should appear nowhere else in this file. */
|
|
|
|
|
static const char *
|
|
|
|
|
string_seq (void)
|
|
|
|
|
{
|
|
|
|
|
const char *s1, *s2;
|
|
|
|
|
size_t l1, l2;
|
|
|
|
|
char *buf;
|
|
|
|
|
|
|
|
|
|
s1 = require (STRING);
|
|
|
|
|
if (s1 == 0)
|
|
|
|
|
return "";
|
|
|
|
|
while (token () == STRING)
|
|
|
|
|
{
|
|
|
|
|
s2 = advance ();
|
|
|
|
|
|
|
|
|
|
l1 = strlen (s1);
|
|
|
|
|
l2 = strlen (s2);
|
|
|
|
|
buf = XRESIZEVEC (char, CONST_CAST (char *, s1), l1 + l2 + 1);
|
|
|
|
|
memcpy (buf + l1, s2, l2 + 1);
|
|
|
|
|
XDELETE (CONST_CAST (char *, s2));
|
|
|
|
|
s1 = buf;
|
|
|
|
|
}
|
|
|
|
|
return s1;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
/* The caller has detected a template declaration that starts
|
|
|
|
|
with TMPL_NAME. Parse up to the closing '>'. This recognizes
|
2015-08-28 15:33:40 +00:00
|
|
|
|
simple template declarations of the form ID<ID1,ID2,...,IDn>,
|
|
|
|
|
potentially with a single level of indirection e.g.
|
|
|
|
|
ID<ID1 *, ID2, ID3 *, ..., IDn>.
|
2014-09-21 17:33:12 +00:00
|
|
|
|
It does not try to parse anything more sophisticated than that.
|
|
|
|
|
|
|
|
|
|
Returns the template declaration string "ID<ID1,ID2,...,IDn>". */
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
static const char *
|
2014-09-21 17:33:12 +00:00
|
|
|
|
require_template_declaration (const char *tmpl_name)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
char *str;
|
2015-08-28 15:33:40 +00:00
|
|
|
|
int num_indirections = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
/* Recognize the opening '<'. */
|
|
|
|
|
require ('<');
|
|
|
|
|
str = concat (tmpl_name, "<", (char *) 0);
|
|
|
|
|
|
|
|
|
|
/* Read the comma-separated list of identifiers. */
|
2015-08-28 15:33:40 +00:00
|
|
|
|
int depth = 1;
|
|
|
|
|
while (depth > 0)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
2015-08-28 15:33:40 +00:00
|
|
|
|
if (token () == ENUM)
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
str = concat (str, "enum ", (char *) 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2017-04-10 11:32:00 +00:00
|
|
|
|
if (token () == NUM
|
|
|
|
|
|| token () == ':'
|
|
|
|
|
|| token () == '+')
|
2015-08-28 15:33:40 +00:00
|
|
|
|
{
|
|
|
|
|
str = concat (str, advance (), (char *) 0);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (token () == '<')
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
str = concat (str, "<", (char *) 0);
|
|
|
|
|
depth += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (token () == '>')
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
str = concat (str, ">", (char *) 0);
|
|
|
|
|
depth -= 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const char *id = require4 (SCALAR, ID, '*', ',');
|
2014-09-21 17:33:12 +00:00
|
|
|
|
if (id == NULL)
|
2015-08-28 15:33:40 +00:00
|
|
|
|
{
|
|
|
|
|
if (T.code == '*')
|
|
|
|
|
{
|
|
|
|
|
id = "*";
|
|
|
|
|
if (num_indirections++)
|
|
|
|
|
parse_error ("only one level of indirection is supported"
|
|
|
|
|
" in template arguments");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
id = ",";
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
num_indirections = 0;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
str = concat (str, id, (char *) 0);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* typedef_name: either an ID, or a template type
|
|
|
|
|
specification of the form ID<t1,t2,...,tn>. */
|
|
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
|
typedef_name (void)
|
|
|
|
|
{
|
|
|
|
|
const char *id = require (ID);
|
|
|
|
|
if (token () == '<')
|
|
|
|
|
return require_template_declaration (id);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
else
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return id;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Absorb a sequence of tokens delimited by balanced ()[]{}. */
|
|
|
|
|
static void
|
|
|
|
|
consume_balanced (int opener, int closer)
|
|
|
|
|
{
|
|
|
|
|
require (opener);
|
|
|
|
|
for (;;)
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
default:
|
|
|
|
|
advance ();
|
|
|
|
|
break;
|
|
|
|
|
case '(':
|
|
|
|
|
consume_balanced ('(', ')');
|
|
|
|
|
break;
|
|
|
|
|
case '[':
|
|
|
|
|
consume_balanced ('[', ']');
|
|
|
|
|
break;
|
|
|
|
|
case '{':
|
|
|
|
|
consume_balanced ('{', '}');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '}':
|
|
|
|
|
case ']':
|
|
|
|
|
case ')':
|
|
|
|
|
if (token () != closer)
|
|
|
|
|
parse_error ("unbalanced delimiters - expected '%c', have '%c'",
|
|
|
|
|
closer, token ());
|
|
|
|
|
advance ();
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
case EOF_TOKEN:
|
|
|
|
|
parse_error ("unexpected end of file within %c%c-delimited construct",
|
|
|
|
|
opener, closer);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
|
2014-09-21 17:33:12 +00:00
|
|
|
|
expressions, until we encounter an end-of-statement marker (a ';' or
|
|
|
|
|
a '}') outside any such delimiters; absorb that too. */
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
static void
|
2014-09-21 17:33:12 +00:00
|
|
|
|
consume_until_eos (void)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
for (;;)
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case ';':
|
|
|
|
|
advance ();
|
|
|
|
|
return;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
|
consume_balanced ('{', '}');
|
|
|
|
|
return;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
|
consume_balanced ('(', ')');
|
|
|
|
|
break;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case '[':
|
|
|
|
|
consume_balanced ('[', ']');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '}':
|
|
|
|
|
case ']':
|
|
|
|
|
case ')':
|
|
|
|
|
parse_error ("unmatched '%c' while scanning for ';'", token ());
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
case EOF_TOKEN:
|
|
|
|
|
parse_error ("unexpected end of file while scanning for ';'");
|
|
|
|
|
return;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
advance ();
|
|
|
|
|
break;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Absorb a sequence of tokens, possibly including ()[]{}-delimited
|
|
|
|
|
expressions, until we encounter a comma or semicolon outside any
|
2014-09-21 17:33:12 +00:00
|
|
|
|
such delimiters; absorb that too. Returns true if the loop ended
|
|
|
|
|
with a comma. */
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
static bool
|
2014-09-21 17:33:12 +00:00
|
|
|
|
consume_until_comma_or_eos ()
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
for (;;)
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case ',':
|
|
|
|
|
advance ();
|
|
|
|
|
return true;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case ';':
|
|
|
|
|
advance ();
|
|
|
|
|
return false;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
case '{':
|
|
|
|
|
consume_balanced ('{', '}');
|
|
|
|
|
return false;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
|
consume_balanced ('(', ')');
|
|
|
|
|
break;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case '[':
|
|
|
|
|
consume_balanced ('[', ']');
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '}':
|
|
|
|
|
case ']':
|
|
|
|
|
case ')':
|
|
|
|
|
parse_error ("unmatched '%s' while scanning for ',' or ';'",
|
|
|
|
|
print_cur_token ());
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
case EOF_TOKEN:
|
|
|
|
|
parse_error ("unexpected end of file while scanning for ',' or ';'");
|
|
|
|
|
return false;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
advance ();
|
|
|
|
|
break;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* GTY(()) option handling. */
|
|
|
|
|
static type_p type (options_p *optsp, bool nested);
|
|
|
|
|
|
|
|
|
|
/* Optional parenthesized string: ('(' string_seq ')')? */
|
|
|
|
|
static options_p
|
|
|
|
|
str_optvalue_opt (options_p prev)
|
|
|
|
|
{
|
|
|
|
|
const char *name = advance ();
|
|
|
|
|
const char *value = "";
|
|
|
|
|
if (token () == '(')
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
value = string_seq ();
|
|
|
|
|
require (')');
|
|
|
|
|
}
|
|
|
|
|
return create_string_option (prev, name, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* absdecl: type '*'*
|
|
|
|
|
-- a vague approximation to what the C standard calls an abstract
|
|
|
|
|
declarator. The only kinds that are actually used are those that
|
|
|
|
|
are just a bare type and those that have trailing pointer-stars.
|
|
|
|
|
Further kinds should be implemented if and when they become
|
|
|
|
|
necessary. Used only within GTY(()) option values, therefore
|
|
|
|
|
further GTY(()) tags within the type are invalid. Note that the
|
|
|
|
|
return value has already been run through adjust_field_type. */
|
|
|
|
|
static type_p
|
|
|
|
|
absdecl (void)
|
|
|
|
|
{
|
|
|
|
|
type_p ty;
|
|
|
|
|
options_p opts;
|
|
|
|
|
|
|
|
|
|
ty = type (&opts, true);
|
|
|
|
|
while (token () == '*')
|
|
|
|
|
{
|
|
|
|
|
ty = create_pointer (ty);
|
|
|
|
|
advance ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (opts)
|
|
|
|
|
parse_error ("nested GTY(()) options are invalid");
|
|
|
|
|
|
|
|
|
|
return adjust_field_type (ty, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Type-option: '(' absdecl ')' */
|
|
|
|
|
static options_p
|
|
|
|
|
type_optvalue (options_p prev, const char *name)
|
|
|
|
|
{
|
|
|
|
|
type_p ty;
|
|
|
|
|
require ('(');
|
|
|
|
|
ty = absdecl ();
|
|
|
|
|
require (')');
|
|
|
|
|
return create_type_option (prev, name, ty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Nested pointer data: '(' type '*'* ',' string_seq ',' string_seq ')' */
|
|
|
|
|
static options_p
|
|
|
|
|
nestedptr_optvalue (options_p prev)
|
|
|
|
|
{
|
|
|
|
|
type_p ty;
|
|
|
|
|
const char *from, *to;
|
|
|
|
|
|
|
|
|
|
require ('(');
|
|
|
|
|
ty = absdecl ();
|
|
|
|
|
require (',');
|
|
|
|
|
to = string_seq ();
|
|
|
|
|
require (',');
|
|
|
|
|
from = string_seq ();
|
|
|
|
|
require (')');
|
|
|
|
|
|
|
|
|
|
return create_nested_ptr_option (prev, ty, to, from);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* One GTY(()) option:
|
|
|
|
|
ID str_optvalue_opt
|
|
|
|
|
| PTR_ALIAS type_optvalue
|
|
|
|
|
| NESTED_PTR nestedptr_optvalue
|
|
|
|
|
*/
|
|
|
|
|
static options_p
|
|
|
|
|
option (options_p prev)
|
|
|
|
|
{
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case ID:
|
|
|
|
|
return str_optvalue_opt (prev);
|
|
|
|
|
|
|
|
|
|
case PTR_ALIAS:
|
|
|
|
|
advance ();
|
|
|
|
|
return type_optvalue (prev, "ptr_alias");
|
|
|
|
|
|
|
|
|
|
case NESTED_PTR:
|
|
|
|
|
advance ();
|
|
|
|
|
return nestedptr_optvalue (prev);
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case USER_GTY:
|
|
|
|
|
advance ();
|
|
|
|
|
return create_string_option (prev, "user", "");
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
default:
|
|
|
|
|
parse_error ("expected an option keyword, have %s", print_cur_token ());
|
|
|
|
|
advance ();
|
|
|
|
|
return create_string_option (prev, "", "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* One comma-separated list of options. */
|
|
|
|
|
static options_p
|
|
|
|
|
option_seq (void)
|
|
|
|
|
{
|
|
|
|
|
options_p o;
|
|
|
|
|
|
|
|
|
|
o = option (0);
|
|
|
|
|
while (token () == ',')
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
o = option (o);
|
|
|
|
|
}
|
|
|
|
|
return o;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GTY marker: 'GTY' '(' '(' option_seq? ')' ')' */
|
|
|
|
|
static options_p
|
|
|
|
|
gtymarker (void)
|
|
|
|
|
{
|
|
|
|
|
options_p result = 0;
|
|
|
|
|
require (GTY_TOKEN);
|
|
|
|
|
require ('(');
|
|
|
|
|
require ('(');
|
|
|
|
|
if (token () != ')')
|
|
|
|
|
result = option_seq ();
|
|
|
|
|
require (')');
|
|
|
|
|
require (')');
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Optional GTY marker. */
|
|
|
|
|
static options_p
|
|
|
|
|
gtymarker_opt (void)
|
|
|
|
|
{
|
|
|
|
|
if (token () != GTY_TOKEN)
|
|
|
|
|
return 0;
|
|
|
|
|
return gtymarker ();
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
2022-10-27 18:55:19 +00:00
|
|
|
|
/* Declarators. The logic here is largely lifted from c-parser.cc.
|
2012-03-27 23:13:14 +00:00
|
|
|
|
Note that we do not have to process abstract declarators, which can
|
|
|
|
|
appear only in parameter type lists or casts (but see absdecl,
|
|
|
|
|
above). Also, type qualifiers are thrown out in gengtype-lex.l so
|
|
|
|
|
we don't have to do it. */
|
|
|
|
|
|
|
|
|
|
/* array_and_function_declarators_opt:
|
|
|
|
|
\epsilon
|
|
|
|
|
array_and_function_declarators_opt ARRAY
|
|
|
|
|
array_and_function_declarators_opt '(' ... ')'
|
|
|
|
|
|
|
|
|
|
where '...' indicates stuff we ignore except insofar as grouping
|
|
|
|
|
symbols ()[]{} must balance.
|
|
|
|
|
|
|
|
|
|
Subroutine of direct_declarator - do not use elsewhere. */
|
|
|
|
|
|
|
|
|
|
static type_p
|
|
|
|
|
array_and_function_declarators_opt (type_p ty)
|
|
|
|
|
{
|
|
|
|
|
if (token () == ARRAY)
|
|
|
|
|
{
|
|
|
|
|
const char *array = advance ();
|
|
|
|
|
return create_array (array_and_function_declarators_opt (ty), array);
|
|
|
|
|
}
|
|
|
|
|
else if (token () == '(')
|
|
|
|
|
{
|
|
|
|
|
/* We don't need exact types for functions. */
|
|
|
|
|
consume_balanced ('(', ')');
|
|
|
|
|
array_and_function_declarators_opt (ty);
|
|
|
|
|
return create_scalar_type ("function type");
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return ty;
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
static type_p inner_declarator (type_p, const char **, options_p *, bool);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
/* direct_declarator:
|
|
|
|
|
'(' inner_declarator ')'
|
2014-09-21 17:33:12 +00:00
|
|
|
|
'(' \epsilon ')' <-- C++ ctors/dtors
|
2012-03-27 23:13:14 +00:00
|
|
|
|
gtymarker_opt ID array_and_function_declarators_opt
|
|
|
|
|
|
|
|
|
|
Subroutine of declarator, mutually recursive with inner_declarator;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
do not use elsewhere.
|
|
|
|
|
|
|
|
|
|
IN_STRUCT is true if we are called while parsing structures or classes. */
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
static type_p
|
2014-09-21 17:33:12 +00:00
|
|
|
|
direct_declarator (type_p ty, const char **namep, options_p *optsp,
|
|
|
|
|
bool in_struct)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
/* The first token in a direct-declarator must be an ID, a
|
|
|
|
|
GTY marker, or an open parenthesis. */
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case GTY_TOKEN:
|
|
|
|
|
*optsp = gtymarker ();
|
|
|
|
|
/* fall through */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case ID:
|
|
|
|
|
*namep = require (ID);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* If the next token is '(', we are parsing a function declaration.
|
|
|
|
|
Functions are ignored by gengtype, so we return NULL. */
|
|
|
|
|
if (token () == '(')
|
|
|
|
|
return NULL;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '(':
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* If the declarator starts with a '(', we have three options. We
|
|
|
|
|
are either parsing 'TYPE (*ID)' (i.e., a function pointer)
|
|
|
|
|
or 'TYPE(...)'.
|
|
|
|
|
|
|
|
|
|
The latter will be a constructor iff we are inside a
|
|
|
|
|
structure or class. Otherwise, it could be a typedef, but
|
|
|
|
|
since we explicitly reject typedefs inside structures, we can
|
|
|
|
|
assume that we found a ctor and return NULL. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
advance ();
|
2014-09-21 17:33:12 +00:00
|
|
|
|
if (in_struct && token () != '*')
|
|
|
|
|
{
|
|
|
|
|
/* Found a constructor. Find and consume the closing ')'. */
|
|
|
|
|
while (token () != ')')
|
|
|
|
|
advance ();
|
|
|
|
|
advance ();
|
|
|
|
|
/* Tell the caller to ignore this. */
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
ty = inner_declarator (ty, namep, optsp, in_struct);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
require (')');
|
|
|
|
|
break;
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case IGNORABLE_CXX_KEYWORD:
|
|
|
|
|
/* Any C++ keyword like 'operator' means that we are not looking
|
|
|
|
|
at a regular data declarator. */
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
default:
|
2014-09-21 17:33:12 +00:00
|
|
|
|
parse_error ("expected '(', ')', 'GTY', or an identifier, have %s",
|
2012-03-27 23:13:14 +00:00
|
|
|
|
print_cur_token ());
|
|
|
|
|
/* Do _not_ advance if what we have is a close squiggle brace, as
|
|
|
|
|
we will get much better error recovery that way. */
|
|
|
|
|
if (token () != '}')
|
|
|
|
|
advance ();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return array_and_function_declarators_opt (ty);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* The difference between inner_declarator and declarator is in the
|
|
|
|
|
handling of stars. Consider this declaration:
|
|
|
|
|
|
|
|
|
|
char * (*pfc) (void)
|
|
|
|
|
|
|
|
|
|
It declares a pointer to a function that takes no arguments and
|
|
|
|
|
returns a char*. To construct the correct type for this
|
|
|
|
|
declaration, the star outside the parentheses must be processed
|
|
|
|
|
_before_ the function type, the star inside the parentheses must
|
|
|
|
|
be processed _after_ the function type. To accomplish this,
|
|
|
|
|
declarator() creates pointers before recursing (it is actually
|
|
|
|
|
coded as a while loop), whereas inner_declarator() recurses before
|
|
|
|
|
creating pointers. */
|
|
|
|
|
|
|
|
|
|
/* inner_declarator:
|
|
|
|
|
'*' inner_declarator
|
|
|
|
|
direct_declarator
|
|
|
|
|
|
|
|
|
|
Mutually recursive subroutine of direct_declarator; do not use
|
2014-09-21 17:33:12 +00:00
|
|
|
|
elsewhere.
|
|
|
|
|
|
|
|
|
|
IN_STRUCT is true if we are called while parsing structures or classes. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
static type_p
|
2014-09-21 17:33:12 +00:00
|
|
|
|
inner_declarator (type_p ty, const char **namep, options_p *optsp,
|
|
|
|
|
bool in_struct)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
if (token () == '*')
|
|
|
|
|
{
|
|
|
|
|
type_p inner;
|
|
|
|
|
advance ();
|
2014-09-21 17:33:12 +00:00
|
|
|
|
inner = inner_declarator (ty, namep, optsp, in_struct);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (inner == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
else
|
|
|
|
|
return create_pointer (ty);
|
|
|
|
|
}
|
|
|
|
|
else
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return direct_declarator (ty, namep, optsp, in_struct);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* declarator: '*'+ direct_declarator
|
|
|
|
|
|
|
|
|
|
This is the sole public interface to this part of the grammar.
|
|
|
|
|
Arguments are the type known so far, a pointer to where the name
|
|
|
|
|
may be stored, and a pointer to where GTY options may be stored.
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
IN_STRUCT is true when we are called to parse declarators inside
|
|
|
|
|
a structure or class.
|
|
|
|
|
|
|
|
|
|
Returns the final type. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
static type_p
|
2014-09-21 17:33:12 +00:00
|
|
|
|
declarator (type_p ty, const char **namep, options_p *optsp,
|
|
|
|
|
bool in_struct = false)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
*namep = 0;
|
|
|
|
|
*optsp = 0;
|
|
|
|
|
while (token () == '*')
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
ty = create_pointer (ty);
|
|
|
|
|
}
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return direct_declarator (ty, namep, optsp, in_struct);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Types and declarations. */
|
|
|
|
|
|
|
|
|
|
/* Structure field(s) declaration:
|
|
|
|
|
(
|
|
|
|
|
type bitfield ';'
|
|
|
|
|
| type declarator bitfield? ( ',' declarator bitfield? )+ ';'
|
2014-09-21 17:33:12 +00:00
|
|
|
|
)*
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
Knows that such declarations must end with a close brace (or,
|
|
|
|
|
erroneously, at EOF).
|
|
|
|
|
*/
|
|
|
|
|
static pair_p
|
|
|
|
|
struct_field_seq (void)
|
|
|
|
|
{
|
|
|
|
|
pair_p f = 0;
|
|
|
|
|
type_p ty, dty;
|
|
|
|
|
options_p opts, dopts;
|
|
|
|
|
const char *name;
|
|
|
|
|
bool another;
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
while (token () != '}' && token () != EOF_TOKEN)
|
2012-03-27 23:13:14 +00:00
|
|
|
|
{
|
|
|
|
|
ty = type (&opts, true);
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
/* Ignore access-control keywords ("public:" etc). */
|
|
|
|
|
while (!ty && token () == IGNORABLE_CXX_KEYWORD)
|
|
|
|
|
{
|
|
|
|
|
const char *keyword = advance ();
|
|
|
|
|
if (strcmp (keyword, "public:") != 0
|
|
|
|
|
&& strcmp (keyword, "private:") != 0
|
|
|
|
|
&& strcmp (keyword, "protected:") != 0)
|
|
|
|
|
break;
|
|
|
|
|
ty = type (&opts, true);
|
|
|
|
|
}
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
if (!ty || token () == ':')
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
consume_until_eos ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
do
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
dty = declarator (ty, &name, &dopts, true);
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* There could be any number of weird things after the declarator,
|
|
|
|
|
notably bitfield declarations and __attribute__s. If this
|
|
|
|
|
function returns true, the last thing was a comma, so we have
|
|
|
|
|
more than one declarator paired with the current type. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
another = consume_until_comma_or_eos ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
|
|
|
|
|
if (!dty)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (opts && dopts)
|
|
|
|
|
parse_error ("two GTY(()) options for field %s", name);
|
|
|
|
|
if (opts && !dopts)
|
|
|
|
|
dopts = opts;
|
|
|
|
|
|
|
|
|
|
f = create_field_at (f, dty, name, dopts, &lexer_line);
|
|
|
|
|
}
|
|
|
|
|
while (another);
|
|
|
|
|
}
|
|
|
|
|
return nreverse_pairs (f);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
/* Return true if OPTS contain the option named STR. */
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
opts_have (options_p opts, const char *str)
|
|
|
|
|
{
|
|
|
|
|
for (options_p opt = opts; opt; opt = opt->next)
|
|
|
|
|
if (strcmp (opt->name, str) == 0)
|
|
|
|
|
return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
/* This is called type(), but what it parses (sort of) is what C calls
|
|
|
|
|
declaration-specifiers and specifier-qualifier-list:
|
|
|
|
|
|
|
|
|
|
SCALAR
|
|
|
|
|
| ID // typedef
|
|
|
|
|
| (STRUCT|UNION) ID? gtymarker? ( '{' gtymarker? struct_field_seq '}' )?
|
|
|
|
|
| ENUM ID ( '{' ... '}' )?
|
|
|
|
|
|
|
|
|
|
Returns a partial type; under some conditions (notably
|
|
|
|
|
"struct foo GTY((...)) thing;") it may write an options
|
|
|
|
|
structure to *OPTSP.
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
NESTED is true when parsing a declaration already known to have a
|
|
|
|
|
GTY marker. In these cases, typedef and enum declarations are not
|
|
|
|
|
allowed because gengtype only understands types at the global
|
|
|
|
|
scope. */
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
static type_p
|
|
|
|
|
type (options_p *optsp, bool nested)
|
|
|
|
|
{
|
|
|
|
|
const char *s;
|
|
|
|
|
*optsp = 0;
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case SCALAR:
|
|
|
|
|
s = advance ();
|
|
|
|
|
return create_scalar_type (s);
|
|
|
|
|
|
|
|
|
|
case ID:
|
|
|
|
|
s = typedef_name ();
|
|
|
|
|
return resolve_typedef (s, &lexer_line);
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case IGNORABLE_CXX_KEYWORD:
|
|
|
|
|
/* By returning NULL here, we indicate to the caller that they
|
|
|
|
|
should ignore everything following this keyword up to the
|
|
|
|
|
next ';' or '}'. */
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case STRUCT:
|
|
|
|
|
case UNION:
|
|
|
|
|
{
|
2014-09-21 17:33:12 +00:00
|
|
|
|
type_p base_class = NULL;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
options_p opts = 0;
|
|
|
|
|
/* GTY annotations follow attribute syntax
|
|
|
|
|
GTY_BEFORE_ID is for union/struct declarations
|
|
|
|
|
GTY_AFTER_ID is for variable declarations. */
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
NO_GTY,
|
|
|
|
|
GTY_BEFORE_ID,
|
|
|
|
|
GTY_AFTER_ID
|
|
|
|
|
} is_gty = NO_GTY;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT;
|
2012-03-27 23:13:14 +00:00
|
|
|
|
advance ();
|
|
|
|
|
|
|
|
|
|
/* Top-level structures that are not explicitly tagged GTY(())
|
|
|
|
|
are treated as mere forward declarations. This is because
|
|
|
|
|
there are a lot of structures that we don't need to know
|
2014-09-21 17:33:12 +00:00
|
|
|
|
about, and some of those have C++ and macro constructs that
|
|
|
|
|
we cannot handle. */
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (nested || token () == GTY_TOKEN)
|
|
|
|
|
{
|
|
|
|
|
is_gty = GTY_BEFORE_ID;
|
|
|
|
|
opts = gtymarker_opt ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (token () == ID)
|
|
|
|
|
s = advance ();
|
|
|
|
|
else
|
|
|
|
|
s = xasprintf ("anonymous:%s:%d",
|
|
|
|
|
get_input_file_name (lexer_line.file),
|
|
|
|
|
lexer_line.line);
|
|
|
|
|
|
|
|
|
|
/* Unfortunately above GTY_TOKEN check does not capture the
|
|
|
|
|
typedef struct_type GTY case. */
|
|
|
|
|
if (token () == GTY_TOKEN)
|
|
|
|
|
{
|
|
|
|
|
is_gty = GTY_AFTER_ID;
|
|
|
|
|
opts = gtymarker_opt ();
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
bool is_user_gty = opts_have (opts, "user");
|
|
|
|
|
|
|
|
|
|
if (token () == ':')
|
|
|
|
|
{
|
|
|
|
|
if (is_gty && !is_user_gty)
|
|
|
|
|
{
|
|
|
|
|
/* For GTY-marked types that are not "user", parse some C++
|
|
|
|
|
inheritance specifications.
|
|
|
|
|
We require single-inheritance from a non-template type. */
|
|
|
|
|
advance ();
|
|
|
|
|
const char *basename = require (ID);
|
|
|
|
|
/* This may be either an access specifier, or the base name. */
|
2018-12-28 15:30:48 +00:00
|
|
|
|
if (strcmp (basename, "public") == 0
|
|
|
|
|
|| strcmp (basename, "protected") == 0
|
|
|
|
|
|| strcmp (basename, "private") == 0)
|
2014-09-21 17:33:12 +00:00
|
|
|
|
basename = require (ID);
|
|
|
|
|
base_class = find_structure (basename, TYPE_STRUCT);
|
|
|
|
|
if (!base_class)
|
|
|
|
|
parse_error ("unrecognized base class: %s", basename);
|
|
|
|
|
require_without_advance ('{');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* For types lacking GTY-markings, skip over C++ inheritance
|
|
|
|
|
specification (and thus avoid having to parse e.g. template
|
|
|
|
|
types). */
|
|
|
|
|
while (token () != '{')
|
|
|
|
|
advance ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (is_gty)
|
|
|
|
|
{
|
|
|
|
|
if (token () == '{')
|
|
|
|
|
{
|
|
|
|
|
pair_p fields;
|
|
|
|
|
|
|
|
|
|
if (is_gty == GTY_AFTER_ID)
|
|
|
|
|
parse_error ("GTY must be specified before identifier");
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
if (!is_user_gty)
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
fields = struct_field_seq ();
|
|
|
|
|
require ('}');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Do not look inside user defined structures. */
|
|
|
|
|
fields = NULL;
|
|
|
|
|
kind = TYPE_USER_STRUCT;
|
|
|
|
|
consume_balanced ('{', '}');
|
|
|
|
|
return create_user_defined_type (s, &lexer_line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new_structure (s, kind, &lexer_line, fields, opts,
|
|
|
|
|
base_class);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (token () == '{')
|
|
|
|
|
consume_balanced ('{', '}');
|
|
|
|
|
if (opts)
|
|
|
|
|
*optsp = opts;
|
2014-09-21 17:33:12 +00:00
|
|
|
|
return find_structure (s, kind);
|
2012-03-27 23:13:14 +00:00
|
|
|
|
}
|
|
|
|
|
|
2014-09-21 17:33:12 +00:00
|
|
|
|
case TYPEDEF:
|
|
|
|
|
/* In C++, a typedef inside a struct/class/union defines a new
|
|
|
|
|
type for that inner scope. We cannot support this in
|
|
|
|
|
gengtype because we have no concept of scoping.
|
|
|
|
|
|
|
|
|
|
We handle typedefs in the global scope separately (see
|
|
|
|
|
parse_file), so if we find a 'typedef', we must be inside
|
|
|
|
|
a struct. */
|
|
|
|
|
gcc_assert (nested);
|
|
|
|
|
parse_error ("typedefs not supported in structures marked with "
|
|
|
|
|
"automatic GTY markers. Use GTY((user)) to mark "
|
|
|
|
|
"this structure.");
|
|
|
|
|
advance ();
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
case ENUM:
|
|
|
|
|
advance ();
|
|
|
|
|
if (token () == ID)
|
|
|
|
|
s = advance ();
|
|
|
|
|
else
|
|
|
|
|
s = xasprintf ("anonymous:%s:%d",
|
|
|
|
|
get_input_file_name (lexer_line.file),
|
|
|
|
|
lexer_line.line);
|
|
|
|
|
|
|
|
|
|
if (token () == '{')
|
|
|
|
|
consume_balanced ('{', '}');
|
2014-09-21 17:33:12 +00:00
|
|
|
|
|
|
|
|
|
/* If after parsing the enum we are at the end of the statement,
|
|
|
|
|
and we are currently inside a structure, then this was an
|
|
|
|
|
enum declaration inside this scope.
|
|
|
|
|
|
|
|
|
|
We cannot support this for the same reason we cannot support
|
|
|
|
|
'typedef' inside structures (see the TYPEDEF handler above).
|
|
|
|
|
If this happens, emit an error and return NULL. */
|
|
|
|
|
if (nested && token () == ';')
|
|
|
|
|
{
|
|
|
|
|
parse_error ("enum definitions not supported in structures marked "
|
|
|
|
|
"with automatic GTY markers. Use GTY((user)) to mark "
|
|
|
|
|
"this structure.");
|
|
|
|
|
advance ();
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-27 23:13:14 +00:00
|
|
|
|
return create_scalar_type (s);
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
parse_error ("expected a type specifier, have %s", print_cur_token ());
|
|
|
|
|
advance ();
|
|
|
|
|
return create_scalar_type ("erroneous type");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Top level constructs. */
|
|
|
|
|
|
|
|
|
|
/* Dispatch declarations beginning with 'typedef'. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
typedef_decl (void)
|
|
|
|
|
{
|
|
|
|
|
type_p ty, dty;
|
|
|
|
|
const char *name;
|
|
|
|
|
options_p opts;
|
|
|
|
|
bool another;
|
|
|
|
|
|
|
|
|
|
gcc_assert (token () == TYPEDEF);
|
|
|
|
|
advance ();
|
|
|
|
|
|
|
|
|
|
ty = type (&opts, false);
|
|
|
|
|
if (!ty)
|
|
|
|
|
return;
|
|
|
|
|
if (opts)
|
|
|
|
|
parse_error ("GTY((...)) cannot be applied to a typedef");
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
dty = declarator (ty, &name, &opts);
|
|
|
|
|
if (opts)
|
|
|
|
|
parse_error ("GTY((...)) cannot be applied to a typedef");
|
|
|
|
|
|
|
|
|
|
/* Yet another place where we could have junk (notably attributes)
|
|
|
|
|
after the declarator. */
|
2014-09-21 17:33:12 +00:00
|
|
|
|
another = consume_until_comma_or_eos ();
|
2012-03-27 23:13:14 +00:00
|
|
|
|
if (dty)
|
|
|
|
|
do_typedef (name, dty, &lexer_line);
|
|
|
|
|
}
|
|
|
|
|
while (another);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Structure definition: type() does all the work. */
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
struct_or_union (void)
|
|
|
|
|
{
|
|
|
|
|
options_p dummy;
|
|
|
|
|
type (&dummy, false);
|
|
|
|
|
/* There may be junk after the type: notably, we cannot currently
|
|
|
|
|
distinguish 'struct foo *function(prototype);' from 'struct foo;'
|
|
|
|
|
... we could call declarator(), but it's a waste of time at
|
|
|
|
|
present. Instead, just eat whatever token is currently lookahead
|
|
|
|
|
and go back to lexical skipping mode. */
|
|
|
|
|
advance ();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* GC root declaration:
|
|
|
|
|
(extern|static) gtymarker? type ID array_declarators_opt (';'|'=')
|
|
|
|
|
If the gtymarker is not present, we ignore the rest of the declaration. */
|
|
|
|
|
static void
|
|
|
|
|
extern_or_static (void)
|
|
|
|
|
{
|
|
|
|
|
options_p opts, opts2, dopts;
|
|
|
|
|
type_p ty, dty;
|
|
|
|
|
const char *name;
|
|
|
|
|
require2 (EXTERN, STATIC);
|
|
|
|
|
|
|
|
|
|
if (token () != GTY_TOKEN)
|
|
|
|
|
{
|
|
|
|
|
advance ();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
opts = gtymarker ();
|
|
|
|
|
ty = type (&opts2, true); /* if we get here, it's got a GTY(()) */
|
|
|
|
|
dty = declarator (ty, &name, &dopts);
|
|
|
|
|
|
|
|
|
|
if ((opts && dopts) || (opts && opts2) || (opts2 && dopts))
|
|
|
|
|
parse_error ("GTY((...)) specified more than once for %s", name);
|
|
|
|
|
else if (opts2)
|
|
|
|
|
opts = opts2;
|
|
|
|
|
else if (dopts)
|
|
|
|
|
opts = dopts;
|
|
|
|
|
|
|
|
|
|
if (dty)
|
|
|
|
|
{
|
|
|
|
|
note_variable (name, adjust_field_type (dty, opts), opts, &lexer_line);
|
|
|
|
|
require2 (';', '=');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the file FNAME for GC-relevant declarations and definitions.
|
|
|
|
|
This is the only entry point to this file. */
|
|
|
|
|
void
|
|
|
|
|
parse_file (const char *fname)
|
|
|
|
|
{
|
|
|
|
|
yybegin (fname);
|
|
|
|
|
for (;;)
|
|
|
|
|
{
|
|
|
|
|
switch (token ())
|
|
|
|
|
{
|
|
|
|
|
case EXTERN:
|
|
|
|
|
case STATIC:
|
|
|
|
|
extern_or_static ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case STRUCT:
|
|
|
|
|
case UNION:
|
|
|
|
|
struct_or_union ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case TYPEDEF:
|
|
|
|
|
typedef_decl ();
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case EOF_TOKEN:
|
|
|
|
|
goto eof;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
parse_error ("unexpected top level token, %s", print_cur_token ());
|
|
|
|
|
goto eof;
|
|
|
|
|
}
|
|
|
|
|
lexer_toplevel_done = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
eof:
|
|
|
|
|
advance ();
|
|
|
|
|
yyend ();
|
|
|
|
|
}
|