【问题标题】:Using semantic action together with attribute propagation in spirit在精神上使用语义动作和属性传播
【发布时间】:2016-11-21 15:11:01
【问题描述】:

我在link 上玩了一点代码,我还有一个问题。我将语义动作添加到: action = actions_ >> '(' >> parameters >> ')'[ /* semantic action placed here */]; 所以我可以在多个地方重复使用规则和验证。问题是,然后精神停止将我的属性类型传播到上层规则(它使用action 作为解析器)。我在link 读到,应该使用运算符%= 再次启用它(以进行语义操作和属性传播)。但后来我收到编译器错误,无法将boost::fuction::vector2<ast::actionid, ast::parameters> 转换为ast::actionfusion 中是否有任何宏可以启用另一个方向的分配?或者我应该怎么做,规则仍然暴露相同的属性,因为它被传递给语义动作,而不是在那里有融合向量?

示例代码:

#include "stdafx.h"

// boost
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/repository/include/qi_iter_pos.hpp>
#include <boost/bind.hpp>
#include <boost/phoenix.hpp>

// std
#include <string>
#include <vector>

namespace bsqi = boost::spirit::qi;
namespace bsqi_coding = boost::spirit::standard_wide;
namespace bsqi_repos = boost::spirit::repository::qi;

//////////////////////////////////////////////////////////////////////////
enum class Action : uint8_t
{
    eAction0 = 0,
    eAction1,
    eAction2
};

//////////////////////////////////////////////////////////////////////////
struct ActionSymbols : public boost::spirit::qi::symbols<wchar_t, Action>
{
    ActionSymbols()
    {
        add
            (L"action0", Action::eAction0)
            (L"action1", Action::eAction1)
            (L"action2", Action::eAction2)
        ;
    }
} actionSymbols;

//////////////////////////////////////////////////////////////////////////
using ParameterValue = boost::variant<int, std::wstring>;
struct Parameter
{
    std::wstring::const_iterator    source; ///< position within the input where parameter begins
    ParameterValue                  value;  ///< type and value of the parameter
};

//////////////////////////////////////////////////////////////////////////
using Parameters = std::vector<Parameter>;

//////////////////////////////////////////////////////////////////////////
struct ActionParameters
{
    Action          action;
    Parameters      parameters;
};

//////////////////////////////////////////////////////////////////////////
BOOST_FUSION_ADAPT_STRUCT(Parameter, (std::wstring::const_iterator, source), (ParameterValue, value));
BOOST_FUSION_ADAPT_STRUCT(ActionParameters, (Action, action), (Parameters, parameters));

//////////////////////////////////////////////////////////////////////////
class SyntaxError : public std::runtime_error
{
public:
    SyntaxError()
        : std::runtime_error("Syntax error!")
    { }
};

//////////////////////////////////////////////////////////////////////////
template<typename IteratorT>
struct ScriptGrammar : bsqi::grammar<IteratorT, std::vector<ActionParameters>, bsqi_coding::space_type>
{
    /// helper type to define all rules
    template<typename T>
    using RuleT = bsqi::rule<iterator_type, T, bsqi_coding::space_type>;

    using result_type = std::vector<ActionParameters>;

    explicit ScriptGrammar()
        : base_type(start, "script")
    {
        // supported parameter types (int or quoted strings)
        // note: iter_pos is used for saving the iterator for the parameter to enable generating more detailed error reports
        parameter = bsqi_repos::iter_pos >> (bsqi::int_ | bsqi::lexeme[L'"' > *(bsqi_coding::char_ - L'"') > L'"']);
        parameter.name("parameter");

        // comma separator list of parameters (or no parameters)
        parameters = -(parameter % L',');
        parameters.name("parameters");

        // action with parameters
        action = (actionSymbols > L'(' > parameters > L')')[bsqi::_pass = boost::phoenix::bind(&ScriptGrammar::ValidateAction, this, bsqi::_1, bsqi::_2)];
        action.name("action");

        // action(..) [-> event(..) -> event(..) -> ..]
        // eps = force to use this rule for parsing
        // eoi = the rule must consume whole input
        start = bsqi::eps > (action % L';') > L';' > bsqi::eoi;
    }

private:
    bool ValidateAction(Action action, const Parameters& parameters)
    {
        return true;
    }

    RuleT<Parameter>                        parameter;
    RuleT<Parameters>                       parameters;
    RuleT<ActionParameters>                 action;
    RuleT<std::vector<ActionParameters>>    start;
};

//////////////////////////////////////////////////////////////////////////
int _tmain(int argc, _TCHAR* argv[])
{
    using ScriptParser = ScriptGrammar<std::wstring::const_iterator>;
    ScriptParser parser;

    auto input = std::wstring(L"\taction0(1, 2, 3); action1(\"str1\", \"str2\"); action2(\"strmix\", 0);\t\t");
    auto it = input.begin();
    ScriptParser::result_type output;
    try
    {
        if(!phrase_parse(it, input.end(), parser, bsqi_coding::space, output))
            throw SyntaxError();
    }
    catch(bsqi::expectation_failure<ScriptParser::iterator_type>& e)
    {
        std::cout << "Error! Expecting " << e.what_ << " here: \"" << std::string(e.first, e.last) << "\"";
    }
    catch(SyntaxError& e)
    {
        std::cout << e.what() << "\n";
    }
    return 0;
}

我尝试从start 规则中获取属性。我在语义操作 (ValidateAction) 中得到正确解析的值,但来自 start 规则的属性仅接收未初始化的值(输出 std::vector 的大小为 3,但值未初始化)。我尝试将规则的初始化替换为%= 而不是简单的=,但随后弹出上述编译错误。

【问题讨论】:

  • 如果您需要有关实际代码的帮助,它需要是 SSCCE。

标签: c++ boost-spirit-qi


【解决方案1】:

BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT 应该允许属性兼容性规则在语义操作中工作,就像它们在自动化属性传播期间工作一样。

但是,更好的解决方案是在您希望的时候指定您希望的转换。

最明显的方法是

  • 将中间包裹到qi::rule&lt;..., T()&gt;

    顺便说一句,在您之前的问题中,我已经在 boost spirit reporting semantic error 以这种方式解决了您的特定问题。

    实际上,我想您希望有一个有状态的验证器在运行中工作,您可以使用Attribute Traits 将您的中间体转换为所需的 AST(例如,如果您不想将迭代器实际存储在您的AST)

  • 将子表达式包装在 qi::transform_attribute&lt;T&gt;()[p] directive 中。

    注意某些版本的 Boost Spirit 中的一个错误,它要求您显式地深复制 transform_attribute 中的子表达式(使用 qi::copy(p)

【讨论】:

  • 添加了一些关于我在回答您上一个问题时展示的第一个解决方案的内容
  • 超级,谢谢。我将原始帖子中的示例代码更改为更有意义的内容。没有任何进一步的更改,代码放入output 3 个项目,但它们未初始化。 - 定义 BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT 并将 action 初始化从 = 更改为 %= 工作或 - 添加 ActionParameters 的模板构造函数以启用从升压融合向量初始化并将 action 的初始化从 = 更改为%= 也可以
  • 我在另一个规则中使用了 qi::attr_cast,但我在 boost 中遇到了一些奇怪的崩溃。您的 qi::copy 提示似乎也适用于这个 attr_cast。谢谢你 - 我相信你让我在弄清楚可能是什么问题时让我头疼:-)我只是盲目地尝试了它并且它有效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-01-14
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 2019-04-27
  • 1970-01-01
相关资源
最近更新 更多