我试图使用Boost Spirit X3指令重复一个可变的重复因子.基本思想是标头+有效负载,其中标头指定有效负载的大小.一个简单的例子"3 1 2 3"被解释为header = 3,data = {1,2,3}(3个整数).
我只能从精神qi文档中找到例子.它使用boost phoenix引用来包装变量因子:http://www.boost.org/doc/libs/1_50_0/libs/spirit/doc/html/spirit/qi/reference/directive/repeat.html
std::string str;
int n;
test_parser_attr("\x0bHello World",
char_[phx::ref(n) = _1] >> repeat(phx::ref(n))[char_], str);
std::cout << n << ',' << str << std::endl; // will print "11,Hello World"
Run Code Online (Sandbox Code Playgroud)
我为精神x3写了以下简单的例子,没有运气:
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
#include <iostream>
namespace x3 = boost::spirit::x3;
using x3::uint_;
using x3::int_;
using x3::phrase_parse;
using x3::repeat;
using x3::space;
using std::string;
using std::cout;
using std::endl;
int main( int argc, char **argv )
{ …Run Code Online (Sandbox Code Playgroud) 我目前仍然坚持使用boost spirit x3解析的规则.对于我要解析的内容,这是te EBNF(使用精神列表中的%运算符):
type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | one_arg_lambda
more_arg_lambda ::= "(", type%",", ")", "=>", type
one_arg_lambda ::= type, "=>", type <- here is the left recursion
class_type ::= identifier%"::", ["<", type%",", ">"]
Run Code Online (Sandbox Code Playgroud)
usng boost spirit x3,我试图解析下面的struct/variant:
typedef x3::variant<
nil,
x3::forward_ast<LambdaType>,
x3::forward_ast<ClassType>
> Type;
struct LambdaType {
std::vector<Type> parameters_;
Type return_type_;
};
struct ClassType{
std::vector<std::string> name_;
std::vector<Type> template_args_;
};
Run Code Online (Sandbox Code Playgroud)
我有一个关于我目前在这里尝试的实例,它不起作用,我也尝试改变变体解析器的顺序,它没有帮助,我得到无尽的回忆,或者没有我期望(或希望)的行为.任何人都可以帮我调试这个解析器吗?我想我在解析器中有一些类型的左递归,是否有机会避免这种情况,或者没有机会重写语法?这个gramar甚至可以用boost spirit x3解析吗?
编辑:
我设法在这个语法中消除了左递归.现在te语法如下:
type ::= class_type | lambda_type
lambda_type ::= more_arg_lambda | …Run Code Online (Sandbox Code Playgroud) 试图调整boost spirit x3 calc示例来解析可以将函数作为参数的函数.但是它没有编译.
namespace client{ namespace ast{
struct ts;
struct fnc;
typedef boost::variant<
ts,
boost::recursive_wrapper<fnc>
> node;
struct ts{
unsigned int id;
};
struct fnc{
std::vector<char> id;
std::vector<node> args;
};
}}
BOOST_FUSION_ADAPT_STRUCT(
client::ast::ts,
(unsigned int, id)
)
BOOST_FUSION_ADAPT_STRUCT(
client::ast::fnc,
(std::vector<char>, id)
(std::vector<client::ast::node>, args)
)
namespace client{
namespace x3 = boost::spirit::x3;
namespace calc_grammar{
using x3::uint_;
using x3::alpha;
using x3::alnum;
using x3::lit;
using x3::char_;
x3::rule<class funct, ast::fnc> const funct("function");
x3::rule<class ts, ast::ts> const ts("timeseries");
x3::rule<class funct_name, std::vector<char>> const funct_name("function_name");
auto const …Run Code Online (Sandbox Code Playgroud) 我正在努力学习Boost.Spirit,但我发现了一个难点.
我试图将字符串解析为以下结构:
struct employee {
std::string name;
std::string location;
};
Run Code Online (Sandbox Code Playgroud)
似乎当两个具有相同类型的属性背靠背时,它们会崩溃(逻辑上)std::vector为该类型的一个.由于该规则,以下解析器
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
Run Code Online (Sandbox Code Playgroud)
会有的属性std::vector<std::string>.
但我试图将其解析为struct,这意味着我的理想属性将是一个boost::fusion::tuple<std::string, std::string>,所以我可以调整我的结构.
不工作代码的完整版本(如上所述):
// Example program
#include <iostream>
#include <string>
#include <boost/spirit/home/x3.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
struct employee {
std::string name;
std::string location;
};
BOOST_FUSION_ADAPT_STRUCT(employee,
(std::string, name),
(std::string, location)
)
namespace x3 = boost::spirit::x3;
x3::rule<struct parse_emp_id, employee> const parse_emp = "Employee Parser";
auto parse_emp_def =
+x3::ascii::alnum >>
+x3::space >>
+x3::ascii::alnum
;
BOOST_SPIRIT_DEFINE(parse_emp);
int main()
{
std::string input …Run Code Online (Sandbox Code Playgroud) 我正试图抓住新的Spirit X3(升级1.61.0).
我的机器是运行Linux的MacBook Pro(i7-4750HQ).
使用Spirit的第2版我习惯了很长的编译时间,但这感觉不对.对于表达式解析器的以下第一步,编译需要20秒.
我以为X3会更快,这个合理吗?我的代码不是最理想的吗?
编译器设置(铿锵3.8.0)
clang++ -c -pipe -std=c++14 -ftemplate-depth=512 -g -w -Wall -Wno-unused-parameter -fPIC
Run Code Online (Sandbox Code Playgroud)
码:
//#define BOOST_SPIRIT_X3_DEBUG
#include <iostream>
#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <string>
#include <vector>
//--------------------------------------------------------------------------------------------------
namespace client { namespace ast
{
namespace fusion = boost::fusion;
namespace x3 = boost::spirit::x3;
struct number : x3::variant<int, double> {
using base_type::base_type;
using base_type::operator=;
};
struct add_ast;
struct mult_ast;
struct block_ast;
struct function;
struct expr_ast : x3::variant<
number,
x3::forward_ast<function>,
x3::forward_ast<add_ast>,
x3::forward_ast<mult_ast>,
x3::forward_ast<block_ast>
> {
using base_type::base_type;
using …Run Code Online (Sandbox Code Playgroud) 此代码不编译(gcc 5.3.1 + boost 1.60):
#include <boost/spirit/home/x3.hpp>
namespace x3 = boost::spirit::x3;
template <typename T>
void parse(T begin, T end) {
auto dest = x3::lit('[') >> x3::int_ >> ';' >> x3::int_ >> ']';
auto on_portal = [&](auto& ctx) {};
auto portal = (x3::char_('P') >> -dest)[on_portal];
auto tiles = +portal;
x3::phrase_parse(begin, end, tiles, x3::eol);
}
int main() {
std::string x;
parse(x.begin(), x.end());
}
Run Code Online (Sandbox Code Playgroud)
它失败并带有静态断言:
error: static assertion failed: Attribute does not have the expected size.
Run Code Online (Sandbox Code Playgroud)
感谢wandbox我也尝试了boost 1.61和clang,两者都产生了相同的结果.
如果我删除附加的语义动作portal,它编译得很好; 如果我dest …
我正在尝试std::array使用boost :: spirit的最新版本x3(包含在boost 1.54中)将数字列表解析为固定大小的容器.由于std::array具有必要的功能,因此它被检测为容器,但缺少插入功能,使其不兼容.这是我想要完成的一个简短示例:
#include <boost/spirit/home/x3.hpp>
#include <array>
#include <iostream>
#include <string>
namespace x3 = boost::spirit::x3;
namespace ascii = boost::spirit::x3::ascii;
typedef std::array<double, 3> Vertex;
int main(int, char**) {
using x3::double_;
using ascii::blank;
std::string input = "3.1415 42 23.5";
auto iter = input.begin();
auto vertex = x3::rule<class vertex, Vertex>{} =
double_ >> double_ >> double_;
Vertex v;
bool const res = x3::phrase_parse(iter, input.end(), vertex, blank, v);
if (!res || iter != input.end()) return EXIT_FAILURE;
std::cout << "Match:" …Run Code Online (Sandbox Code Playgroud) 我正在尝试将LaTeX转义码(例如\alpha)解析为Unicode(数学)字符(即U+1D6FC).
现在这意味着我正在使用这个symbols解析器(规则):
struct greek_lower_case_letters_ : x3::symbols<char32_t>
{
greek_lower_case_letters_::greek_lower_case_letters_()
{
add("alpha", U'\u03B1');
}
} greek_lower_case_letter;
Run Code Online (Sandbox Code Playgroud)
这很好,但意味着我得到了std::u32string一个结果.我想要一种优雅的方法来保持代码中的Unicode代码点(可能是未来的自动化)和维护原因.有没有办法让这种解析器解析为UTF-8 std::string?
我想过将symbolsstruct解析为a std::string,但这样效率非常低(我知道,早期优化bla bla).
我希望有一些优雅的方式,而不是通过一堆箍来使这工作(symbols将结果附加到字符串).
我担心使用代码点值并想要UTF8会产生转换的运行时成本(或者是否有constexprUTF32-> UTF8转换?).
所以,我已经编写了我的语法,并希望提供一些调试信息,如行号,以便能够使用我自己的调试器逐步生成生成的可执行代码.
经过一些谷歌搜索后,我发现可以完全定义规则中使用的标记类,如下所示:
x3::rule<class CodeLine, ast::InstructionOrDirectiveAndArgs> const code_line = "code_line";
auto const code_line_def = ...
class CodeLine {
public:
template <typename T, typename Iterator, typename Context>
inline void on_success(Iterator const& first, Iterator const& last, T& ast, Context const& context) {
static std::uint64_t line = 0;
auto& error_handler = x3::get<error_handler_tag>(context).get();
error_handler.tag(ast, first, last);
ast.line_no = line;
if (*last == '\0') {
line = 0;
} else {
line += 1;
}
}
};
Run Code Online (Sandbox Code Playgroud)
在这个完全定义的标记类中,可以实现on_success方法,该方法在成功匹配规则时调用.所以我为匹配一行代码的规则实现了标记类.但由于我找不到从精神中获取当前行号的方法,因此我采用了跟踪当前行的静态变量.问题是要知道何时重置行计数器,正如你在我非常愚蠢的尝试中看到的那样.
这似乎是一种非常复杂的方式来跟踪行号,因此必须有更好的方法.
现在的问题是,获得当前行号的最佳或正确方法是什么?
谢谢阅读!
boost-spirit-x3 ×10
boost-spirit ×9
c++ ×9
boost ×4
c++14 ×4
parsing ×1
stdarray ×1
visual-c++ ×1