Boost Spirit x3: lỗi thời gian biên dịch thuộc tính phức hợp (lớp enum)

Jan 13 2021

Gần đây tôi đã viết một trình phân tích cú pháp đơn giản nhất có thể bằng cách sử dụng boost Spirit x3 . Nó chứa 2 quy tắc: mã định danh và một toán tử ký tự đơn . Đương nhiên, tôi đã triển khai toán tử bằng cách sử dụng bảng ký hiệu, bảng này tạo ra một loại toán tử enum class. Số nhận dạng được phân tích cú pháp thành std::strings. Tuy nhiên, mã từ chối biên dịch khi kết hợp số nhận dạng và toán tử vào một trình phân tích cú pháp duy nhất (xem đoạn mã ở cuối câu hỏi).

Lưu ý rằng nếu bạn thay đổi kiểu toán tử enum bằng một số nguyên, mọi thứ đều hoạt động tốt. Toán tử và số nhận dạng cũng được phân tích cú pháp tốt khi tách biệt nhau.

Thông báo lỗi mẫu khá lớn để được đính kèm và quá khó hiểu đối với tôi, nhưng tôi nghi ngờ nó có liên quan gì đó đến ngữ nghĩa xây dựng / di chuyển của std::variant<std::string, OperType>. Tuy nhiên, enum classkhông nên khác biệt mạnh so với đồng bằng int. Nó có liên quan gì đến hàm tạo enum classmặc định không? Làm thế nào điều này có thể được bỏ qua?

Đây là mảnh ghép

#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ó cạm bẫy nào khi viết phân tích cú pháp ghép không? Tôi đang thiếu cái gì? Cảm ơn vì đã dành thời gian cho tôi.

Trả lời

2 sehe Jan 13 2021 at 10:26

std::variant chưa được hỗ trợ cho khả năng tương thích thuộc tính.

Thay đổi để boost::variantlàm cho nó biên dịch: Trình biên dịch Explorer

Ngoài ra, đây là những cách để làm cho nó thực sự hoạt động nếu bạn yêu cầu biến thể std ::: Chuyển bộ phân tích cú pháp Boost Spirit từ boost :: biến thể sang std :: biến thể

#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));
    }
}

Bản in

Parsed: {iden1, plus, minus, iden2}