Boost spirit x3: bileşik öznitelik derleme zamanı hatası (enum sınıfı)

Jan 13 2021

Geçenlerde boost spirit x3 kullanarak mümkün olan en basit ayrıştırıcıyı yazıyordum . 2 kural içerir: tanımlayıcı ve tek karakter operatörü . Doğal olarak, operatörü bir operatör tipi üreten bir sembol tablosu kullanarak uyguladım enum class. Tanımlayıcılarstd::string s olarak ayrıştırılır . Bununla birlikte, kod, tanımlayıcıları ve işleçleri tek bir ayrıştırıcıda birleştirirken derlemeyi reddeder (sorunun sonundaki kod parçasına bakın).

Operatör türü numaralandırmayı bir tamsayı ile değiştirirseniz, her şeyin yolunda gittiğini unutmayın. İşleçler ve tanımlayıcılar da ayrı olduklarında iyi ayrıştırılır.

Şablon hata mesajı, eklenemeyecek kadar büyük ve anlayamayacağım kadar belirsiz, ancak bunun yapı / hareket semantikiyle bir ilgisi olduğundan şüpheleniyorum std::variant<std::string, OperType>. Bununla birlikte, enum classdüzlükten büyük ölçüde farklı olmamalıdır int. enum classVarsayılan kurucu ile ilgisi var mı ? Bu nasıl baypas edilebilir?

İşte kod parçası

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

Bileşik ayrıştırıcı yazarken herhangi bir tuzak var mı? Neyi kaçırıyorum? Zaman ayırdığınız için teşekkürler.

Yanıtlar

2 sehe Jan 13 2021 at 10:26

std::variant henüz öznitelik uyumluluğu için desteklenmemektedir.

Değiştirmek, boost::variantderlemesini sağlar: Derleyici Gezgini

Alternatif olarak, std :: variant'a ihtiyacınız varsa, işte gerçekten çalışmasını sağlamanın yolları : boost :: variant'tan std :: variant'a Boost Spirit ayrıştırıcısını geçiş

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

Baskılar

Parsed: {iden1, plus, minus, iden2}