Mercurial > hg > CbC > CbC_gcc
diff gcc/gengtype-parse.c @ 111:04ced10e8804
gcc 7
author | kono |
---|---|
date | Fri, 27 Oct 2017 22:46:09 +0900 |
parents | f6334be47118 |
children | 84e7813d76e9 |
line wrap: on
line diff
--- a/gcc/gengtype-parse.c Sun Aug 21 07:07:55 2011 +0900 +++ b/gcc/gengtype-parse.c Fri Oct 27 22:46:09 2017 +0900 @@ -1,5 +1,5 @@ /* Process source files and output type information. - Copyright (C) 2006, 2007, 2010 Free Software Foundation, Inc. + Copyright (C) 2006-2017 Free Software Foundation, Inc. This file is part of GCC. @@ -17,7 +17,12 @@ 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" @@ -72,10 +77,6 @@ "union", "struct", "enum", - "VEC", - "DEF_VEC_[OP]", - "DEF_VEC_I", - "DEF_VEC_ALLOC_[IOP]", "...", "ptr_alias", "nested_ptr", @@ -86,6 +87,7 @@ "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. */ @@ -97,6 +99,7 @@ "'\"%s\"'", "\"'%s'\"", "'[%s]'", + "'%s'", }; /* Produce a printable representation for a token defined by CODE and @@ -163,6 +166,21 @@ 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 * @@ -180,6 +198,24 @@ 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+ @@ -208,28 +244,89 @@ return s1; } -/* typedef_name: either an ID, or VEC(x,y) which is translated to VEC_x_y. - Use only where VEC(x,y) is legitimate, i.e. in positions where a - typedef name may appear. */ + +/* 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 + || token () == ':' + || token () == '+') + { + 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, '*', ','); + 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) { - if (token () == VEC_TOKEN) - { - const char *c1, *c2, *r; - advance (); - require ('('); - c1 = require2 (ID, SCALAR); - require (','); - c2 = require (ID); - require (')'); - r = concat ("VEC_", c1, "_", c2, (char *) 0); - free (CONST_CAST (char *, c1)); - free (CONST_CAST (char *, c2)); - return r; - } + const char *id = require (ID); + if (token () == '<') + return require_template_declaration (id); else - return require (ID); + return id; } /* Absorb a sequence of tokens delimited by balanced ()[]{}. */ @@ -270,78 +367,77 @@ } /* Absorb a sequence of tokens, possibly including ()[]{}-delimited - expressions, until we encounter a semicolon outside any such - delimiters; absorb that too. If IMMEDIATE is true, it is an error - if the semicolon is not the first token encountered. */ + expressions, until we encounter an end-of-statement marker (a ';' or + a '}') outside any such delimiters; absorb that too. */ + static void -consume_until_semi (bool immediate) +consume_until_eos (void) { - if (immediate && token () != ';') - require (';'); for (;;) switch (token ()) { case ';': advance (); return; - default: - advance (); - break; + + case '{': + consume_balanced ('{', '}'); + return; case '(': consume_balanced ('(', ')'); break; + case '[': consume_balanced ('[', ']'); break; - case '{': - consume_balanced ('{', '}'); - break; case '}': case ']': case ')': parse_error ("unmatched '%c' while scanning for ';'", token ()); - return; + 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. If IMMEDIATE is true, it is an - error if the comma or semicolon is not the first token encountered. - Returns true if the loop ended with a comma. */ + such delimiters; absorb that too. Returns true if the loop ended + with a comma. */ + static bool -consume_until_comma_or_semi (bool immediate) +consume_until_comma_or_eos () { - if (immediate && token () != ',' && token () != ';') - require2 (',', ';'); for (;;) switch (token ()) { case ',': advance (); return true; + case ';': advance (); return false; - default: - advance (); - break; + + case '{': + consume_balanced ('{', '}'); + return false; case '(': consume_balanced ('(', ')'); break; + case '[': consume_balanced ('[', ']'); break; - case '{': - consume_balanced ('{', '}'); - break; case '}': case ']': @@ -353,6 +449,10 @@ case EOF_TOKEN: parse_error ("unexpected end of file while scanning for ',' or ';'"); return false; + + default: + advance (); + break; } } @@ -434,7 +534,6 @@ /* One GTY(()) option: ID str_optvalue_opt | PTR_ALIAS type_optvalue - | PARAM_IS type_optvalue | NESTED_PTR nestedptr_optvalue */ static options_p @@ -449,13 +548,14 @@ advance (); return type_optvalue (prev, "ptr_alias"); - case PARAM_IS: - return type_optvalue (prev, advance ()); - 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 (); @@ -501,6 +601,8 @@ 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 @@ -537,16 +639,21 @@ return ty; } -static type_p inner_declarator (type_p, const char **, options_p *); +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. */ + 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) +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. */ @@ -555,18 +662,45 @@ 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 (); - ty = inner_declarator (ty, namep, optsp); + 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", + 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. */ @@ -596,23 +730,26 @@ direct_declarator Mutually recursive subroutine of direct_declarator; do not use - elsewhere. */ + 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) +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); + 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); + return direct_declarator (ty, namep, optsp, in_struct); } /* declarator: '*'+ direct_declarator @@ -620,10 +757,15 @@ 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. - Returns the final type. */ + + 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) +declarator (type_p ty, const char **namep, options_p *optsp, + bool in_struct = false) { *namep = 0; *optsp = 0; @@ -632,7 +774,7 @@ advance (); ty = create_pointer (ty); } - return direct_declarator (ty, namep, optsp); + return direct_declarator (ty, namep, optsp, in_struct); } /* Types and declarations. */ @@ -641,7 +783,7 @@ ( type bitfield ';' | type declarator bitfield? ( ',' declarator bitfield? )+ ';' - )+ + )* Knows that such declarations must end with a close brace (or, erroneously, at EOF). @@ -655,27 +797,36 @@ const char *name; bool another; - do + while (token () != '}' && token () != EOF_TOKEN) { ty = type (&opts, true); - /* Another piece of the IFCVT_EXTRA_FIELDS special case, see type(). */ - if (!ty && token () == '}') - break; + + /* 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_semi (false); + consume_until_eos (); continue; } do { - dty = declarator (ty, &name, &dopts); + 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_semi (false); + another = consume_until_comma_or_eos (); if (!dty) continue; @@ -689,10 +840,21 @@ } while (another); } - while (token () != '}' && token () != EOF_TOKEN); 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: @@ -704,7 +866,12 @@ 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) { @@ -717,13 +884,19 @@ return create_scalar_type (s); case ID: - case VEC_TOKEN: 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 @@ -734,14 +907,14 @@ GTY_BEFORE_ID, GTY_AFTER_ID } is_gty = NO_GTY; - bool is_union = (token () == UNION); + 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 weird macro stuff in them - that we can't handle. */ + about, and some of those have C++ and macro constructs that + we cannot handle. */ if (nested || token () == GTY_TOKEN) { is_gty = GTY_BEFORE_ID; @@ -763,6 +936,37 @@ 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 () == '{') @@ -772,19 +976,47 @@ if (is_gty == GTY_AFTER_ID) parse_error ("GTY must be specified before identifier"); - advance (); - fields = struct_field_seq (); - require ('}'); - return new_structure (s, is_union, &lexer_line, fields, opts); + 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, is_union); + 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) @@ -796,6 +1028,23 @@ 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: @@ -833,7 +1082,7 @@ /* Yet another place where we could have junk (notably attributes) after the declarator. */ - another = consume_until_comma_or_semi (false); + another = consume_until_comma_or_eos (); if (dty) do_typedef (name, dty, &lexer_line); } @@ -890,55 +1139,6 @@ } } -/* Definition of a generic VEC structure: - - 'DEF_VEC_[IPO]' '(' id ')' ';' - - Scalar VECs require slightly different treatment than otherwise - - that's handled in note_def_vec, we just pass it along.*/ -static void -def_vec (void) -{ - bool is_scalar = (token () == DEFVEC_I); - const char *type; - - require2 (DEFVEC_OP, DEFVEC_I); - require ('('); - type = require2 (ID, SCALAR); - require (')'); - require (';'); - - if (!type) - return; - - note_def_vec (type, is_scalar, &lexer_line); - note_def_vec_alloc (type, "none", &lexer_line); -} - -/* Definition of an allocation strategy for a VEC structure: - - 'DEF_VEC_ALLOC_[IPO]' '(' id ',' id ')' ';' - - For purposes of gengtype, this just declares a wrapper structure. */ -static void -def_vec_alloc (void) -{ - const char *type, *astrat; - - require (DEFVEC_ALLOC); - require ('('); - type = require2 (ID, SCALAR); - require (','); - astrat = require (ID); - require (')'); - require (';'); - - if (!type || !astrat) - return; - - note_def_vec_alloc (type, astrat, &lexer_line); -} - /* Parse the file FNAME for GC-relevant declarations and definitions. This is the only entry point to this file. */ void @@ -963,15 +1163,6 @@ typedef_decl (); break; - case DEFVEC_OP: - case DEFVEC_I: - def_vec (); - break; - - case DEFVEC_ALLOC: - def_vec_alloc (); - break; - case EOF_TOKEN: goto eof;