1
구현 한 BNF는 연산자에 따라이 생산 규칙에서 연쇄되거나 이벤트가 될 수있는 재미있는 규칙을 가지고 있습니다. 따라서 I 만 열거 변경 이후 동일한 AST 데이터 구조를 사용 boost.spirit x3 move_to 그리고 ast 회원을 나열하십시오
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <iostream>
#include <string>
#include <list>
namespace ast
{
struct identifer {
int name;
};
struct expression {
struct chunk {
char operator_;
ast::identifer identifer;
};
ast::identifer identifer;
std::list<chunk> chunk_list;
};
}
BOOST_FUSION_ADAPT_STRUCT(ast::identifer,
name
)
BOOST_FUSION_ADAPT_STRUCT(ast::expression::chunk,
operator_, identifer
)
BOOST_FUSION_ADAPT_STRUCT(ast::expression,
identifer, chunk_list
)
namespace boost { namespace spirit { namespace x3 { namespace traits {
void move_to(ast::expression::chunk&& chunk, std::list<ast::expression::chunk>& chunk_list,
mpl::identity<container_attribute>)
{
chunk_list.emplace(chunk_list.end(), std::move(chunk));
}
} } } }
namespace parser
{
namespace x3 = boost::spirit::x3;
auto const identifier = x3::rule<struct _, int> { "identifier" } =
x3::int_;
auto const operator_1 = x3::rule<struct _, char> { "operator" } =
x3::char_("ABC");
auto const operator_2 = x3::rule<struct _, char> { "operator" } =
x3::char_("XYZ");
auto const expression_chunk_1 = x3::rule<struct _, ast::expression::chunk> { "expression" } =
operator_1 > identifier
;
auto const expression_chunk_2 = x3::rule<struct _, ast::expression::chunk> { "expression" } =
operator_2 > identifier
;
auto const expression = x3::rule<struct _, ast::expression> { "expression" } =
identifier >> *expression_chunk_1 // foo { and foo }
// rule below fails to compile
| identifier >> expression_chunk_2 // foo [ nand foo ]
;
}
struct visitor {
visitor(std::ostream& os) : os{ os } { }
void operator()(ast::expression const& node) {
os << "(";
(*this)(node.identifer);
for(auto const& chunk : node.chunk_list) {
os << "(" << chunk.operator_ << " ";
(*this)(chunk.identifer);
os << ")";
}
os << ")\n";
}
void operator()(ast::identifer const& node) {
os << "(" << node.name << ")";
}
std::ostream& os;
};
int main()
{
namespace x3 = boost::spirit::x3;
for(std::string const str: {
"1 X 2",
"3 A 4 A 5"
}) {
auto iter = str.begin(), end = str.end();
ast::expression attr;
bool r = x3::phrase_parse(iter, end, parser::expression, x3::space, attr);
std::cout << "parse '" << str << "': ";
if (r && iter == end) {
std::cout << "succeeded:\n";
visitor(std::cout)(attr);
} else {
std::cout << "*** failed ***\n";
}
}
return 0;
}
이
는 아이디어 - 오퍼레이터 X는, Y는 Z가 나열 하나의 청크를 추가한다. 컴파일러 오류 다음에, 나는 x3 :: traits :: move_to를 전문화해야한다. 그러나 이것을 컴파일 할 수있는 해결책을 찾지 못했다. 할 일이 뭐야? 목록 :: emplace()와 std :: move()는 안전합니까?
감사합니다 : 대신, 인위적으로
repeat
를 사용하여vector<T>
의 문법 결과를 확인합니다. 이 솔루션은 [link] (http://coliru.stacked-crooked.com/a/898343ea7611a40a)와 같이 컴파일되지만 구문 분석에 실패했습니다. 작은 변경 만 있습니다 (식별자는 이제 char이며 규칙에는 고유 한 이름이 있습니다). ... DEBUG로 실행하면 식별자가 사용되며 expression_chunk_1이 실패해야합니다. 하나의 (가능한) 방법은 쓸 것입니다. – Olx"1 X 2"'에 대한 예상 결과를 말하면 새로운 질문에서 그 질문을 할 수 있습니다. 나는 그것을 통과하지 못한다는 것을 알았지 만, 그것을 보면서 나는 그것이 문법을 통과해야하는 이유가 없음을 알았다. – sehe
문제를 해결하는 pragamtic 방법. 이 솔루션은 [link] (http://coliru.stacked-crooked.com/a/898343ea7611a40a)와 같이 컴파일되지만 구문 분석에 실패했습니다. 작은 변경 만 있습니다 (식별자는 이제 char이며 규칙에는 고유 한 이름이 있습니다). ... DEBUG로 실행하면 식별자가 사용되며 expression_chunk_1이 실패해야합니다. 하나 (가능한) 방법은 쓸 것입니다 (식별자 >> * expression_chunk_1) | (식별자 >> x3 :: repeat (1) [expression_chunk_2]) 식별자에 대한 반복기를 백 트랙킹/풀기 때문에 영리하지 않습니다. 다음 주석 달기 ... – Olx