【问题标题】:Boost Spirit : can't manage to have the alternative operator working as I expectBoost Spirit:无法让替代操作员按我的预期工作
【发布时间】:2020-11-06 17:30:19
【问题描述】:

我无法让精神替代解析器工作(或者说做我期望的)。

这是我的 MCVE

#include <string>
#include <iostream>

#include <boost/variant.hpp>
#include <boost/spirit/include/qi_parse.hpp>
#include <boost/spirit/include/qi.hpp>

using namespace boost::spirit;
namespace charset = boost::spirit::qi::standard_wide;

using Expr = boost::variant<std::string, int >;

int main(int argc, char ** argv)
{
    std::string intToParse = "{int:  45}";
    std::string stringToParse = "{string:  \"foo\"}";

    using It = std::string::const_iterator;
    using Sk = qi::space_type;
    qi::rule<It, std::string(), Sk> parseString;
    qi::rule<It, int(), Sk> parseInt;
    qi::rule<It, std::string(),Sk> string_;
    
    qi::rule<It,Expr(),Sk > orParse;


    string_ =
            qi::lit('"')
            > *(charset::char_ - '"')
            > '"';
    
    parseString = qi::omit[  qi::string("string")] >  qi::lit(':') > string_;

    parseInt = qi::omit[ qi::string("int")] > qi::lit(':') > qi::uint_ ;

    orParse =  qi::omit[qi::lit('{')] >  parseString | parseInt >  '}';
    
    orParse.name_ =  "alternative parser";
    parseString.name_ = "string parser";
    parseInt.name_= "int parser";

    qi::debug(orParse);
    qi::debug(parseString);
    qi::debug(parseInt);

    Expr res2;
    qi::phrase_parse(stringToParse.cbegin(), stringToParse.cend(), orParse, qi::space, res2);
    std::cout << res2<< std::endl;


    Expr res;
    qi::phrase_parse(intToParse.cbegin(), intToParse.cend(), orParse, qi::space, res);
    std::cout << res << std::endl;
  
    return 0;
}

当第一个替代方案失败时,解析停止,第二个规则不会尝试!我做错了什么?

这是显示我的问题的输出,对于 stringToParse,第一个替代方法失败但我希望执行 int 解析器,但事实并非如此!

<alternative parser>
  <try>{string:  "foo"}</try>
  <string parser>
    <try>string:  "foo"}</try>
    <success>}</success>
    <attributes>[[f, o, o]]</attributes>
  </string parser>
  <success>}</success>
  <attributes>[[f, o, o]]</attributes>
</alternative parser>
foo
<alternative parser>
  <try>{int:  45}</try>
  <string parser>
    <try>int:  45}</try>
    <fail/>
  </string parser>
  <fail/>
</alternative parser>
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::spirit::qi::expectation_failure<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > >'
  what():  boost::spirit::qi::expectation_failure
Aborted (core dumped)

【问题讨论】:

    标签: c++ boost boost-spirit


    【解决方案1】:

    operator &gt;C++ Operator Precedence 表中高于operator |,因此需要括号:

    orParse =  qi::omit[qi::lit('{')] >  (parseString | parseInt) >  '}';
    //                              here ^             and here ^
    

    结果:

    <alternative parser>
      <try>{string:  "foo"}</try>
      <string parser>
        <try>string:  "foo"}</try>
        <success>}</success>
        <attributes>[[f, o, o]]</attributes>
      </string parser>
      <success></success>
      <attributes>[[f, o, o]]</attributes>
    </alternative parser>
    foo
    <alternative parser>
      <try>{int:  45}</try>
      <string parser>
        <try>int:  45}</try>
        <fail/>
      </string parser>
      <int parser>
        <try>int:  45}</try>
        <success>}</success>
        <attributes>[45]</attributes>
      </int parser>
      <success></success>
      <attributes>[45]</attributes>
    </alternative parser>
    45
    

    【讨论】:

    • 哦,是的!那太简单了……我的错。
    • 注意到了一些事情,所以发布了一个额外的答案
    【解决方案2】:

    所以,已经指出了优先级问题。请注意,您可以通过使用编译器的警告来捕捉到这一点:

    test.cpp|25 col 23| warning: suggest parentheses around comparison in operand of ‘|’ []8;;https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#index-Wparentheses-Wparentheses]8;;]
    

    还有许多其他问题。让我从有问题的开始:

    在需要的地方使用词素

    不要使用船长或在船长不得采取行动的qi::lexeme[] 中换行。具体来说,您的 string_ 规则可能不应该跳过空格。

    另请参阅 Boost spirit skipper issues

    其他问题

    • 字符集用法略有不一致。这可能是也可能不是什么大问题。如果不是,我通常会使用默认值 (qiL::char_, lit, string)。

    • 为什么要手动调整调试规则的内部?

       BOOST_SPIRIT_DEBUG_NODES((orParse)(parseString)(parseInt))
      
    • 为什么在不公开属性的指令上省略属性?

    • 当你想省略属性时为什么要使用qi::string?请改用lit

    • 记得处理错误条件和部分解析

    简化和固定代码

    Live On Coliru

    #define BOOST_SPIRIT_DEBUG
    #include <boost/spirit/include/qi.hpp>
    
    namespace qi = boost::spirit::qi;
    namespace charset = boost::spirit::qi::standard_wide;
    
    using Expr = boost::variant<std::string, int >;
    using It = std::string::const_iterator;
    using Sk = charset::space_type;
    
    int main()
    {
        // lexeme!
        qi::rule<It, std::string()> string_ 
            = '"' > *~charset::char_('"') > '"';
    
        // with skipper
        Sk skip;
        qi::rule<It, Expr(),        Sk> orParse;
        qi::rule<It, std::string(), Sk> parseString;
        qi::rule<It, int(),         Sk> parseInt;
    
        parseString = qi::lit("string") > ':' > string_;
        parseInt    = qi::lit("int")    > ':' > qi::uint_;
        orParse     = '{' > (parseString | parseInt) > '}';
        
        BOOST_SPIRIT_DEBUG_NODES((orParse)(parseString)(parseInt))
    
        for (std::string const input: { "{int:  45}", "{string:  \"foo\"}" }) {
            Expr res;
            It f = input.begin(), l = input.end();
    
            if (phrase_parse(f, l, orParse, skip, res)) {
                std::cout << "Parsed: " << res << std::endl;
            } else {
                std::cout << "Failed" << std::endl;
            }
            if (f != l) {
                std::cout << "Remaining: " << std::string(f,l) << "\n";
            }
        }
    }
    

    打印

    Parsed: 45
    Parsed: foo
    

    如果启用调试:

    <orParse>
      <try>{int:  45}</try>
      <parseString>
        <try>int:  45}</try>
        <fail/>
      </parseString>
      <parseInt>
        <try>int:  45}</try>
        <success>}</success>
        <attributes>[45]</attributes>
      </parseInt>
      <success></success>
      <attributes>[45]</attributes>
    </orParse>
    <orParse>
      <try>{string:  "foo"}</try>
      <parseString>
        <try>string:  "foo"}</try>
        <success>}</success>
        <attributes>[[f, o, o]]</attributes>
      </parseString>
      <success></success>
      <attributes>[[f, o, o]]</attributes>
    </orParse>
    

    【讨论】:

      猜你喜欢
      • 2012-08-25
      • 1970-01-01
      • 2020-08-26
      • 1970-01-01
      • 2016-11-12
      • 2021-01-16
      • 1970-01-01
      • 2014-09-10
      • 1970-01-01
      相关资源
      最近更新 更多