4 rule
4.1 what rule?
rule本身是一个parser,rule对象可以作为所有parser的容器。
4.2 why rule?
当你创建了一个复合parser对象,比如:
a | b >> c >> *(d >> f)
它本身的结果type你很难写出来,应该是:sequence< alternative<a, b>, sequence <parser<c>, kleene_star< sequence <d, f> > > >,必须很清楚每一个组合所对应的模板类。
有了rule,你可以不用担心这个问题了,rule类有一个copy ctor:rule(ParserT rhs)和一个assignment:rule operator=(PaserT rhs),可以直接把一个复合的parser对象直接赋值给rule,让编译器去推导他的类型。
rule本身还对parser的功能做了一些扩充,他集成了一个parse_context和parse_id类,用来实现hook parse function和每一个rule的唯一ID功能。
4.3 rule structure
rule所含的唯一成员是一个abstract_parser<rule, scanne r_t, attr_t>类型的指针。这个指针指向一个concrete_parser类,has一个parser对象。rule对ParserT的copy ctor实际上就是创建一个concrete_parser对象指针,然后在其parse函数中调用该类的do_parse_virtual方法(该方法实际上简单转调其持有的parser对象的parse方法)
rule类一共有三个模板参数:
ScannerT:scanner类型,必须和最终调用rule.parse(ScannerT& scan)中的scan类型一致。
ContextT:parse_context,这个类是为在调用rule.parse之前和之后加入一些附加操作。
TagT:parse_id,这个类是为了作为rule的唯一标识。
rule的这三个模板参数可以以任何顺序传入,如果不传,则使用默认值。rule类是如何实现这一点的呢?这里有一个实现技巧。
看看rule的定义:
template <
typename T0 = nil_t
, typename T1 = nil_t
, typename T2 = nil_t
>
class rule
: public impl::rule_base<
rule<T0, T1, T2>
, rule<T0, T1, T2> const&
, T0, T1, T2>
rule是从类rule_base继承的,实际上,rule的所有实际工作都在rule_base中实现,而rule中本身只实现一个pointer holder(concrete_parser pointer)。以及对parser类的copy ctor和assignment。
template <
typename DerivedT // derived class
, typename EmbedT // how derived class is embedded
, typename T0 // see rule class
, typename T1 // see rule class
, typename T2 // see rule class
>