问题在底部以粗体显示,问题也通过最终的蒸馏代码片段进行了总结.
我试图统一我的类型系统(类型系统从类型到字符串)和单个组件(由Lakos定义).我正在使用boost::array
,, boost::variant
和boost::mpl
,以实现这一目标.我想让我的类型的解析器和生成器规则统一在一个变体中.有一个未定义的类型,一个int4(见下文)类型和一个int8类型.该变体读作variant<undefined, int4,int8>
.
int4特征:
struct rbl_int4_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, rbl_int4()> rule_type;
boost::spirit::qi::int_parser<rbl_int4> parser_int32_t;
rule_type rule;
rbl_int4_parser_rule_definition()
{
rule.name("rbl int4 rule");
rule = parser_int32_t;
}
};
template<>
struct rbl_type_parser_rule<rbl_int4>
{
typedef rbl_int4_parser_rule_definition string_parser;
};
Run Code Online (Sandbox Code Playgroud)
上面的变体从未定义开始,然后我初始化规则.我有一个问题,导致50页的错误,我终于设法跟踪它,Variant operator=
在分配期间使用,而a boost::spirit::qi::int_parser<>
不能分配给另一个(operator =).
相比之下,我的未定义类型没有问题:
struct rbl_undefined_parser_rule_definition
{
typedef boost::spirit::qi::rule<std::string::iterator, void()> rule_type;
rule_type rule;
rbl_undefined_parser_rule_definition()
{
rule.name("undefined parse rule");
rule = boost::spirit::qi::eps;
}
};
template<>
struct rbl_type_parser_rule<rbl_undefined>
{
typedef rbl_undefined_parser_rule_definition string_parser;
};
Run Code Online (Sandbox Code Playgroud)
蒸馏问题:
#include <string>
#include <boost/spirit/include/qi.hpp> …
Run Code Online (Sandbox Code Playgroud) 在这篇关于提升精神语义行为的文章中提到了这一点
实际上还有2个参数被传递:解析器上下文和对布尔"命中"参数的引用.仅当语义操作附加到规则右侧的某个位置时,解析器上下文才有意义.我们很快就会看到更多相关信息.在语义操作中,布尔值可以设置为false,从而使回溯中的匹配失效,从而使解析器失败.
一切都很好,但我一直试图找到一个示例传递函数对象作为语义动作使用其他参数(解析器上下文和命中布尔)但我还没有找到任何.我很想看到一个使用常规函数或函数对象的例子,因为我几乎无法理解凤凰伏都教
下面的代码来自Boost.Spirit x3文档.它使用了我以前从未见过的有趣的C++语法,如果不知道正确的术语,几乎不可能在搜索查询中描述.这是一个类的前向声明的简写吗?C++标准中提到的这个功能在哪里?
namespace parser
{
using x3::eps;
using x3::lit;
using x3::_val;
using x3::_attr;
using ascii::char_;
auto set_zero = [&](auto& ctx){ _val(ctx) = 0; };
auto add1000 = [&](auto& ctx){ _val(ctx) += 1000; };
auto add = [&](auto& ctx){ _val(ctx) += _attr(ctx); };
// What is this? This is the very first use of the identifier `roman`.
x3::rule<class roman, unsigned> const roman = "roman";
// ^^^^^^^^^^^
auto const roman_def =
eps [set_zero]
>>
(
-(+lit('M') [add1000])
>> -hundreds [add] …
Run Code Online (Sandbox Code Playgroud) 我有一个包含数百万行的文件,每行有3个以空格分隔的浮点数.读取文件需要花费大量时间,因此我尝试使用内存映射文件读取它们,但发现问题不在于IO的速度,而在于解析速度.
我当前的解析是获取流(称为文件)并执行以下操作
float x,y,z;
file >> x >> y >> z;
Run Code Online (Sandbox Code Playgroud)
Stack Overflow中的某些人建议使用Boost.Spirit,但我找不到任何简单的教程来解释如何使用它.
我正在尝试找到一种简单有效的方法来解析看起来像这样的行:
"134.32 3545.87 3425"
Run Code Online (Sandbox Code Playgroud)
我真的很感激一些帮助.我想用strtok来分割它,但我不知道如何将字符串转换为浮点数,我不太确定它是最好的方法.
我不介意解决方案是否会提升.我不介意它是不是有史以来最有效的解决方案,但我确信它可以加倍速度.
提前致谢.
我想解析一个布尔表达式(在C++中).输入表格:
a and b xor (c and d or a and b);
Run Code Online (Sandbox Code Playgroud)
我只想将这个表达式解析为树,知道优先级规则(不是,和,xor,或).所以上面的表达式应该类似于:
(a and b) xor ((c and d) or (a and b));
Run Code Online (Sandbox Code Playgroud)
到解析器.
树将是以下形式:
a
and
b
or
c
and
d
xor
a
and
b
Run Code Online (Sandbox Code Playgroud)
输入将通过命令行或以字符串的形式.我只需要解析器.
有没有可以帮助我做到这一点的消息来源?
我最近一直在寻找Boost.Spirit(Boost 1.39中包含的版本),但是我对单独的文档很困惑.我正在寻找的是一个用Boost.Spirit实现的玩具语言的例子 - 一些微小的Javascript或Lua左右的东西,你基本上创建一个AST和进程.如果它只支持函数/变量定义和基本运算符,我会很高兴,我只想看看如何使用Boost.Spirit创建一个普通的AST,以及如何实现标识符,声明等基本规则.
到目前为止,我已经尝试过计算器示例,但我不清楚如何使用Spirit实现更大的语法.另一方面捆绑的mini_c示例看起来已经非常复杂了,并且记录得不是很好.是否有一些易于理解的Boost.Spirit指南,或者可能是一本书?
这可能非常明显,但为什么boost中的基于流的解析复制了最后一个字母?我一定做错了什么:
#include <iostream>
#include <sstream>
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
int main() {
std::string input = "hello";
std::stringstream ss(input);
std::string r1, r2;
boost::spirit::istream_iterator first(ss), last;
qi::phrase_parse(input.begin(), input.end(), qi::lexeme[qi::alpha >> *qi::alnum], qi::space, r1);
std::cout << r1 << std::endl; // prints "hello"
qi::phrase_parse(first, last, qi::lexeme[qi::alpha >> *qi::alnum], qi::space, r2);
std::cout << r2 << std::endl; // prints "helloo"
}
Run Code Online (Sandbox Code Playgroud)
使用XCode 5.0和Boost 1.54.0进行测试.
编辑: 问题似乎是特定于libc ++.有人使用Clang护理确认吗?
任何减少boost :: spirit编译时间的想法?
我刚刚将flex解析器移植到boost :: spirit.EBNF有大约25条规则.
结果运行良好,运行时性能良好.
问题是编译需要永远!它需要大约十分钟,并且需要几乎一千兆字节的内存.原始的flex解析器在几秒钟内编译完成.
我正在使用boost版本1.44.0和Visual Studio 2008.
在Joel de Guzman的文章"最佳实践"中,它说
具有复杂定义的规则严重损害了编译器.我们已经看到超过一百行的规则,需要花费几分钟来编译
好吧,我没有接近那么久,但我的编译仍然需要超过几分钟
这是我语法中最复杂的部分.它是以某种方式分解成较小部分的候选者吗?
rule
= ( tok.if_ >> condition >> tok.then_ >> *sequel ) [ bind( &cRuleKit::AddRule, &myRulekit ) ]
| ( tok.if_ >> condition >> tok.and_ >> condition >> tok.then_ >> *sequel ) [ bind( &cRuleKit::AddRule, &myRulekit ) ]
;
condition
= ( tok.identifier >> tok.oper_ >> tok.value ) [ bind( &cRuleKit::AddCondition, &myRulekit, _pass, _1, _2, _3 ) ]
| ( tok.identifier >> …
Run Code Online (Sandbox Code Playgroud) 是否可以boost::spirit:qi
在另一种语法中重用语法(例如,规则)?
例如,如果我定义一个语法来解析文本行到一个持有街道地址的结构中.
template< typename iter >
struct address_grammar : qi::grammar< iter, address() >
{
...
qi::rule< iter, std::string() > street_name;
qi::rule< iter, std::string() > street_number;
qi::rule< iter, address() > address_;
}
Run Code Online (Sandbox Code Playgroud)
我可能想在另外两个语法中重用该语法,例如,一个可能用于解析存储在文件中的地址向量.另一种重复使用可能是在更复杂的结构中,其中一个字段是此街道地址结构.
template< typename iter >
struct company_grammar : qi::grammar< iter, company() >
{
...
qi::rule< iter, std::string() > comp_name;
// can I reuse the address grammar somehow here ???
qi::rule< iter, company() > company;
}
Run Code Online (Sandbox Code Playgroud)
我没有在一个地方定义整个语法,而是想把它分成更小的可重用块,如果它们在一个头文件中,那就好了.我的数据结构稍微复杂一些(struct中的几个字段和其他结构的列表等等)所以我不想把它放在一个语法中.
是否有可能以boost::spirit::qi
这种方式重用语法?
编辑:考虑一下,我只是qi::rule
在命名空间中定义s,然后从我需要的规则中汇总一个语法?