boost.spirit -- parser

Boost.Spirit的parser提供解析类的基本框架,而非实际解析工作。解析器需要遵循一定的规范,如继承自parser<self>,提供result模板类定义返回类型,并实现parse函数。parser返回类型由parser_result模板类通过匹配策略类和解析结果类型推导得出。parse_info类封装了解析结果,包括解析长度、成功状态和完整度等信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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>的一个封装,包括四个成员:

stopparse结束的位置

hit:解析是否成功?

full:解析是否完全?(解析覆盖了整个输入流)

length:解析的长度

 

 

1.3    parse函数

 

parse函数有两类:

1.解析的过程中不忽略任何输入符号

parse函数接受三个参数:输入开始迭代器,结束迭代器,parser

过程:首先创建一个scanner,根据输入迭代器。然后调用parserparse(scanner)方法;根据返回的match<T>结果,构造parse_info

 

2.解析的过程中跳过一些符号

除了接受1的三个参数外,另外接受一个parser对象,这个对象用来识别用来跳过的符号。

该类与1的不同在于,两者创建的scanner对象所用的迭代策略类不同;1中所用的迭代策略类是普通的iterator_policy,而2scanner所用的迭代策略类是一类skipper_iteration_policy细节在scanner一节中描述。

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值