- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我正在尝试掌握新的 Spirit X3(boost 1.61.0)。
我的机器是运行 Linux 的 MacBook Pro (i7-4750HQ)。
使用 Spirit 的第 2 版后,我习惯了较长的编译时间,但这感觉不对。对于表达式解析器的以下第一步,编译需要 20 秒。
我以为 X3 会更快,这合理吗?我的代码不是最理想的吗?
编译器设置(clang 3.8.0)
clang++ -c -pipe -std=c++14 -ftemplate-depth=512 -g -w -Wall -Wno-unused-parameter -fPIC
代码:
//#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 base_type::operator=;
};
struct add_ast {
expr_ast lhs;
bool add;
expr_ast rhs;
};
struct mult_ast {
expr_ast lhs;
bool mult;
expr_ast rhs;
};
struct block_ast {
expr_ast body;
};
struct function {
std::string name;
std::vector<expr_ast> params;
};
}}
//--------------------------------------------------------------------------------------------------
BOOST_FUSION_ADAPT_STRUCT(client::ast::add_ast,
(client::ast::expr_ast, lhs),
(bool, add),
(client::ast::expr_ast, rhs)
)
BOOST_FUSION_ADAPT_STRUCT(client::ast::mult_ast,
(client::ast::expr_ast, lhs),
(bool, mult),
(client::ast::expr_ast, rhs)
)
BOOST_FUSION_ADAPT_STRUCT(client::ast::block_ast,
(client::ast::expr_ast, body)
)
BOOST_FUSION_ADAPT_STRUCT(client::ast::function,
(std::string, name),
(std::vector<client::ast::expr_ast>, params)
)
//--------------------------------------------------------------------------------------------------
namespace client { namespace parser
{
namespace x3 = boost::spirit::x3;
const x3::rule<class expr, ast::expr_ast> expr = "expr";
const x3::rule<class add_expr, ast::expr_ast> add_expr = "add_expr";
const x3::rule<class mult_expr, ast::expr_ast> mult_expr = "mult_expr";
const x3::rule<class block_expr, ast::expr_ast> block_expr = "block_expr";
auto const number = x3::rule<class number, ast::number> {"number"}
= (x3::int_ >> !x3::lit('.')) | x3::double_;
auto const fct_name = x3::rule<class fct_name, std::string> {"fct_name"}
= x3::lexeme[ *x3::alpha >> *(x3::alnum | x3::char_('_')) ];
auto const function = x3::rule<class function, ast::function> {"function"}
= fct_name >> x3::lit("(") >> -expr % ',' >> ")";
auto const simple_expr = x3::rule<class simple_expr, ast::expr_ast> {"simple_expr"}
= function | number;
auto const block_term = x3::rule<class block_term, ast::block_ast> {"block_term"}
= "(" >> expr >> ")";
auto const mult_term = x3::rule<class mult_term, ast::mult_ast> {"mult_term"}
= block_expr
>> ((x3::lit("*") >> x3::attr(true)) | (x3::lit("/") >> x3::attr(false)))
>> mult_expr;
auto const add_term = x3::rule<class add_term, ast::add_ast> {"add_term"}
= mult_expr
>> ((x3::lit("+") >> x3::attr(true)) | (x3::lit("-") >> x3::attr(false)))
>> add_expr;
auto const block_expr_def = block_term | simple_expr;
auto const mult_expr_def = mult_term | block_expr;
auto const add_expr_def = add_term | mult_expr;
auto const expr_def = add_expr;
BOOST_SPIRIT_DEFINE(expr, add_expr, mult_expr, block_expr);
}}
//--------------------------------------------------------------------------------------------------
namespace client { namespace ast
{
struct printer
{
typedef std::string result_type;
std::string operator()(const expr_ast &ast) const
{
return boost::apply_visitor(printer(), ast);
}
std::string operator()(const number &value) const
{
return boost::apply_visitor(printer(), value);
}
std::string operator()(const add_ast &expr) const {
return "(" + boost::apply_visitor(printer(), expr.lhs) + (expr.add?" + ":" - ")
+ boost::apply_visitor(printer(), expr.rhs) + ")";
}
std::string operator()(const mult_ast &expr) const {
return "(" + boost::apply_visitor(printer(), expr.lhs) + (expr.mult?" * ":" / ")
+ boost::apply_visitor(printer(), expr.rhs) + ")";
}
std::string operator()(const block_ast &expr) const {
return boost::apply_visitor(printer(), expr.body);
}
std::string operator()(const function &fct) const
{
std::string result = fct.name + "(";
for (std::size_t i = 0; i < fct.params.size(); ++i) {
result += printer()(fct.params[i]);
if (i != fct.params.size() - 1)
result += ",";
}
result += ")";
return result;
}
std::string operator()(int const& value) const
{
return std::to_string(value);
}
std::string operator()(double const& value) const
{
return std::to_string(value);
}
};
}}
//--------------------------------------------------------------------------------------------------
int main()
{
std::vector<std::string> storage = {
"foo()", "-foo()",
"f1_2()",
"foo_bar ()",
"foo( bar (42, baz()))",
"foo(5)", "foo(-5)",
"foo(1.1, foo(4.21e-2, 4., 6))",
"1.1", "-1.1",
"1 * 1",
"foo(1 * 1) * bar(42)",
"foo(2 + 5.5, bar()*3.4-7)",
"foo(2 + 5.5, bar(baz(-5/foo())) * 3.4 - 7)",
"4 + 5 * 6",
"1+2+3+4*5*6*-7+-8*+9-0",
"(foo())",
"foo() * ((1+2)+3*(2+3))",
"(1+2)*3", "1+2*3",
"foo"
};
using boost::spirit::x3::ascii::space;
for (const auto &item : storage) {
using client::parser::expr; // Our grammar
client::ast::expr_ast ast; // Our tree
std::string::const_iterator iter = item.begin();
std::string::const_iterator end = item.end();
bool r = phrase_parse(iter, end, expr, space, ast);
if (r && iter == end)
{
std::cout << "Ok: " << item << " result: " << client::ast::printer()(ast) << std::endl;
}
else
{
std::cout << "Fail: " << item << std::endl;
}
}
}
最佳答案
对我来说,这看起来像是严重的倒退。
在我的机器上花了很长时间:
gcc 5:在 4 分钟 30 秒后慢慢使用越来越多的内存,最高可达 3GiB,然后是约 20 秒的汇编程序阶段:
g++-5 -std=c++14 -Wall -pedantic -Wextra -fsanitize=undefined,address -Wno-unused -g -O3 -isystem /home/sehe/custom/nonius/include -isystem /home/sehe/custom/boost_1_60_0 -pthread -march=native test.cpp -c -o test.o
test.cpp:119:62: warning: extra ‘;’ [-Wpedantic]
BOOST_SPIRIT_DEFINE(expr, add_expr, mult_expr, block_expr);
^
g++-5 -std=c++14 -Wall -pedantic -Wextra -fsanitize=undefined,address -Wno-unused -g -O3 -isystem /home/sehe/custom/nonius/include -isystem /home/sehe/custom/boost_1_60_0 -pthread -march=native test.o -o test -L /home/sehe/custom/boost_1_60_0/stage/lib/ -Wl,-rpath,/home/sehe/custom/boost_1_60_0/stage/lib -lboost_system -lboost_regex -lboost_thread -lboost_iostreams -lboost_serialization -lboost_filesystem -lboost_chrono -lrt -lboost_unit_test_framework -lpugixml -lssl -lcrypto -lxml2
real 4m50.427s
user 4m48.248s
sys 0m1.856s
clang 3.6:因超出模板实例化深度而失败
/home/sehe/custom/boost_1_60_0/boost/spirit/home/x3/support/context.hpp|30 col 25| fatal error: recursive template instantiation exceeded maximum depth of 256
然后这就给出了导致它的原因的直接提示。
我的第一个预感是 x3::variant
可能会导致编译器更积极地内联事物,但是 replacing with boost::variant没有太大帮助:
g++-5 -std=c++14 -Wall -pedantic -Wextra -fsanitize=undefined,address -Wno-unused -g -O3 -isystem /home/sehe/custom/nonius/include -isystem /home/sehe/custom/boost_1_60_0 -pthread -march=native test.cpp -c -o test.o
test.cpp:135:62: warning: extra ‘;’ [-Wpedantic]
BOOST_SPIRIT_DEFINE(expr, add_expr, mult_expr, block_expr);
^
g++-5 -std=c++14 -Wall -pedantic -Wextra -fsanitize=undefined,address -Wno-unused -g -O3 -isystem /home/sehe/custom/nonius/include -isystem /home/sehe/custom/boost_1_60_0 -pthread -march=native test.o -o test -L /home/sehe/custom/boost_1_60_0/stage/lib/ -Wl,-rpath,/home/sehe/custom/boost_1_60_0/stage/lib -lboost_system -lboost_regex -lboost_thread -lboost_iostreams -lboost_serialization -lboost_filesystem -lboost_chrono -lrt -lboost_unit_test_framework -lpugixml -lssl -lcrypto -lxml2
real 3m55.728s
结果没有区别:
Ok: foo() result: foo()
Fail: -foo()
Ok: f1_2() result: f1_2()
Ok: foo_bar () result: foo_bar()
Ok: foo( bar (42, baz())) result: foo(bar(42,baz()))
Ok: foo(5) result: foo(5)
Ok: foo(-5) result: foo(-5)
Ok: foo(1.1, foo(4.21e-2, 4., 6)) result: foo(1.100000,foo(0.042100,4.000000,6))
Ok: 1.1 result: 1.100000
Ok: -1.1 result: -1.100000
Ok: 1 * 1 result: (1 * 1)
Ok: foo(1 * 1) * bar(42) result: (foo((1 * 1)) * bar(42))
Ok: foo(2 + 5.5, bar()*3.4-7) result: foo((2 + 5.500000),((bar() * 3.400000) - 7))
Ok: foo(2 + 5.5, bar(baz(-5/foo())) * 3.4 - 7) result: foo((2 + 5.500000),((bar(baz((-5 / foo()))) * 3.400000) - 7))
Ok: 4 + 5 * 6 result: (4 + (5 * 6))
Ok: 1+2+3+4*5*6*-7+-8*+9-0 result: (1 + (2 + (3 + ((4 * (5 * (6 * -7))) + ((-8 * 9) - 0)))))
Ok: (foo()) result: foo()
Ok: foo() * ((1+2)+3*(2+3)) result: (foo() * ((1 + 2) + (3 * (2 + 3))))
Ok: (1+2)*3 result: ((1 + 2) * 3)
Ok: 1+2*3 result: (1 + (2 * 3))
Fail: foo
我会在 Spirit 邮件列表中报告此事:http://boost.2283326.n4.nabble.com/spirit-general-f2672582.html
关于c++ - 使用 boost spirit x3 编译时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37230653/
我正在尝试使用boost.spirit的qi库解析某些内容,而我遇到了一个问题。根据spirit docs,a >> b应该产生类型为tuple的东西。但这是boost::tuple(又名 fusio
似乎有/正在努力做到这一点,但到目前为止我看到的大多数资源要么已经过时(带有死链接),要么几乎没有信息来实际构建一个小的工作样本(例如,依赖于boost program_options 以构建可执行文
我对 Boost.Log 的状态有点困惑。这是 Boost 的官方部分,还是尚未被接受?当我用谷歌搜索时,我看到一些帖子谈论它在 2010 年是如何被接受的,等等,但是当我查看最后一个 Boost 库
Boost 提供了两种不同的实现 string_view ,这将成为 C++17 的一部分: boost::string_ref在 utility/string_ref.hpp boost::stri
最近,我被一家GIS公司雇用来重写他们的旧地理信息库。所以我目前正在寻找一个好的计算几何库。我看过CGAL,这真是了不起,但是我的老板想要免费的东西。 所以我现在正在检查Boost.Geometry。
假设我有一个无向图 G。假设我添加以下内容 add_edge(1,2,G); add_edge(1,3,G); add_edge(0,2,G); 现在我再说一遍: add_edge(0,2,G); 我
我使用 CMake 来查找 Boost。找到了 Boost,但 CMake 出错了 Imported targets not available for Boost version 请参阅下面的完整错
我是 boost::fusion 和 boost::mpl 库的新手。谁能告诉我这两个库之间的主要区别? 到目前为止,我只使用 fusion::vector 和其他一些简单的东西。现在我想使用 fus
这个问题已经有答案了: 已关闭10 年前。 Possible Duplicate: What are the benefits of using Boost.Phoenix? 所以我开始阅读 boos
我正在尝试获得一个使用 Boost.Timer 的简单示例,用于一些秒表性能测量,但我不明白为什么我无法成功地将 Boost.Timer 链接到 Boost.Chrono。我使用以下简单脚本从源代码构
我有这样的东西: enum EFood{ eMeat, eFruit }; class Food{ }; class Meat: public Food{ void someM
有人可以告诉我,我如何获得boost::Variant处理无序地图? typedef boost::variant lut_value;unordered_map table; 我认为有一个用于boo
我对 Boost.Geometry 中的环和多边形感到困惑。 在文档中,没有图形显示什么是环,什么是多边形。 谁能画图解释两个概念的区别? 最佳答案 在 Boost.Geometry 中,多边形被定义
我正在使用 boost.pool,但我不知道何时使用 boost::pool<>::malloc和 boost::pool<>::ordered_malloc ? 所以, boost::pool<>:
我正在尝试通过 *boost::fast_pool_allocator* 使用 *boost::container::flat_set*。但是,我收到编译错误。非常感谢您的意见和建议。为了突出这个问题
sau_timer::sau_timer(int secs, timerparam f) : strnd(io), t(io, boost::posix_time::seconds(secs)
我无法理解此功能的文档,我已多次看到以下内容 tie (ei,ei_end) = out_edges(*(vi+a),g); **g**::out_edge_iterator ei, ei_end;
我想在 C++ 中序列化分层数据结构。我正在处理的项目使用 boost,所以我使用 boost::property_tree::ptree 作为我的数据节点结构。 我们有像 Person 这样的高级结
我需要一些帮助来解决这个异常,我正在实现一个 NPAPI 插件,以便能够使用来自浏览器扩展的本地套接字,为此我正在使用 Firebreath 框架。 对于套接字和连接,我使用带有异步调用的 Boost
我尝试将 boost::bind 与 boost::factory 结合使用但没有成功 我有这个类 Zambas 有 4 个参数(2 个字符串和 2 个整数)和 class Zambas { publ
我是一名优秀的程序员,十分优秀!