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

5.12.5.      第三个例子

现在我们已经有了“ SmallObject ”的定义,那么我们使用下面的“ main ”函数来使用这个类,从中看一下将会产生怎样的中间树。

using namespace Loki;

int main ()

{

SmallObject<> object_;

return 1;
}

5.12.5.1.              using 指示

假定这个“ main ”函数在另一个源文件中,它也构成一个编译单元,因此解析器由以下调用开始, cp_parser_translation_unit à cp_parser_declaration_seq_opt ,其中的 WHILE 循环将依次处理语句。

对于第一个是 using 指示的语句,调用栈进一步延伸,从 cp_parser_declaration à cp_parser_block_declaration à cp_parser_using_directive à parse_using_directive à do_using_directive

 

3350   void

3351   do_using_directive (tree namespace)                                                         in name-lookup.c

3352   {

3353     if (namespace == error_mark_node)

3354       return ;

3355  

3356     my_friendly_assert (TREE_CODE (namespace) == NAMESPACE_DECL, 20050830);

3357  

3358     if (building_stmt_tree ())

3359       add_stmt (build_stmt (USING_STMT, namespace));

3360     namespace = ORIGINAL_NAMESPACE (namespace);

3361  

3362     if (!toplevel_bindings_p ())

3363       push_using_directive (namespace);

3364     else

3365        /* direct usage */

3366       add_using_namespace ( current_namespace , namespace, 0);

3367   }

 

如果 building_stmt_tree 是非 0 值,表示正在为函数、块等结构产生语句,那么 using 指示将有 USING_STMT 为之生成。这里的实参 namespace 是相应的 NAMESPACE_DECL 。在 3362 行,如果最里层的有效非类作用域是一个名字空间( using 指示不允许在类域中使用,但可以用在其方法作用域中), toplevel_bindings_p 返回非 0 值。例如:

namespace A {

    int i;

}

class B {

    int func() {

        using namespace A;

        return i;

    }

};

对于用在名字空间域的那些 using 指示,在对应于该名字空间作用域的 NAMESPACE_DECL 节点中,域 DECL_NAMESPACE_USING 将是一个 tree_list ,通过 add_using_namespace 用来把这些 using 指示串接起来。

 

3275   static void

3276   add_using_namespace (tree user, tree used, bool indirect)                     in name-lookup.c

3277   {

3278     tree t;

3279     timevar_push (TV_NAME_LOOKUP);

3280     /* Using oneself is a no-op.  */

3281     if (user == used)

3282     {

3283       timevar_pop (TV_NAME_LOOKUP);

3284       return ;

3285     }

3286     my_friendly_assert (TREE_CODE (user) == NAMESPACE_DECL, 380);

3287     my_friendly_assert (TREE_CODE (used) == NAMESPACE_DECL, 380);

3288     /* Check if we already have this.  */

3290     t = purpose_member (used, DECL_NAMESPACE_USING (user));

3291     if (t != NULL_TREE)

3292     {

3293       if (!indirect)

3294         /* Promote to direct usage.  */

3295         TREE_INDIRECT_USING (t) = 0;

3296       timevar_pop (TV_NAME_LOOKUP);

3297       return ;

3298     }

3299  

3300     /* Add used to the user's using list.  */

3301     DECL_NAMESPACE_USING (user)

3302       = tree_cons (used, namespace_ancestor (user, used),

3303               DECL_NAMESPACE_USING (user));

3304  

3305     TREE_INDIRECT_USING (DECL_NAMESPACE_USING (user)) = indirect;

3306  

3307     /* Add user to the used's users list.  */

3308     DECL_NAMESPACE_USERS (used)

3309       = tree_cons (user, 0, DECL_NAMESPACE_USERS (used));

3310  

3311     /* Recursively add all namespaces used.  */

3312     for (t = DECL_NAMESPACE_USING (used); t; t = TREE_CHAIN (t))

3313       /* indirect usage */

3314       add_using_namespace (user, TREE_PURPOSE (t), 1);

3315  

3316     /* Tell everyone using us about the new used namespaces.  */

3317     for (t = DECL_NAMESPACE_USERS (user); t; t = TREE_CHAIN (t))

3318       add_using_namespace (TREE_PURPOSE (t), used, 1);

3319     timevar_pop (TV_NAME_LOOKUP);

3320   }

 

5.12.4.1.1.2.1.3.2. 其他名字 一节中,我们看到 using 指示的使用必须不能混淆名字空间的层次,在名字查找时,前端将严格按照其层次进行搜寻。 add_using_namespace 需要记录必要的层次信息。这里 namespace_ancestor 找出 ns1 ns2 最接近的公共祖先。看到所有的名字空间都有相同的公共祖先——全局名字空间。(关于 add_using_namespace 生成的这个列表的使用,参考 lookup_using_namespace )。

 

3194   static tree

3195   namespace_ancestor (tree ns1, tree ns2)                                             in name-lookup.c

3196   {

3197     timevar_push (TV_NAME_LOOKUP);

3198     if (is_ancestor (ns1, ns2))

3199       POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP, ns1);

3200     POP_TIMEVAR_AND_RETURN (TV_NAME_LOOKUP,

3201                             namespace_ancestor (CP_DECL_CONTEXT (ns1), ns2));

3202   }

 

这里参数 root 是当前名字空间,而 child 是由 using 指示指定的名字空间。那么 is_ancestor 持续地从 child 开始获取上下文,直到找到 root 或离开这棵树。对于前一种情形, root child 的祖先,并且函数返回非 0 值;反之,函数返回 0

 

2502   bool

2503   is_ancestor (tree root, tree child)                                                               in name-lookup.c

2504   {

2505     my_friendly_assert ((TREE_CODE (root) == NAMESPACE_DECL

2506                       || TREE_CODE (root) == FUNCTION_DECL

2507                      || CLASS_TYPE_P (root)), 20030307);

2508     my_friendly_assert ((TREE_CODE (child) == NAMESPACE_DECL

2509                      || CLASS_TYPE_P (child)),

2510                       20030307);

2511    

2512     /* The global namespace encloses everything.  */

2513     if (root == global_namespace )

2514       return true;

2515  

2516     while (true)

2517     {

2518       /* If we've run out of scopes, stop.  */

2519       if (!child)

2520         return false;

2521       /* If we've reached the ROOT, it encloses CHILD.  */

2522       if (root == child)

2523         return true;

2524        /* Go out one level.  */

2525       if (TYPE_P (child))

2526         child = TYPE_NAME (child);

2527       child = DECL_CONTEXT (child);

2528     }

2529   }

 

那么对于我们的例子,全局名字空间在其 DECL_NAMESPACE_USERS 域串接了“ Loki ”。

5.12.5.2.              Main() 的定义
5.12.5.2.1.        函数定义 声明符部分

对于 main 函数, cp_parser_declaration 又一次调用 cp_parser_block_declaration à cp_parser_simple_declaration 。在我们的上下文中,参数 function_definition_allowed_p true ,这表示我们同时把一个函数定义( function-definition )识别作简单声明( simple-declaration )。

block-declaration 的语法如下:

block-declaration:

     simple-declaration | asm-definition | namespace-alias-definition | using-declaration |

     using-directive 

GNU Extension:

   block-declaration: __extension__ block-declaration | label-declaration

 

6370   static void

6371   cp_parser_block_declaration (cp_parser *parser,                                        in parser.c

6372                           bool      statement_p)

6373   {

6374     cp_token *token1;

6375     int saved_pedantic;

6376  

6377     /* Check for the `__extension__' keyword.  */

6378     if (cp_parser_extension_opt (parser, &saved_pedantic))

6379     {

          …

6386     }

6387  

6388     /* Peek at the next token to figure out which kind of declaration is

6389        present.  */

6390     token1 = cp_lexer_peek_token (parser->lexer);

6391  

6392     /* If the next keyword is `asm', we have an asm-definition.  */

6393     if (token1->keyword == RID_ASM)

6394     {

          …

6398     }

6399     /* If the next keyword is `namespace', we have a

6400       namespace-alias-definition.  */

6401     else if (token1->keyword == RID_NAMESPACE)

6402       cp_parser_namespace_alias_definition (parser);

6403     /* If the next keyword is `using', we have either a

6404       using-declaration or a using-directive.  */

6405     else if (token1->keyword == RID_USING)

6406     {

          …

6419     }

6420     /* If the next keyword is `__label__' we have a label declaration.  */

6421     else if (token1->keyword == RID_LABEL)

6422     {

          …

6426     }

6427     /* Anything else must be a simple-declaration.  */

6428     else

6429       cp_parser_simple_declaration (parser, !statement_p);

6430   }

 

simple-declaration 的语法是:

simple-declaration:

     decl-specifier-seq [opt] init-declarator-list [opt] ; 

init-declarator-list:

     init-declarator | init-declarator-list , init-declarator

看到 simple-declaration 可能被包含在一个 block-declaraition 中,而该 block-declaraition 则可能在一个函数域或类方法域中,其中要求访问控制,因此期望一个新的延迟访问实例。而在 6475 行的 stop_deferring_access_checks 防止加入更多由 perform_or_defer_access_check 检查的延迟访问控制,不过对于 decl-specifier-seq init-declarator-list 访问检查都是需要的,因此稍后将通过 resume_deferring_access_checks 重新开始检查。

 

6444   static void

6445   cp_parser_simple_declaration (cp_parser* parser,                                       in parser.c

6446                            bool function_definition_allowed_p)

6447   {

6448     tree decl_specifiers;

6449     tree attributes;

6450     int declares_class_or_enum;

6451     bool saw_declarator;

6452  

6453     /* Defer access checks until we know what is being declared; the

6454       checks for names appearing in the decl-specifier-seq should be

6455       done as if we were in the scope of the thing being declared.  */

6456     push_deferring_access_checks (dk_deferred);

6457  

6458     /* Parse the decl-specifier-seq. We have to keep track of whether

6459       or not the decl-specifier-seq declares a named class or

6460       enumeration type, since that is the only case in which the

6461       init-declarator-list is allowed to be empty. 

6462  

6463       [dcl.dcl]

6464  

6465       I n a simple-declaration, the optional init-declarator-list can be

6466       omitted only when declaring a class or enumeration, that is when

6467       the decl-specifier-seq contains either a class-specifier, an

6468       elaborated-type-specifier, or an enum-specifier.  */

6469     decl_specifiers

6470       = cp_parser_decl_specifier_seq (parser,

6471                                 CP_PARSER_FLAGS_OPTIONAL,

6472                                 &attributes,

6473                                  &declares_class_or_enum);

6474     /* We no longer need to defer access checks.  */

6475     stop_deferring_access_checks ();

6476  

6477     /* In a block scope, a valid declaration must always have a

6478       decl-specifier-seq. By not trying to parse declarators, we can

6479       resolve the declaration/expression ambiguity more quickly.  */

6480     if (!function_definition_allowed_p && !decl_specifiers)

6481     {

6482       cp_parser_error (parser, "expected declaration");

6483       goto done;

6484     }

6485  

6486     /* If the next two tokens are both identifiers, the code is

6487       erroneous. The usual cause of this situation is code like:

6488  

6489         T t;

6490  

6491       where "T" should name a type -- but does not.  */

6492     if (cp_parser_diagnose_invalid_type_name (parser))

6493     {

6494       /* If parsing tentatively, we should commit; we really are

6495         looking at a declaration.  */

6496       cp_parser_commit_to_tentative_parse (parser);

6497       /* Give up.  */

6498       goto done;

6499     }

 

我们前面已经看到, cp_parser_decl_specifier_seq 将解析函数的返回类型;那么在这里 decl_specifiers 是一个 tree_list ,其中的 TREE_VALUE 域指向 integer_type_node 节点。注意一个函数定义可能没有返回类型(它默认为 int )。

 

1950   static bool

1951   cp_parser_diagnose_invalid_type_name (cp_parser *parser)                        in parser.c

1952   {

1953     /* If the next two tokens are both identifiers, the code is

1954       erroneous. The usual cause of this situation is code like:

1955  

1956       T t;

1957  

1958       where "T" should name a type -- but does not.  */

1959     if (cp_lexer_next_token_is (parser->lexer, CPP_NAME)

1960        && cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_NAME)

1961     {

1962       tree name;

1963  

1964       /* If parsing tentatively, we should commit; we really are

1965         looking at a declaration.  */

1966       /* Consume the first identifier.  */

1967       name = cp_lexer_consume_token (parser->lexer)->value;

1968       /* Issue an error message.  */

1969       error ("`%s' does not name a type", IDENTIFIER_POINTER (name));

1970       /* If we're in a template class, it's possible that the user was

1971         referring to a type from a base class. For example:

1972  

1973         template <typename T> struct A { typedef T X; };

1974         template <typename T> struct B : public A<T> { X x; };

1975  

1976         The user should have said "typename A<T>::X".  */

1977       if (processing_template_decl && current_class_type )

1978       {

1979         tree b;

1980  

1981         for (b = TREE_CHAIN (TYPE_BINFO (current_class_type ));

1982             b;

1983             b = TREE_CHAIN (b))

1984         {

1985           tree base_type = BINFO_TYPE (b);

1986           if (CLASS_TYPE_P (base_type)

1987              && dependent_type_p (base_type))

1988           {

1989             tree field;

1990             /* Go from a particular instantiation of the

1991               template (which will have an empty TYPE_FIELDs),

1992               to the main version.  */

1993             base_type = CLASSTYPE_PRIMARY_TEMPLATE_TYPE (base_type);

1994             for (field = TYPE_FIELDS (base_type);

1995                 field;

1996                 field = TREE_CHAIN (field))

1997               if (TREE_CODE (field) == TYPE_DECL

1998                  && DECL_NAME (field) == name)

1999               {

2000                 error ("(perhaps `typename %T::%s' was intended)",

2001                      BINFO_TYPE (b), IDENTIFIER_POINTER (name));

2002                 break ;

2003               }

2004               if (field)

2005                 break ;

2006           }

2007         }

2008       }

2009       /* Skip to the end of the declaration; there's no point in

2010         trying to process it.  */

2011       cp_parser_skip_to_end_of_statement (parser);

2012        

2013       return true;

2014     }

2015  

2016     return false;

2017   }

 

作为正确的形式, decl-specifier-seq 的核心部分应该命名一个类型。通过名字查找规则找到的该类型将被返回给 decl-specifiers ;而如果没有找到适合的类型,这个符号保持为标识符,那么 cp_parser_diagnose_invalid_type_name 诊断这个错误情况,并给出诊断消息。

 

cp_parser_simple_declaration (continue)

 

6501     /* If we have seen at least one decl-specifier, and the next token

6502       is not a parenthesis, then we must be looking at a declaration.

6503       (After "int (" we might be looking at a functional cast.)  */

6504     if (decl_specifiers

6505        && cp_lexer_next_token_is_not (parser->lexer, CPP_OPEN_PAREN))

6506       cp_parser_commit_to_tentative_parse (parser);

6507  

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

6509       declaration.  */

6510     saw_declarator = false;

6511     while (cp_lexer_next_token_is_not (parser->lexer,

6512                                   CPP_SEMICOLON))

6513     {

6514       cp_token *token;

6515       bool function_definition_p;

6516       tree decl;

6517  

6518       saw_declarator = true;

6519       /* Parse the init-declarator.  */

6520       decl = cp_parser_init_declarator (parser, decl_specifiers, attributes,

6521                                  function_definition_allowed_p,

6522                                   /*member_p=*/ false,

6523                                  declares_class_or_enum,

6524                                  &function_definition_p);

6525       /* If an error occurred while parsing tentatively, exit quickly.

6526         (That usually happens when in the body of a function; each

6527         statement is treated as a declaration-statement until proven

6528         otherwise.)  */

6529       if (cp_parser_error_occurred (parser))

6530         goto done;

6531       /* Handle function definitions specially.  */

6532       if (function_definition_p)

6533       {

6534         /* If the next token is a `,', then we are probably

6535           processing something like:

6536  

6537           void f() {}, *p;

6538  

6539           which is erroneous.  */

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

6541           error ("mixing declarations and function-definitions is forbidden");

6542         /* Otherwise, we're done with the list of declarators.  */

6543         else

6544         {

6545           pop_deferring_access_checks ();

6546           return ;

6547         }

6548       }

          …

6580     }

       …

6593     /* Consume the `;'.  */

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

6595  

6596   done:

6597     pop_deferring_access_checks ();

6598   }

 

注意到参数 declares_class_or_enum 0 ,因为该 type-specifier 不是 class-specifier enum-specifier ,也不是 elaborated-type-specifier init-declarator 的内容包括:

init-declarator:

     declarator initializer [opt]

function-definition:

     decl-specifier-seq [opt] declarator ctor-initializer [opt] function-body

     decl-specifier-seq [opt] declarator function-try-block 

GNU Extension:

   init-declarator:

     declarator asm-specification [opt] attributes [opt] initializer [opt]

   function-definition:

     __extension__ function-definition

注意 ctor-initializer 仅用于构造函数中。

 

9933   static tree

9934   cp_parser_init_declarator (cp_parser* parser,                                             in parser.c

9935                         tree decl_specifiers,

9936                         tree prefix_attributes,

9937                         bool function_definition_allowed_p,

9938                         bool member_p,

9939                         int declares_class_or_enum,

9940                         bool* function_definition_p)

9941   {

9942     cp_token *token;

9943     tree declarator;

9944     tree attributes;

9945     tree asm_specification;

9946     tree initializer;

9947     tree decl = NULL_TREE;

9948     tree scope;

9949     bool is_initialized;

9950     bool is_parenthesized_init;

9951     bool is_non_constant_init;

9952     int ctor_dtor_or_conv_p;

9953     bool friend_p;

9954     bool pop_p = false;

9955  

9956     /* Assume that this is not the declarator for a function

9957       definition.  */

9958     if (function_definition_p)

9959       *function_definition_p = false;

9960  

9961     /* Defer access checks while parsing the declarator; we cannot know

9962       what names are accessible until we know what is being

9963       declared.  */

9964     resume_deferring_access_checks ();

9965  

9966     /* Parse the declarator.  */

9967     declarator

9968       = cp_parser_declarator (parser, CP_PARSER_DECLARATOR_NAMED,

9969                           &ctor_dtor_or_conv_p,

9970                           /*parenthesized_p=*/ NULL,

9971                           /*member_p=*/ false);

9972     /* Gather up the deferred checks.  */

9973     stop_deferring_access_checks ();

 

main () ”部分是声明符,其中包括作为 declarator-id 的“ main ”,而“ () ”是参数列表。那么在 cp_parser_declarator 中, cp_parser_direct_declarator 迭代其主 WHILE 循环 2 次。在第一次中调用: cp_parser_declarator_id à cp_parser_id_expression à cp_parser_identifier 返回“ main ”的 IDENTIFIER_NODE 。第二次中调用: cp_parser_parameter_declaration_clause 返回空参数列表对应的 void_list_node 。然后 make_call_declarator 把这个 declarator-id parameter-list 组合成一个如下图的 CALL_EXPR (它极像我们之前看到的类方法的解析)。

t3

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值