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

5.12.3.2.1.1.1.          解析类体 – typedef 声明

5.12.3.2.1.1.4.1.    找出 decl-specifier-spec declarator

退出结构体“ Lock ”的定义,现在回到类“ SingleThreaded ”的定义。接下来的声明是“ typedef Host VolatileType; ”。

对于这个声明,“ typedef Host ”部分是 decl-specifier-seq ,而“ VolatileType ”就是声明符。再一次,我们的旅程从 cp_parser_member_declaration 开始,这个函数逐个处理类的方法。

 

12457 static void

12458 cp _parser_member_declaration (cp_parser* parser)                                     in parser.c

12459 {

12460   tree decl_specifiers;

12461   tree prefix_attributes;

12462   tree decl;

12463   int declares_class_or_enum;

12464   bool friend_p;

12465   cp_token *token;

12466   int saved_pedantic;

       …

12502   /* Parse the decl-specifier-seq.  */

12503   decl_specifiers

12504     = cp_parser_decl_specifier_seq (parser,

12505                               CP_PARSER_FLAGS_OPTIONAL,

12506                               &prefix_attributes,

12507                                &declares_class_or_enum);

 

关键字“ typedef 仅使得 cp_parser_decl_specifier_seq 返回表示“ typedef ”的全局唯一的标识符节点,这个节点在设置运行时环境时创建。同时标识符“ Host ”则经历以下的调用栈来找出对应的 TYPE_DECL 节点。

cp_parser_type_specifier à cp_parser_simple_type_specifier à cp_parser_type_name à cp_parser_class_name 。那么在 12504 行的 decl_specifiers 如下图所示。

点此打开

87 :对应 typedef 声明的 decl-specifier-seq

那么对于声明符“ VolatileType ”,通过以下的调用栈,它被识别为一个新的标识符: cp_parser_declarator à cp_parser_direct_declarator à cp_parser_declarator_id à cp_parser_id_expression à cp_parser_unqualified_id à cp_parser_identifier

 

cp_parser_member_declaration (continue)

 

12603   else

12604   {

12605      /* See if these declarations will be friends.  */

12606     friend_p = cp_parser_friend_p (decl_specifiers);

12607

12608     /* Keep going until we hit the `;' at the end of the

12609       declaration.  */

12610     while (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))

12611     {

12612       tree attributes = NULL_TREE;

12613       tree first_attribute;

12614

12615       /* Peek at the next token.  */

12616       token = cp_lexer_peek_token (parser->lexer);

12617

12618        /* Check for a bitfield declaration.  */

12619       if (token->type == CPP_COLON

12620          || (token->type == CPP_NAME

12621            && cp_lexer_peek_nth_token (parser->lexer, 2)->type

12622                        == CPP_COLON))

12623       {

              …

12657       }

12658       else

12659       {

12660         tree declarator;

12661         tree initializer;

12662         tree asm_specification;

12663         int ctor_dtor_or_conv_p;

12664

12665           /* Parse the declarator.  */

12666         declarator

12667             = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,

12668                                 &ctor_dtor_or_conv_p,

12669                                  /*parenthesized_p=*/ NULL,

12670                                 /*member_p=*/ true);

              …

12710         if (cp_lexer_next_token_is (parser->lexer, CPP_EQ))

12711         {

                 …

12730         }

12731         /* Otherwise, there is no initializer.  */

12732         else

12733           initializer = NULL_TREE;

5.12.3.2.1.1.4.2.    为类字段构建节点

在解析了 decl-specifier-seq declarator 后,需要把结果打包入相应的节点,并插入中间树中。

 

cp_parser_member_declaration (continue)

 

12735         /* See if we are probably looking at a function

12736           definition. We are certainly not looking at at a

12737           member-declarator. Calling `grokfield' has

12738           side-effects, so we must not do it unless we are sure

12739           that we are looking at a member-declarator.  */

12740         if (cp_parser_token_starts_function_definition_p

12741                         ( cp_lexer_peek_token (parser->lexer)))

12742         {

                …

12763         }

12764         else

12765         {

12766           /* Create the declaration.  */

12767           decl = grokfield (declarator, decl_specifiers,

12768                         initializer, asm_specification,

12769                         attributes);

12770           /* Any initialization must have been from a

12771             constant-expression.  */

12772           if (decl && TREE_CODE (decl) == VAR_DECL && initializer)

12773             DECL_INITIALIZED_BY_CONSTANT_EXPRESSION_P (decl) = 1;

12774         }

12775       }

 

相应地如果这不是一个函数定义,它被假设为域来处理。在前一节中,我们已经看过特殊函数定义的处理——构造函数。

 

821    tree

822    grokfield (tree declarator, tree declspecs, tree init, tree asmspec_tree,            in decl2.c

823            tree attrlist)

824    {

825      tree value;

826      const char *asmspec = 0;

827      int flags = LOOKUP_ONLYCONVERTING;

828   

829      if (declspecs == NULL_TREE

830         && TREE_CODE (declarator) == SCOPE_REF

831          && TREE_CODE (TREE_OPERAND (declarator, 1)) == IDENTIFIER_NODE)

832      {

833        /* Access declaration */

834        if (! IS_AGGR_TYPE_CODE (TREE_CODE (TREE_OPERAND (declarator, 0))))

835          ;

836        else if (TREE_COMPLEXITY (declarator) == current_class_depth)

837          pop_nested_class ();

838        return do_class_using_decl (declarator);

839      }

840   

841      if (init

842         && TREE_CODE (init) == TREE_LIST

843         && TREE_VALUE (init) == error_mark_node

844         && TREE_CHAIN (init) == NULL_TREE)

845        init = NULL_TREE;

846   

847      value = grokdeclarator (declarator, declspecs, FIELD, init != 0, &attrlist);

848      if (! value || error_operand_p (value))

849        /* friend or constructor went bad.  */

850        return error_mark_node;

 

该函数也需要 grokdeclarator 来为域声明创建合适的树节点。在这次调用中, initialized false ,而 attrlist NULL_TREE

 

6462   tree

6463   grokdeclarator (tree declarator,                                                                        in decl.c

6464                tree declspecs,

6465                enum decl_context decl_context,

6466                int initialized,

6467                tree* attrlist)

6468   {

6469     RID_BIT_TYPE specbits;

6470     int nclasses = 0;

6471     tree spec;

6472     tree type = NULL_TREE;

6473     int longlong = 0;

6474     int type_quals;

6475     int virtualp, explicitp, friendp, inlinep, staticp;

6476     int explicit_int = 0;

6477     int explicit_char = 0;

6478     int defaulted_int = 0;

6479     int extern_langp = 0;

6480     tree dependant_name = NULL_TREE;

6481    

6482     tree typedef_decl = NULL_TREE;

6483     const char *name;

6484     tree typedef_type = NULL_TREE;

6485     int funcdef_flag = 0;

6486     enum tree_code innermost_code = ERROR_MARK;

6487     int bitfield = 0;

6488   #if 0

6489     /* See the code below that used this.  */

6490     tree decl_attr = NULL_TREE;

6491   #endif

6492  

6493     /* Keep track of what sort of function is being processed

6494       so that we can warn about default return values, or explicit

6495       return values which do not match prescribed defaults.  */

6496     special_function_kind sfk = sfk_none;

6497  

6498     tree dname = NULL_TREE;

6499     tree ctype = current_class_type ;

6500     tree ctor_return_type = NULL_TREE;

6501     enum overload_flags flags = NO_SPECIAL;

6502     tree quals = NULL_TREE;

6503     tree raises = NULL_TREE;

6504     int template_count = 0;

6505     tree in_namespace = NULL_TREE;

6506     tree returned_attrs = NULL_TREE;

6507     tree scope = NULL_TREE;

6508     tree parms = NULL_TREE;

6509  

6510     RIDBIT_RESET_ALL (specbits);

6511     if (decl_context == FUNCDEF)

6512       funcdef_flag = 1, decl_context = NORMAL;

6513     else if (decl_context == MEMFUNCDEF)

6514       funcdef_flag = -1, decl_context = FIELD;

6515     else if (decl_context == BITFIELD)

6516       bitfield = 1, decl_context = FIELD;

6517  

6518     /* Look inside a declarator for the name being declared

6519       and get it as a string, for an error message.  */

6520     {

6521       tree *next = &declarator;

6522       tree decl;

6523       name = NULL;

6524  

6525        while (next && *next)

6526       {

6527         decl = *next;

6528         switch (TREE_CODE (decl))

6529         {

              …        

6629           case IDENTIFIER_NODE:

6630           if (TREE_CODE (decl) == IDENTIFIER_NODE)

6631             dname = decl;

6632  

6633           next = 0;

6634  

6635           if (C_IS_RESERVED_WORD (dname))

6636           {

6637             error ("declarator-id missing; using reserved word `%D'",

6638                   dname);

6639             name = IDENTIFIER_POINTER (dname);

6640           }

6641           else if (!IDENTIFIER_TYPENAME_P (dname))

6642             name = IDENTIFIER_POINTER (dname);

6643           else

6644           {

6645             my_friendly_assert (flags == NO_SPECIAL, 154);

6646             flags = TYPENAME_FLAG;

6647             ctor_return_type = TREE_TYPE (dname);

6648             sfk = sfk_conversion;

6649             if (is_typename_at_global_scope (dname))

6650               name = IDENTIFIER_POINTER (dname);

6651             else

6652               name = "<invalid operator>";

6653           }

6654           break ;

              …

6784         }

6785       }

6786     }

 

正如我们之前所见,首先,函数处理声明符来找出 decl-specifier-seq 所描述对象。这里,在 6631 行,标识符“ VolatileType ”被赋予 dname 。在 6642 行, IDENTIFIER_POINTER 返回该标识符中的代表名字的字符串(即字符串“ VolatileType ”)。

然后在对声明符处理结果的一些检查后,开始处理 decl-specifier-seq 部分。这里的 decl-specifier-seq 的第一部分是关键字“ typedef ”。我们已经在函数 init_reswords 中看到,它的信息被记录在全局数组 ridpointers 里,因此在下面的 6929 行, RIDBIT_SET 把看到 typedef 的事实记录入 specbits

 

grokdeclarator (continue)

 

6828     /* Look through the decl specs and record which ones appear.

6829       Some typespecs are defined as built-in typenames.

6830       Others, the ones that are modifiers of other types,

6831       are represented by bits in SPECBITS: set the bits for

6832       the modifiers that appear. Storage class keywords are also in SPECBITS.

6833  

6834       If there is a typedef name or a type, store the type in TYPE.

6835       This includes builtin typedefs such as `int'.

6836  

6837       Set EXPLICIT_INT if the type is `int' or `char' and did not

6838       come from a user typedef.

6839  

6840       Set LONGLONG if `long' is mentioned twice.

6841  

6842       For C++, constructors and destructors have their own fast treatment.  */

6843  

6844     for (spec = declspecs; spec; spec = TREE_CHAIN (spec))

6845     {

6846       int i;

6847        tree id;

6848  

6849       /* Certain parse errors slip through. For example,

6850         `int class;' is not caught by the parser. Try

6851          weakly to recover here.  */

6852       if (TREE_CODE (spec) != TREE_LIST)

6853         return 0;

6854  

6855       id = TREE_VALUE (spec);

6856  

6857       /* If the entire declaration is itself tagged as deprecated then

6858         suppress reports of deprecated items.  */

6859       if (!adding_implicit_members && id && TREE_DEPRECATED (id))

6860       {

6861         if (deprecated_state != DEPRECATED_SUPPRESS)

6862           warn_deprecated_use (id);

6863       }

6864  

6865       if (TREE_CODE (id) == IDENTIFIER_NODE)

6866       {

6867         if (id == ridpointers [(int) RID_INT]

6868            || id == ridpointers [(int) RID_CHAR]

6869             || id == ridpointers [(int) RID_BOOL]

6870            || id == ridpointers [(int) RID_WCHAR])

6871         {

6872           if (type)

6873           {

6874             if (id == ridpointers [(int) RID_BOOL])

6875               error ("`bool' is now a keyword");

6876             else

6877               error ("extraneous `%T' ignored", id);

6878           }

6879           else

6880           {

6881             if (id == ridpointers [(int) RID_INT])

6882               explicit_int = 1;

6883             else if (id == ridpointers [(int) RID_CHAR])

6884               explicit_char = 1;

6885             type = TREE_TYPE (IDENTIFIER_GLOBAL_VALUE (id));

6886           }

6887           goto found;

6888         }

6889         /* C++ aggregate types.  */

6890         if (IDENTIFIER_HAS_TYPE_VALUE (id))

6891         {

6892           if (type)

6893             error ("multiple declarations `%T' and `%T'", type, id);

6894           else

6895             type = IDENTIFIER_TYPE_VALUE (id);

6896           goto found;

6897         }

6898  

6899         for (i = (int) RID_FIRST_MODIFIER; i <= (int) RID_LAST_MODIFIER; i++)

6900         {

6901           if (ridpointers [i] == id)

6902           {

6903             if (i == (int) RID_LONG && RIDBIT_SETP (i, specbits))

6904             {

6905               if (pedantic && ! in_system_header && warn_long_long )

6906                 pedwarn ("ISO C++ does not support `long long'");

6907               if (longlong)

6908                 error ("`long long long' is too long for GCC");

6909               else

6910                 longlong = 1;

6911             }

6912              else if (RIDBIT_SETP (i, specbits))

6913               pedwarn ("duplicate `%s'", IDENTIFIER_POINTER (id));

6914  

6915             /* Diagnose "__thread extern" or "__thread static".  */

6916             if (RIDBIT_SETP (RID_THREAD, specbits))

6917              {

6918               if (i == (int)RID_EXTERN)

6919                 error ("`__thread' before `extern'");

6920               else if (i == (int)RID_STATIC)

6921                 error ("`__thread' before `static'");

6922             }

6923  

6924             if (i == (int)RID_EXTERN

6925                && TREE_PURPOSE (spec) == error_mark_node)

6926               /* This extern was part of a language linkage.  */

6927               extern_langp = 1;

6928  

6929             RIDBIT_SET (i, specbits);

6930             goto found;

6931           }

6932         }

6933       }

6934       else if (TREE_CODE (id) == TYPE_DECL)

6935       {

6936         if (type)

6937           error ("multiple declarations `%T' and `%T'", type,

6938                 TREE_TYPE (id));

6939         else

6940         {

6941            type = TREE_TYPE (id);

6942           TREE_VALUE (spec) = type;

6943           typedef_decl = id;

6944         }

6945         goto found;

6946       }

6947       if (type)

6948         error ("two or more data types in declaration of `%s'", name);

6949       else if (TREE_CODE (id) == IDENTIFIER_NODE)

6950       {

6951         tree t = lookup_name (id, 1);

6952         if (!t || TREE_CODE (t) != TYPE_DECL)

6953           error ("`%s' fails to be a typedef or built in type",

6954                IDENTIFIER_POINTER (id));

6955          else

6956         {

6957           type = TREE_TYPE (t);

6958           typedef_decl = t;

6959         }

6960       }

6961       else if (id != error_mark_node)

6962         /* Can't change CLASS nodes into RECORD nodes here!  */

6963         type = id;

6964  

6965   found: ;

6966     }

 

decl-specifier-seq 的第二部分是代表“ Host ”的 TYPE_DECL ,它被 6934 6949 的代码所处理。注意到从 6949 6960 行的代码只是处理发现的未能解析的名字。此时, declspecs 看起来如下:

点此打开

88 :处理 decl-specifier-seq 后的 declspecs

下面的 nclasses 记录了已经见到的存储类别声明符的数目。除了“ static __thread ”及“ extern __thread ”,每个声明符只允许有一个存储类别声明符。

 

grokdeclarator (continue)

 

6973     typedef_type = type;

       …

7019     ctype = NULL_TREE;

       …

7206     if (RIDBIT_ANY_SET (specbits))

7207     {

7208       if (RIDBIT_SETP (RID_STATIC, specbits)) nclasses++;

7209       if (RIDBIT_SETP (RID_EXTERN, specbits) && !extern_langp) nclasses++;

7210       if (RIDBIT_SETP (RID_THREAD, specbits)) nclasses++;

7211       if (decl_context == PARM && nclasses > 0)

7212         error ("storage class specifiers invalid in parameter declarations");

7213       if (RIDBIT_SETP (RID_TYPEDEF, specbits))

7214       {

7215         if (decl_context == PARM)

7216           error ("typedef declaration invalid in parameter declaration");

7217         nclasses++;

7218       }

7219       if (RIDBIT_SETP (RID_AUTO, specbits)) nclasses++;

7220       if (RIDBIT_SETP (RID_REGISTER, specbits)) nclasses++;

7221       if (!nclasses && !friendp && extern_langp)

7222          nclasses++;

7223     }

       …

7249     if (nclasses > 1)

7250       error ("multiple storage classes in declaration of `%s'", name);

7930     if (RIDBIT_SETP (RID_TYPEDEF, specbits) && decl_context != TYPENAME)

7931     {

7932       tree decl;

7933  

7934       /* Note that the grammar rejects storage classes

7935         in typenames, fields or parameters.  */

7936       if (current_lang_name == lang_name_java)

7937         TYPE_FOR_JAVA (type) = 1;

7938  

7939       if (decl_context == FIELD)

7940       {

7941         if (constructor_name_p (declarator, current_class_type ))

7942           pedwarn ("ISO C++ forbids nested type `%D' with same name as enclosing class",

7943                    declarator);

7944         decl = build_lang_decl (TYPE_DECL, declarator, type);

7945       }

7946       else

7947       {

7948         decl = build_decl (TYPE_DECL, declarator, type);

7949          if (in_namespace || ctype)

7950           error ("%Jtypedef name may not be a nested-name-specifier", decl);

7951         if (!current_function_decl )

7952           DECL_CONTEXT (decl) = FROB_CONTEXT (current_namespace);

7953       }

7954        

7955       /* If the user declares "typedef struct {...} foo" then the

7956         struct will have an anonymous name. Fill that name in now.

7957         Nothing can refer to it, so nothing needs know about the name

7958         change.  */

7959       if (type != error_mark_node

7960          && declarator

7961          && TYPE_NAME (type)

7962          && TREE_CODE (TYPE_NAME (type)) == TYPE_DECL

7963          && TYPE_ANONYMOUS_P (type)

7964          /* Don't do this if there are attributes.  */

7965          && (!attrlist || !*attrlist)

7966          && cp_type_quals (type) == TYPE_UNQUALIFIED)

7967       {

7968         tree oldname = TYPE_NAME (type);

7969         tree t;

7970  

7971         /* Replace the anonymous name with the real name everywhere.  */

7972         lookup_tag_reverse (type, declarator);

7973         for (t = TYPE_MAIN_VARIANT (type); t; t = TYPE_NEXT_VARIANT (t))

7974           if (TYPE_NAME (t) == oldname)

7975             TYPE_NAME (t) = decl;

7976  

7977         if (TYPE_LANG_SPECIFIC (type))

7978           TYPE_WAS_ANONYMOUS (type) = 1;

7979  

7980         /* If this is a typedef within a template class, the nested

7981           type is a (non-primary) template. The name for the

7982             template needs updating as well.  */

7983         if (TYPE_LANG_SPECIFIC (type) && CLASSTYPE_TEMPLATE_INFO (type))

7984           DECL_NAME (CLASSTYPE_TI_TEMPLATE (type))

7985                 = TYPE_IDENTIFIER (type);

7986  

7987         /* FIXME remangle member functions; member functions of a

7988           type with external linkage have external linkage.  */

7989       }

7990  

7991       if (quals)

7992       {

7993         if (ctype == NULL_TREE)

7994         {

7995           if (TREE_CODE (type) != METHOD_TYPE)

7996             error ("%Jinvalid type qualifier for non-member function type",

7997                  decl);

7998           else

7999             ctype = TYPE_METHOD_BASETYPE (type);

8000         }

8001         if (ctype != NULL_TREE)

8002           grok_method_quals (ctype, decl, quals);

8003       }

8004  

8005       if (RIDBIT_SETP (RID_SIGNED, specbits)

8006          || (typedef_decl && C_TYPEDEF_EXPLICITLY_SIGNED (typedef_decl)))

8007         C_TYPEDEF_EXPLICITLY_SIGNED (decl) = 1;

8008  

8009       bad_specifiers (decl, "type", virtualp, quals != NULL_TREE,

8010                    inlinep, friendp, raises != NULL_TREE);

8011  

8012       return decl;

8013     }

 

对于 typedef 声明,在创建了 TYPE_DEF 节点之后,绝大部分工作已经完成,在 8009 行, bad_specifier 检查不应该出现在声明符里的声明符。

 

5540   static void

5541   bad_specifiers (tree object,                                                                              in decl.c

5542                const char* type,

5543                int virtualp,

5544                int quals,

5545                int inlinep,

5546                int friendp,

5547                int raises)

5548   {

5549     if (virtualp)

5550       error ("`%D' declared as a `virtual' %s", object, type);

5551     if (inlinep)

5552       error ("`%D' declared as an `inline' %s", object, type);

5553     if (quals)

5554       error ("`const' and `volatile' function specifiers on `%D' invalid in %s declaration",

5555              object, type);

5556     if (friendp)

5557       cp_error_at ("`%D' declared as a friend", object);

5558     if (raises

5559        && (TREE_CODE (object) == TYPE_DECL

5560            || (!TYPE_PTRFN_P (TREE_TYPE (object))

5561        && !TYPE_REFFN_P (TREE_TYPE (object))

5562        && !TYPE_PTRMEMFUNC_P (TREE_TYPE (object)))))

5563       cp_error_at ("`%D' declared with an exception specification", object);

5564   }

5.12.3.2.1.1.4.3.    加入类字段的节点

下面的 value 是为 typedef 语句构建的 TYPE_DECL 节点。在 881 行的 push_template_decl 之前,它具有如下的结构。

点此打开

89 typedef 声明的 TYPE_DECL

同样,因为 current_class_type 是“ SingleThreaded ”,这是一个仍旧在定义中的模板,毫无疑问, push_template_decl 被调用来为 typedef 语句构建及插入相应的 TEMPLATE_DECL 节点。

 

grokfield (continue)

 

852      if (TREE_CODE (value) == TYPE_DECL && init)

853      {

854        error ("typedef `%D' is initialized (use __typeof__ instead)", value);

855        init = NULL_TREE;

856      }

857   

858      /* Pass friendly classes back.  */

859      if (value == void_type_node)

860        return value;

861   

862      /* Pass friend decls back.  */

863      if ((TREE_CODE (value) == FUNCTION_DECL

864           || TREE_CODE (value) == TEMPLATE_DECL)

865          && DECL_CONTEXT (value) != current_class_type )

866        return value;

867   

868      if (DECL_NAME (value) != NULL_TREE

869         && IDENTIFIER_POINTER (DECL_NAME (value))[0] == '_'

870         && ! strcmp (IDENTIFIER_POINTER (DECL_NAME (value)), "_vptr"))

871        error ("member `%D' conflicts with virtual function table field name",

872              value);

873   

874      /* Stash away type declarations.  */

875      if (TREE_CODE (value) == TYPE_DECL)

876      {

877        DECL_NONLOCAL (value) = 1;

878        DECL_CONTEXT (value) = current_class_type ;

879   

880        if (processing_template_decl )

881          value = push_template_decl (value);

882   

883        return value;

884      }

        …

995    }

 

接下来在 push_template_decl_real 中,同样 primary 也是 false ,因为我们不是在 sk_template_parm 域中。整个过程与我们之前看到的相同。那么我们将得到以下的中间树,而在 881 行的 value 指向所创建的 TEMPLATE_DECL 节点的 result 域。

点此打开

90 :插入 typedef 声明的节点

那么当从 grokfield 返回时, cp_parser_member_declaration 知道这是类的项,因此检查后续的符号,并在 12806 行由 finish_member_declaration 把该项加入类中。

 

cp_parser_member_declaration (continue)

 

12777       /* Reset PREFIX_ATTRIBUTES.  */

12778       while (attributes && TREE_CHAIN (attributes) != first_attribute)

12779         attributes = TREE_CHAIN (attributes);

12780       if (attributes)

12781         TREE_CHAIN (attributes) = NULL_TREE;

12782

12783       /* If there is any qualification still in effect, clear it

12784         now; we will be starting fresh with the next declarator.  */

12785        parser->scope = NULL_TREE;

12786       parser->qualifying_scope = NULL_TREE;

12787       parser->object_scope = NULL_TREE;

12788       /* If it's a `,', then there are more declarators.  */

12789       if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))

12790         cp_lexer_consume_token (parser->lexer);

12791       /* If the next token isn't a `;', then we have a parse error.  */

12792       else if (cp_lexer_next_token_is_not (parser->lexer,

12793                                     CPP_SEMICOLON))

12794       {

12795         cp_parser_error (parser, "expected `;'");

12796         /* Skip tokens until we find a `;'.  */

12797         cp_parser_skip_to_end_of_statement (parser);

12798

12799         break ;

12800       }

12801

12802       if (decl)

12803       {

12804         /* Add DECL to the list of members.  */

12805         if (!friend_p)

12806           finish_member_declaration (decl);

12807

12808         if (TREE_CODE (decl) == FUNCTION_DECL)

12809           cp_parser_save_default_args (parser, decl);

12810        }

12811     }

12812   }

12813

12814   cp_parser_require (parser, CPP_SEMICOLON, "`;'");

12815 }

 

finish_member_declaration 的细节参考章节 作为成员加入 ,解析之后,中间树现在如下:

点此打开

91 完成 typedef 语句

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值