Boost Spirit x3: ข้อผิดพลาดเวลาคอมไพล์แอตทริบิวต์ผสม (คลาส enum)
ผมเพิ่งเขียนแยกวิเคราะห์เป็นไปได้ง่ายโดยใช้x3 จิตวิญญาณเพิ่ม มันมี 2 กฎ: ระบุและตัวเดียวประกอบ ธรรมชาติฉันดำเนินการประกอบการenum class
โดยใช้ตารางสัญลักษณ์ซึ่งเป็นผู้ผลิตประเภทผู้ประกอบการ ตัวระบุจะแยกวิเคราะห์เป็นstd::string
s อย่างไรก็ตามรหัสปฏิเสธที่จะรวบรวมเมื่อรวมตัวระบุและตัวดำเนินการไว้ในตัวแยกวิเคราะห์เดียว (ดูส่วนของรหัสที่ส่วนท้ายของคำถาม)
โปรดทราบว่าหากคุณเปลี่ยนประเภทโอเปอเรเตอร์ enum ด้วยจำนวนเต็มทุกอย่างจะทำงานได้ดี ตัวดำเนินการและตัวระบุจะแยกวิเคราะห์ได้ดีเมื่อแยกกันเช่นกัน
ข้อผิดพลาดแม่แบบที่ค่อนข้างใหญ่ที่จะแนบและปิดบังเกินไปสำหรับผมที่จะเข้าใจ แต่ผมสงสัยว่ามันมีสิ่งที่จะทำอย่างไรกับการก่อสร้าง / std::variant<std::string, OperType>
ย้ายความหมายของ อย่างไรก็ตามenum class
ไม่ควรแตกต่างจากที่ราบint
อย่างมาก มีอะไรเกี่ยวข้องกับตัวenum class
สร้างเริ่มต้นหรือไม่? สิ่งนี้จะข้ามได้อย่างไร?
นี่คือ codepiece
#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;
}
มีข้อผิดพลาดใด ๆ เมื่อเขียนตัวแยกวิเคราะห์แบบผสมหรือไม่? ฉันขาดอะไรไป? ขอบคุณที่สละเวลา.
คำตอบ
std::variant
ยังไม่รองรับความเข้ากันได้ของแอตทริบิวต์
การเปลี่ยนเพื่อboost::variant
ทำให้คอมไพล์: Compiler Explorer
อีกวิธีหนึ่งคือวิธีทำให้ใช้งานได้จริงหากคุณต้องการ std :: variant: การเปลี่ยนตัวแยกวิเคราะห์ Boost Spirit จาก boost :: variant เป็น 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}