您的位置:首页 > 编程语言

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

:构建的模板模板参数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: