gcc源码阅读--语法解析

gcc 源码阅读---语法树 GCC语法树节点类型定义摘要 GCC编译器在tree.def文件中定义了丰富的语法树节点类型,涵盖编译器前端到后端处理的各类语法结构。主要分类包括: 基础节点类:ERROR_MARK、IDENTIFIER_NODE等异常标记节点 类型节点:INTEGER_TYPE、POINTER_TYPE等30+种数据类型 常量节点:INTEGER_CST、REAL_CST等10+种常量类型 声明节点:FUNCTION_DECL、VAR_DECL等20+种声明类型 表达式节点:包含算术运算(PLUS_EXPR)、比较运算( 阅读详情

语法解析的开始函数:

/* 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);
}
 

总体来说,语法解析的代码非常大,细节的实现难以看明白,需要的话需要很深入的去了解

CentOS下源码安装GCC 5.2.0 今天开始研读c++ primer fifth edition, 这本书遵循了C++11标准,很多新特性需要GNU compiler 4.7.0之后才支持,而CentOS6通过yum最多只能升到4.4.7,这就必须源码安装GCC了。废话不多说,首先下载源码包:wget http://mirrors-usa.go-parts.com/gcc/releases/gcc-5.2.0/gcc-5.2.0.ta 阅读详情

相关推荐

高效阅读嵌入式源码系列一:静态分析神器understand软件基本操作

之前一直使用source insight 4阅读C程序源码,非常喜欢它的context与relation,可惜source insight不能过滤复杂的条件编译(会干扰对源码的理解)。机缘巧合之下,从知乎中获知了understand这个静态分析神器,本系列文章便是介绍这几个月使用understand的方法与技巧。...............

eagle11235的博客 1万+

warning: ISO C forbids an empty translation unit [-pedantic]

root@Ubuntu32:/home/zhangbin/codeStore/testCODE/testMeServerRTSP/mework/meserver/meserver# make gcc -pedantic -Wall -Wextra -march=native -ggdb3 -o testmeserver config.h config.h:12:

突围 4762

gcc源码分析与应用系列教程(1)

因为工作的原因,接触到gcc源码,经过两个多月的分析和学习之后,对它有了一个初步的认识,打算写一篇文章来分享下自己的工作经验。 本系列采用gcc-9.2.0的源码,源码阅读工具为vscode,下面我们来看具体的内容。 gcc编译器分为三部分,分别是前端,中端,和后端。 前端主要实现词法分析,语法分析,语义分析等相关的功能,并将其转换为一种中间语言,我们把这种中间语言,我们把它称之为gimple。 ...

m0_46338137的博客 1201

Pch文件的主要作用 和分类Category的作用

pch:( Prefix  Header File) 1.放一些公共的宏定义 2.放一些公共的某个类的头文件 3.自定义NSLog() 什么是Category Category模式用于向已经存在的类添加方法从而达到扩展已有类的目的,在很多情形下Category也是比创建子类更优的选择。新添加的方法 同样也会被被扩展的类的所有子类自动继承。当知道已有类中

yoyo_lzj的博客 636

gcc源码阅读--gimple 介绍

摘要:GENERIC是一种规范化的AST表示形式,旨在建立与前端语言无关的统一AST标准。在GCC编译器中,前端语言通常会将AST/GENERIC转换为GIMPLE中间表示。GIMPLE是一种三地址码形式的语言无关中间表示,相比树形结构的AST/GENERIC,它具有线性序列的特点,更利于后续编译优化。从AST到GIMPLE的转换包含高级GIMPLE和低级GIMPLE两个阶段,最终会消除作用域等相关语句,形成更简洁的中间表示形式。这一转换过程实现了从语言相关到语言无关的过渡,为编译器后端处理提供了统一基础。

633

深入GCC源码:解析C++26模块与反射机制的实现原理

C++模块化编程是现代C++演进的核心方向,旨在通过模块(Modules)机制替代传统的头文件包含(#include),从根本上解决编译速度慢、宏污染和接口隔离等问题。其原理在于编译器将模块接口序列化为二进制模块接口(BMI)文件,实现一次解析、多次复用,大幅提升构建效率。这一技术价值不仅体现在编译加速上,更在于为大型工程提供了更清晰的物理架构和更强的封装性。在应用场景上,模块化特性正逐步从C++20向C++26演进,并与反射(Reflection)等新特性深度集成,为元编程和代码生成开辟了新路径。本文以G

weixin_33290540的博客 273

GCC-3.4.6源代码学习笔记(76)

5.4.由-include包含的头文件<br />根据【6】,由选项–include包含的头文件应该在源文件中所包含的头文件之前被引入,但要在被–macro指定的文件处理完成后,才能被处理。如果给出了多个-include选项,那么文件要按在命令行出现的顺序被引入。<br /> <br />finish_options (continue)<br /> <br />1466  include_cursor = 0;<br />1467  push_command_line_include ();<br />1

wuhui_gdnt的专栏 1306

加速你的 C++ 编译:使用预编译头文件(PCH)

幸运的是,C++ 提供了一种简单但有效的方法来加快编译速度:使用预编译头文件(PCH)。通过使用预编译头文件,我们可以避免重复编译常用头文件和声明,从而大大加快编译速度。在大型项目中使用预编译头文件是一个非常好的习惯,希望这个小技巧能够帮助你加速 C++ 编译过程。然后,我们将创建一个名为“pch.h”的预编译头文件,包含常用头文件,并将其编译为一个名为“pch.pch”的二进制文件。参数指定要包含的预编译头文件,“-Winvalid-pch”参数表示如果找不到预编译头文件就会出现错误。

James_CODER的博客 778

GCC源代码阅读

获取GCC源代码 阅读源代码的第一步是获取源代码,巧妇难为无米之炊嘛! 使用以下任意方法均可获得gcc源代码: svn checkout svn://gcc.gnu.org/svn/gcc/trunk SomeLocalDir (摘自http://gcc.gnu.org/svn.html) git clone git://gcc.gnu.org/git/gcc.git(摘自http...

weiyinchao88 531

Linux GCC-4.4.7编译器源码解析与实战学习

GCC(GNU Compiler Collection)是GNU项目的核心组件之一,最初由Richard Stallman于1987年发起,旨在提供一个自由、开放、支持多种编程语言和目标平台的编译器套件。它不仅支持C和C++,还涵盖Fortran、Java、Objective-C等多种语言。GCC的开源特性使其在操作系统开发、嵌入式系统、高性能计算等领域广泛应用。return t;这段代码构建了一个函数类型节点,用于表示函数的返回类型和参数类型列表。make_node:创建一个树节点;

weixin_33431149的博客 689

Gcc核心源代码分析

Gcc核心源代码分析

Linux纯命令行以源码编译安装gcc(2024年2月5日)

欢迎阅读这篇关于在Linux系统中从源码编译安装GCC 13的详细指南。GCC(GNU Compiler Collection)作为一个强大的编译器集合,对于开发者来说是至关重要的工具之一。在这篇文章中,我们将探讨如何通过纯命令行的方式,从源代码构建并安装最新版本的GCC 13。为什么选择源码编译?源码编译不仅能够让我们获得最新的GCC版本,还允许我们在系统中灵活地配置和使用编译器。通过深入了解每个步骤,读者将能够更好地理解GCC的安装过程,并根据自己的需求进行定制。

m0_73062333的博客 1万+

不经意传输(OT)协议 - Mike Rosulek教授课堂笔记

OT扩展协议-IKNP

qq_43569221的博客 1850

linux编译gcc源码,源码安装gcc各种情况的解决

现在很多程序员都应用GCC,怎样才能更好的应用GCC。目前,GCC可以用来编译C/C++、FORTRAN、JAVA、OBJC、ADA等语言 的程序,可根据需要选择安装支持的语言。本文以在Redhat Linux安装GCC4.1.2为例(因在项目开发过程中要求使用,没有用最新的GCC版本),介绍Linux安装GCC过程。安装之前,系统中必须要有cc或者gcc等编译器,并且是可用的,或者用环境变量CC...

weixin_39641103的博客 1791

Google AdSense收款前必做:W-8BEN税务认证的3个关键选择与1个提交时机小技巧

本文深入解析Google AdSense收款前必须完成的W-8BEN税务认证,重点介绍账号类型选择、特殊税率勾选、美国活动界定等3个关键决策,并分享提交时机的小技巧,帮助站长高效通过审核,确保广告收入顺利到账。

weixin_30443731的博客 671

JetBrains Air:多Agent协同的IDE运行时架构解析

IDE智能编程正从单模型增强迈向多Agent协同范式。多Agent架构通过职责分离、上下文精简与运行时隔离,显著提升代码生成稳定性与合规性;其核心依赖轻量级嵌入式运行时(如ARL),支持AST级内存共享、eBPF安全拦截与毫秒级冷启动。该架构天然适配本地化部署、离线开发与高安全合规场景(如PCI-DSS、金融内网),并为Java/Python/TS等语言提供可扩展的规则驱动开发流水线。JetBrains Air正是这一技术路径的工程化落地代表。

weixin_30443075的博客 565

一个超级实用的源码阅读小技巧

大家好,我是小麦。在学习编程的路途漫漫,优秀的源码是非常珍贵的学习资源,阅读源码也是有效提高自己的一个好方法。工欲善其事必先利其器;我发现函数调用图可以让我们更加直观地了解到源码函数直接的...

一名热爱技术的工程师的博客。分享技术干货,记录美好生活。永远相信美好的事情即将发生。 1924

【从零开始学Skynet】基础篇(一):Skynet环境搭建

Skynet运行于Linux操作系统,我们可以在自己的电脑上搭建虚拟机系统,也可以购买阿里云、腾讯云服务器,笔者这个系列的所有代码都是在Ubuntu16.04版本的虚拟机系统下运行编辑。

我是一条寻水的鱼 3167

科普文:软件架构数据库系列之【MySQL源码阅读小技巧】

开源软件已经广泛的被互联网公司所应用,不仅仅是因为其能给企业节省一大笔成本,而且最重要的是拥有更多的自主可控性,能从源头上对软件质量进行把控。另一方面,由于开源软件背后往往没有大型的商业公司,所以文档相对来说不是非常完善(或者说文档和代码不一定相互对应),因此,作为一名合格程序员,尤其是基础软件开发的程序员,阅读源码的能力是必备的素质。

为无为,事无事,味无味。 1542

(MATLAB)一维信号峰值检测findpeaks

一维信号波峰波谷检测,峰值、峰宽、到达时间计算。MATLAB自带的findpeaks函数能完成这一任务,在这里分享其基本用法与特殊用法。

HPC_ZY 2万+

【WRF数据准备】海温(SST)数据替换

【WRF数据准备】海温(SST)数据替换

WW、forever的博客 1117

使用源码安装gcc 9.2.0

安装之前,系统中必须要有cc或者gcc等编译器,并且是可用的,或者用环境变量CC指定系统上的编译器。如果系统上没有编译器,不能安装源代码形式的GCC 9.2.0。如果是这种情况,可以在网上找一个与你系统相适应的如RPM等二进制形式的GCC软件包来安装使用。本文介绍的是以源代码形式提供的GCC软件包的安装过程,软件包本身和其安装过程同样适用于其它Linux和Unix系统。 1 下载 在GC...

lucboll的博客 9231

C#单例模式在工控上位机的实战应用:一台设备只连一次,稳定运行7×24小时

在工控行业,稳定性比功能更重要。一台上位机需要7×24小时运行,任何一次因资源冲突导致的停机,都可能给工厂带来巨大损失。单例模式的核心价值,就是通过保证资源唯一性,避免PLC连接冲突、串口占用、日志写入错乱等问题,为工控上位机的稳定运行保驾护航。按需使用:不是所有类都要单例,只有资源唯一性的类才用;线程安全:多线程场景下,必须用双重检查锁定或静态内部类写法;手动释放:单例类中的硬件资源(PLC、串口),程序退出时必须手动释放,避免资源泄漏。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 549

【Linux指南】gcc/g++编译器:从源码到可执行文件的全流程解析

在Linux开发环境中,gcc和g++是最常用的编译器工具,它们承担着将源代码转化为可执行程序的核心任务。其中,gcc专注于C语言程序的编译,而g++则同时支持C和C++语言。理解这两款编译器的工作原理和使用方法,是掌握Linux开发的基础技能。

倔强的石头的博客 3万+

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

gcc 源码阅读--C语言预处理

此hash桶是自动扩展的,在ht搜索函数ht_lookup_with_hash中,若发现整个hash table超过3/4都满了,就会主动扩展此hash table(重新分配,复制,释放原有的)。alloc_node函数是用来分配节点内存的,分配后hashnode[]数组中的指针,也就指向这个内存中的元素,在ht搜索过程中(ht_lookup_with_hash),若发现需要新。/* 当前正在处理的语法符号c_token的地址,这里除了初始化时,应该指向 tokens_buf[0] */

615

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

上一篇: gcc 源码阅读--C语言预处理
下一篇: gcc 源码阅读--全局符号表管理
GoldKey
博客等级 码龄25年 82粉丝 27原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

GoldKey

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值