C++ 为传递到qi::PHASE\U parse的表达式设置语义操作的属性

C++ 为传递到qi::PHASE\U parse的表达式设置语义操作的属性,c++,boost-spirit,boost-spirit-qi,C++,Boost Spirit,Boost Spirit Qi,在解析过程中,我只需要在语义操作中设置一些属性(因为它们是从解析的数据中派生出来的,我希望避免global变量和对BOOST\u FUSION\u ADAPT\u STRUCT的依赖,并且我的代码应该是泛型的,这样我就可以对多种类型重用它)。如果我使用一个以上的变量传递到qi::phrase\u parse中,我会得到很长的编译错误列表。我急需帮助:-) 允许您操作规则上下文中的重要信息。当您在调用parse或phrase\u parse的表达式中直接使用它们时,没有规则,因此也没有上下文。在版

在解析过程中,我只需要在语义操作中设置一些属性(因为它们是从解析的数据中派生出来的,我希望避免
global
变量和对
BOOST\u FUSION\u ADAPT\u STRUCT
的依赖,并且我的代码应该是泛型的,这样我就可以对多种类型重用它)。如果我使用一个以上的变量传递到
qi::phrase\u parse
中,我会得到很长的编译错误列表。我急需帮助:-)

允许您操作规则上下文中的重要信息。当您在调用
parse
phrase\u parse
的表达式中直接使用它们时,没有规则,因此也没有上下文。在版本Boost 1.47.0之前,这不起作用,为了使这种行为一致,对这些函数的单参数版本进行了修复,但显然不适用于可变参数版本

避免此问题的一种方法是创建一个规则,该规则的属性为
fusion::vector
,它引用您在调用
短语解析时使用的类型

编辑:删除了“我的短语分析”,因为我不相信它是正确的

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/function.hpp>
#include <boost/phoenix/fusion.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;
namespace ph = boost::phoenix;
namespace ascii = boost::spirit::ascii;
namespace fusion = boost::fusion;

int main( int argc, char**argv )
{
    bool rc;
    std::string input("");

    //Test case works fine
    {
        auto iter( input.begin() );
        auto last( input.end() );
        int val1=33;
        rc = qi::phrase_parse( iter, last, qi::eps[ qi::_val=11 ] , 
                   ascii::space, val1 ) && iter==last;
        if( rc )
            std::cout << "val1=" << val1 << std::endl; 
    }
    //You can use a rule
    {
        auto iter( input.begin() );
        auto last( input.end() );
        int val1=33;
        int val2=0;

        qi::rule<decltype(iter),fusion::vector<int&, int&>(),ascii::space_type> parser=qi::eps[ ph::at_c<0>(qi::_val)=1,ph::at_c<1>(qi::_val)=2 ];

        rc = qi::phrase_parse( iter, last, 
                parser,
                ascii::space, val1,val2 ) && iter==last;
        if( rc )
            std::cout << "val1=" << val1 << 
                         " val2=" << val2 << std::endl;      
    }

    return 0;
}
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/spirit/include/qi_core.hpp>
#include <boost/spirit/include/qi_omit.hpp>

#include <iostream>
#include <string>
#include <climits>

namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;

template <typename T>
struct min_max_set
{
    min_max_set():min(std::numeric_limits<T>::max()),max(std::numeric_limits<T>::min()),set(){}
    T min;
    T max;
    std::vector<T> set;
};

namespace boost{ namespace spirit { namespace traits
{
    template <typename T>
    struct is_container<min_max_set<T>>
        : boost::mpl::true_
    {};

    template <typename T>
    struct container_value<min_max_set<T>>
    {
        typedef T type;
    };

    template <typename T>
    struct push_back_container<min_max_set<T>,T>
    {
        static bool call(min_max_set<T>& cont, const T& val)
        {
            if(cont.min>val)
                cont.min=val;
            if(cont.max<val)
                cont.max=val;
            cont.set.push_back(val);
            return true;
        }
    };

}}}

template<typename T,typename R>
void testParser( R rule )
{
    for ( const auto input : std::vector< std::string >{ "5 1.0 2.0 3.0 4.0 5.0", "1 1.0", "0" , "", "2 3 ab" } )
    {
        bool rc;

        auto iter( input.begin() );
        auto last( input.end() );
        min_max_set<T> accum;   

        rc = qi::phrase_parse( iter, last,
                qi::omit[qi::int_] >> *rule
                ,ascii::space, accum ) && iter==last;
        std::cout << ( rc ? "ok :`" : "err:`" ) << input << "` -> ";
        if( rc )
        {
            std::cout << "min=" << accum.min << " max=" << accum.max << "\t";
            std::copy( accum.set.begin(), accum.set.end(), std::ostream_iterator<T>( std::cout," " ));
        }
        else
            std::cout << *iter;
        std::cout << std::endl;
    }
}


int main( int argc, char**argv )
{
    testParser<double>(qi::double_);
    return 0;
}
#定义BOOST_RESULT_OF_USE_DECLTYPE
#定义增强\u精神\u使用\u凤凰\u V3
#包括
#包括
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间ph=boost::phoenix;
名称空间ascii=boost::spirit::ascii;
名称空间融合=boost::fusion;
int main(int argc,字符**argv)
{
布尔rc;
std::字符串输入(“”);
//测试用例运行良好
{
自动iter(input.begin());
自动结束(input.end());
int val1=33;
rc=qi::短语解析(iter,last,qi::eps[qi::\u val=11],
ascii::space,val1)和&iter==last;
if(rc)

std::cout我希望我能正确地看到问题,但即使有点不同,您也可以轻松地存储多个值:

struct data {
  int _a;
  int _b;
  data(int a, int b) : _a(a), _b(b) {};
};
并构建它:

qi::eps[qi::_val = phx::construct<data>(1, 2)]
qi::eps[qi::val=phx::construct(1,2)]

这是解决我最初问题的方法:

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/function.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <climits>

namespace qi = boost::spirit::qi;
namespace ph = boost::phoenix;
namespace ascii = boost::spirit::ascii;

template<typename T,typename R>
void testParser( R rule )
{
    for ( const auto &input : std::vector< std::string >{ "5 1.0 2.0 3.0 4.0 5.0" } )
    {
        bool rc=false;
        T maxValue, minValue;
        auto iter( input.begin() ), last( input.end() );
        std::vector< T > data;

        qi::rule< decltype(iter),std::vector<T>( T&, T& ),qi::space_type > mrule;

        mrule %=
            qi::eps[ qi::_r1=std::numeric_limits<T>::max(),
                     qi::_r2=std::numeric_limits<T>::min() ] >>
             -( qi::omit[ qi::int_[ ph::reserve( qi::_val,qi::_1 ) ] ]
                >> *rule[ ph::if_(qi::_r1>qi::_1)[ qi::_r1=qi::_1 ],
                          ph::if_(qi::_r2<qi::_1)[ qi::_r2=qi::_1 ]
                        ] );

        rc = qi::phrase_parse( iter, last, mrule( ph::ref(minValue), ph::ref(maxValue) ), qi::space, data ) && iter==last;

    std::cout << ( rc ? "ok :`" : "err:`" ) << input << "` -> ";
    if( rc )
    {
        std::cout << "min=" << minValue << " max=" << maxValue << "\t";
        std::copy( data.begin(), data.end(), std::ostream_iterator<T>( std::cout," " ));
        }
        else
            std::cout << *iter;
        std::cout << std::endl;
    }
}

int main( int argc, char**argv )
{
    testParser<double>( qi::double_ );
    return 0;
}
#定义BOOST_RESULT_OF_USE_DECLTYPE
#定义增强\u精神\u使用\u凤凰\u V3
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
名称空间qi=boost::spirit::qi;
名称空间ph=boost::phoenix;
名称空间ascii=boost::spirit::ascii;
模板
void testParser(R规则)
{
for(const auto&input:std::vector{“51.02.03.045.0”})
{
bool rc=假;
T最大值,最小值;
自动iter(input.begin()),last(input.end());
std::向量数据;
规则mrule;
mrule%=
qi::eps[qi::_r1=std::数值限制::max(),
qi::_r2=std::numeric_limits::min()]>>
-(qi::省略[qi::int.[ph::储备(qi::_val,qi:_1)]]
>>规则[ph::如果(qi::r1>qi:1)[qi:r1=qi::1],

ph::if_uq(qi::r2)。在该版本中,修复程序应用于“正常的”
parse
phrase_uparse
,但显然不适用于“可变的”。如果您创建一个规则,如
qi::rule parser=qi::eps[ph::at_c(qi:val)=1,ph::at_c(qi:val)=2]
它会起作用的。@cv_和_-he嗨,谢谢你的反馈。我使用的是1_52。如果单变量的情况不起作用,我就不会问这个问题,因为它会很明显:-)因为我可以避免使用attr生成测试用例3的问题。我知道它是有效的。如果你阅读链接,你会发现它有效的唯一原因是因为它被更改为只使用单个属性的
parse
phrase\u parse
。谢谢你的
详细的
响应。它为我节省了时间rom周日下午沮丧:-)不要相信我的短语解析是100%正确的,因为我基本上不知道我在做什么。“它似乎有效”这是我能做的唯一保证。你介意我扩展这个问题吗?我采用了你的代码,但如果我向eps表达式中添加一些规则,这些规则将自动合成ATTR。它不会再次编译:-(或者我应该打开一个新问题吗?编辑它,如果它是一个不同的问题,你总是可以创建一个新问题。我不能让它工作,但我不确定这是一个问题与此解决方案。如果你认为它只是不接受答案,我会删除它。我更喜欢通过使结构表现为这是一个容器。你可以看到一个例子。你只需要在构造函数中初始化min和max,然后专门化
is_container
container_value
push_back_container
。我遇到的问题是qi::phrase_parse。如果你检查我问题中的三个简单测试用例……我感觉像sem反动作应该有效果!:-)但是他们没有。
cv_和_他
提供的信息表明它不应该像我预期的那样工作。他尝试了一些
技巧
,但它不够一般,这一系列实验已经帮助我理解它是死胡同。我能够使用qi::语法和我可以继承的属性找到解决方案用于语义规则中我需要的内容。正如sehe所做的那样,您可以轻松地将
qi::\r1
qi:\r2
重命名为
min
max
分别使用:
qi:\r1\u类型min;qi:\u r2\u类型max;mrule%=qi::eps[min=std::numeric\u limits::max(),max=std::numeric\u limits::min()]>>-(qi::省略[qi::int.[ph::储备(qi::\u val,qi::\u 1)]>>*规则[ph::如果(min>qi::\u 1)[min=qi::\u 1],ph::如果(max)]
qi::eps[qi::_val = phx::construct<data>(1, 2)]
#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3

#include <boost/function.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/qi.hpp>

#include <iostream>
#include <algorithm>
#include <iterator>
#include <string>
#include <climits>

namespace qi = boost::spirit::qi;
namespace ph = boost::phoenix;
namespace ascii = boost::spirit::ascii;

template<typename T,typename R>
void testParser( R rule )
{
    for ( const auto &input : std::vector< std::string >{ "5 1.0 2.0 3.0 4.0 5.0" } )
    {
        bool rc=false;
        T maxValue, minValue;
        auto iter( input.begin() ), last( input.end() );
        std::vector< T > data;

        qi::rule< decltype(iter),std::vector<T>( T&, T& ),qi::space_type > mrule;

        mrule %=
            qi::eps[ qi::_r1=std::numeric_limits<T>::max(),
                     qi::_r2=std::numeric_limits<T>::min() ] >>
             -( qi::omit[ qi::int_[ ph::reserve( qi::_val,qi::_1 ) ] ]
                >> *rule[ ph::if_(qi::_r1>qi::_1)[ qi::_r1=qi::_1 ],
                          ph::if_(qi::_r2<qi::_1)[ qi::_r2=qi::_1 ]
                        ] );

        rc = qi::phrase_parse( iter, last, mrule( ph::ref(minValue), ph::ref(maxValue) ), qi::space, data ) && iter==last;

    std::cout << ( rc ? "ok :`" : "err:`" ) << input << "` -> ";
    if( rc )
    {
        std::cout << "min=" << minValue << " max=" << maxValue << "\t";
        std::copy( data.begin(), data.end(), std::ostream_iterator<T>( std::cout," " ));
        }
        else
            std::cout << *iter;
        std::cout << std::endl;
    }
}

int main( int argc, char**argv )
{
    testParser<double>( qi::double_ );
    return 0;
}