GCC-3.4.6源代码学习笔记(114)
2010-10-18 11:51
465 查看
5.12.4.
第二个例子
我们已经看过了解析器处理类模板“SingleThreaded
”的过程,不过这个例子作为模板声明来说相当简单。接下来,我们来看一个从“
SingleThreaded
”派生来的模板声明,它能启示我们前端是如何处理模板模板参数及继承关系。下面是我们将要处理的
class-head
:
template
<
template
<class
>
class
ThreadingModel = DEFAULT_THREADING,
std
::size_t chunkSize =
DEFAULT_CHUNK_SIZE,
std
::size_t maxSmallObjectSize =
MAX_SMALL_OBJECT_SIZE
>
class
SmallObject : public
ThreadingModel<
SmallObject<ThreadingModel, chunkSize, maxSmallObjectSize> >
其中,
DEFAULT_THREADING
是“
::Loki::SingleThreaded
”的别名。该声明遵循以下规则:
template-declaration:
export [opt]
template-parameter-list-seq decl-specifier-seq [opt] init-declarator [opt] ;
5.12.4.1.
解析模板参数列表
5.12.4.1.1.模板模板参数
5.12.4.1.1.1.
参数
如同前一个例子,经受如下调用栈
cp_parser_template_declaration
à
cp_parser_template_declaration_after_export
à
begin_template_parm_list
(插入作用域
sk_template_parms
),
cp_parser_template_parameter_list
à
cp_parser_template_parameter
à
cp_parser_type_parameter
,该声明运行以下
cp_parser_type_parameter
的代码。
7720
static
tree
7721
cp_parser_type_parameter
(cp_parser* parser)
in parser.c
7722
{
7723
cp_token *token;
7724
tree parameter;
7725
7726
/*
Look for a keyword to tell us what kind of parameter this is.
*/
7727
token = cp_parser_require
(parser, CPP_KEYWORD,
7728
"`class',
`typename', or `template'");
7729
if (!token)
7730
return
error_mark_node;
7731
7732
switch
(token->keyword)
7733
{
7734
case
RID_CLASS:
7735
case
RID_TYPENAME:
7736
{
...
7764
}
7765
break
;
7766
7767
case
RID_TEMPLATE:
7768
{
7769
tree parameter_list;
7770
tree identifier;
7771
tree default_argument;
7772
7773
/*
Look for the `<'.
*/
7774
cp_parser_require
(parser, CPP_LESS,
"`<'");
7775
/*
Parse the template-parameter-list.
*/
7776
begin_template_parm_list
();
7777
parameter_list
7778
= cp_parser_template_parameter_list
(parser);
7779
parameter_list =
end_template_parm_list
(parameter_list);
我们例子的第一个模板参数是以关键字
template
开头的模板模板参数。这个关键字
template
使得事情变得有趣——一个额外的
sk_template_parms
作用域被加入,我们将得到如下的结构。
图
96
:处理模板模板参数之前
对于这个模板模板参数,它本身也是一个模板声明。这里在这个例子中,这个模板模板参数是:“
template <class> class ThreadingModel
”,现在开头的“
template <
”被解析器消化掉了。因此在
cp_parser_template_parameter
(由
7778
行的
cp_parser_template_parameter_list
调用)中,以下代码将为下一个进入的符号“
class
”所执行。
7654
static
tree
7655
cp_parser_template_parameter (cp_parser* parser)
in parser.c
7656
{
7657
cp_token *token;
7658
7659
/*
Peek at the next token.
*/
7660
token = cp_lexer_peek_token
(parser->lexer);
7661
/*
If it is `class' or `template', we have a type-parameter.
*/
7662
if (token->keyword ==
RID_TEMPLATE)
7663
return
cp_parser_type_parameter (parser);
7664
/*
If it is `class' or `typename' we do not know yet whether it is a
7665
type
parameter or a non-type parameter. Consider:
7666
7667
template <typename T, typename T::X X> ...
7668
7669
or:
7670
7671
template <class C, class D*> ...
7672
7673
Here,
the first parameter is a type parameter, and the second is
7674
a
non-type parameter. We can tell by looking at the token after
7675
the
identifier -- if it is a `,', `=', or `>' then we have a type
7676
parameter.
*/
7677
if (token->keyword ==
RID_TYPENAME || token->keyword == RID_CLASS)
7678
{
7679
/* Peek at the token after `class' or
`typename'.
*/
7680
token = cp_lexer_peek_nth_token
(parser->lexer,
2);
7681
/*
If it's an identifier, skip it.
*/
7682
if (token->type ==
CPP_NAME)
7683
token =
cp_lexer_peek_nth_token (parser->lexer, 3);
7684
/*
Now, see if the token looks like the end of a template
7685
parameter.
*/
7686
if (token->type ==
CPP_COMMA
7687
|| token->type ==
CPP_EQ
7688
|| token->type ==
CPP_GREATER)
7689
return
cp_parser_type_parameter
(parser);
7690
}
…
7703
}
显然,“
<class>
”部分是该模板模板参数声明中的模板参数;这听起来怪怪的,但正反映了
C++
的功能强大。模板可以嵌套至深的层次——标准规定至少要允许
12
层,事实上,商业编译器都允许不少于
128
层的嵌套。
对于这个模板参数“
<class>
”,
cp_parser_type_parameter
被递归调用。
7720
static
tree
7721
cp_parser_type_parameter
(cp_parser* parser)
in parser.c
7722
{
7723
cp_token *token;
7724
tree parameter;
7725
7726
/*
Look for a keyword to tell us what kind of parameter this is.
*/
7727
token = cp_parser_require
(parser, CPP_KEYWORD,
7728
"`class', `typename', or
`template'");
7729
if (!token)
7730
return
error_mark_node;
7731
7732
switch
(token->keyword)
7733
{
7734
case
RID_CLASS:
7735
case
RID_TYPENAME:
7736
{
7737
tree identifier;
7738
tree default_argument;
7739
7740
/*
If the next token is an identifier, then it names the
7741
parameter.
*/
7742
if (cp_lexer_next_token_is
(parser->lexer,
CPP_NAME))
7743
identifier = cp_parser_identifier (parser);
7744
else
7745
identifier =
NULL_TREE;
7746
7747
/*
Create the parameter.
*/
7748
parameter = finish_template_type_parm
(class_type_node, identifier);
7749
7750
/*
If the next token is an `=', we have a default argument.
*/
7751
if (cp_lexer_next_token_is
(parser->lexer,
CPP_EQ))
7752
{
...
7757
}
7758
else
7759
default_argument =
NULL_TREE;
7760
7761
/* Create the combined representation of the
parameter and the
7762
default
argument.
*/
7763
parameter =
build_tree_list
(default_argument, parameter);
7764
}
7765
break
;
…
7848
}
7849
7850
return
parameter;
7851
}
上面的
finish_template_type_parm
为该参数构建了
tree_list
节点;并且在
7763
行将其整合入另一个
tree_list
节点。那么
parameter
指向如下的节点,因为该参数是匿名而且没有缺省参数。
图
97
:模板模板参数的节点
回到
cp_parser_template_parameter_list
,
process_template_parm
打包模板的参数。注意到这是模板模板参数声明的模板参数!参数
next
指向上图中的
parameter
节点。
2161
tree
2162
process_template_parm (tree list, tree next)
in pt.c
2163
{
2164
tree parm;
2165
tree decl = 0;
2166
tree defval;
2167
int is_type, idx;
2168
2169
parm = next;
2170
my_friendly_assert
(TREE_CODE (parm) == TREE_LIST, 259);
2171
defval = TREE_PURPOSE
(parm);
2172
parm = TREE_VALUE (parm);
2173
is_type = TREE_PURPOSE
(parm) == class_type_node;
2174
2175
if (list)
2176
{
…
2184
}
2185
else
2186
idx = 0;
2187
2188
if (!is_type)
2189
{
…
2212
}
2213
else
2214
{
2215
tree t;
2216
parm = TREE_VALUE (parm);
2217
2218
if (parm &&
TREE_CODE (parm) == TEMPLATE_DECL)
2219
{
...
2226
}
2227
else
2228
{
2229
t =
make_aggr_type
(TEMPLATE_TYPE_PARM);
2230
/*
parm is either IDENTIFIER_NODE or NULL_TREE.
*/
2231
decl = build_decl
(TYPE_DECL, parm, t);
2232
}
2233
2234
TYPE_NAME (t) = decl;
2235
TYPE_STUB_DECL (t) = decl;
2236
parm = decl;
2237
TEMPLATE_TYPE_PARM_INDEX
(t)
2238
= build_template_parm_index
(idx, processing_template_decl
,
2239
processing_template_decl
,
2240
decl, TREE_TYPE (parm));
2241
}
2242
DECL_ARTIFICIAL (decl) = 1;
2243
SET_DECL_TEMPLATE_PARM_P
(decl);
2244
pushdecl
(decl);
2245
parm = build_tree_list
(defval, parm);
2246
return
chainon (list, parm);
2247
}
此处,
begin_template_parm_list
目前已经被调用了
2
次,所以
processing_template_decl
是
2
。注意到
TEMPLATE_TPYE_PARM
的
TYPE_DECL
是匿名的,因此在下面的
pushdecl
中,这个
TYPE_DECL
,通过
add_decl_to_level
,被链入相关
cxx_scope
对象的
names
域。
566
tree
567
pushdecl (tree x)
in name-lookup.c
568
{
569
tree t;
570
tree name;
571
int need_new_binding;
572
573
timevar_push
(TV_NAME_LOOKUP);
574
575
need_new_binding = 1;
576
577
if (DECL_TEMPLATE_PARM_P
(x))
578
/*
Template parameters have no context; they are not X::T even
579
when
declared within a class or namespace.
*/
580
;
581
else
582
{
…
602
}
603
604
name = DECL_NAME (x);
605
if (name)
606
{
…
1007
}
1008
1009
if (need_new_binding)
1010
add_decl_to_level
(x,
1011
DECL_NAMESPACE_SCOPE_P (x)
1012
?
NAMESPACE_LEVEL (CP_DECL_CONTEXT (x))
1013
:
current_binding_level);
1014
1015
POP_TIMEVAR_AND_RETURN
(TV_NAME_LOOKUP, x);
1016
}
那么从
cp_parser_template_parameter_list
回到外面的
cp_parser_type_parameter
,
end_template_parm_list
接下来准备
current_template_parms
。而返回的
parameter_list
就如下图。
(
点此打开
)
图
98
:模板模板参数声明中的模板参数列表
下一个符号必须是“
> class identifier [opt]
”。由这些符号,这个模板模板参数开始形成。
cp_parser_type_parameter (continue)
7780
/* Look for the `>'.
*/
7781
cp_parser_require
(parser, CPP_GREATER,
"`>'");
7782
/*
Look for the `class' keyword.
*/
7783
cp_parser_require_keyword
(parser,
RID_CLASS, "`class'");
7784
/*
If the next token is an `=', then there is a
7785
default-argument. If the next token is a `>', we are at
7786
the end of the parameter-list. If the next token is a `,',
7787
then we are at the end of this parameter.
*/
7788
if
(cp_lexer_next_token_is_not (parser->lexer, CPP_EQ)
7789
&&
cp_lexer_next_token_is_not (parser->lexer, CPP_GREATER)
7790
&&
cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
7791
{
7792
identifier =
cp_parser_identifier
(parser);
7793
/* Treat invalid names as if the parameter were nameless.
*/
7794
if (identifier ==
error_mark_node)
7795
identifier =
NULL_TREE;
7796
}
7797
else
7798
identifier =
NULL_TREE;
7799
7800
/*
Create the template parameter.
*/
7801
parameter = finish_template_template_parm
(class_type_node
,
7802
identifier);
这个模板模板参数是一个用于模板参数的模板声明,它应该有一个
TEMPLATE_DECL
来代表这个模板声明。
1943
tree
1944
finish_template_template_parm
(tree aggr, tree identifier)
in semantics.c
1945
{
1946
tree decl = build_decl
(TYPE_DECL, identifier, NULL_TREE);
1947
tree tmpl = build_lang_decl
(TEMPLATE_DECL, identifier,
NULL_TREE);
1948
DECL_TEMPLATE_PARMS (tmpl) =
current_template_parms
;
1949
DECL_TEMPLATE_RESULT (tmpl)
= decl;
1950
DECL_ARTIFICIAL (decl) = 1;
1951
end_template_decl
();
1952
1953
my_friendly_assert
(DECL_TEMPLATE_PARMS (tmpl), 20010110);
1954
1955
return
finish_template_type_parm
(aggr,
tmpl);
1956
}
因为当可选的标识符被读入时,这个模板声明就结束了,
end_template_decl
必须被调用来使
processing_template_decl
减一,并跳回该声明的绑定域(看到这是
sk_template_parms
)。进一步,
finish_template_type_parm
把这个
TEMPLATE_DECL
打包入模板参数的节点。因此在解析缺省参数前,我们得到如下图形。
(
点此打开
)
图
99
:构建的模板模板参数
相关文章推荐
- GCC-3.4.6源代码学习笔记(79)
- GCC-3.4.6源代码学习笔记(23)
- GCC-3.4.6源代码学习笔记(136)
- GCC-3.4.6源代码学习笔记(179)
- GCC-3.4.6源代码学习笔记(163)
- GCC-3.4.6源代码学习笔记(9)
- GCC-3.4.6源代码学习笔记(26续1)
- GCC-3.4.6源代码学习笔记(60)
- GCC-3.4.6源代码学习笔记(12)
- GCC-3.4.6源代码学习笔记(115)
- GCC-3.4.6源代码学习笔记(141)
- GCC-3.4.6源代码学习笔记(129 续)
- GCC-3.4.6源代码学习笔记(143)
- GCC-3.4.6源代码学习笔记(147-续2)
- GCC-3.4.6源代码学习笔记(73)
- GCC-3.4.6源代码学习笔记(132)
- GCC-3.4.6源代码学习笔记(124)
- GCC-3.4.6源代码学习笔记(133)
- GCC-3.4.6源代码学习笔记(175)
- GCC-3.4.6源代码学习笔记(157)