12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184 |
- /* Process source files and output type information.
- Copyright (C) 2006-2015 Free Software Foundation, Inc.
- This file is part of GCC.
- GCC is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free
- Software Foundation; either version 3, or (at your option) any later
- version.
- GCC is distributed in the hope that it will be useful, but WITHOUT ANY
- WARRANTY; without even the implied warranty of MERCHANTABILITY or
- FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- for more details.
- You should have received a copy of the GNU General Public License
- along with GCC; see the file COPYING3. If not see
- <http://www.gnu.org/licenses/>. */
- #ifdef HOST_GENERATOR_FILE
- #include "config.h"
- #define GENERATOR_FILE 1
- #else
- #include "bconfig.h"
- #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",
- "a C++ keyword to ignore"
- };
- /* 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]'",
- "'%s'",
- };
- /* 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;
- }
- /* 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;
- }
- /* 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;
- }
- /* 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;
- }
- /* 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;
- }
- /* The caller has detected a template declaration that starts
- with TMPL_NAME. Parse up to the closing '>'. This recognizes
- simple template declarations of the form ID<ID1,ID2,...,IDn>,
- potentially with a single level of indirection e.g.
- ID<ID1 *, ID2, ID3 *, ..., IDn>.
- It does not try to parse anything more sophisticated than that.
- Returns the template declaration string "ID<ID1,ID2,...,IDn>". */
- static const char *
- require_template_declaration (const char *tmpl_name)
- {
- char *str;
- int num_indirections = 0;
- /* Recognize the opening '<'. */
- require ('<');
- str = concat (tmpl_name, "<", (char *) 0);
- /* Read the comma-separated list of identifiers. */
- int depth = 1;
- while (depth > 0)
- {
- if (token () == ENUM)
- {
- advance ();
- str = concat (str, "enum ", (char *) 0);
- continue;
- }
- if (token () == NUM)
- {
- str = concat (str, advance (), (char *) 0);
- continue;
- }
- if (token () == ':')
- {
- advance ();
- str = concat (str, ":", (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, '*', ',');
- if (id == NULL)
- {
- 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;
- str = concat (str, id, (char *) 0);
- }
- 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);
- else
- return id;
- }
- /* 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
- expressions, until we encounter an end-of-statement marker (a ';' or
- a '}') outside any such delimiters; absorb that too. */
- static void
- consume_until_eos (void)
- {
- for (;;)
- switch (token ())
- {
- case ';':
- advance ();
- return;
- case '{':
- consume_balanced ('{', '}');
- return;
- case '(':
- consume_balanced ('(', ')');
- break;
- case '[':
- consume_balanced ('[', ']');
- break;
- case '}':
- case ']':
- case ')':
- parse_error ("unmatched '%c' while scanning for ';'", token ());
- return;
- case EOF_TOKEN:
- parse_error ("unexpected end of file while scanning for ';'");
- return;
- default:
- advance ();
- break;
- }
- }
- /* Absorb a sequence of tokens, possibly including ()[]{}-delimited
- expressions, until we encounter a comma or semicolon outside any
- such delimiters; absorb that too. Returns true if the loop ended
- with a comma. */
- static bool
- consume_until_comma_or_eos ()
- {
- for (;;)
- switch (token ())
- {
- case ',':
- advance ();
- return true;
- case ';':
- advance ();
- return false;
- case '{':
- consume_balanced ('{', '}');
- return false;
- case '(':
- consume_balanced ('(', ')');
- break;
- 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;
- default:
- advance ();
- break;
- }
- }
- /* 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);
- case USER_GTY:
- advance ();
- return create_string_option (prev, "user", "");
- 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 ();
- }
- /* Declarators. The logic here is largely lifted from c-parser.c.
- 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;
- }
- static type_p inner_declarator (type_p, const char **, options_p *, bool);
- /* direct_declarator:
- '(' inner_declarator ')'
- '(' \epsilon ')' <-- C++ ctors/dtors
- gtymarker_opt ID array_and_function_declarators_opt
- Subroutine of declarator, mutually recursive with inner_declarator;
- do not use elsewhere.
- IN_STRUCT is true if we are called while parsing structures or classes. */
- static type_p
- direct_declarator (type_p ty, const char **namep, options_p *optsp,
- bool in_struct)
- {
- /* 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 */
- case ID:
- *namep = require (ID);
- /* If the next token is '(', we are parsing a function declaration.
- Functions are ignored by gengtype, so we return NULL. */
- if (token () == '(')
- return NULL;
- break;
- case '(':
- /* 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. */
- advance ();
- 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);
- require (')');
- break;
- case IGNORABLE_CXX_KEYWORD:
- /* Any C++ keyword like 'operator' means that we are not looking
- at a regular data declarator. */
- return NULL;
- default:
- parse_error ("expected '(', ')', 'GTY', or an identifier, have %s",
- 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
- elsewhere.
- IN_STRUCT is true if we are called while parsing structures or classes. */
- static type_p
- inner_declarator (type_p ty, const char **namep, options_p *optsp,
- bool in_struct)
- {
- if (token () == '*')
- {
- type_p inner;
- advance ();
- inner = inner_declarator (ty, namep, optsp, in_struct);
- if (inner == 0)
- return 0;
- else
- return create_pointer (ty);
- }
- else
- return direct_declarator (ty, namep, optsp, in_struct);
- }
- /* 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.
- IN_STRUCT is true when we are called to parse declarators inside
- a structure or class.
- Returns the final type. */
- static type_p
- declarator (type_p ty, const char **namep, options_p *optsp,
- bool in_struct = false)
- {
- *namep = 0;
- *optsp = 0;
- while (token () == '*')
- {
- advance ();
- ty = create_pointer (ty);
- }
- return direct_declarator (ty, namep, optsp, in_struct);
- }
- /* Types and declarations. */
- /* Structure field(s) declaration:
- (
- type bitfield ';'
- | type declarator bitfield? ( ',' declarator bitfield? )+ ';'
- )*
- 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;
- while (token () != '}' && token () != EOF_TOKEN)
- {
- ty = type (&opts, true);
- /* 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);
- }
- if (!ty || token () == ':')
- {
- consume_until_eos ();
- continue;
- }
- do
- {
- dty = declarator (ty, &name, &dopts, true);
- /* 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. */
- another = consume_until_comma_or_eos ();
- 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);
- }
- /* 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;
- }
- /* 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.
- 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. */
- 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);
- 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;
- case STRUCT:
- case UNION:
- {
- type_p base_class = NULL;
- 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;
- enum typekind kind = (token () == UNION) ? TYPE_UNION : TYPE_STRUCT;
- 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
- about, and some of those have C++ and macro constructs that
- we cannot handle. */
- 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 ();
- }
- 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. */
- if (0 == strcmp (basename, "public")
- || 0 == strcmp (basename, "protected")
- || 0 == strcmp (basename, "private"))
- 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 ();
- }
- }
- if (is_gty)
- {
- if (token () == '{')
- {
- pair_p fields;
- if (is_gty == GTY_AFTER_ID)
- parse_error ("GTY must be specified before identifier");
- 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);
- }
- }
- else if (token () == '{')
- consume_balanced ('{', '}');
- if (opts)
- *optsp = opts;
- return find_structure (s, kind);
- }
- 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;
- 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 ('{', '}');
- /* 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;
- }
- 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. */
- another = consume_until_comma_or_eos ();
- 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 ();
- }
|