【问题标题】:boost spirit x3 variant and std::pair提升精神 x3 变体和 std::pair
【发布时间】:2018-11-26 21:38:43
【问题描述】:

我尝试运行一些简单的解析器来解析 [1, 11, 3, 6-4]。基本上,带有范围表示法的整数列表。

我想将所有内容都放入 AST 中,而不需要语义操作。所以我使用 x3::variant。我的代码“似乎”与表达式示例非常相似。但是,它不能在 g++ 6.2 下编译。它确实可以用 clang++ 6.0 编译,但产生错误的结果。

增强版本是 1.63。 看来我有一些“移动”或初始化问题。

#include <iostream>
#include <list>
#include <vector>
#include <utility> 

#include <boost/spirit/home/x3.hpp>
#include <boost/spirit/home/x3/support/ast/variant.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/adapted/std_pair.hpp>
#include <boost/fusion/include/io.hpp>

namespace ns
{
  namespace ast
  {
    namespace x3 = boost::spirit::x3;

    // forward definition
    class uintObj;
    struct varVec;

    // define type
    using uintPair_t = std::pair<unsigned int, unsigned int>;
    using uintVec_t = std::vector<uintObj>;

    // general token value:
    class uintObj : public x3::variant <
      unsigned int,
      uintPair_t
      >
    {
     public:
      using base_type::base_type;
      using base_type::operator=;
    };

    struct varVec
    {
      uintVec_t valVector;
    };
  }
}

BOOST_FUSION_ADAPT_STRUCT(
  ns::ast::varVec,
  valVector
  )

namespace ns
{
  namespace parser
  {
    // namespace x3 = boost::spirit::x3;
    // using namespace x3;
    using namespace boost::spirit::x3;

    // definition of the range pair:
    rule<class uintPair, ast::uintPair_t> const uintPair = "uintPair";

    auto const uintPair_def =
      uint_
      >> '-'
      >> uint_
      ;

    rule<class uintObj, ast::uintObj> const uintObj = "uintObj";

    auto const uintObj_def =
      uint_
      | uintPair
      ;

    // define rule definition : rule<ID, attrib>
    // more terse definition :
    // struct varVec_class;
    // using varVec_rule_t = x3::rule<varVec_class, ast::varVec>;
    // varVec_rule_t const varVec = "varVec";
    // varVec is the rule, "varVec" is the string name of the rule.
    rule<class varVec, ast::varVec> const varVec = "varVec";

    auto const varVec_def =
      '['
      >> uintObj % ','
      >> ']'
      ;

    BOOST_SPIRIT_DEFINE(
      varVec,
      uintObj,
      uintPair
      );
  }
}

int main()
{
  std::string input ("[1, 11, 3, 6-4]\n");
  std::string::const_iterator begin = input.begin();
  std::string::const_iterator end = input.end();

  ns::ast::varVec result;                 // ast tree
  using ns::parser::varVec;               // grammar
  using boost::spirit::x3::ascii::space;

  bool success = phrase_parse(begin, end, varVec, space, result);

  if (success && begin == end)
    std::cout << "good" << std::endl;
  else
    std::cout << "bad" << std::endl;

  return 0;
}

【问题讨论】:

  • 我知道还有其他类似的问题。我的问题不是还有其他方法可以做到这一点。我只是觉得没有语义动作的简单 AST 似乎更严格。 stackoverflow.com/questions/34599506/…
  • 交换uintPair和uint_后,clang++编译结果很好。但是,另一个问题是我的 g++ v6.2 仍然无法编译。该命令类似于 g++ -I/install/boost_1_63_0/include -std=c++14 -o par21.o -c par21.cpp。不只是我的版本。我的g++也编译不了sehe的版本。
  • 在我的回答中查看 cmets

标签: c++ boost-spirit


【解决方案1】:

交换uintObj_def的替代顺序

auto const uintObj_def =
    uintPair
  | uint_
  ;

您现在拥有的公式将始终与uint_ 匹配,因为uintPair 以有效的uint_ 开头。

【讨论】:

    【解决方案2】:

    mjcaisse 的回答指出了我认为您遇到的主要问题。有一些缺失的部分,所以我决定制作一个显示解析结果的简化版本:

    Live On Wandbox

    #include <iostream>
    #include <iomanip>
    
    //#include <boost/fusion/adapted.hpp>
    //#include <boost/fusion/include/io.hpp>
    #include <boost/spirit/home/x3.hpp>
    #include <boost/spirit/home/x3/support/ast/variant.hpp>
    
    namespace x3 = boost::spirit::x3;
    
    namespace ns { namespace ast {
    
        // forward definition
        struct uintObj;
        //struct varVec;
    
        // define type
        using uintPair_t = std::pair<unsigned int, unsigned int>;
        using uintVec_t = std::vector<uintObj>;
    
        // general token value:
        struct uintObj : x3::variant<unsigned int, uintPair_t> {
            using base_type::base_type;
            using base_type::operator=;
    
            friend std::ostream& operator<<(std::ostream& os, uintObj const& This) {
                struct {
                    std::ostream& os;
                    void operator()(unsigned int v) const { os << v; }
                    void operator()(uintPair_t v) const { os << v.first << "-" << v.second; }
                } vis { os };
                boost::apply_visitor(vis, This);
                return os;
            }
        };
    
        using varVec = uintVec_t;
    } }
    
    namespace ns { namespace parser {
        using namespace boost::spirit::x3;
    
        template <typename T> auto as = [](auto p) { return rule<struct _, T> {} = p; };
    
        auto const uintPair = as<ast::uintPair_t> ( uint_ >> '-' >> uint_       );
        auto const uintObj  = as<ast::uintObj>    ( uintPair | uint_            );
        auto const varVec   = as<ast::varVec>     ( '[' >> uintObj % ',' >> ']' );
    } }
    
    int main() {
        using namespace ns;
        std::string const input("[1, 11, 3, 6-4]\n");
        auto begin = input.begin(), end = input.end();
    
        ast::varVec result; // ast tree
        bool success = phrase_parse(begin, end, parser::varVec, x3::ascii::space, result);
    
        if (success) {
            std::cout << "good\n";
            for (auto& r : result) 
                std::cout << r << "\n";
        }
        else
            std::cout << "bad\n";
    
        if (begin != end)
            std::cout << "Remaining unparsed: " << std::quoted(std::string(begin, end)) << std::endl;
    }
    

    打印

    good
    1
    11
    3
    6-4
    

    【讨论】:

    • 好的,代码确实看起来更简单更漂亮。我想知道 youtube 和 boost 网站 x3 教程都使用类似于“expr_class”、“expr_def”、“expr”和 BOOST_SPIRIT_DEFINE() 的类似方法。如果我们可以像上面的代码那样使用“更简单”的方式,那么这样做的原因是什么。
    • 关于使用BOOST_SPIRIT_DEFINE 定义规则:仅1.递归规则2.外部链接需要。 (也许我的一些answers 会有所启发)
    • 关于编译器问题,GCC 6.3.0 显然无法为uintObj 生成特殊成员。添加它们修复它:Live On Wandbox
    猜你喜欢
    • 2013-06-20
    • 1970-01-01
    • 2016-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多