【问题标题】:Alternative attribute synthesis and AST design替代属性合成和 AST 设计
【发布时间】:2018-03-09 20:46:45
【问题描述】:

在下面的语法中,当我将替代项(| 属性)添加到开始规则时,我得到了这个错误

'boost::spirit::x3::traits::detail::move_to': 3 个重载都没有 可以转换所有参数类型 e:\data\boost\boost_1_65_1\boost\spirit\home\x3\support\traits\move_to.hpp 180

我怀疑问题在于property属性是一个结构,而property_list是一个向量(x3不应该创建一个条目的向量吗?)。设计 AST 结构以支持替代方案的推荐方法是什么? Boost 变体?

#include <string>
#include <vector>
#include <iostream>
#include <iomanip>
#include <map>

#pragma warning(push)
#pragma warning(disable : 4348)
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/home/x3.hpp>
#include <boost/variant.hpp>
#include <boost/fusion/adapted/struct.hpp>
#pragma warning(pop)

namespace x3 = boost::spirit::x3;

namespace scl_ast
    {

    struct KEYWORD : std::string
        {
        using std::string::string;
        using std::string::operator=;
        };

    struct NIL
        {
        };

    using VALUE = boost::variant <NIL, std::string, int, double, KEYWORD>;

    struct PROPERTY
        {
        KEYWORD     name;
        VALUE       value;
        };

    static inline std::ostream& operator<< (std::ostream& os, VALUE const& v)
        {
        struct
            {
            std::ostream&   _os;

            void operator () (std::string const& s) const { _os << std::quoted (s); }
            void operator () (int i)                const { _os << i; }
            void operator () (double d)             const { _os << d; }
            void operator () (KEYWORD const& k)     const { _os << k; }
            void operator () (NIL)                  const { }
            } vis { os };

            boost::apply_visitor (vis, v);
            return os;
        }

    static inline std::ostream& operator<< (std::ostream& os, PROPERTY const& prop)
        {
        os << prop.name;

        if (prop.value.which ())
            {
            os << "=" << prop.value;
            }

        return os;
        }

    static inline std::ostream& operator<< (std::ostream& os, std::vector <PROPERTY> const& props)
        {
        for (auto const& prop : props)
            {
            os << prop << " ";
            }

        return os;
        }

    };  // End namespace scl_ast

BOOST_FUSION_ADAPT_STRUCT (scl_ast::PROPERTY, name, value)

//
// Keyword-value grammar for simple command language
//

namespace scl
    {
    using namespace x3;


    auto const  keyword = rule <struct _keyword, std::string> { "keyword" }
                    = lexeme [+char_ ("a-zA-Z0-9$_")];

    auto const  quoted_string
                    = lexeme ['"' >> *('\\' > char_ | ~char_ ('"')) >> '"'];

    auto const  value
                    = quoted_string
                    | x3::real_parser<double, x3::strict_real_policies<double>>{}
                    | x3::int_
                    | keyword;

    auto const  property = rule <struct _property, scl_ast::PROPERTY> { "property" }
                    = keyword >> -(("=" >> value));

    auto const  property_list = rule <struct _property_list, std::vector <scl_ast::PROPERTY>> { "property_list" }
                    = lit ('(') >> property % ',' >> lit (')');

    auto const  start = skip (blank) [property_list | property];

    };  // End namespace scl


int
main ()

{
std::vector <std::string>   input =
    {
    "(abc=1.,def=.5,ghi=2.0)",
    "(ghi = 1, jkl = 3)",
    "(abc,def=1,ghi=2.4,jkl=\"mno 123\", pqr = stu)",
    "(abc = test, def, ghi=2)",
    "abc=1",
    "def = 2.7",
    "ghi"
    };


    for (auto const& str : input)
        {
        std::vector <scl_ast::PROPERTY>     result;
        auto    b = str.begin (), e = str.end ();


        bool    ok = x3::parse (b, e, scl::start, result);
        std::cout << (ok ? "OK" : "FAIL") << '\t' << std::quoted (str) << std::endl;

        if (ok)
            {
            std::cout << " -- Parsed: " << result << std::endl;

            if (b != e)
                {
                std::cout << " -- Unparsed: " << std::quoted (std::string (b, e)) << std::endl;
                }

            }

        std::cout << std::endl;
        }   // End for

    return 0;
}                           // End main

【问题讨论】:

    标签: c++ boost c++14 boost-spirit boost-spirit-x3


    【解决方案1】:

    我怀疑问题是property属性是一个struct,而property_list是一个向量(x3不应该创建一个条目的向量吗?)

    是的,是的,是的,取决于。

    我看到大约 3 种方法来解决这个问题。让我们从简单的开始:

    1. 强制类容器合成:Live On Coliru

      = skip(blank)[property_list | repeat(1)[property] ];
      
    2. 强制属性类型。原来我在这里错了:它曾经为 Qi 工作,但显然已经被放弃了。在这里,不工作和所有:

      auto coerce = [](auto p) { return rule<struct _, std::vector<scl_ast::PROPERTY> > {} = p; };
      
      auto const start 
          = skip(blank)[property_list | coerce(property)];
      
    3. 第三个实际上没有实际意义,因为同样的问题。所以我想我欠你一个人为的解决方法,使用语义操作:Live On Coliru

      auto push_back = [](auto& ctx) {
          _val(ctx).push_back(_attr(ctx));
      };
      
      auto const start 
          = rule<struct _start, std::vector<scl_ast::PROPERTY>, true>{ "start" } 
          = skip(blank)[property_list | omit[property[push_back]]];
      

    【讨论】:

    • 添加了修复错误的实时示例 :)
    • 再次感谢您!使用 repeat 并不明显,但我现在明白它为什么起作用了。我试图从你的另一篇文章中强制使用 #2 之类的类型,但我无法让它工作。我很高兴这不是我的错。 #1 和 #3 的优缺点是什么?最后,我从未在所有 x3 代码和帖子中看到过这样的解决方案,所以这种语言真的很时髦,还是我接近它错了,需要 x3 跳过箍(我认为替代方案会处理得更好)
    • X3 仍处于试验阶段,是的,X3 中的替代处理远不如 Qi 中的成熟。我什至会说它已经坏了,但幸运的是,使用 #2 方法通常很容易解决,并且 #3 提供了完整的图灵完整性,所以我不害怕在我的代码中使用 X3。
    • 我会使用方法 #1 - 富有表现力,将其保存在解析器表达式域中。如果我的解决方法开始失败,我会通过邮件列表游说/开发修复:)
    猜你喜欢
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-25
    • 2011-01-21
    • 2018-05-02
    • 2016-04-18
    相关资源
    最近更新 更多