boost :: spirit :: qi ::解析语法不能按预期工作 [英] boost::spirit::qi::parse grammar not working as expected

查看:170
本文介绍了boost :: spirit :: qi ::解析语法不能按预期工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我尝试编写语法来解析以下语法:

  //  -  command 
// - 命令value0 ... valueN
// - 命令-arg0 ... -argN
// - 命令-arg0 value0 ... valueN ... -argN value0 ... valueN




  • 每个元素都应解释为字符串


  • 一个参数总是以 - 开始。
  • / li>
  • 结果应存储在结构中:

      struct Data 
    {
    std :: string m_command;
    std :: map< std :: string,std :: vector< std :: string> m_arg;
    }




    • m_command将存储已解析的命令

    • m_arg应将解析的参数和相应的值存储在向量中




我在一个简短示例中添加了我当前的语法这里



我的问题:



向量包含比可用值更多的条目,因为空格也被解释为值

解决方案

这不是很清楚你想要的语法函数¹,但从目标数据结构,我得到的印象可以大大简化


  1. 使用船长(请参阅 Boost精灵船长问题作为背景)

  2. 使用自动属性传播而不是phoenix(另请参阅 Boost Spirit:Semantic actions are evil?)。

     code> token = +〜char _(\r\\\
    - );
    values = + token;

    //
    entry =(lexeme [' - '>> token]> --values | attr(empty)>>值);
    args = * entry;

    //
    data = skip(qi :: blank)[token>> args]


适用于启用自动属性传播(可立即使用

  #define BOOST_SPIRIT_DEBUG 

Live on Coliru

  //#define BOOST_SPIRIT_DEBUG 
#include< boost / fusion / adapted.hpp>
#include< boost / spirit / include / qi.hpp>
#include< map>
#include< ; string>
#include< vector>

//结构存储已解析的命令行信息:
struct CmdData
{
typedef std :: string Name;

typedef std :: string ArgName;
typedef std :: string Value;

typedef std :: vector< Value> Values; // Type定义值列表:
typedef std :: map< ArgName,Values> Args; // Type定义一个存储参数和相应值之间关系的映射:

Name cmd; //将命令名存储为字符串。
Args arg; //将参数和相应的值存储为字符串。
};

BOOST_FUSION_ADAPT_STRUCT(CmdData,(CmdData :: Name,cmd)(CmdData :: Args,arg))

命名空间语法
{
namespace qi = boost :: spirit :: qi;

//此类实现用于解析命令行的语法。
//预期的格式如下:
// - command
// - command value0 ... valueN
// - command -arg0 ... -argN
// - command -arg0 value0 ... valueN ... -argN value0 ... valueN
template< typename It>
struct decode:qi :: grammar< It,CmdData()>
{
decode():decode :: base_type(data)
{
使用命名空间qi;

token = +〜char _(\r\\\
- );
values = + token;

//
entry =(lexeme [' - '>> token]> --values | attr(empty)>>值);
args = * entry;

//
data = skip(qi :: blank)[token>> args];

BOOST_SPIRIT_DEBUG_NODES((token)(values)(entry)(args)(data))
}

private:
qi :: rule< It,CmdData()>数据;

//以下变量定义了此语法中使用的规则:
typedef std :: pair< CmdData :: ArgName,CmdData :: Values>条目;
qi :: rule< It,CmdData :: Values(),qi :: blank_type>值;
qi :: rule< It,Entry(),qi :: blank_type>条目;
qi :: rules< It,CmdData :: Args(),qi :: blank_type> args;

// lexemes
qi :: rule< It,std :: string()>令牌
};

} //命名空间

bool parse(const std :: string& in)
{
CmdData data;

//创建一个使用语法的实例:
Grammar :: decode< std :: string :: const_iterator> gr;

//尝试根据语法解析存储在流中的数据,并将结果存储在标记变量中:
bool b = boost :: spirit :: qi :: parse(in .begin(),in.end(),gr,data);

std :: cout<< Parsing:'<<在<< 'ok:<< std :: boolalpha< b<< \\\
;
if(b)
std :: cout<< 条目解析:< data.arg.size()< \\\
;

return b;
}

int main()
{
parse(cmd0)
parse(cmd0 -23.0 value0 value1 value2);
parse(cmd0 -arg0 -arg1 -arg2);
parse(cmd0 -arg0 value0 -arg1 value0 value1 -arg2 value0 value1 value2);
}

列印

 解析:'cmd0'ok:true 
解析的条目:0
解析:'cmd0 -23.0 value0 value1 value2'ok:true
解析的条目:1
解析:'cmd0 -arg0 -arg1 -arg2'ok:true
解析的条目:3
解析:'cmd0 -arg0 value0 -arg1 value0 value1 -arg2 value0 value1 value2'ok:true
条目解析:3

(禁用调试输出)






¹(例如 -23.0 明确表示某个选项)


I try to write a grammar to parse the following syntax:

// - command
// - command value0 ... valueN
// - command -arg0 ... -argN
// - command -arg0 value0 ... valueN ... -argN value0 ... valueN

  • Each element shall be interpreted as a string
  • Within a string all symbols are allowed
  • Between command, argument and value multiple blanks shall be allowed
  • An argument starts always with '-'
  • The results shall be stored in a struct:

    struct Data
    {
        std::string                                       m_command;
        std::map< std::string, std::vector< std::string > m_arg;
    }
    

    • m_command shall store the parsed command
    • m_arg shall store the parsed argument and the corresponding values within a vector

I added my current grammar within a short example here

My problem:

The vector contains more entries than available values because blanks are also interpreted as values

解决方案

It's not exactly clear how you want the grammer to function¹, but from the target data structure I get the impression things could be simplified vastly by

  1. using a skipper (see Boost spirit skipper issues for background)
  2. using automatic attribute propagation instead of phoenix (see also Boost Spirit: "Semantic actions are evil"?).

    token  = +~char_("\r\n -");
    values = +token;
    
    //
    entry  = (lexeme['-' >> token] >> -values | attr("empty") >> values);
    args   = *entry;
    
    //
    data   = skip(qi::blank) [ token >> args ];
    

In the sample below I've used Fusion adaptation to enable automatic attribute propagation (which, at once, enables debug output with

#define BOOST_SPIRIT_DEBUG

Live On Coliru

//#define BOOST_SPIRIT_DEBUG
#include <boost/fusion/adapted.hpp>
#include <boost/spirit/include/qi.hpp>
#include <map>
#include <string>
#include <vector>

// Structure stores the parsed command line information:
struct CmdData
{
    typedef std::string               Name;

    typedef std::string               ArgName;
    typedef std::string               Value;

    typedef std::vector<Value>        Values;  // Type defines a list of values:
    typedef std::map<ArgName, Values> Args;    // Type defines a map storing the relation between a argument and the corresponding values:

    Name cmd; // Stores the command name as a string.
    Args arg; // Stores the arguments and the corresponding values as strings.
};

BOOST_FUSION_ADAPT_STRUCT(CmdData, (CmdData::Name, cmd)(CmdData::Args, arg))

namespace Grammar
{
    namespace qi = boost::spirit::qi;

    // This class implements the grammar used to parse a command line.
    // The expected format is as follows:
    // - command
    // - command value0 ... valueN
    // - command -arg0 ... -argN
    // - command -arg0 value0 ... valueN ... -argN value0 ... valueN
    template <typename It>
    struct decode : qi::grammar<It, CmdData()>
    {
        decode() : decode::base_type(data)
        {
            using namespace qi;

            token  = +~char_("\r\n -");
            values = +token;

            //
            entry  = (lexeme['-' >> token] >> -values | attr("empty") >> values);
            args   = *entry;

            //
            data   = skip(qi::blank) [ token >> args ];

            BOOST_SPIRIT_DEBUG_NODES( (token)(values)(entry)(args)(data) )
        }

      private:
        qi::rule<It, CmdData()> data;

        // The following variables define the rules used within this grammar:
        typedef std::pair<CmdData::ArgName, CmdData::Values> Entry;
        qi::rule<It, CmdData::Values(), qi::blank_type> values;
        qi::rule<It, Entry(),           qi::blank_type> entry;
        qi::rule<It, CmdData::Args(),   qi::blank_type> args;

        // lexemes
        qi::rule<It, std::string()> token;
    };

}   // namespace

bool parse(const std::string& in)
{
    CmdData data;

    // Create an instance of the used grammar:
    Grammar::decode<std::string::const_iterator> gr;

    // Try to parse the data stored within the stream according the grammar and store the result in the tag variable:
    bool b = boost::spirit::qi::parse(in.begin(), in.end(), gr, data);

    std::cout << "Parsing: '" << in << "' ok: " << std::boolalpha << b << "\n";
    if (b)
        std::cout << "Entries parsed: " << data.arg.size() << "\n";

    return b;
}

int main()
{
    parse("   cmd0");
    parse("   cmd0  -23.0 value0  value1  value2");
    parse("   cmd0  -arg0  -arg1  -arg2");
    parse("   cmd0  -arg0  value0  -arg1  value0  value1  -arg2  value0  value1  value2");
}

Prints

Parsing: '   cmd0' ok: true
Entries parsed: 0
Parsing: '   cmd0  -23.0 value0  value1  value2' ok: true
Entries parsed: 1
Parsing: '   cmd0  -arg0  -arg1  -arg2' ok: true
Entries parsed: 3
Parsing: '   cmd0  -arg0  value0  -arg1  value0  value1  -arg2  value0  value1  value2' ok: true
Entries parsed: 3

(with debug output disabled)


¹ (e.g. is -23.0 expressly an option or not)

这篇关于boost :: spirit :: qi ::解析语法不能按预期工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆