Meningkatkan semangat x3: kesalahan waktu kompilasi atribut gabungan (kelas enum)

Jan 13 2021

Saya baru-baru ini menulis parser sesederhana mungkin menggunakan boost spirit x3 . Ini berisi 2 aturan: pengenal dan operator karakter tunggal . Biasanya, saya mengimplementasikan operator menggunakan tabel simbol, yang menghasilkan tipe operator enum class. Pengenal diuraikan sebagai std::strings. Namun, kode tersebut menolak untuk dikompilasi saat menggabungkan pengidentifikasi dan operator menjadi satu parser (lihat potongan kode di akhir pertanyaan).

Perhatikan, jika Anda mengubah enum jenis operator dengan integer, semuanya berfungsi dengan baik. Operator dan pengenal juga diurai dengan baik saat terpisah.

Pesan kesalahan template cukup besar untuk dilampirkan dan terlalu kabur bagi saya untuk memahaminya, tetapi saya curiga ini ada hubungannya dengan konstruksi / pemindahan semantik std::variant<std::string, OperType>. Namun, enum classsebaiknya tidak jauh berbeda dengan dataran int. Apakah itu ada hubungannya dengan enum classkonstruktor default? Bagaimana ini bisa dilewati?

Ini codepiece-nya

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

Apakah ada kendala saat menulis pengurai gabungan? Apa yang saya lewatkan? Terima kasih atas waktunya.

Jawaban

2 sehe Jan 13 2021 at 10:26

std::variant belum didukung untuk kompatibilitas atribut.

Mengubah untuk boost::variantmembuatnya menjadi kompilasi: Compiler Explorer

Sebagai alternatif, berikut adalah cara untuk membuatnya benar-benar berfungsi jika Anda memerlukan std :: variant: Transitioning Boost Spirit parser dari boost :: variant ke 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));
    }
}

Cetakan

Parsed: {iden1, plus, minus, iden2}