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

5.12.3.      第二条语句 – TEMPLATE_DECL

第二条语句是模板声明,其简要语法树如下。第一条规则是类模板声明,其下是函数模板声明。现在我们正在定义类模板。

template-declaration

export [opt] template < template-parameter-list> decl-specific-seq [opt] init-declarator [opt];

export [opt] template < template- parameter -list> function-definition

cp_parser_declaration 中,下面的代码片段处理与模板相关的定义。

 

cp_parser_declaration (continue)

 

6306    /* If the next token is `template', then we have either a template

6307      declaration, an explicit instantiation, or an explicit

6308      specialization.  */

6309    else if (token1.keyword == RID_TEMPLATE)

6310    {

6311       /* `template <>' indicates a template specialization.  */

6312      if (token2.type == CPP_LESS

6313          && cp_lexer_peek_nth_token (parser->lexer, 3)->type == CPP_GREATER)

6314        cp_parser_explicit_specialization (parser);

6315      /* `template <' indicates a template declaration.  */

6316      else if (token2.type == CPP_LESS)

6317        cp_parser_template_declaration (parser, /*member_p=*/ false);

6318       /* Anything else must be an explicit instantiation.  */

6319      else

6320        cp_parser_explicit_instantiation (parser);

6321    }

6322     /* If the next token is `export', then we have a template

6323      declaration.  */

6324    else if (token1.keyword == RID_EXPORT)

6325      cp_parser_template_declaration (parser, /*member_p=*/ false);

6326     /* If the next token is `extern', 'static' or 'inline' and the one

6327      after that is `template', we have a GNU extended explicit

6328      instantiation directive.  */

6329    else if (cp_parser_allow_gnu_extensions_p (parser)

6330          && (token1.keyword == RID_EXTERN

6331               || token1.keyword == RID_STATIC

6332               || token1.keyword == RID_INLINE)

6333           && token2.keyword == RID_TEMPLATE)

6334      cp_parser_explicit_instantiation (parser);

 

当看到开头的符号:“ template <class Host> class SingleThreaded ”,在 6316 行,解析器就能知道这是一个模板声明,并调用处理句柄。

 

7593 static void

7594 cp_parser_template_declaration (cp_parser* parser, bool member_p)              in parser.c

7595 {

7596    /* Check for `export'.  */

7597    if (cp_lexer_next_token_is_keyword (parser->lexer, RID_EXPORT))

7598    {

7599       /* Consume the `export' token.  */

7600       cp_lexer_consume_token (parser->lexer);

7601      /* Warn that we do not support `export'.  */

7602      warning ("keyword `export' not implemented, and will be ignored");

7603    }

7604

7605    cp_parser_template_declaration_after_export (parser, member_p);

7606 }

 

关键字 export 用于分离编译模式( separation compilation model )。通过分离编译模式,类模板定义及其内联成员函数的定义放在头文件里,而非内联成员函数的定义及静态数据成员放在源文件中。通过这个模式,类模板及其成员的定义,与我们组织非模板类及其成员的方式一致。但是当前版本,尚未支持。

 

14420 static void

14421 cp_parser_template_declaration_after_export (cp_parser* parser, bool member_p) in parser.c

14422 {

14423    tree decl = NULL_TREE;

14424    tree parameter_list;

14425    bool friend_p = false;

14426

14427    /* Look for the `template' keyword.  */

14428    if (!cp_parser_require_keyword (parser, RID_TEMPLATE, "`template'"))

14429      return ;

14430       

14431    /* And the `<'.  */

14432    if (!cp_parser_require (parser, CPP_LESS, "`<'"))

14433      return ;

14434       

14435    /* If the next token is `>', then we have an invalid

14436      specialization. Rather than complain about an invalid template

14437      parameter, issue an error message here.  */

14438    if (cp_lexer_next_token_is (parser->lexer, CPP_GREATER))

14439    {

14440      cp_parser_error (parser, "invalid explicit specialization");

14441      begin_specialization ();

14442      parameter_list = NULL_TREE;

14443    }

14444    else

14445    {

14446      /* Parse the template parameters.  */

14447      begin_template_parm_list ();

14448      parameter_list = cp_parser_template_parameter_list (parser);

14449      parameter_list = end_template_parm_list (parameter_list);

14450    }

 

我们知道,在模板参数列表中,形如 class T 的声明不是一个普通的类声明,而是更接近于一个占位符,然后在具现( template instantiation )期间,它将为具体的类型所替代。把这个类型声明从当前绑定域中分离出去,放在特定的域中(即, sk_template_parms ),是很重要的一步。

 

598  void

599  begin_template_parm_list (void)                                                                         in pt.c

600  {

601    /* We use a non-tag-transparent scope here, which causes pushtag to

602      put tags in this scope, rather than in the enclosing class or

603      namespace scope. This is the right thing, since we want

604      TEMPLATE_DECLS, and not TYPE_DECLS for template classes. For a

605      global template class, push_template_decl handles putting the

606      TEMPLATE_DECL into top-level scope. For a nested template class,

607      e.g.:

608 

609         template <class T> struct S1 {

610           template <class T> struct S2 {};

611         };

612 

613      pushtag contains special code to call pushdecl_with_scope on the

614      TEMPLATE_DECL for S2.  */

615    begin_scope (sk_template_parms, NULL);

616    ++processing_template_decl ;

617    ++processing_template_parmlist ;

618    note_template_header (0);

619  }

 

上面的 processing_template_decl 指向 scope_chain x_processing_template_decl 域。它与全局变量 processing_template_parmlist 一起记录了正在处理的模板声明及模板参数列表的嵌套深度。

 

687  static void

688  note_template_header (int specialization)                                                            in pt.c

689  {

690    processing_specialization = specialization;

691    template_header_count ++;

692  }

 

在加入特殊的域 sk_template_parms 后的布局大致如下。


 

 

47 :加入 sk_template_parm 后的简要布局

5.12.3.1.              解析模板参数列表

这里 processing_specialization 指向 scope_chain x_processing_specialization 域。如果它不为 0 ,表示找到了特化的模板(即看到 template <> )。而全局变量 template_header_count 如果不为 0 ,表示看到模板头(即, template )。

从下面的简要语法树,这部分的语法相当的复杂。

template < template-parameter-list >

template-parameter

template-parameter-list , template-parameter

type-parameter

class identifier [opt]

class identifier [opt] = type-id

typename identifier [opt]

template < template-parameter-list > class identifer [opt]

template < template-parameter-list > class identifer [opt] = id-expression

|

parameter-declaration

decl-specifier-seq declarator

decl-specifier-seq declarator = assignment-expression

decl-specifier-seq abstract-declarator [opt]

decl-specifier-seq abstract-declarator [opt] = assignment-expression

因为参数列表可以包含任意数目的参数(至少理论上如此),在下面 7622 行的 WHILE 循环由符号“逗号”来驱动。

 

7617 static tree

7618 cp_parser_template_parameter_list (cp_parser* parser)                                  in parser.c

7619 {

7620   tree parameter_list = NULL_TREE;

7621

7622   while (true)

7623   {

7624     tree parameter;

7625     cp_token *token;

7626

7627     /* Parse the template-parameter.  */

7628     parameter = cp_parser_template_parameter (parser);

7629     /* Add it to the list.  */

7630     parameter_list = process_template_parm (parameter_list,

7631                                       parameter);

7632

7633      /* Peek at the next token.  */

7634     token = cp_lexer_peek_token (parser->lexer);

7635     /* If it's not a `,', we're done.  */

7636     if (token->type != CPP_COMMA)

7637       break ;

7638     /* Otherwise, consume the `,' token.  */

7639     cp_lexer_consume_token (parser->lexer);

7640   }

7641

7642   return parameter_list;

7643 }

 

在上面的语法树中 template-parameter type-parameter 构建类型参数 template-parameter parameter-declaration 构建非类型参数。它们的构成极为不同 不过它们仍可能拥有相同的头部 例如

template < typename T, typename T::X X> ,第一个 T 是类型参数,而第二个 T::X 是非类型参数。

同样, template <class C, class D*> C 是类型参数,而 D* 是非类型参数。

相关的函数要小心处理这些情况。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值