提升精神 x3 变体和 std::pair
Posted
技术标签:
【中文标题】提升精神 x3 变体和 std::pair【英文标题】:boost spirit x3 variant and std::pair 【发布时间】:2018-11-26 21:38:43 【问题描述】:我尝试运行一些简单的解析器来解析 [1, 11, 3, 6-4]。基本上,带有范围表示法的整数列表。
我想将所有内容都放入 AST 中,而不需要语义操作。所以我使用 x3::variant。我的代码“似乎”与表达式示例非常相似。但是,它不能在 g++ 6.2 下编译。它确实可以用 clang++ 6.0 编译,但产生错误的结果。
增强版本是 1.63。 看来我有一些“移动”或初始化问题。
#include <iostream>
#include <list>
#include <vector>
#include <utility>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/io.hpp>
namespace ns
namespace ast
namespace x3 = boost::spirit::x3;
// forward definition
class uintObj;
struct varVec;
// define type
using uintPair_t = std::pair<unsigned int, unsigned int>;
using uintVec_t = std::vector<uintObj>;
// general token value:
class uintObj : public x3::variant <
unsigned int,
uintPair_t
>
public:
using base_type::base_type;
using base_type::operator=;
;
struct varVec
uintVec_t valVector;
;
BOOST_FUSION_ADAPT_STRUCT(
ns::ast::varVec,
valVector
)
namespace ns
namespace parser
// namespace x3 = boost::spirit::x3;
// using namespace x3;
using namespace boost::spirit::x3;
// definition of the range pair:
rule<class uintPair, ast::uintPair_t> const uintPair = "uintPair";
auto const uintPair_def =
uint_
>> '-'
>> uint_
;
rule<class uintObj, ast::uintObj> const uintObj = "uintObj";
auto const uintObj_def =
uint_
| uintPair
;
// define rule definition : rule<ID, attrib>
// more terse definition :
// struct varVec_class;
// using varVec_rule_t = x3::rule<varVec_class, ast::varVec>;
// varVec_rule_t const varVec = "varVec";
// varVec is the rule, "varVec" is the string name of the rule.
rule<class varVec, ast::varVec> const varVec = "varVec";
auto const varVec_def =
'['
>> uintObj % ','
>> ']'
;
BOOST_SPIRIT_DEFINE(
varVec,
uintObj,
uintPair
);
int main()
std::string input ("[1, 11, 3, 6-4]\n");
std::string::const_iterator begin = input.begin();
std::string::const_iterator end = input.end();
ns::ast::varVec result; // ast tree
using ns::parser::varVec; // grammar
using boost::spirit::x3::ascii::space;
bool success = phrase_parse(begin, end, varVec, space, result);
if (success && begin == end)
std::cout << "good" << std::endl;
else
std::cout << "bad" << std::endl;
return 0;
【问题讨论】:
我知道还有其他类似的问题。我的问题不是还有其他方法可以做到这一点。我只是觉得没有语义动作的简单 AST 似乎更严格。 ***.com/questions/34599506/… 交换uintPair和uint_后,clang++编译结果很好。但是,另一个问题是我的 g++ v6.2 仍然无法编译。该命令类似于 g++ -I/install/boost_1_63_0/include -std=c++14 -o par21.o -c par21.cpp。不只是我的版本。我的g++也编译不了sehe的版本。 在我的回答中查看 cmets 【参考方案1】:交换uintObj_def
的替代顺序
auto const uintObj_def =
uintPair
| uint_
;
您现在拥有的公式将始终与uint_
匹配,因为uintPair
以有效的uint_
开头。
【讨论】:
【参考方案2】:mjcaisse 的回答指出了我认为您遇到的主要问题。有一些缺失的部分,所以我决定制作一个显示解析结果的简化版本:
Live On Wandbox
#include <iostream>
#include <iomanip>
//#include <boost/fusion/adapted.hpp>
//#include <boost/fusion/include/io.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
namespace x3 = boost::spirit::x3;
namespace ns namespace ast
// forward definition
struct uintObj;
//struct varVec;
// define type
using uintPair_t = std::pair<unsigned int, unsigned int>;
using uintVec_t = std::vector<uintObj>;
// general token value:
struct uintObj : x3::variant<unsigned int, uintPair_t>
using base_type::base_type;
using base_type::operator=;
friend std::ostream& operator<<(std::ostream& os, uintObj const& This)
struct
std::ostream& os;
void operator()(unsigned int v) const os << v;
void operator()(uintPair_t v) const os << v.first << "-" << v.second;
vis os ;
boost::apply_visitor(vis, This);
return os;
;
using varVec = uintVec_t;
namespace ns namespace parser
using namespace boost::spirit::x3;
template <typename T> auto as = [](auto p) return rule<struct _, T> = p; ;
auto const uintPair = as<ast::uintPair_t> ( uint_ >> '-' >> uint_ );
auto const uintObj = as<ast::uintObj> ( uintPair | uint_ );
auto const varVec = as<ast::varVec> ( '[' >> uintObj % ',' >> ']' );
int main()
using namespace ns;
std::string const input("[1, 11, 3, 6-4]\n");
auto begin = input.begin(), end = input.end();
ast::varVec result; // ast tree
bool success = phrase_parse(begin, end, parser::varVec, x3::ascii::space, result);
if (success)
std::cout << "good\n";
for (auto& r : result)
std::cout << r << "\n";
else
std::cout << "bad\n";
if (begin != end)
std::cout << "Remaining unparsed: " << std::quoted(std::string(begin, end)) << std::endl;
打印
good
1
11
3
6-4
【讨论】:
好的,代码确实看起来更简单更漂亮。我想知道 youtube 和 boost 网站 x3 教程都使用类似于“expr_class”、“expr_def”、“expr”和 BOOST_SPIRIT_DEFINE() 的类似方法。如果我们可以像上面的代码那样使用“更简单”的方式,那么这样做的原因是什么。 关于使用BOOST_SPIRIT_DEFINE
定义规则:仅1.递归规则2.外部链接需要。 (也许我的一些answers 会有所启发)
关于编译器问题,GCC 6.3.0 显然无法为uintObj
生成特殊成员。添加它们修复它:Live On Wandbox以上是关于提升精神 x3 变体和 std::pair的主要内容,如果未能解决你的问题,请参考以下文章