1 parser
location: spirit/core/parser.hpp
parser只提供一个解析类的基本框架,本身并不进行任何解析工作。所有具体的解析工作都是由子类进行。
parser 本身提供一个协议(规范),来标明子类(实际解析类)应该做哪些工作,才能成为一个合格的parser。
1.1 parser规范
1. 继承自parser<self>类,比如类number想要作为一个数字解析类。
struct number : parser<number> {}
2. 提供一个result模板类,这个类实际上是一个类型萃取器,提供parse函数的返回类型。
3. 提供一个parse函数,这一点最重要,每个parser的主要工作都在这个函数里完成,parse函数的原型如下:
template <typename ScannerT>
typename parse_result<self_t, ScannerT>::type
parse(ScannerT& const scan) const ;
其中ScannerT是读取输入的类,parse_result也是一个类型萃取器,通过这个萃取器,可以得到这个parser应该返回的类型,由2中的result模板提供。
parse函数接受一个参数:输入扫描类,通过利用这个类提供的迭代方法,读取输入流中的每一个符号,进行解析。
1.2 parser返回类型
每个parser的返回类型都不一样,这个类型是由每个具体的parser类来提供,类似于stl中每个容器类提供自己的iterator。
1.2.1 parser_result
这是一个模板类,前面说过,这个一个类型萃取器。利用一个模板里的typedef声明来推导类型的方法被成为【template meta programming】,实际上这些模板类似于函数,给定一个参数,返回一个值;只不过,这些特殊的函数是在编译的时候运行的。
可以和普通函数来做一个对比:
/**
* 普通函数foo, 输入参数:T(字符串);
* 功能:得到字符串的长度;返回值:输入字符串的长度。
* 利用return语句返回值
*/
int foo(const string& T)
{
return T.size();
}
/**
*模板元函数(template meta function) foo,输入参数:任意类型;
* 功能:得到该类型的size_type,返回值:输入类型的size_type。
* 利用typedef实现返回值的功能
*/
template <typename T>
class foo
{
typedef T::size_type result;
};
两者调用方式不同:
普通函数的调用:foo(“cccc”) = 4
模板元函数的调用:foo<string>::result = unsigned int
两者目的不同:一个是运算为了得到某个值,一个是运算为了得到某种类型。
看看parse_result都做了哪些工作:
template <typename ParserT, typename ScannerT>
struct parser_result
{
typedef typename ParserT::template result<ScannerT>::type type;
};
parse_result萃取每个具体parser类的内嵌模板类result::type类型作为返回类型。
1.2.2 parser::template result
如parser规范接口中第1点中所描述的那样,每个parser类都必须提供一个result模板类来标识其返回类型。
基础parser类的result类是所有parser的默认返回类型,如果具体parser没有定义result,那么使用这个默认的。
template <typename ScannerT>
struct result
{
typedef typename match_result<ScannerT, nil_t>::type type;
};
这个模板类调用了另一个meta function :match_result,其实具体parser类也大都调用这个函数,只不过传入的参数不一样罢了。
1.2.3 match_result
定义如下:
template <typename MatchPolicyT, typename T>
struct match_result
{
typedef typename MatchPolicyT::template result<T>::type type;
};
match_result有两个参数,一个MatchPolicyT是匹配策略类,一般传入的是ScannerT,另一个参数T,是根据每个解析类的所解析的结果而定的,这个类型将作为parser类最终解析结果的属性值。比如一个整数解析类,解析的结果应该是一个整数值,这个T就传入int。
所以这个meta function在执行的时候,是取的MatchPolicyT::result<T>,实际上,一般情况而言,也就是ScannerT::result<T>,对于系统提供的默认ScannerT,就是scanner类,最终结果推导为:match_policy::result<T>(具体细节在match_policy一节);最终类型为:match<T>
1.2.4 match<T>
match模板类封装了解析结果;主要包含如下几个成员:
std::ptrdiff_t len: 解析的长度。
boost::optional<T> val:解析结果(解析出来的属性值)
match还有一个特化的类match<nil_t>,只有一个length成员,没有属性值。
1.2.5 parse_info
parse_info是对parse结果match<T>的一个封装,包括四个成员:
stop:parse结束的位置
hit:解析是否成功?
full:解析是否完全?(解析覆盖了整个输入流)
length:解析的长度
1.3 parse函数
parse函数有两类:
1.解析的过程中不忽略任何输入符号
parse函数接受三个参数:输入开始迭代器,结束迭代器,parser。
过程:首先创建一个scanner,根据输入迭代器。然后调用parser的parse(scanner)方法;根据返回的match<T>结果,构造parse_info。
2.解析的过程中跳过一些符号
除了接受1的三个参数外,另外接受一个parser对象,这个对象用来识别用来跳过的符号。
该类与1的不同在于,两者创建的scanner对象所用的迭代策略类不同;1中所用的迭代策略类是普通的iterator_policy,而2中scanner所用的迭代策略类是一类skipper_iteration_policy细节在scanner一节中描述。