就像其他许多问题一样,我正在尝试使用Boost.Spirit.Qi将简单语法解析为结构树.
我会尝试提炼我想要做的最简单的案例.我有:
struct Integer {
int value;
};
BOOST_FUSION_ADAPT_STRUCT(Integer, (int, value))
Run Code Online (Sandbox Code Playgroud)
后来,在语法结构中,我有以下成员变量:
qi::rule<Iterator, Integer> integer;
Run Code Online (Sandbox Code Playgroud)
这是我定义的
integer = qi::int_;
Run Code Online (Sandbox Code Playgroud)
但是,当我尝试实际解析整数时,使用
qi::phrase_parse(iter, end, g, space, myInteger);
Run Code Online (Sandbox Code Playgroud)
myInteger.value
在成功解析后始终未初始化.同样,我尝试了以下定义(显然那些不编译的定义是错误的):
integer = qi::int_[qi::_val = qi::_1]; //compiles, uninitialized value
integer = qi::int_[qi::_r1 = qi::_1]; //doesn't compile
integer = qi::int_[phoenix::bind(&Integer::value, qi::_val) = qi::_1]; //doesn't
integer = qi::int_[phoenix::at_c<0>(qi::_val) = qi::_1]; //doesn't
Run Code Online (Sandbox Code Playgroud)
显然,我误解了一些关于精神,凤凰或其他东西的东西.我的理解是,当方括号中的部分作为函数对象执行时,这里qi::_1
的第一个属性qi::int_
应该表示已解析的整数.我假设函数对象将采用封闭integer
属性qi::_val
并尝试将解析后的整数分配给它.我的猜测是因为我的BOOST_FUSION_ADAPT_STRUCT
调用,两者兼容,从静态分析的角度来看,情况似乎确实如此,但数据并未得到保留.
是否有参考(&)指定我在某处或某处遗漏?
我想用C++编写一个函数来替换C的sscanf,它将匹配分配给迭代器.
基本上,我想要的东西:
string s = "0.5 6 hello";
std::vector<boost::any> any_vector;
sscanv(s, "%f %i %s", any_vector);
cout << "float: " << any_cast<float>(any_vector[0]);
cout << "integer: " << any_cast<integer(any_vector[1]);
cout << "string: " << any_cast<string>(any_vector[2]);
Run Code Online (Sandbox Code Playgroud)
确切的细节可能会有所不同,但你明白了.任何实施的想法?
到目前为止的选项以及目前的问题:
到目前为止,我的语法一直使用标准boost::spirit::ascii::space
/ boost::spirit::ascii::space_type
队长.
我有一些使用船长的规则和一些不使用船长的规则
qi::rule<Iterator, PTR<Expression>(), ascii::space_type> expression;
qi::rule<Iterator, PTR<Term>()> term;
Run Code Online (Sandbox Code Playgroud)
当我在跳过非终结符(例如term
)中使用非跳过非终结符(例如expression
)时,一切都像我期望的那样工作 - 空格只对term
非终结内部很重要.
此外,到目前为止,我一直很好,包括使用不使用qi::skip
重新跳过的非终端内的队长的非终结者,例如
index = (qi::lit('[') >> qi::skip(ascii::space)[explist >> qi::lit(']')]);
Run Code Online (Sandbox Code Playgroud)
这样,在[]
括号内部的空白并不重要,但在外面.
但是,现在我想添加我自己的自定义队列(我想让换行有意义,然后添加评论跳过).我的船长语法看起来像:
struct skip_grammar : qi::grammar<Iterator> {
qi::rule<Iterator> start;
skip_grammar() : skip_grammar::base_type(start) {
start = qi::char_("\t\r ");
}
};
Run Code Online (Sandbox Code Playgroud)
我已经能够将它添加到我的规则定义中就好了
qi::rule<Iterator, PTR<Expression>(), skip_grammar> expression;
Run Code Online (Sandbox Code Playgroud)
但我似乎无法弄清楚如何使用我的跳过语法作为参数qi::skip
(和替换ascii::space
).我尝试使用类型,本地实例变量和全局实例变量.我得到的最远的就是抱怨我的skip_grammar需要一个拷贝构造函数.所以我尝试将一个复制构造函数添加到我的跳过语法中,但显然boost::noncopyable
基类是有原因的,因为我的二进制文件几乎立即就被发现了.
我应该如何使用它?
谢谢
我正在尝试使用Boost Spirit商店JSON对象将JSON字符串解析为递归数据结构:
Value <== [null, bool, long, double, std::string, Array, Object];
Array <== [Value, Value, Value, ...];
Object <== ["name1": Value, "name2": Value, ...];
Run Code Online (Sandbox Code Playgroud)
这是我的代码:
#include <map>
#include <vector>
#include <string>
#include <boost/variant.hpp>
#include <boost/shared_array.hpp>
#include <boost/shared_ptr.hpp>
struct JsonNull {};
struct JsonValue;
typedef std::map<std::string, JsonValue *> JsonObject;
typedef std::vector<JsonValue *> JsonArray;
struct JsonValue : boost::variant<JsonNull, bool, long, double, std::string, JsonArray, JsonObject>
{
};
JsonValue aval = JsonObject();
Run Code Online (Sandbox Code Playgroud)
编译时我得到错误:
Error C2440: 'initializing' : cannot convert from 'std::map<_Kty,_Ty>' to 'JsonValue'
Run Code Online (Sandbox Code Playgroud)
而且,如何安全地将JsonValue转换为JsonObject?当我尝试做:
boost::get<JsonObject>(aval) …
Run Code Online (Sandbox Code Playgroud) 我正在努力学习boost::spirit
.作为一个例子,我试图将一系列单词解析成一个单词vector<string>
.我试过这个:
#include <boost/spirit/include/qi.hpp>
#include <boost/foreach.hpp>
namespace qi = boost::spirit::qi;
int main() {
std::vector<std::string> words;
std::string input = "this is a test";
bool result = qi::phrase_parse(
input.begin(), input.end(),
+(+qi::char_),
qi::space,
words);
BOOST_FOREACH(std::string str, words) {
std::cout << "'" << str << "'" << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
这给了我这个输出:
'thisisatest'
Run Code Online (Sandbox Code Playgroud)
但我想要以下输出,其中每个单词分别匹配:
'this'
'is'
'a'
'test'
Run Code Online (Sandbox Code Playgroud)
如果可能的话,我想避免qi::grammar
为这个简单的情况定义我自己的子类.
我创建了一个数据库引擎,我可以在其中创建和修改表,并将它们添加到数据库中.为了解析SQL查询,我使用EBNF表单实现了Boost.Spirit库.我正确设置了解析器,并成功解析了每个规则.
我的问题是我现在不知道如何整合这两者.Boost.Spirit解析器只验证输入是否正确,但我需要它来实际执行某些操作.我查找了语义操作,但它们似乎没有处理我正在寻找的内容.
例如,如果我有一个查询,例如:
new_table <- SELECT (id < 5) old_table;
我希望它使用规则验证输入,然后调用函数
Table Database::Select(Table t , Condition c){ ... }
并将标记作为参数传递.
我如何整合解析器?
我试图浏览Boost Spirit页面上的官方文档,但我发现它完全无法理解(尽管有超过25年的编程经验和英语语言学位) - 它显然是由一个对系统了解得很好的人(好)但假设读者也很了解系统(坏).我需要一些不会像这样的句子
精神中的解析器和发电机完全归功于它
显然是"归属"的含义,我不知道,网络搜索没有帮助.要么
序列需要属性类型来公开融合序列的概念,其中该融合序列的所有元素必须与组件序列的相应元素兼容
什么是融合序列?我所知道的唯一一个发生在太阳下.如何在C++中"揭露"一个"概念"?
从初学者的角度来看,是否有任何好的教程描述了Boost Spirit?
我尝试使用Boost Spirit QI解析TPCH文件.我的实现灵感来自Spirit QI的员工示例(http://www.boost.org/doc/libs/1_52_0/libs/spirit/example/qi/employee.cpp).数据采用csv格式,令牌以"|"分隔.字符.
它工作但很慢(1秒时为20秒).
这是我对lineitem文件的qi语法:
struct lineitem {
int l_orderkey;
int l_partkey;
int l_suppkey;
int l_linenumber;
std::string l_quantity;
std::string l_extendedprice;
std::string l_discount;
std::string l_tax;
std::string l_returnflag;
std::string l_linestatus;
std::string l_shipdate;
std::string l_commitdate;
std::string l_recepitdate;
std::string l_shipinstruct;
std::string l_shipmode;
std::string l_comment;
};
BOOST_FUSION_ADAPT_STRUCT( lineitem,
(int, l_orderkey)
(int, l_partkey)
(int, l_suppkey)
(int, l_linenumber)
(std::string, l_quantity)
(std::string, l_extendedprice)
(std::string, l_discount)
(std::string, l_tax)
(std::string, l_returnflag)
(std::string, l_linestatus)
(std::string, l_shipdate)
(std::string, l_commitdate)
(std::string, l_recepitdate)
(std::string, l_shipinstruct)
(std::string, l_shipmode)
(std::string, l_comment))
vector<lineitem>* lineitems=new …
Run Code Online (Sandbox Code Playgroud) 我有这个csv线
std::string s = R"(1997,Ford,E350,"ac, abs, moon","some "rusty" parts",3000.00)";
Run Code Online (Sandbox Code Playgroud)
我可以用boost::tokenizer
以下方法解析它:
typedef boost::tokenizer< boost::escaped_list_separator<char> , std::string::const_iterator, std::string> Tokenizer;
boost::escaped_list_separator<char> seps('\\', ',', '\"');
Tokenizer tok(s, seps);
for (auto i : tok)
{
std::cout << i << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
它是正确的,除了令牌"生锈"应该有双引号被剥离.
这是我尝试使用boost :: spirit
boost::spirit::classic::rule<> list_csv_item = !(boost::spirit::classic::confix_p('\"', *boost::spirit::classic::c_escape_ch_p, '\"') | boost::spirit::classic::longest_d[boost::spirit::classic::real_p | boost::spirit::classic::int_p]);
std::vector<std::string> vec_item;
std::vector<std::string> vec_list;
boost::spirit::classic::rule<> list_csv = boost::spirit::classic::list_p(list_csv_item[boost::spirit::classic::push_back_a(vec_item)],',')[boost::spirit::classic::push_back_a(vec_list)];
boost::spirit::classic::parse_info<> result = parse(s.c_str(), list_csv);
if (result.hit)
{
for (auto i : vec_item)
{
cout << i << endl;
} …
Run Code Online (Sandbox Code Playgroud) 我正在尝试将字符串解析为symbol
包含std::string
成员的自定义类型的属性.我以为我可以BOOST_FUSION_ADAPT_STRUCT
在这里使用,但这不起作用.
如果我宣布规则是rule<It, std::string(), space_type>
有效的.如果我将其定义为rule<It, symbol(), space_type>
失败,并显示错误"no type name value_type
in symbol
".我认为Spirit正在尝试将值字符附加到属性中,该属性会按预期失败.但是,如果没有添加额外的中间规则来捕获std::string
属性,是不是有办法使这项工作成功?
这是完整的MWE:
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
struct symbol
{
std::string repr;
};
BOOST_FUSION_ADAPT_STRUCT(symbol, (std::string, repr))
namespace qi = boost::spirit::qi;
template <typename Iterator>
struct test_grammar : qi::grammar<Iterator, symbol(), qi::ascii::space_type> {
test_grammar() : test_grammar::base_type{start} {
start = qi::lexeme[+qi::char_("a-z")];
}
qi::rule<Iterator, symbol(), qi::ascii::space_type> start;
};
#include <iostream>
auto main() -> int {
test_grammar<std::string::iterator> grammar{};
auto input …
Run Code Online (Sandbox Code Playgroud) boost-spirit ×10
c++ ×10
boost ×4
parsing ×3
csv ×2
boost-fusion ×1
boost-regex ×1
json ×1
sql ×1