替代属性合成和AST设计

时间:2018-03-09 20:46:45

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

在下面的语法中,当我将替代(| property)添加到开始规则时,我收到此错误

  

' 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_list是一个向量(不应该创建一个条目的向量吗?)。设计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

1 个答案:

答案 0 :(得分:2)

  

我怀疑问题是属性属性是一个结构,而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]]];