语法解析的开始函数:
/* Initialize the integrated preprocessor after debug output has been
initialized; loop over each input file. */
void
c_common_parse_file (void)
{
auto dumps = g->get_dumps ();
for (unsigned int i = 0;;)
{
c_finish_options ();
/* Open the dump file to use for the original dump output
here, to be used during parsing for the current file. */
dumps->dump_start (TDI_original, &dump_flags);
pch_init ();
push_file_scope ();
c_parse_file ();
pop_file_scope ();
/* And end the main input file, if the debug writer wants it */
if (debug_hooks->start_end_main_source_file)
(*debug_hooks->end_source_file) (0);
if (++i >= num_in_fnames)
break;
cpp_undef_all (parse_in);
cpp_clear_file_cache (parse_in);
this_input_filename
= cpp_read_main_file (parse_in, in_fnames[i]);
/* If an input file is missing, abandon further compilation.
cpplib has issued a diagnostic. */
if (!this_input_filename)
break;
dumps->dump_finish (TDI_original);
}
c_parse_final_cleanups ();
dumps->dump_finish (TDI_original);
}
/* Parse a single source file. */
void
c_parse_file (void)
{
/* Use local storage to begin. If the first token is a pragma, parse it.
If it is #pragma GCC pch_preprocess, then this will load a PCH file
which will cause garbage collection. */
c_parser tparser;
memset (&tparser, 0, sizeof tparser);
tparser.translate_strings_p = true;
tparser.tokens = &tparser.tokens_buf[0];
the_parser = &tparser;
if (c_parser_peek_token (&tparser)->pragma_kind == PRAGMA_GCC_PCH_PREPROCESS)
c_parser_pragma_pch_preprocess (&tparser);
else
c_common_no_more_pch ();
the_parser = ggc_alloc<c_parser> ();
*the_parser = tparser;
if (tparser.tokens == &tparser.tokens_buf[0])
the_parser->tokens = &the_parser->tokens_buf[0];
/* Initialize EH, if we've been told to do so. */
if (flag_exceptions)
using_eh_for_cleanups ();
c_parser_translation_unit (the_parser);
the_parser = NULL;
}
/* Parse a translation unit (C90 6.7, C99 6.9, C11 6.9).
translation-unit:
external-declarations
external-declarations:
external-declaration
external-declarations external-declaration
GNU extensions:
translation-unit:
empty
*/
static void
c_parser_translation_unit (c_parser *parser)
{
if (c_parser_next_token_is (parser, CPP_EOF))
{
pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
"ISO C forbids an empty translation unit");
}
else
{
void *obstack_position = obstack_alloc (&parser_obstack, 0);
mark_valid_location_for_stdc_pragma (false);
do
{
ggc_collect ();
c_parser_external_declaration (parser);
obstack_free (&parser_obstack, obstack_position);
}
while (c_parser_next_token_is_not (parser, CPP_EOF));
}
unsigned int i;
tree decl;
FOR_EACH_VEC_ELT (incomplete_record_decls, i, decl)
if (DECL_SIZE (decl) == NULL_TREE && TREE_TYPE (decl) != error_mark_node)
error ("storage size of %q+D isn%'t known", decl);
if (vec_safe_length (current_omp_declare_target_attribute))
{
c_omp_declare_target_attr
a = current_omp_declare_target_attribute->pop ();
if (!errorcount)
error ("%qs without corresponding %qs",
a.device_type >= 0 ? "#pragma omp begin declare target"
: "#pragma omp declare target",
"#pragma omp end declare target");
vec_safe_truncate (current_omp_declare_target_attribute, 0);
}
if (vec_safe_length (current_omp_begin_assumes))
{
if (!errorcount)
error ("%qs without corresponding %qs",
"#pragma omp begin assumes", "#pragma omp end assumes");
vec_safe_truncate (current_omp_begin_assumes, 0);
}
#if ENABLE_ANALYZER
if (flag_analyzer)
{
ana::c_translation_unit tu;
ana::on_finish_translation_unit (tu);
}
#endif
}
c_parser_external_declaration (c_parser *parser)
{
int ext;
switch (c_parser_peek_token (parser)->type)
{
case CPP_KEYWORD:
switch (c_parser_peek_token (parser)->keyword)
{
case RID_EXTENSION:
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
c_parser_external_declaration (parser);
restore_extension_diagnostics (ext);
break;
case RID_ASM:
c_parser_asm_definition (parser);
break;
case RID_AT_INTERFACE:
case RID_AT_IMPLEMENTATION:
gcc_assert (c_dialect_objc ());
c_parser_objc_class_definition (parser, NULL_TREE);
break;
case RID_AT_CLASS:
gcc_assert (c_dialect_objc ());
c_parser_objc_class_declaration (parser);
break;
case RID_AT_ALIAS:
gcc_assert (c_dialect_objc ());
c_parser_objc_alias_declaration (parser);
break;
case RID_AT_PROTOCOL:
gcc_assert (c_dialect_objc ());
c_parser_objc_protocol_definition (parser, NULL_TREE);
break;
case RID_AT_PROPERTY:
gcc_assert (c_dialect_objc ());
c_parser_objc_at_property_declaration (parser);
break;
case RID_AT_SYNTHESIZE:
gcc_assert (c_dialect_objc ());
c_parser_objc_at_synthesize_declaration (parser);
break;
case RID_AT_DYNAMIC:
gcc_assert (c_dialect_objc ());
c_parser_objc_at_dynamic_declaration (parser);
break;
case RID_AT_END:
gcc_assert (c_dialect_objc ());
c_parser_consume_token (parser);
objc_finish_implementation ();
break;
default:
goto decl_or_fndef;
}
break;
case CPP_SEMICOLON:
pedwarn (c_parser_peek_token (parser)->location, OPT_Wpedantic,
"ISO C does not allow extra %<;%> outside of a function");
c_parser_consume_token (parser);
break;
case CPP_PRAGMA:
mark_valid_location_for_stdc_pragma (true);
c_parser_pragma (parser, pragma_external, NULL, NULL_TREE);
mark_valid_location_for_stdc_pragma (false);
break;
case CPP_PLUS:
case CPP_MINUS:
if (c_dialect_objc ())
{
c_parser_objc_method_definition (parser);
break;
}
/* Else fall through, and yield a syntax error trying to parse
as a declaration or function definition. */
/* FALLTHRU */
default:
decl_or_fndef:
/* A declaration or a function definition (or, in Objective-C,
an @interface or @protocol with prefix attributes). We can
only tell which after parsing the declaration specifiers, if
any, and the first declarator. */
c_parser_declaration_or_fndef (parser, true, true, true, false, true,
false);
break;
}
}
/* Parse a declaration or function definition (C90 6.5, 6.7.1, C99
6.7, 6.9.1, C11 6.7, 6.9.1). If FNDEF_OK is true, a function definition
is accepted; otherwise (old-style parameter declarations) only other
declarations are accepted. If STATIC_ASSERT_OK is true, a static
assertion is accepted; otherwise (old-style parameter declarations)
it is not. If NESTED is true, we are inside a function or parsing
old-style parameter declarations; any functions encountered are
nested functions and declaration specifiers are required; otherwise
we are at top level and functions are normal functions and
declaration specifiers may be optional. If EMPTY_OK is true, empty
declarations are OK (subject to all other constraints); otherwise
(old-style parameter declarations) they are diagnosed. If
START_ATTR_OK is true, the declaration specifiers may start with
attributes (GNU or standard); otherwise they may not.
OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
declaration when parsing an Objective-C foreach statement.
FALLTHRU_ATTR_P is used to signal whether this function parsed
"__attribute__((fallthrough));". ATTRS are any standard attributes
parsed in the caller (in contexts where such attributes had to be
parsed to determine whether what follows is a declaration or a
statement); HAVE_ATTRS says whether there were any such attributes
(even empty). If SIMPLE_OK, the construct can be a simple-declaration;
in that case, the ';' is not consumed (left to the caller so that it
can figure out if there was a simple-declaration or not), there must
be an initializer, and only one object may be declared. When SIMPLE_OK
is true we are called from c_parser_selection_header.
Returns the resulting declaration, if there was any with an initializer.
declaration:
declaration-specifiers init-declarator-list[opt] ;
static_assert-declaration
function-definition:
declaration-specifiers[opt] declarator declaration-list[opt]
compound-statement
declaration-list:
declaration
declaration-list declaration
init-declarator-list:
init-declarator
init-declarator-list , init-declarator
init-declarator:
declarator simple-asm-expr[opt] gnu-attributes[opt]
declarator simple-asm-expr[opt] gnu-attributes[opt] = initializer
simple-declaration:
attribute-specifier-sequence[opt] declaration-specifiers declarator
= initializer
GNU extensions:
nested-function-definition:
declaration-specifiers declarator declaration-list[opt]
compound-statement
attribute ;
Objective-C:
gnu-attributes objc-class-definition
gnu-attributes objc-category-definition
gnu-attributes objc-protocol-definition
The simple-asm-expr and gnu-attributes are GNU extensions.
This function does not handle __extension__; that is handled in its
callers. ??? Following the old parser, __extension__ may start
external declarations, declarations in functions and declarations
at the start of "for" loops, but not old-style parameter
declarations.
C99 requires declaration specifiers in a function definition; the
absence is diagnosed through the diagnosis of implicit int. In GNU
C we also allow but diagnose declarations without declaration
specifiers, but only at top level (elsewhere they conflict with
other syntax).
In Objective-C, declarations of the looping variable in a foreach
statement are exceptionally terminated by 'in' (for example, 'for
(NSObject *object in array) { ... }').
OpenMP:
declaration:
threadprivate-directive
GIMPLE:
gimple-function-definition:
declaration-specifiers[opt] __GIMPLE (gimple-or-rtl-pass-list) declarator
declaration-list[opt] compound-statement
rtl-function-definition:
declaration-specifiers[opt] __RTL (gimple-or-rtl-pass-list) declarator
declaration-list[opt] compound-statement */
static tree
c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool static_assert_ok, bool empty_ok,
bool nested, bool start_attr_ok,
bool simple_ok,
tree *objc_foreach_object_declaration
/* = NULL */,
vec<c_token> *omp_declare_simd_clauses
/* = NULL */,
bool have_attrs /* = false */,
tree attrs /* = NULL_TREE */,
struct oacc_routine_data *oacc_routine_data
/* = NULL */,
bool *fallthru_attr_p /* = NULL */)
{
struct c_declspecs *specs;
tree prefix_attrs;
tree all_prefix_attrs;
bool diagnosed_no_specs = false;
location_t here = c_parser_peek_token (parser)->location;
tree result = NULL_TREE;
add_debug_begin_stmt (c_parser_peek_token (parser)->location);
if (static_assert_ok
&& c_parser_next_token_is_keyword (parser, RID_STATIC_ASSERT))
{
c_parser_static_assert_declaration (parser);
return result;
}
specs = build_null_declspecs ();
/* Handle any standard attributes parsed in the caller. */
if (have_attrs)
{
declspecs_add_attrs (here, specs, attrs);
specs->non_std_attrs_seen_p = false;
}
/* Try to detect an unknown type name when we have "A B" or "A *B". */
if (c_parser_peek_token (parser)->type == CPP_NAME
&& c_parser_peek_token (parser)->id_kind == C_ID_ID
&& (c_parser_peek_2nd_token (parser)->type == CPP_NAME
|| c_parser_peek_2nd_token (parser)->type == CPP_MULT)
&& (!nested || !lookup_name (c_parser_peek_token (parser)->value)))
{
tree name = c_parser_peek_token (parser)->value;
/* Issue a warning about NAME being an unknown type name, perhaps
with some kind of hint.
If the user forgot a "struct" etc, suggest inserting
it. Otherwise, attempt to look for misspellings. */
gcc_rich_location richloc (here);
if (tag_exists_p (RECORD_TYPE, name))
{
/* This is not C++ with its implicit typedef. */
richloc.add_fixit_insert_before ("struct ");
error_at (&richloc,
"unknown type name %qE;"
" use %<struct%> keyword to refer to the type",
name);
}
else if (tag_exists_p (UNION_TYPE, name))
{
richloc.add_fixit_insert_before ("union ");
error_at (&richloc,
"unknown type name %qE;"
" use %<union%> keyword to refer to the type",
name);
}
else if (tag_exists_p (ENUMERAL_TYPE, name))
{
richloc.add_fixit_insert_before ("enum ");
error_at (&richloc,
"unknown type name %qE;"
" use %<enum%> keyword to refer to the type",
name);
}
else
{
auto_diagnostic_group d;
name_hint hint = lookup_name_fuzzy (name, FUZZY_LOOKUP_TYPENAME,
here);
if (const char *suggestion = hint.suggestion ())
{
richloc.add_fixit_replace (suggestion);
error_at (&richloc,
"unknown type name %qE; did you mean %qs?",
name, suggestion);
}
else
error_at (here, "unknown type name %qE", name);
}
/* Parse declspecs normally to get a correct pointer type, but avoid
a further "fails to be a type name" error. Refuse nested functions
since it is not how the user likely wants us to recover. */
c_parser_peek_token (parser)->type = CPP_KEYWORD;
c_parser_peek_token (parser)->keyword = RID_VOID;
c_parser_peek_token (parser)->value = error_mark_node;
fndef_ok = !nested;
}
/* When there are standard attributes at the start of the
declaration (to apply to the entity being declared), an
init-declarator-list or function definition must be present. */
if (c_parser_nth_token_starts_std_attributes (parser, 1))
have_attrs = true;
c_parser_declspecs (parser, specs, true, true, start_attr_ok,
true, true, start_attr_ok, true, cla_nonabstract_decl);
if (parser->error)
{
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
if (nested && !specs->declspecs_seen_p)
{
c_parser_error (parser, "expected declaration specifiers");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
finish_declspecs (specs);
bool gnu_auto_type_p = specs->typespec_word == cts_auto_type;
bool std_auto_type_p = specs->c23_auto_p;
bool any_auto_type_p = gnu_auto_type_p || std_auto_type_p;
gcc_assert (!(gnu_auto_type_p && std_auto_type_p));
const char *auto_type_keyword = gnu_auto_type_p ? "__auto_type" : "auto";
if (specs->constexpr_p)
{
/* An underspecified declaration may not declare tags or members
or structures or unions; it is undefined behavior to declare
the members of an enumeration. Where the structure, union or
enumeration type is declared within an initializer, this is
diagnosed elsewhere. Diagnose here the case of declaring
such a type in the type specifiers of a constexpr
declaration. */
switch (specs->typespec_kind)
{
case ctsk_tagfirstref:
case ctsk_tagfirstref_attrs:
error_at (here, "%qT declared in underspecified object declaration",
specs->type);
break;
case ctsk_tagdef:
error_at (here, "%qT defined in underspecified object declaration",
specs->type);
break;
default:
break;
}
}
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
bool handled_assume = false;
if (specs->attrs
&& !nested
&& specs->typespec_kind == ctsk_none
&& c_parser_handle_statement_omp_attributes (parser, specs->attrs,
NULL))
{
if (specs->attrs)
c_warn_unused_attributes (specs->attrs);
while (parser->in_omp_attribute_pragma)
{
gcc_assert (c_parser_next_token_is (parser, CPP_PRAGMA));
c_parser_pragma (parser, pragma_external, NULL, NULL_TREE);
}
c_parser_consume_token (parser);
return result;
}
if (specs->typespec_kind == ctsk_none
&& lookup_attribute ("gnu", "assume", specs->attrs))
{
handled_assume = true;
specs->attrs
= handle_assume_attribute (here, specs->attrs, nested);
}
if (any_auto_type_p)
error_at (here, "%qs in empty declaration", auto_type_keyword);
else if (specs->typespec_kind == ctsk_none
&& attribute_fallthrough_p (specs->attrs))
{
if (fallthru_attr_p != NULL)
*fallthru_attr_p = true;
if (nested)
{
tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH,
void_type_node, 0);
add_stmt (fn);
}
else
pedwarn (here, OPT_Wattributes,
"%<fallthrough%> attribute at top level");
}
else if (empty_ok
&& !(have_attrs && specs->non_std_attrs_seen_p)
&& !handled_assume)
shadow_tag (specs);
else
{
shadow_tag_warned (specs, 1);
if (!handled_assume)
pedwarn (here, 0, "empty declaration");
}
/* We still have to evaluate size expressions. */
if (specs->expr)
add_stmt (fold_convert (void_type_node, specs->expr));
c_parser_consume_token (parser);
if (oacc_routine_data)
c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
return result;
}
else if (specs->typespec_kind == ctsk_none
&& nested
/* Only parse __attribute__((musttail)) when called from
c_parser_compound_statement_nostart. This certainly isn't
a declaration in that case, but we don't do tentative parsing
of GNU attributes right now. */
&& fallthru_attr_p
&& c_parser_next_token_is_keyword (parser, RID_RETURN))
{
attr_state astate = {};
specs->attrs = c_parser_handle_musttail (parser, specs->attrs, astate);
if (astate.musttail_p)
{
if (specs->attrs)
{
auto_urlify_attributes sentinel;
warning_at (c_parser_peek_token (parser)->location,
OPT_Wattributes,
"attribute %<musttail%> mixed with other attributes "
"on %<return%> statement");
}
c_parser_statement_after_labels (parser, NULL, NULL_TREE, NULL,
astate);
return result;
}
}
/* Provide better error recovery. Note that a type name here is usually
better diagnosed as a redeclaration. */
if (empty_ok
&& specs->typespec_kind == ctsk_tagdef
&& c_parser_next_token_starts_declspecs (parser)
&& !c_parser_next_token_is (parser, CPP_NAME))
{
c_parser_error (parser, "expected %<;%>, identifier or %<(%>");
parser->error = false;
shadow_tag_warned (specs, 1);
return result;
}
else if (c_dialect_objc () && !any_auto_type_p)
{
/* Prefix attributes are an error on method decls. */
switch (c_parser_peek_token (parser)->type)
{
case CPP_PLUS:
case CPP_MINUS:
if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
return result;
if (specs->attrs)
{
warning_at (c_parser_peek_token (parser)->location,
OPT_Wattributes,
"prefix attributes are ignored for methods");
specs->attrs = NULL_TREE;
}
if (fndef_ok)
c_parser_objc_method_definition (parser);
else
c_parser_objc_methodproto (parser);
return result;
break;
default:
break;
}
/* This is where we parse 'attributes @interface ...',
'attributes @implementation ...', 'attributes @protocol ...'
(where attributes could be, for example, __attribute__
((deprecated)).
*/
switch (c_parser_peek_token (parser)->keyword)
{
case RID_AT_INTERFACE:
{
if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
return result;
c_parser_objc_class_definition (parser, specs->attrs);
return result;
}
break;
case RID_AT_IMPLEMENTATION:
{
if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
return result;
if (specs->attrs)
{
warning_at (c_parser_peek_token (parser)->location,
OPT_Wattributes,
"prefix attributes are ignored for implementations");
specs->attrs = NULL_TREE;
}
c_parser_objc_class_definition (parser, NULL_TREE);
return result;
}
break;
case RID_AT_PROTOCOL:
{
if (c_parser_objc_diagnose_bad_element_prefix (parser, specs))
return result;
c_parser_objc_protocol_definition (parser, specs->attrs);
return result;
}
break;
case RID_AT_ALIAS:
case RID_AT_CLASS:
case RID_AT_END:
case RID_AT_PROPERTY:
if (specs->attrs)
{
c_parser_error (parser, "unexpected attribute");
specs->attrs = NULL;
}
break;
default:
break;
}
}
else if (attribute_fallthrough_p (specs->attrs))
warning_at (here, OPT_Wattributes,
"%<fallthrough%> attribute not followed by %<;%>");
else if (lookup_attribute ("gnu", "assume", specs->attrs))
warning_at (here, OPT_Wattributes,
"%<assume%> attribute not followed by %<;%>");
auto_vec<c_token> omp_declare_simd_attr_clauses;
c_parser_handle_directive_omp_attributes (specs->attrs,
omp_declare_simd_clauses,
&omp_declare_simd_attr_clauses);
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
specs->attrs = NULL_TREE;
bool more_than_one_decl = false;
while (true)
{
struct c_declarator *declarator;
bool dummy = false;
timevar_id_t tv;
tree fnbody = NULL_TREE;
tree underspec_name = NULL_TREE;
auto_vec<c_token> omp_dsimd_idattr_clauses;
/* Declaring either one or more declarators (in which case we
should diagnose if there were no declaration specifiers) or a
function definition (in which case the diagnostic for
implicit int suffices). */
declarator = c_parser_declarator (parser,
specs->typespec_kind != ctsk_none,
C_DTR_NORMAL, &dummy);
if (declarator == NULL)
{
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE,
omp_declare_simd_clauses);
if (oacc_routine_data)
c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false);
/* This check is here purely to improve the diagnostic. */
if (!simple_ok)
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
if (flag_openmp || flag_openmp_simd)
{
struct c_declarator *d = declarator;
while (d->kind != cdk_id)
d = d->declarator;
vec<c_token> *dummy = NULL;
c_parser_handle_directive_omp_attributes (d->u.id.attrs, dummy,
&omp_dsimd_idattr_clauses);
}
if (gnu_auto_type_p && declarator->kind != cdk_id)
{
error_at (here,
"%<__auto_type%> requires a plain identifier"
" as declarator");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
if (std_auto_type_p)
{
struct c_declarator *d = declarator;
while (d->kind == cdk_attrs)
d = d->declarator;
if (d->kind != cdk_id)
{
error_at (here,
"%<auto%> requires a plain identifier, possibly with"
" attributes, as declarator");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
underspec_name = d->u.id.id;
}
else if (specs->constexpr_p)
{
struct c_declarator *d = declarator;
while (d->kind != cdk_id)
d = d->declarator;
underspec_name = d->u.id.id;
}
if (c_parser_next_token_is (parser, CPP_EQ)
|| c_parser_next_token_is (parser, CPP_COMMA)
|| c_parser_next_token_is (parser, CPP_SEMICOLON)
|| c_parser_next_token_is_keyword (parser, RID_ASM)
|| c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE)
|| c_parser_next_token_is_keyword (parser, RID_IN))
{
tree asm_name = NULL_TREE;
tree postfix_attrs = NULL_TREE;
if (!diagnosed_no_specs && !specs->declspecs_seen_p)
{
diagnosed_no_specs = true;
pedwarn (here, 0, "data definition has no type or storage class");
}
/* Having seen a data definition, there cannot now be a
function definition. */
fndef_ok = false;
if (c_parser_next_token_is_keyword (parser, RID_ASM))
asm_name = c_parser_simple_asm_expr (parser);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
{
postfix_attrs = c_parser_gnu_attributes (parser);
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
{
/* This means there is an attribute specifier after
the declarator in a function definition. Provide
some more information for the user. */
error_at (here, "attributes should be specified before the "
"declarator in a function definition");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
}
if (c_parser_next_token_is (parser, CPP_EQ))
{
tree d;
struct c_expr init;
location_t init_loc;
c_parser_consume_token (parser);
if (any_auto_type_p)
{
init_loc = c_parser_peek_token (parser)->location;
rich_location richloc (line_table, init_loc);
unsigned int underspec_state = 0;
if (std_auto_type_p)
underspec_state =
start_underspecified_init (init_loc, underspec_name);
start_init (NULL_TREE, asm_name,
(global_bindings_p ()
|| specs->storage_class == csc_static
|| specs->constexpr_p),
specs->constexpr_p, &richloc);
/* A parameter is initialized, which is invalid. Don't
attempt to instrument the initializer. */
int flag_sanitize_save = flag_sanitize;
if (nested && !empty_ok)
flag_sanitize = 0;
init = c_parser_expr_no_commas (parser, NULL);
if (std_auto_type_p)
finish_underspecified_init (underspec_name,
underspec_state);
flag_sanitize = flag_sanitize_save;
if (gnu_auto_type_p
&& TREE_CODE (init.value) == COMPONENT_REF
&& DECL_C_BIT_FIELD (TREE_OPERAND (init.value, 1)))
error_at (here,
"%<__auto_type%> used with a bit-field"
" initializer");
init = convert_lvalue_to_rvalue (init_loc, init, true, true,
true);
tree init_type = TREE_TYPE (init.value);
bool vm_type = c_type_variably_modified_p (init_type);
if (vm_type)
init.value = save_expr (init.value);
finish_init ();
specs->typespec_kind = ctsk_typeof;
specs->locations[cdw_typedef] = init_loc;
specs->typedef_p = true;
specs->type = init_type;
if (specs->postfix_attrs)
{
/* Postfix [[]] attributes are valid with C23
auto, although not with __auto_type, and
modify the type given by the initializer. */
specs->postfix_attrs
= c_warn_type_attributes (specs->type,
specs->postfix_attrs);
decl_attributes (&specs->type, specs->postfix_attrs, 0);
specs->postfix_attrs = NULL_TREE;
}
if (vm_type)
{
bool maybe_const = true;
tree type_expr = c_fully_fold (init.value, false,
&maybe_const);
specs->expr_const_operands &= maybe_const;
if (specs->expr)
specs->expr = build2 (COMPOUND_EXPR,
TREE_TYPE (type_expr),
specs->expr, type_expr);
else
specs->expr = type_expr;
}
d = start_decl (declarator, specs, true,
chainon (postfix_attrs, all_prefix_attrs));
if (!d)
d = error_mark_node;
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
if (!omp_dsimd_idattr_clauses.is_empty ())
c_finish_omp_declare_simd (parser, d, NULL_TREE,
&omp_dsimd_idattr_clauses);
}
else
{
/* The declaration of the variable is in effect while
its initializer is parsed, except for a constexpr
variable. */
init_loc = c_parser_peek_token (parser)->location;
rich_location richloc (line_table, init_loc);
unsigned int underspec_state = 0;
if (specs->constexpr_p)
underspec_state =
start_underspecified_init (init_loc, underspec_name);
d = start_decl (declarator, specs, true,
chainon (postfix_attrs,
all_prefix_attrs),
!specs->constexpr_p);
if (!d)
d = error_mark_node;
if (!specs->constexpr_p && omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
if (!specs->constexpr_p
&& !omp_dsimd_idattr_clauses.is_empty ())
c_finish_omp_declare_simd (parser, d, NULL_TREE,
&omp_dsimd_idattr_clauses);
start_init (d, asm_name,
TREE_STATIC (d) || specs->constexpr_p,
specs->constexpr_p, &richloc);
/* A parameter is initialized, which is invalid. Don't
attempt to instrument the initializer. */
int flag_sanitize_save = flag_sanitize;
if (TREE_CODE (d) == PARM_DECL)
flag_sanitize = 0;
init = c_parser_initializer (parser, d);
flag_sanitize = flag_sanitize_save;
if (specs->constexpr_p)
{
finish_underspecified_init (underspec_name,
underspec_state);
d = pushdecl (d);
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, NULL_TREE,
omp_declare_simd_clauses);
if (!specs->constexpr_p
&& !omp_dsimd_idattr_clauses.is_empty ())
c_finish_omp_declare_simd (parser, d, NULL_TREE,
&omp_dsimd_idattr_clauses);
}
finish_init ();
}
if (oacc_routine_data)
c_finish_oacc_routine (oacc_routine_data, d, false);
if (d != error_mark_node)
{
maybe_warn_string_init (init_loc, TREE_TYPE (d), init);
finish_decl (d, init_loc, init.value,
init.original_type, asm_name);
result = d;
}
}
else
{
if (any_auto_type_p || specs->constexpr_p)
{
error_at (here,
"%qs requires an initialized data declaration",
any_auto_type_p ? auto_type_keyword : "constexpr");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
location_t lastloc = UNKNOWN_LOCATION;
tree attrs = chainon (postfix_attrs, all_prefix_attrs);
tree d = start_decl (declarator, specs, false, attrs, true,
&lastloc);
if (d && TREE_CODE (d) == FUNCTION_DECL)
{
/* Find the innermost declarator that is neither cdk_id
nor cdk_attrs. */
const struct c_declarator *decl = declarator;
const struct c_declarator *last_non_id_attrs = NULL;
while (decl)
switch (decl->kind)
{
case cdk_array:
case cdk_function:
case cdk_pointer:
last_non_id_attrs = decl;
decl = decl->declarator;
break;
case cdk_attrs:
decl = decl->declarator;
break;
case cdk_id:
decl = 0;
break;
default:
gcc_unreachable ();
}
/* If it exists and is cdk_function declaration whose
arguments have not been set yet, use its arguments. */
if (last_non_id_attrs
&& last_non_id_attrs->kind == cdk_function)
{
tree parms = last_non_id_attrs->u.arg_info->parms;
if (DECL_ARGUMENTS (d) == NULL_TREE
&& DECL_INITIAL (d) == NULL_TREE)
DECL_ARGUMENTS (d) = parms;
warn_parm_array_mismatch (lastloc, d, parms);
}
}
if (omp_declare_simd_clauses
|| !omp_dsimd_idattr_clauses.is_empty ())
{
tree parms = NULL_TREE;
if (d && TREE_CODE (d) == FUNCTION_DECL)
{
struct c_declarator *ce = declarator;
while (ce != NULL)
if (ce->kind == cdk_function)
{
parms = ce->u.arg_info->parms;
break;
}
else
ce = ce->declarator;
}
if (parms)
temp_store_parm_decls (d, parms);
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, d, parms,
omp_declare_simd_clauses);
if (!specs->constexpr_p
&& !omp_dsimd_idattr_clauses.is_empty ())
c_finish_omp_declare_simd (parser, d, parms,
&omp_dsimd_idattr_clauses);
if (parms)
temp_pop_parm_decls ();
}
if (oacc_routine_data)
c_finish_oacc_routine (oacc_routine_data, d, false);
if (d)
finish_decl (d, UNKNOWN_LOCATION, NULL_TREE,
NULL_TREE, asm_name);
if (c_parser_next_token_is_keyword (parser, RID_IN))
{
if (d)
*objc_foreach_object_declaration = d;
else
*objc_foreach_object_declaration = error_mark_node;
}
}
if (c_parser_next_token_is (parser, CPP_COMMA))
{
more_than_one_decl = true;
if (any_auto_type_p || specs->constexpr_p)
{
error_at (here,
"%qs may only be used with a single declarator",
any_auto_type_p ? auto_type_keyword : "constexpr");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
c_parser_consume_token (parser);
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
all_prefix_attrs = chainon (c_parser_gnu_attributes (parser),
prefix_attrs);
else
all_prefix_attrs = prefix_attrs;
continue;
}
else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
{
if (!simple_ok)
c_parser_consume_token (parser);
return result;
}
else if (c_parser_next_token_is_keyword (parser, RID_IN))
{
/* This can only happen in Objective-C: we found the
'in' that terminates the declaration inside an
Objective-C foreach statement. Do not consume the
token, so that the caller can use it to determine
that this indeed is a foreach context. */
return result;
}
else
{
if (!simple_ok)
{
c_parser_error (parser, "expected %<,%> or %<;%>");
c_parser_skip_to_end_of_block_or_statement (parser);
}
/* It's not valid to use if (int i = 2, j = 3). */
else if (more_than_one_decl)
error_at (here, "declaration in condition can only declare "
"a single object");
return result;
}
}
else if (any_auto_type_p || specs->constexpr_p)
{
error_at (here,
"%qs requires an initialized data declaration",
any_auto_type_p ? auto_type_keyword : "constexpr");
c_parser_skip_to_end_of_block_or_statement (parser);
return result;
}
else if (!fndef_ok)
{
if (simple_ok && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
/* Let c_parser_selection_header emit the error. */;
else
{
c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, "
"%<asm%> or %<__attribute__%>");
c_parser_skip_to_end_of_block_or_statement (parser);
}
return result;
}
/* Function definition (nested or otherwise). */
if (nested)
{
pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions");
c_push_function_context ();
}
if (!start_function (specs, declarator, all_prefix_attrs))
{
/* At this point we've consumed:
declaration-specifiers declarator
and the next token isn't CPP_EQ, CPP_COMMA, CPP_SEMICOLON,
RID_ASM, RID_ATTRIBUTE, or RID_IN,
but the
declaration-specifiers declarator
aren't grokkable as a function definition, so we have
an error. */
gcc_assert (!c_parser_next_token_is (parser, CPP_SEMICOLON));
if (c_parser_next_token_starts_declspecs (parser))
{
/* If we have
declaration-specifiers declarator decl-specs
then assume we have a missing semicolon, which would
give us:
declaration-specifiers declarator decl-specs
^
;
<~~~~~~~~~ declaration ~~~~~~~~~~>
Use c_parser_require to get an error with a fix-it hint. */
c_parser_require (parser, CPP_SEMICOLON, "expected %<;%>");
parser->error = false;
}
else
{
/* This can appear in many cases looking nothing like a
function definition, so we don't give a more specific
error suggesting there was one. */
c_parser_error (parser, "expected %<=%>, %<,%>, %<;%>, %<asm%> "
"or %<__attribute__%>");
}
if (nested)
c_pop_function_context ();
break;
}
if (DECL_DECLARED_INLINE_P (current_function_decl))
tv = TV_PARSE_INLINE;
else
tv = TV_PARSE_FUNC;
auto_timevar at (g_timer, tv);
/* Parse old-style parameter declarations. ??? Attributes are
not allowed to start declaration specifiers here because of a
syntax conflict between a function declaration with attribute
suffix and a function definition with an attribute prefix on
first old-style parameter declaration. Following the old
parser, they are not accepted on subsequent old-style
parameter declarations either. However, there is no
ambiguity after the first declaration, nor indeed on the
first as long as we don't allow postfix attributes after a
declarator with a nonempty identifier list in a definition;
and postfix attributes have never been accepted here in
function definitions either. */
int save_debug_nonbind_markers_p = debug_nonbind_markers_p;
debug_nonbind_markers_p = 0;
c_parser_maybe_reclassify_token (parser);
while (c_parser_next_token_is_not (parser, CPP_EOF)
&& c_parser_next_token_is_not (parser, CPP_OPEN_BRACE))
c_parser_declaration_or_fndef (parser, false, false, false,
true, false, false);
debug_nonbind_markers_p = save_debug_nonbind_markers_p;
store_parm_decls ();
if (omp_declare_simd_clauses)
c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
omp_declare_simd_clauses);
if (!omp_dsimd_idattr_clauses.is_empty ())
c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE,
&omp_dsimd_idattr_clauses);
if (oacc_routine_data)
c_finish_oacc_routine (oacc_routine_data, current_function_decl, true);
location_t startloc = c_parser_peek_token (parser)->location;
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= startloc;
location_t endloc = startloc;
/* If the definition was marked with __RTL, use the RTL parser now,
consuming the function body. */
if (specs->declspec_il == cdil_rtl)
{
endloc = c_parser_parse_rtl_body (parser, specs->gimple_or_rtl_pass);
/* Normally, store_parm_decls sets next_is_function_body,
anticipating a function body. We need a push_scope/pop_scope
pair to flush out this state, or subsequent function parsing
will go wrong. */
push_scope ();
pop_scope ();
finish_function (endloc);
return result;
}
/* If the definition was marked with __GIMPLE then parse the
function body as GIMPLE. */
else if (specs->declspec_il != cdil_none)
{
bool saved = in_late_binary_op;
in_late_binary_op = true;
c_parser_parse_gimple_body (parser, specs->gimple_or_rtl_pass,
specs->declspec_il,
specs->entry_bb_count);
in_late_binary_op = saved;
}
else
fnbody = c_parser_compound_statement (parser, &endloc);
tree fndecl = current_function_decl;
if (nested)
{
tree decl = current_function_decl;
/* Mark nested functions as needing static-chain initially.
lower_nested_functions will recompute it but the
DECL_STATIC_CHAIN flag is also used before that happens,
by initializer_constant_valid_p. See gcc.dg/nested-fn-2.c. */
DECL_STATIC_CHAIN (decl) = 1;
add_stmt (fnbody);
finish_function (endloc);
c_pop_function_context ();
add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
}
else
{
if (fnbody)
add_stmt (fnbody);
finish_function (endloc);
}
/* Get rid of the empty stmt list for GIMPLE/RTL. */
if (specs->declspec_il != cdil_none)
DECL_SAVED_TREE (fndecl) = NULL_TREE;
break;
}
return result;
}
当完成变量或者函数的解析后,会在符号表注册
/* Finish up a function declaration and compile that function
all the way to assembler language output. Then free the storage
for the function definition.
This is called after parsing the body of the function definition. */
void
finish_function (location_t end_loc)
{
tree fndecl = current_function_decl;
if (c_dialect_objc ())
objc_finish_function ();
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
{
tree args = DECL_ARGUMENTS (fndecl);
for (; args; args = DECL_CHAIN (args))
{
tree type = TREE_TYPE (args);
if (INTEGRAL_TYPE_P (type)
&& TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node))
DECL_ARG_TYPE (args) = c_type_promotes_to (type);
}
}
if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node)
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
/* Must mark the RESULT_DECL as being in this function. */
if (DECL_RESULT (fndecl) && DECL_RESULT (fndecl) != error_mark_node)
DECL_CONTEXT (DECL_RESULT (fndecl)) = fndecl;
if (MAIN_NAME_P (DECL_NAME (fndecl)) && !TREE_THIS_VOLATILE (fndecl)
&& TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (fndecl)))
== integer_type_node && flag_isoc99)
{
/* Hack. We don't want the middle-end to warn that this return
is unreachable, so we mark its location as special. Using
UNKNOWN_LOCATION has the problem that it gets clobbered in
annotate_one_with_locus. A cleaner solution might be to
ensure ! should_carry_locus_p (stmt), but that needs a flag.
*/
c_finish_return (BUILTINS_LOCATION, integer_zero_node, NULL_TREE);
}
/* Tie off the statement tree for this function. */
DECL_SAVED_TREE (fndecl) = pop_stmt_list (DECL_SAVED_TREE (fndecl));
finish_fname_decls ();
/* Complain if there's no return statement only if option specified on
command line. */
if (warn_return_type > 0
&& TREE_CODE (TREE_TYPE (TREE_TYPE (fndecl))) != VOID_TYPE
&& !current_function_returns_value && !current_function_returns_null
/* Don't complain if we are no-return. */
&& !current_function_returns_abnormally
/* Don't complain if we are declared noreturn. */
&& !TREE_THIS_VOLATILE (fndecl)
/* Don't warn for main(). */
&& !MAIN_NAME_P (DECL_NAME (fndecl))
/* Or if they didn't actually specify a return type. */
&& !C_FUNCTION_IMPLICIT_INT (fndecl)
/* Normally, with -Wreturn-type, flow will complain, but we might
optimize out static functions. */
&& !TREE_PUBLIC (fndecl)
&& targetm.warn_func_return (fndecl)
&& warning (OPT_Wreturn_type,
"no return statement in function returning non-void"))
suppress_warning (fndecl, OPT_Wreturn_type);
/* Complain about parameters that are only set, but never otherwise used. */
if (warn_unused_but_set_parameter)
{
tree decl;
for (decl = DECL_ARGUMENTS (fndecl);
decl;
decl = DECL_CHAIN (decl))
if (TREE_USED (decl)
&& TREE_CODE (decl) == PARM_DECL
&& !DECL_READ_P (decl)
&& DECL_NAME (decl)
&& !DECL_ARTIFICIAL (decl)
&& !warning_suppressed_p (decl, OPT_Wunused_but_set_parameter))
warning_at (DECL_SOURCE_LOCATION (decl),
OPT_Wunused_but_set_parameter,
"parameter %qD set but not used", decl);
}
/* Complain about locally defined typedefs that are not used in this
function. */
maybe_warn_unused_local_typedefs ();
/* Possibly warn about unused parameters. */
if (warn_unused_parameter)
do_warn_unused_parameter (fndecl);
/* Store the end of the function, so that we get good line number
info for the epilogue. */
cfun->function_end_locus = end_loc;
/* Finalize the ELF visibility for the function. */
c_determine_visibility (fndecl);
/* For GNU C extern inline functions disregard inline limits. */
if (DECL_EXTERNAL (fndecl)
&& DECL_DECLARED_INLINE_P (fndecl)
&& (flag_gnu89_inline
|| lookup_attribute ("gnu_inline", DECL_ATTRIBUTES (fndecl))))
DECL_DISREGARD_INLINE_LIMITS (fndecl) = 1;
/* Genericize before inlining. Delay genericizing nested functions
until their parent function is genericized. Since finalizing
requires GENERIC, delay that as well. */
if (DECL_INITIAL (fndecl) && DECL_INITIAL (fndecl) != error_mark_node
&& !undef_nested_function)
{
if (!decl_function_context (fndecl))
{
invoke_plugin_callbacks (PLUGIN_PRE_GENERICIZE, fndecl);
c_genericize (fndecl);
/* ??? Objc emits functions after finalizing the compilation unit.
This should be cleaned up later and this conditional removed. */
if (symtab->global_info_ready)
{
cgraph_node::add_new_function (fndecl, false);
return;
}
cgraph_node::finalize_function (fndecl, false);
}
else
{
/* Register this function with cgraph just far enough to get it
added to our parent's nested function list. Handy, since the
C front end doesn't have such a list. */
(void) cgraph_node::get_create (fndecl);
}
}
if (!decl_function_context (fndecl))
undef_nested_function = false;
if (cfun->language != NULL)
{
ggc_free (cfun->language);
cfun->language = NULL;
}
/* We're leaving the context of this function, so zap cfun.
It's still in DECL_STRUCT_FUNCTION, and we'll restore it in
tree_rest_of_compilation. */
set_cfun (NULL);
invoke_plugin_callbacks (PLUGIN_FINISH_PARSE_FUNCTION, current_function_decl);
current_function_decl = NULL;
}
符号或者函数的实现需要注册到符号表中去
/* Add node into symbol table. This function is not used directly, but via
cgraph/varpool node creation routines. */
void
symtab_node::register_symbol (void)
{
symtab->register_symbol (this);
if (!decl->decl_with_vis.symtab_node)
decl->decl_with_vis.symtab_node = this;
ref_list.clear ();
/* Be sure to do this last; C++ FE might create new nodes via
DECL_ASSEMBLER_NAME langhook! */
symtab->insert_to_assembler_name_hash (this, false);
}
总体来说,语法解析的代码非常大,细节的实现难以看明白,需要的话需要很深入的去了解