Boost:spirit解析为结构并重用其中的一部分 [英] Boost:spirit Parsing into structure and reusing parts of it

查看:44
本文介绍了Boost:spirit解析为结构并重用其中的一部分的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我必须在句子中找到变量并将其替换为它们的值.变量可以用不同的形式编写,例如$ varName或$(varName).

I have to find variables in a sentence and replace them by their value. Variables can be written in different forms, like $varName, or $(varName) for example.

我希望拥有一个VariableHolder结构以方便地访问两者:

I'd like to have a struct VariableHolder to have easy access to both :

struct VariableHolder
{
    string name;    // contains "varName"
    string fromFile;  // contains "$(varName)" or "$varName"
    void setName(ustring n) { name = n; }
}

很显然,我想避免进行多次传递和调用多个解析器.到目前为止,我是这样的:

Obviously, I'd like to avoid doing multiple passes and calling multiple parsers. What I have so far is this :

BOOST_FUSION_ADAPT_STRUCT(VariableHolder,
(ustring, fromFile)
)
// variableName is another parser that returns a string
qi::rule<Iterator, VariableHolder()> variable %=
                (qi::char_("$")
                    >> (variableName[phoenix::bind(&VariableHolder::setName, qi::_val, qi::_1)]
                        | (qi::char_("(")
                            >> variableName[phoenix::bind(&VariableHolder::setName, qi::_val, qi::_1)]
                            >> qi::char_(")")))
                    );

这不起作用.名称已正确设置,但是fromFile变量仅包含"$",并且没有其他任何内容.

Which doesn't work. The name is correctly set, but the fromFile variable only contains a "$", and never anything else.

好吧,我对您的问题:

  1. 我的想法是仅使用BOOST_FUSION_ADAPT_STRUCT调整结构的一部分,并用语义动作填充其余部分.愚蠢的主意,还是我做错了?
  2. 有没有办法绑定语义动作并仍然获取输出?像

  1. My idea was to only adapt part of the structure with BOOST_FUSION_ADAPT_STRUCT, and fill the rest with semantic actions. Stupid idea, or am I just doing it wrong?
  2. Is there a way to bind a semantic action and still get the output? Like

char_ [doSomething]//这两者都可以调用doSomething并解析字符吗?

char_[doSomething] // Can this both call doSomething, and parse a char?

推荐答案

解决问题:

  1. 我的想法是只使用 BOOST_FUSION_ADAPT_STRUCT 修改结构的一部分,并用语义动作填充其余部分.愚蠢的主意,还是我做错了?
  1. My idea was to only adapt part of the structure with BOOST_FUSION_ADAPT_STRUCT, and fill the rest with semantic actions. Stupid idea, or am I just doing it wrong?

并非不可思议.不是我的建议(请参阅 Boost Spirit:语义行为是邪恶的"?).但是,是的,您做错了:

Not unthinkable. Not my recommendation (see Boost Spirit: "Semantic actions are evil"?). But yeah you're doing it wrong:

如果您不希望它成为公开属性的一部分,则希望使用 lit("$")而不是 char _("$").实际上,'$'将在此处执行

You want lit("$") instead of char_("$") if you don't want it to be part of the exposed attribute. In fact, '$' will do here

  1. 有没有办法绑定语义动作并仍然获取输出?喜欢

  1. Is there a way to bind a semantic action and still get the output? Like

char_[doSomething] // Can this both call doSomething, and parse a char?

是的.您正在执行此操作,它之所以有效,是因为您使用了 operator%= 而不是 operator = (请参阅文档: http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi.reference.nonterminal.rule.expression_semantics ).

Yes. You're doing it right now, and it works because of operator%= you used instead of operator= (see the docs: http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/qi/reference/nonterminal/rule.html#spirit.qi.reference.nonterminal.rule.expression_semantics).

但是,您似乎真的在尝试两次使用相同的输入(原始为 fromFile 和"cooked"为 name ?),因为它会自动生效规则属性传播用您想要的 fromFile 值覆盖 name .

However, it seems you are really trying to use the same input twice (raw as fromFile and "cooked" as name?) it backfires, because the auto-rule attribute propagation also overwrites name with the value you want for fromFile.

这里唯一快速的解决方法是仅使用SA.我建议尽管使 VariableHolder 的构造函数负责细节.

The only quick way out, here, is to use SA only. I'd suggest making VariableHolder's constructor responsible for details though.

旁注:看起来有点像可选的括号暗示了表达式语法.如果是这样,请在语法中使其明确,而不是在 variableName 的规则中对特殊情况进行硬编码.如果没有,继续:)

Side note: it looks a bit as if the optional parentheses suggest an expression grammar. If so, make that explicit in the grammar, instead of hardcoding a special case in the rule for a variableName. If not, carry on :)

这是尝试的解决方法:

在Coliru上直播

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace qi      = boost::spirit::qi;
namespace phoenix = boost::phoenix;

struct VariableHolder {
    std::string name;     // contains "varName"
    std::string fromFile; // contains "$(varName)" or "$varName"
};

template <typename It, typename Skipper = qi::ascii::space_type> struct P : qi::grammar<It, VariableHolder(), Skipper> {
    P() : P::base_type(start) {
        auto _name     = phoenix::bind(&VariableHolder::name, qi::_val);
        auto _fromFile = phoenix::bind(&VariableHolder::fromFile, qi::_val);

        variableName = qi::alpha >> +qi::alnum;
        variable = '$' >> (variableName | '(' >> variableName >> ')');

        start = qi::as_string [ qi::raw [ 
                variable [ _name = qi::_1 ]] 
            ] [ _fromFile = qi::_1 ];

        BOOST_SPIRIT_DEBUG_NODES((start)(variable)(variableName))
    }

  private:
    qi::rule<It, std::string(), Skipper> variable;
    qi::rule<It, VariableHolder(), Skipper> start;
    // lexemes
    qi::rule<It, std::string()> variableName;
};

int main() {
    using It = std::string::const_iterator;
    P<It> const p;

    for (std::string const input : { 
            "$foo1",
            "$(bar2)" 
        }) 
    {
        It f = input.begin(), l = input.end();
        VariableHolder data;

        bool ok = qi::phrase_parse(f, l, p, qi::ascii::space, data);

        if (ok) {
            std::cout << "Parse success: " << data.name << " (source: '" << data.fromFile << "')\n";
        } else {
            std::cout << "Parse failure ('" << input << "')\n";
        }

        if (f != l) {
            std::cout << "Remaining unparsed input: '" << std::string(f, l) << "'\n";
        }
    }
}

打印

Parse success: foo1 (source: '$foo1')
Parse success: bar2 (source: '$(bar2)')

这篇关于Boost:spirit解析为结构并重用其中的一部分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆