最近工作中要用到一些静态文本分析的功能, 大体说来就是按照内部定义的格式解析一个配置文件.以前也做过类似的工作, 当时想当然直接用win32 API读取INI文件.当然项目是完成了,而时隔几年之后, 又要用到类似的功能, 有什么其他解决方案呢.
这里不得不提到DSL和EBNF.具体的定义实在不是三言两语能讲得清楚的, 不过好在我们有wiki.
基本上, 我们定义自己的配置文件格式, 相当于定义了自己的文法.而在应用中, 按照我们事先定义好的文法来解析并读取这些配置文件, 也就完成了这一循环.
忘记在哪里看到这么一句话"C++程序员都是脑力劳动的施虐者和受虐者", 所以我们有了Boost. 而我们的boost::spirit, 帮我们提供了一个绝好的定义DSL的工具.
从这篇文章开始, 我会用一个个的小例子来逐渐引入spirit, 最后实现并超过原有的需求.
很多例子以及源代码都是来在网络, 包括但不限于(http://boost-spirit.com/home/, http://www.codeproject.com/, 等等)
<一> 计算器
这是Spirit的作者推荐的快速开始的例子,废话少说, 主要的代码如下(稍微做了些修改)
struct CalculatorParser : public grammar<CalculatorParser> { template<typename ScannerType> struct definition { definition(const CalculatorParser & c) { factor = real_p[& push_real] | '(' >> expression >> ')' | ('-' >> factor[&do_neg]) | ('+' >> factor); term = factor >> *( ('*' >> factor[Calculator<multiplies<double> >()]) | ('/' >> factor[Calculator<divides<double> >()]) ); expression = term >> *( ('+' >> term[Calculator<plus<double> >()]) | ('-' >> term[Calculator<minus<double> >()]) ) >> ch_p(';'); } rule<ScannerType> expression, term, factor; rule<ScannerType> const& start() const { return expression; } }; };
文法的核心就定义在expression, term, factor中了
factor是基本单元, 在满足real_p的时候(即factor是个real variable), 执行push_real(函数指针)
而factor也可以是括号内的表达式, 负数或显式指定的正数
term在做乘除运算而expression则是在做加减运算,同时整个表达式以";"作为结束符
以上我们就定义了一个非常简单的EBNF,如何,方便吧
使用时,直接parse即可
parse_info<> info = parse("1+2;", CalculatorParser());
以上, 我们简单接触了EBNF, 可以看出了,要想解析自定义的格式, 使用spirit是非常方便的一件事
下一篇, 我们会来看一个稍微复杂些的例子, 并用到更多的功能
原文链接: https://www.cnblogs.com/rc-tech/archive/2010/05/26/1744710.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/11205
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!