问题描述
我有我想要使用一个工作项目有点语法。最低可执行的例子是:
I have a little grammar that I want to use for a work project. A minimum executable example is:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#pragma GCC diagnostic ignored "-Wunused-variable"
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/qi_grammar.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
#pragma GCC diagnostic pop // pops
#include <iostream>
int main()
{
typedef unsigned long long ull;
std::string curline = "1;2;;3,4;5";
std::cout << "parsing: " << curline << "\n";
namespace qi = boost::spirit::qi;
auto ids = -qi::ulong_long % ','; // '-' allows for empty vecs.
auto match_type_res = ids % ';' ;
std::vector<std::vector<ull> > r;
qi::parse(curline.begin(), curline.end(), match_type_res, r);
std::cout << "got: ";
for (auto v: r){
for (auto i : v)
std::cout << i << ",";
std::cout << ";";
}
std::cout <<"\n";
}
在我个人的机器这将产生正确的输出:
解析:1; 2 ;; 3,4; 5
有:1,2,3,4 ;;; 5,;
On my personal machine this produces the correct output:parsing: 1;2;;3,4;5got: 1,;2,;;3,4,;5,;
但在工作中它产生:
解析:1; 2 ;; 3,4; 5
有:1,; 2,; 3,
But at work it produces:parsing: 1;2;;3,4;5got: 1,;2,;;3,
在换句话说,它未能尽快有一个以上的元素的解析长整数的向量在它
In other words, it fails to parse the vector of long integers as soon as there's more than one element in it.
现在,我已经确定了工作的系统使用的是提升1.56,而我的私人计算机使用的是1.57。这是什么原因?
Now, I have identified that the work system is using boost 1.56, while my private computer is using 1.57. Is this the cause?
Knowning我们有一些真正的精神的专家在这里堆栈溢出,我希望有人会知道这个问题是从哪里来的,或者至少可以缩小东西我需要检查的次数。
Knowning we have some real spirit experts here on stack overflow, I was hoping someone might know where this issue is coming from, or can at least narrow down the number of things I need to check.
如果增压版本的问题,我也许可以说服公司进行升级,而是一个解决方法是在任何情况下的欢迎。
If the boost version is the problem, I can probably convince the company to upgrade, but a workaround would be welcome in any case.
推荐答案
您是在调用包含临时的成为的在的含全EX pression结束的¹
Specifically where you use auto
to store a parser expression. The Expression Template contains references to temporaries that become dangling at the end of the containing full-expression¹.
UB意味着,任何事情都有可能发生。这两种编译器是正确的!而最好的部分是,根据所使用的编译器标志,你可能会看到不同的行为。
UB implies that anything can happen. Both compilers are right! And the best part is, you will probably see varying behaviour depending on the compiler flags used.
通过对其进行修复或者:
Fix it either by using:
-
齐::复制
(或的boost ::原:: DEEP_COPY
v.1.55 IIRC之前) - 使用
BOOST_SPIRIT_AUTO
而不是BOOST_AUTO
(主要是当且仅当您有帮助还支持C ++ 03) -
使用
齐::规则&LT;&GT;
和齐::语法&LT;&GT;
(中非终端)键入擦除和前pressions。这有性能的影响太多,但也提供了更多的功能,如
qi::copy
(orboost::proto::deep_copy
before v.1.55 IIRC)- use
BOOST_SPIRIT_AUTO
instead ofBOOST_AUTO
(mostly helpful iff you also support C++03) use
qi::rule<>
andqi::grammar<>
(the non-terminals) to type-erase and the expressions. This has performance impact too, but also gives more features like
- 递归规则
- 当地人和继承的属性
- 宣布船长(方便,因为规则可以隐
语义[]
(见here) - 更好code组织。
的还要注意的是精神X3承诺砸自动使用有限制。这基本上是一个一大堆更加轻便由于使用C ++ 14的特性。请记住,这还不稳定。的
-
显示与-O2是GCC显示不确定的结果;
Showing that GCC with -O2 shows undefined results; Live On Coliru
固定的版本:
骨节病>
//#pragma GCC diagnostic push //#pragma GCC diagnostic ignored "-Wunused-local-typedefs" //#pragma GCC diagnostic ignored "-Wmaybe-uninitialized" //#pragma GCC diagnostic ignored "-Wunused-variable" #include <boost/spirit/include/karma.hpp> #include <boost/spirit/include/qi.hpp> //#pragma GCC diagnostic pop // pops #include <iostream> int main() { typedef unsigned long long ull; std::string const curline = "1;2;;3,4;5"; std::cout << "parsing: '" << curline << "'\n"; namespace qi = boost::spirit::qi; #if 0 // THIS IS UNDEFINED BEHAVIOUR: auto ids = -qi::ulong_long % ','; // '-' allows for empty vecs. auto grammar = ids % ';'; #else // THIS IS CORRECT: auto ids = qi::copy(-qi::ulong_long % ','); // '-' allows for empty vecs. auto grammar = qi::copy(ids % ';'); #endif std::vector<std::vector<ull> > r; qi::parse(curline.begin(), curline.end(), grammar, r); std::cout << "got: "; for (auto v: r){ for (auto i : v) std::cout << i << ","; std::cout << ";"; } std::cout <<"\n"; }
打印(也与GCC -O2!):
Printing (also with GCC -O2!):
parsing: '1;2;;3,4;5' got: 1,;2,;;3,4,;5,;
¹(这是基本上是下一个分号在这里;但在standardese)
¹ (that's basically "at the next semicolon" here; but in standardese)
这篇关于提振精神的语法不一致的行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!