将转义的换行视为续行

时间:2016-01-18 04:21:15

标签: c++ parsing boost escaping boost-spirit

以下是语法示例 - 两组项目:

I_name m_name parameter1=value parameter2=value
I_name m_name parameter1=value \
parameter2=value

我的问题是如何定义跳过类型。 它不仅仅是space_type而是space_type减去换行符。 但是新行后跟反斜杠是一种跳过类型。

E.g。 我定义了这样的名字:

qi::rule<Iterator, std::string(), ascii::space_type> m_sName;

m_sName %= qi::lexeme[ascii::alpha >> *ascii::alnum];

这显然不正确,因为space_type必须包含换行符反斜杠。

2 个答案:

答案 0 :(得分:1)

以下语法适用于我。

*("\\\n" | ~qi::char_('\n')) % '\n'

反斜杠后会忽略任何换行符。以下是一个简单的测试。

#include <vector>
#include <string>
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>

#define BOOST_TEST_MODULE example
#include <boost/test/unit_test.hpp>

typedef std::vector<std::string> Lines;

inline auto ParseLines(std::string const& str) {
    Lines lines;
    namespace qi = boost::spirit::qi;
    if (qi::parse(
        str.begin(), str.end(),
        *("\\\n" | ~qi::char_('\n')) % '\n',
        lines)) {
        return lines;
    }
    else {
        throw std::invalid_argument("Parse error at ParseLines");
    }
}

BOOST_AUTO_TEST_CASE(TestParseLines) {
    std::string const str =
        "I_name m_name parameter1=value parameter2=value\n"
        "I_name m_name parameter1 = value \\\n"
        "parameter2 = value";
    Lines const expected{
        "I_name m_name parameter1=value parameter2=value",
        "I_name m_name parameter1 = value parameter2 = value"
    };
    BOOST_TEST(ParseLines(str) == expected);
}

您应该使用“-std=c++14 -lboost_unit_test_framework”进行编译。无论如何,很容易转换c ++ 03的代码。

答案 1 :(得分:0)

qi::blank就是这样。它没有换行符qi::space

你也可以这样做:("\\\n" | qi::blank)

为了能够使用这样的队长声明规则 ,定义一个队长语法:

template <typename It>
   struct my_skipper : qi::grammar<It> {
       my_skipper() : my_skipper::base_type(start) {}
       qi::rule<It> start = ("\\\n" | qi::blank);
   };

完整演示

<强> Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapted.hpp>
#include <map>

namespace qi = boost::spirit::qi;

namespace ast {
    struct record {
        std::string iname, mname;
        std::map<std::string, std::string> params;
    };

    using records = std::vector<record>;
}

BOOST_FUSION_ADAPT_STRUCT(ast::record, iname, mname, params)

template <typename It>
struct my_parser : qi::grammar<It, ast::records()> {
    using Skipper = qi::rule<It>;

    my_parser() : my_parser::base_type(start) {
        skipper = ("\\\n" | qi::blank);
        name    = +qi::graph;
        key     = +(qi::graph - '=');
        param   = key >> '=' >> name;
        record  = name >> name >> *param;
        records = *(record >> +qi::eol);
        start   = qi::skip(qi::copy(skipper)) [ records ];
    }

  private:
    Skipper skipper;
    qi::rule<It, ast::records(), Skipper> records;
    qi::rule<It, ast::record(),  Skipper> record;
    qi::rule<It, ast::records()> start;
    qi::rule<It, std::pair<std::string, std::string>()>  param;
    qi::rule<It, std::string()>  name, key;
};

int main() {
#if 1
    using It = boost::spirit::istream_iterator;
    It f(std::cin >> std::noskipws), l;
#else
    using It = std::string::const_iterator;
    std::string const input = "something here a=1\n";
    It f = input.begin(), l = input.end();
#endif

    ast::records data;
    bool ok = qi::parse(f, l, my_parser<It>(), data);
    if (ok) {
        std::cout << "Parsed:\n";
        for (auto& r : data) {
            std::cout << "\t" << r.iname << " " << r.mname;
            for (auto& p : r.params)
                std::cout << " [" << p.first << ": " << p.second << "]";
            std::cout << "\n";
        }
    } else {
        std::cout << "Parse failed\n";
    }

    if (f!=l)
        std::cout << "Remaining input: '" << std::string(f,l) << "'\n";
}

打印(针对您问题中的输入):

Parsed:
    I_name m_name [parameter1: value] [parameter2: value]
    I_name m_name [parameter1: value] [parameter2: value]
相关问题