在 Qi 中使用 Boost Phoenix 在语法中引用以前的匹配项

Use Boost Phoenix in Qi to reference a previous match in a grammar

本文关键字:语法 Qi Boost Phoenix 引用      更新时间:2023-10-16

我对Boost Spirit很陌生。 理想情况下,我想使用 Phoenix 确保我的语法中的两个值同时存在。 我试图开始工作的一个愚蠢版本将是一个两个整数相等的元组。

我想解析一个字符串"14,14,test",但"14,12,

test"失败,因为 14 不等于 12。 我想打印下面的代码:

Good: (14 14 test)
Fail

目前两个输入都将通过,因为我允许 qi::int_ 在没有任何检查的情况下解析第二个值。

#include <iostream>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/fusion/include/vector.hpp>
#include <boost/spirit/include/qi_matches.hpp>
#include <string>
#include <vector>
#include <algorithm>
namespace qi = boost::spirit::qi;
namespace phx = boost::phoenix;

int main(){

    std::vector<std::string> test_inputs = {"14,14,test","14,12,test"};
    std::for_each(test_inputs.begin(),test_inputs.end(),[](const std::string& input){
        boost::fusion::vector<int,int,std::string> result;
        int i(0);
        auto res = qi::parse(input.begin(),input.end(),
            //works but also parses "14,12,test"
            qi::int_[phx::ref(i) = qi::_1] >> qi::lit(",") >> qi::int_ >> qi::lit(",") >> +qi::char_,
            //Fails to compile
            //qi::int_[phx::ref(i) = qi::_1] >> qi::lit(",") >> qi::int_(phx::val(i)) >> qi::lit(",") >> +qi::char_,
            //qi::int_[phx::ref(i) = qi::_1] >> qi::lit(",") >> qi::int_(phx::ref(i)) >> qi::lit(",") >> +qi::char_,
            result);
        if(res){
            std::cout << "Good: " << result << std::endl;
        }
        else{
            std::cout << "Fail" << std::endl;
        }
    });         
}

我可以使用 phoenix::ref 来捕获第一个值,但我无法弄清楚测试我的第二个 qi::int_ 解析器以获取 i 的值。 我尝试使用phoenix::val和phoenix::ref,但没有运气编译。 理想情况下,我想捕获第二个 int 中的值,并认为 int_ 解析器会从 Phoenix 中获取懒惰的文字。

感谢您对此的任何帮助。

最简单的

解决方法是将i从第一个 qi::int_ 获取的值提供给第二个 qi

::,即:
qi::int_[phx::ref(i) = qi::_1] >> qi::lit(",") >> qi::int_(phx::ref(i)) >> qi::lit(",") >> +qi::char_,

带有参数的 qi::_int 需要提供的值。

要考虑的另一种方法是使用规则局部变量。 你可以这样做:

typedef boost::fusion::vector<int,int,std::string> result_t;
result_t result;
qi::rule<std::string::const_iterator, result_t(),
     boost::spirit::qi::locals<int> > r;
r %= qi::int_[qi::_a = qi::_1] >> qi::lit(",") >> qi::int_(qi::_a) >> qi::lit(",") >> +qi::char_;

然后使用"r"代替您的规则。 虽然我想如果你只是打算直接使用 qi::p arse 运行规则,这是没有意义的。