Boost spirit x3: bileşik öznitelik derleme zamanı hatası (enum sınıfı)
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 class
düzlükten büyük ölçüde farklı olmamalıdır int
. enum class
Varsayı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
std::variant
henüz öznitelik uyumluluğu için desteklenmemektedir.
Değiştirmek, boost::variant
derlemesini 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}