【问题标题】:avoid construct template in boost spirit semantic action避免在提升精神语义动作中构建模板
【发布时间】:2017-11-08 06:33:55
【问题描述】:

此代码有效。这个问题是关于让它(看起来)更好。 我看过有关utrees 的文章,但我不确定这是最好的方法。

让我给你看代码的“丑陋”版本,它使用construct<>

newcall =(nocaselit(L"new") > tyname)
            [_val = construct<common_node>(type_cmd_new,key_typename, construct<std::wstring>(_1))];

将规则声明为:

qi::rule<Iterator, common_node(), Skipper> newcall
qi::rule<Iterator, std::wstring()> tyname;

目标公共AST节点为:

struct common_node {
    template <typename X>
    common_node(node_type t, node_key k1, const X & m1)

第一个参数是节点类型,第二个是某种成员键,最后一个是作为模板参数给出的有效负载(后来存储在一个变体中)。

我们可以避免使用construct 模板吗?

【问题讨论】:

  • utree 从未发展到真正有用的程度。

标签: c++ boost-spirit boost-spirit-qi boost-phoenix


【解决方案1】:

这是我always linkBoost Spirit: "Semantic actions are evil"? 的经典案例:避免语义动作。

在这种情况下,我不知道您的 AST 到底是什么样子(什么是 node_key,key_typename 来自哪里等),所以我无法真正向您展示。

通常我会调整节点类型并为具体节点类型声明规则。如果这不起作用,我更喜欢 phoenix::function&lt;&gt; 包装器:

Live On Coliru

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
namespace qi = boost::spirit::qi;

struct SomeComplicatedType {
    enum Type { None, NewCall };
    struct Key{};
    SomeComplicatedType(Type = {}, Key = {}, std::string n = "") : name(std::move(n)) { }

    std::string name;
};

static SomeComplicatedType::Key const s_default_key;

template <typename It>
struct Grammar : qi::grammar<It, SomeComplicatedType()>
{
    Grammar() : Grammar::base_type(start) {
        using namespace qi;
        start  = skip(space) [new_];
        tyname = raw[(alpha|'_') >> +(alnum|'_')];

        new_   = no_case["new"] > tyname [_val = make_new(_1)];

        BOOST_SPIRIT_DEBUG_NODES((start)(new_)(tyname))
    }
  private:
    qi::rule<It, SomeComplicatedType()> start;
    qi::rule<It, SomeComplicatedType(), qi::space_type> new_;
    qi::rule<It, std::string()> tyname;

    struct make_complicated_t {
        SomeComplicatedType::Type _type;

        SomeComplicatedType operator()(std::string const& s) const {
            return SomeComplicatedType{_type, s_default_key, s};
        }
    };
    boost::phoenix::function<make_complicated_t> make_new { make_complicated_t{SomeComplicatedType::NewCall } };
};

int main() {
    std::string const input = "new Sandwich";

    SomeComplicatedType result;
    if (parse(input.begin(), input.end(), Grammar<std::string::const_iterator>{}, result))
        std::cout << "Parsed: " << result.name << "\n";

}

打印

Parsed: Sandwich

【讨论】:

  • 谢谢。你的样品对我有用..所以我可以用凤凰的东西交换结构。也许我会重构我的解析器以某种方式避免语义操作。
猜你喜欢
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
  • 1970-01-01
  • 2016-09-06
相关资源
最近更新 更多