秘笈18 解析简单的输入(2)
工作原理
这是一个非常简单的实现,它不检查数值的数字个数。解析发生在boost::spirit::qi:: parse函数。我们把它简化一点,消除成功解析后的行动:

first 参数指向待解析数据的开始点,它必须是一个能够修改(非恒定)的变量,因为parse函数将用它来显示解析得出的序列的结束。end参数指向最后一个元素以外的元素。first和end应当是迭代器。
函数的第三个参数是解析规则。它正是用EBNF规则编写的:

只将空格替换为>>操作符。
若执行成功,parse函数返回true。如果想要确保整个字符串都被成功解析,需要检查解析器的返回值并与输入迭代器相等。
现在,需要处理成功解析后的动作,而这个秘笈将结束。Boost.Spirit的语义动作写在[]里面,并且它们可以使用函数指针、函数对象、boost::bind、std::bind(或其他bind()的实现)或C++11 lambda函数编写。
所以,也可以使用C++11的lambda编写 YYYY (年份)的规则:

现在,我们仔细看看在月份上的语义动作:

对于那些从头读了这本书的读者,这将使你回忆起boost::bind和占位符。ref(res.month) 意味着将 res.month作为可修改的引用传递,而_1表示第一个输入参数,其将是一个数值(ushort_ parsing的结果)。
还有更多
现在,修改解析器,以便它可以处理数字的计数。为了这个目的,将采用unit_parser模板类,并仅设置正确的参数:

如果觉得这些例子有些复杂,不要担心。第一次我也被Boost.Spirit吓坏了,但现在它真正简化了我的工作。如果这个代码没能吓到你,你是非常勇敢的。
如果你想避免代码膨胀,尝试在源文件中而不是在头文件中编写解析器。也注意传递到 boost::spirit::parse函数的迭代器类型,使用的迭代器的不同类型越少,得到的二进制文件大小就越小。在源文件编写解析器还有一个好处:它不会降低项目编译速度(你可能会注意到,Spirit 解析器编译缓慢,所以最好是在源文件编译一次,而不是在头文件中定义它们并在整个项目中使用此文件)。
如果你现在认为使用STL手工实现解析日期更简单,你是对的!但仅是现在。我们看下一个秘笈,它会给你提供更多的Boost.Spirit用途的例子并扩展这个例子的情况,那时手工编写解析器比使用Boost.Spirit更难。
Boost.Spirit库不属于C++11,并且据我所知,它也未被建议纳入最近即将发布的C++标准中。
参见
参考秘笈8。
参考秘笈9。
Boost.Spirit是一个巨大的只有头文件的库。关于它的使用可以写成一本单独的书,所以请放心地使用其文档http://www.boost.org/doc/libs/1_53_0/libs/spirit/doc/html/index.html。你可能还会找到如何直接在C++11使用Boost的代码编写词法分析器和代码生成器的信息。