Boost::spirit::qi::parse语法不能正常工作



我试着写一个语法来解析以下语法:

// - command
// - command value0 ... valueN
// - command -arg0 ... -argN
// - command -arg0 value0 ... valueN ... -argN value0 ... valueN
  • 每个元素应解释为字符串
  • 命令、参数和值之间允许有多个空格
  • 参数总是以'-'开头
  • 结果存储在结构体中:

    struct Data
    {
        std::string                                       m_command;
        std::map< std::string, std::vector< std::string > m_arg;
    }
    
    • m_command将存储解析后的命令
    • m_arg将解析后的参数和相应的值存储在一个vector
    • 中。

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

我问题:

由于空白也被解释为值

,因此vector包含的条目数多于可用值。

您希望该语法如何工作并不完全清楚,但从目标数据结构来看,我认为

可以极大地简化事情。
  1. 使用船长(见背景的增强精神船长问题)
  2. 使用自动属性传播代替phoenix(参见Boost Spirit: "语义行为是邪恶的"?)。

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

在下面的示例中,我使用Fusion自适应来启用自动属性传播(这将立即启用带有

的调试输出)
#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_("rn -");
            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");
}

打印

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

(禁用调试输出)


¹(例如,-23.0是否明确为选项)

最新更新