boost spirit 语法解析

使用spirit能很方便的解析自定义的语法规则,在他的文档中也说明了spirit与regex还有其他库的不同点。灵活,伸缩性好,可以用来搭建小的语法解析器也可以用来开发大型编译器等等。

定义语法规则之前首先要了解一下Extended Backus-Normal Form (EBNF)

EBNF可以定义一下生成合法字符串的公式,例如:

例1:
rule1 = "0" | "1" | "2" | "3".
rule2 = "4" | "5" | "6" | "7" | "8" | "9"  | rule1.

字符 | 表示 或,则 rule2 可以表示0-9所有的数字;一个复杂点的例子:

例2:
expression = term  { ("+" | "-") term} .
term       = factor  { ("*"|"/") factor} .
factor     = constant | variable | "("  expression  ")" .
variable   = "x" | "y" | "z" .
constant   = digit {digit} .
digit      = "0" | "1" | "..." | "9" .

表示一个合法的数学计算公式。

使用EBNF表示的语法可以很方便地用boost spirit表示:

例3:

EBNF:
    group       ::= ‘(‘ expression ‘)‘
    factor      ::= integer | group
    term        ::= factor ((‘*‘ factor) | (‘/‘ factor))*
    expression  ::= term ((‘+‘ term) | (‘-‘ term))*

Boost Spirit:
    group       = ‘(‘ >> expression >> ‘)‘;
    factor      = integer | group;
    term        = factor >> *((‘*‘ >> factor) | (‘/‘ >> factor));
    expression  = term >> *((‘+‘ >> term) | (‘-‘ >> term));

其中 ::= 表示 被定义为 的意思,与=号表示的意思相同,integer表示所有整数,在例3中如下这些表达式都是合法的:

    12345
    -12345
    +12345
    1 + 2
    1 * 2
    1/2 + 3/4
    1 + 2 + 3 + 4
    1 * 2 * 3 * 4
    (1 + 2) * (3 + 4)
    (-1 + 2) * (3 + -4)
    1 + ((6 * 200) - 20) / 6
    (1 + (2 + (3 + (4 + 5))))

但是这些表达式则不合法:

    1/2 +-+ 3/4
    1 +/ 2 += 3 + 4
    1 + 2 * 3.14 * 4
    (1 + 2) .* (3 + 4)

直接上代码:

    #include <...>
    using namespace ...
    int main()
    {
        std::string cmd_str = "$aaa[bbb]==ccc LINE 123"
        std::vector<char> name1;
        std::vector<char> name2;
        std::vector<char> value;
        int var=0;
        std::string::iterator iter_begin = cmd_str.begin();
        bool parse_ok = qi::phrase_parse(iter_begin, cmd_str.end(),
                //  Begin grammar
                (
                         (‘$‘
                         >>(+(qi::char_ - ‘[‘))[boost::phoenix::ref( component_name ) = qi::_1]  // 获得aaa
                         >> ‘[‘
                         >> (+(qi::char_ - ‘]‘))[boost::phoenix::ref( variable_name ) = qi::_1]  // 获得bbb
                         >> ‘]‘
                         >> lit("==")
                         >> (+(qi::char_-lit("LINE")))[boost::phoenix::ref( target_value ) = qi::_1]  // 获得ccc
                         ^
                        (-(lit("LINE") >> qi::int_[boost::phoenix::ref(var) = qi::_1]))  // 获得123
                ),
                //  End grammar
                ascii::space  // skip the space
                );
        // 判断是否符合语法规则
        if (!parse_ok || iter_begin != cmd_str.end())
        {
            return -1
        }
        std::cout << std::string(name1.begin(), name1.end()) << std::endl;
        std::cout << std::string(name2.begin(), name2.end()) << std::endl;
        std::cout << std::string(value.begin(), value.end()) << std::endl;
        return 0;
    }

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-31 22:53:46

boost spirit 语法解析的相关文章

使用BOOST.SPIRIT.X3的RULE和ACTION进行复杂的语法制导过程

Preface 上一篇简述了boost.spirit.x3的基本使用方法.在四个简单的示例中,展示了如何使用x3组织构造一个语法产生式,与源码串匹配并生成一个综合属性.这些简单的示例中通过组合x3库中的基本语法单元,创建了一些复杂语法单元,也就是非终结符.但这些示例中的语法单元完成的事情还不够,它们只能配合phrase_parse函数告诉我们,与源码是否匹配:并且通过一个简单赋值操作返回一个综合属性.如果我想要在匹配成功的时候完成一些用户自定义的Action,如何完成这种需求?此外,仅使用基本语

boost spirit 解析字符串 (一)

项目中需要解析一段sql 语句,然后各种百度,看了一些文章,然后就头晕了,根本不知道他们在讲啥,感觉好像非常深奥的一样.感觉他们讲的太专业了,不能通俗易懂.所以把自己学习的记录下来,以便后面查看 1) 要解析一个字符串,首先你得要有一些规则吧,比如说字符串按照逗号分割,取出字符串中的特定字符串,或者把字符串中的整数取出来,这些我们都称为规则.在boost 库中有一个专门对应的模版类.翻译成中文名字也是"规则" boost::spirit::rule<>. 2)有了规则就可以

Atitit.sql&#160;ast&#160;表达式&#160;语法树&#160;语法&#160;解析原理与实现&#160;java&#160;php&#160;c#.net&#160;js&#160;python

Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python 1.1. Sql语法树 ast 如下图锁死1 2. SQL语句解析的思路和过程3 2.1. lexer作为一个工具,完成了对SQL字符串的切割,将语句转化成一个tokens数组.3 2.2. Parser完成了SQL解析的后序部分:使用一个lexer对象作为工具,切出tokens,然后解析语义,绑定相关的系统接口.3 2.3. 关系数据和XML数据库下其抽象语法树分别为: 如图

Mysql Join语法解析与性能分析详解

一.Join语法概述 join 用于多表中字段之间的联系,语法如下: ... FROM table1 INNER|LEFT|RIGHT JOIN table2 ON conditiona table1:左表:table2:右表. JOIN 按照功能大致分为如下三类: INNER JOIN(内连接,或等值连接):取得两个表中存在连接匹配关系的记录. LEFT JOIN(左连接):取得左表(table1)完全记录,即是右表(table2)并无对应匹配记录. RIGHT JOIN(右连接):与 LEF

工作中的那些坑(2)——语法解析器

工作项目里用到线性回归算法,用于计算账户的分值,表明某账户是否是有风险的账户.其中参数都配好了,代码里直接用逆波兰表达式解析即可.本来事情到这里已经结束,突然来了新的需求:账户算出来的分数较为无序,于是考虑用sigmoid函数将其映射到(0,1)区间内,在乘以系数使其显示更为直观.为了使整个表达式更将通用,要求做到同时能解析sigmoid函数,即:原来单纯解析常量.变量.运算符的逆波兰表达式已经不能直接解析新增的sigmoid函数(即表达式),另外对嵌套的情况也没做处理,所以需要重新设计一个更为

C++ 中使用boost::property_tree读取解析ini文件

boost 官网 http://www.boost.org/ 下载页面 http://sourceforge.net/projects/boost/files/boost/1.53.0/ 我下载的是 boost_1_53_0.tar.gz 使用系统  ubuntu 12.10 一.解压 [plain] view plaincopy tar -zxvf  boost_1_53_0.tar.gz 得到一个文件夹 boost_1_53_0,  拷贝其子目录 boost 到以下路径 [plain] vi

nsis安装包_示例脚本语法解析

以下是代码及解析,其中有底色的部分为脚本内容. 注释.!define.变量.!include.常量 ; Script generated by the HM NIS Edit Script Wizard. ; HM NIS Edit Wizard helper defines !define PRODUCT_NAME "signjing安装示例" !define PRODUCT_VERSION "0.0.0.1" !define PRODUCT_PUBLISHER

boost::property_tree读取解析ini文件--推荐

boost::property_tree读取解析ini文件 [cpp] view plaincopy #include "stdafx.h" #include <iostream> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ini_parser.hpp> int main() { boost::property_tree::ptree pt; boos

boost::property_tree读取解析.xml文件

1)read_xml 支持中文路径  boost::property_tree::wptree wpt;    std::locale::global(std::locale(""));    boost::property_tree::xml_parser::read_xml("E:\\测试\\test.xml",wpt); 2)get  ptree pt;    read_xml("D://test1.xml",pt); //读入一个xml文