【问题标题】:Boost spirit x3: compound attribute compile time error (enum class)Boost Spirit x3:复合属性编译时错误(枚举类)
【发布时间】:2021-04-17 21:58:44
【问题描述】:

我最近正在使用 boost spirit x3 编写一个最简单的解析器。它包含 2 个规则:identifier 和单个字符 operator。自然地,我使用符号表实现了运算符,它产生了一个运算符类型enum class标识符被解析为std::strings。但是,当将标识符和运算符组合到一个解析器中时,代码会拒绝编译(请参阅问题末尾的代码段)。

请注意,如果您将运算符类型枚举更改为整数,则一切正常。运算符和标识符在分开时也能很好地解析。

模板错误消息很大,无法附加,而且我无法理解,但我怀疑它与std::variant<std::string, OperType> 的构造/移动语义有关。然而,enum class 不应该与普通的int 有很大不同。它与enum class 默认构造函数有什么关系吗?如何绕过?

这是密码

#include <variant>
#include <string>

#include <boost/spirit/home/x3.hpp>

namespace x3 = boost::spirit::x3;

auto addCharacter = [](auto &context) {
    x3::_val(context).push_back(x3::_attr(context));
};

x3::rule<class IdentifierTag, std::string> identifier{"identifier"};
const auto identifier_def = x3::lexeme[x3::char_("a-zA-Z")[addCharacter] >> *(x3::char_("a-zA-Z0-9")[addCharacter])];

BOOST_SPIRIT_DEFINE(identifier);

enum class OperType
{
    plus,
    minus
};

struct Opers_ : x3::symbols<OperType>
{
    Opers_()
    {
        add("+", OperType::plus)("-", OperType::minus);
    }
} opers_;

x3::rule<class OperTypeTag, OperType> oper{"operator"};
const auto oper_def = x3::lexeme[opers_];

BOOST_SPIRIT_DEFINE(oper);

int main()
{
    std::string input{"iden1 + - iden2"};

    std::vector<std::variant<std::string, OperType>> tokens;

    auto start = input.cbegin();
    auto result = x3::phrase_parse(start, input.cend(), (+(identifier | oper)), x3::space, tokens);

    return 0;
}

编写复合解析器时有什么陷阱吗?我错过了什么?感谢您的宝贵时间。

【问题讨论】:

    标签: c++ boost boost-spirit boost-spirit-x3


    【解决方案1】:

    std::variant 尚不支持属性兼容性。

    更改为boost::variant 使其编译:Compiler Explorer

    或者,如果您需要 std::variant:Transitioning Boost Spirit parser from boost::variant to std::variant

    ,可以通过以下方法使其实际工作
    #include <boost/spirit/home/x3.hpp>
    #include <variant>
    #include <fmt/ranges.h>
    #include <fmt/ostream.h>
    
    namespace x3 = boost::spirit::x3;
    
    auto addCharacter = [](auto& context) {
        x3::_val(context).push_back(x3::_attr(context));
    };
    
    x3::rule<class IdentifierTag, std::string> identifier{"identifier"};
    const auto identifier_def =
        x3::lexeme[x3::char_("a-zA-Z")[addCharacter] >> *(x3::char_("a-zA-Z0-9")[addCharacter])];
    
    BOOST_SPIRIT_DEFINE(identifier)
    
    enum class OperType
    {
        plus,
        minus
    };
    
    static inline std::ostream& operator<<(std::ostream& os, OperType ot) {
        switch(ot) {
            case OperType::plus: return os << "plus";
            case OperType::minus: return os << "minus";
        }
        return os << "?";
    }
    
    struct Opers_ : x3::symbols<OperType>
    {
        Opers_()
        {
            add("+", OperType::plus)
               ("-", OperType::minus);
        }
    } opers_;
    
    x3::rule<class OperTypeTag, OperType> oper{"operator"};
    const auto oper_def = x3::lexeme[opers_];
    
    BOOST_SPIRIT_DEFINE(oper)
    
    int main() {
        std::string const input{"iden1 + - iden2"};
    
        std::vector<boost::variant<std::string, OperType>> tokens;
    
        auto f = input.begin(), l = input.end();
        auto result = x3::phrase_parse(
                f, l,
                +(identifier | oper),
                x3::space,
                tokens);
    
        if (result) {
            fmt::print("Parsed: {}\n", tokens);
        } else {
            fmt::print("Parse failed\n");
        }
    
        if (f!=l) {
            fmt::print("Remaining: '{}'\n", std::string(f,l));
        }
    }
    

    打印

    Parsed: {iden1, plus, minus, iden2}
    

    【讨论】:

    • 也少了 20 行代码:godbolt.org/z/Eozchn
    • 非常感谢您一直以来的帮助!似乎精神 x3 文档中没有显着提及这个细节,或者我不小心错过了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多