Spirit X3组成了属性

时间:2017-12-07 14:21:58

标签: c++ boost-spirit

我正在尝试撰写精神规则,但我无法弄清楚这条新规则的属性是什么。

以下代码正如我所料。

#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>
#include <boost/fusion/tuple.hpp>
namespace ast{
    struct Record{
       int id;
       std::string name;
    };
    struct Document{
        Record rec;
        Record rec2;
        //std::vector<Record> rec;
        std::string name;
    };
    using boost::fusion::operator<<;
}
BOOST_FUSION_ADAPT_STRUCT(ast::Record,
    name, id
)
BOOST_FUSION_ADAPT_STRUCT(ast::Document,
    rec, rec2, 
    //rec,
    name
)
namespace parser{
    namespace x3 = boost::spirit::x3;
    namespace ascii = boost::spirit::x3::ascii;
    using x3::lit;
    using x3::int_;
    using ascii::char_;

    const auto identifier = +char_("a-z");
    const x3::rule<class record, ast::Record> record = "record";
    const auto record_def = lit("record") >> identifier >> lit("{") >> int_ >> lit("}");
    const x3::rule<class document, ast::Document> document = "document";
    const auto document_def =
         record >> record
         //+record // This should generate a sequence
         >> identifier
         ;
    BOOST_SPIRIT_DEFINE(document, record);
}

namespace{
    constexpr char g_input[] = R"input(
                record foo{42}
                record bar{73}
                foobar
                )input";
}

int main(){
    using boost::spirit::x3::ascii::space;
    std::string str = g_input;
    ast::Document unit;
    bool r = phrase_parse(str.begin(), str.end(), parser::document, space, unit);
    std::cout << "Got: " << unit << "\n";
    return 0;
}

但是当我更改规则以解析多个记录(而不是正好为2)时,我希望它有一个std::vector<Record>作为属性。但我得到的只是一个很长的编译错误,对我没什么帮助。 有人能指出我做错了什么才能正确地构成属性吗?

1 个答案:

答案 0 :(得分:1)

我认为它没有编译的全部原因是因为你试图打印结果...... std::vector<Record>不知道如何流式传输:

namespace ast {
    using boost::fusion::operator<<;
    static inline std::ostream& operator<<(std::ostream& os, std::vector<Record> const& rs) {
        os << "{ ";
        for (auto& r : rs) os << r << " ";
        return os << "}";
    }
}

更多说明:

  • 在绝对必要的地方添加lexemes(!)
  • 简化(除非递归规则/单独的TU,否则不需要BOOST_SPIRIT_DEFINE)
  • 删除多余lit

我到了

<强> Live On Coliru

#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/io.hpp>

namespace ast {
    struct Record{
       int id;
       std::string name;
    };
    struct Document{
        std::vector<Record> rec;
        std::string name;
    };
}

BOOST_FUSION_ADAPT_STRUCT(ast::Record, name, id)
BOOST_FUSION_ADAPT_STRUCT(ast::Document, rec, name)

namespace ast {
    using boost::fusion::operator<<;
    static inline std::ostream& operator<<(std::ostream& os, std::vector<Record> const& rs) {
        os << "{ ";
        for (auto& r : rs) os << r << " ";
        return os << "}";
    }
}

namespace parser {
    namespace x3    = boost::spirit::x3;
    namespace ascii = x3::ascii;

    const auto identifier = x3::lexeme[+x3::char_("a-z")];
    const auto record     = x3::rule<class record, ast::Record> {"record"}
                          = x3::lexeme["record"] >> identifier >> "{" >> x3::int_ >> "}";
    const auto document   = x3::rule<class document, ast::Document> {"document"}
                          = +record
                          >> identifier
                          ;
}

int main(){
    std::string const str =  "record foo{42} record bar{73} foobar";
    auto f = str.begin(), l = str.end();

    ast::Document unit;
    if (phrase_parse(f, l, parser::document, parser::ascii::space, unit)) {
        std::cout << "Got: " << unit << "\n";
    } else {
        std::cout << "Parse failed\n";
    }

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

打印

Got: ({ (foo 42) (bar 73) } foobar)