使用局部变量增强精神 [英] Boost spirit using local variables
问题描述
我想基于先前解析的值i定义一个规则. e.输入字符串具有以下结构:D <double number>
或I <integer number>
.无论第一个读取字符是D
还是I
,我都保留在本地布尔变量中.完整的代码是:
I would like to define a rule based on a previously parsed value, i. e. the input string has the following structure: D <double number>
or I <integer number>
. I keep in a local boolean variable whether the first read character is D
or I
. The complete code is:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
using boost::phoenix::ref;
template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, std::string(), ascii::space_type>
{
public:
x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
{
using namespace qi;
bool is_int = false;
start_rule = lit("I")[ref(is_int) = true] | lit("D")[ref(is_int) = false] > digit_rule;
if(ref(is_int)()) {
digit_rule = int_[std::cout << "int " << _1 << ".\n"];
} else {
digit_rule = double_[std::cout << "double " << _1 << ".\n"];
}
}
private:
qi::rule<Iterator, std::string(), ascii::space_type> start_rule;
qi::rule<Iterator, std::string(), ascii::space_type> digit_rule;
};
int main()
{
typedef std::string::const_iterator iter;
std::string storage("I 5");
iter it_begin(storage.begin());
iter it_end(storage.end());
std::string read_data;
using boost::spirit::ascii::space;
x_grammar<iter> g;
try {
bool r = qi::phrase_parse(it_begin, it_end, g, space, read_data);
if(r) {
std::cout << "Pass!\n";
} else {
std::cout << "Fail!\n";
}
} catch (const qi::expectation_failure<iter>& x) {
std::cout << "Fail!\n";
}
return 0;
}
输出为:double Pass!
!它既不识别if
语句,也不打印已解析的数字!
The output is: double Pass!
!! It neither recognizes the if
statement, nor prints the parsed number!
注意:我知道还有其他简单的方法可以解析上述示例.我必须解析的实际字符串看起来很复杂,此示例仅说明了我想要实现的目标.总体目标是使用局部变量并基于这些变量定义其他规则.
Note: I know that there are other straightforward ways to parse the example above. The actual string I have to parse looks quite complicated, and this example just illustrates what I want to achieve. The general goal is to use local variables and define other rules based on those variables.
我使用了4.6.1和Boost 1.55版本.
I have used 4.6.1 and Boost 1.55 versions.
推荐答案
if(ref(is_int)()) {
在这里您可以评估施工过程中的状况.这不是它的工作方式.规则将始终采用相同的分支.
here you evaluate condition during construction. This is not how it works. The rule will always take the same branch.
相反,请看一下Nabialek技巧: http://boost-spirit.com/home/articles/qi-example/nabialek-trick/
Instead, look at the Nabialek trick: http://boost-spirit.com/home/articles/qi-example/nabialek-trick/
以下是完整的Nabialek技巧已应用于您的示例 在Coliru直播 :
Here's the full Nabialek Trick applied to your sample Live On Coliru:
-
您需要使
std::cout << "int"
懒惰演员(至少包装phx::ref(std::cout)
或phx::val("int")
作为Phoenix演员)
you needed to make
std::cout << "int"
lazy actors (by wrapping at leastphx::ref(std::cout)
orphx::val("int")
as a Phoenix Actor)
您仍然没有使用属性传播(std::string()
),因为在存在语义动作的情况下禁用了该属性传播(请参阅上一个答案).不过,您可以传播Nabialek子规则中的值:
you still have no use for the attribute propagation (std::string()
) since it is disabled in the presence of Semantic Actions (see the previous answer). You can propagate values from Nabialek subrules, though:
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <string>
namespace qi = boost::spirit::qi;
namespace spirit = boost::spirit;
namespace ascii = boost::spirit::ascii;
namespace phx = boost::phoenix;
using boost::phoenix::ref;
template <typename Iterator>
struct x_grammar : public qi::grammar<Iterator, ascii::space_type, qi::locals<qi::rule<Iterator, ascii::space_type>*> >
{
public:
x_grammar() : x_grammar::base_type(start_rule, "x_grammar")
{
using namespace qi;
int_rule = int_ [std::cout << phx::val("int ") << _1 << ".\n"];
dbl_rule = double_[std::cout << phx::val("double ") << _1 << ".\n"];
subrules.add
("I", &int_rule)
("D", &dbl_rule);
start_rule = subrules[_a = _1] >> lazy(*_a);
}
private:
typedef qi::rule<Iterator, ascii::space_type> subrule;
qi::symbols<char, subrule*> subrules;
qi::rule<Iterator, ascii::space_type, qi::locals<subrule*> > start_rule;
qi::rule<Iterator, ascii::space_type> int_rule, dbl_rule;
};
int main()
{
typedef std::string::const_iterator iter;
std::string storage("I 5");
iter it_begin(storage.begin());
iter it_end(storage.end());
using boost::spirit::ascii::space;
x_grammar<iter> g;
try {
bool r = qi::phrase_parse(it_begin, it_end, g, space);
if (r) {
std::cout << "Pass!\n";
}
else {
std::cout << "Fail!\n";
}
}
catch (const qi::expectation_failure<iter>&) {
std::cout << "Fail!\n";
}
return 0;
}
这篇关于使用局部变量增强精神的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!