C++ 语义动作与属性传播在精神上的结合

C++ 语义动作与属性传播在精神上的结合,c++,boost-spirit-qi,C++,Boost Spirit Qi,我在上玩了一点代码,我还有一个问题。我将语义操作添加到: action=actions_>>”(“>>参数>>”)”[/*此处放置语义操作*/] 因此,我可以在多个地方重复使用该规则并进行验证。问题是,然后spirit停止将我的属性类型传播到上层规则(使用操作作为解析器)。我读到,应该使用操作符%=再次启用它(具有语义操作和属性传播)。但是我得到了一个编译器错误,无法将boost::fuction::vector2转换为ast::action。fusion中是否有任何宏用于启用另一个方向的赋值?

我在上玩了一点代码,我还有一个问题。我将语义操作添加到:
action=actions_>>”(“>>参数>>”)”[/*此处放置语义操作*/]
因此,我可以在多个地方重复使用该规则并进行验证。问题是,然后spirit停止将我的属性类型传播到上层规则(使用
操作
作为解析器)。我读到,应该使用操作符
%=
再次启用它(具有语义操作和属性传播)。但是我得到了一个编译器错误,无法将
boost::fuction::vector2
转换为
ast::action
fusion
中是否有任何宏用于启用另一个方向的赋值?或者,我应该怎么做才能使规则在传递给语义操作时仍然公开相同的属性,而不是在那里使用融合向量

示例代码:

#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;
}
#包括“stdafx.h”
//促进
#包括
#包括
#包括
#包括
//性病
#包括
#包括
命名空间bsqi=boost::spirit::qi;
命名空间bsqi_编码=boost::spirit::standard_wide;
命名空间bsqi_repos=boost::spirit::repository::qi;
//////////////////////////////////////////////////////////////////////////
枚举类操作:uint8\t
{
eAction0=0,
反应1,
反应2
};
//////////////////////////////////////////////////////////////////////////
struct ActionSymbols:public boost::spirit::qi::symbols
{
动作符号()
{
添加
(L“action0”,Action::eAction0)
(L“行动1”,行动::行动1)
(L“行动2”,行动::行动2)
;
}
}动作符号;
//////////////////////////////////////////////////////////////////////////
使用参数value=boost::variant;
结构参数
{
std::wstring::const_迭代器源;//<输入中参数开始的位置
ParameterValue value;//<参数的类型和值
};
//////////////////////////////////////////////////////////////////////////
使用参数=std::vector;
//////////////////////////////////////////////////////////////////////////
结构动作参数
{
行动;
参数;
};
//////////////////////////////////////////////////////////////////////////
BOOST_FUSION_ADAPT_STRUCT(参数,(std::wstring::const_迭代器,源),(参数值,值));
BOOST_FUSION_ADAPT_STRUCT(动作参数,(动作,动作),(参数,参数));
//////////////////////////////////////////////////////////////////////////
类SyntaxError:public std::runtime\u错误
{
公众:
SyntaxError()
:std::运行时错误(“语法错误!”)
{ }
};
//////////////////////////////////////////////////////////////////////////
模板
结构脚本语法:bsqi::语法
{
///用于定义所有规则的帮助器类型
模板
使用RuleT=bsqi::rule;
使用结果_type=std::vector;
显式脚本语法()
:基本类型(开始,“脚本”)
{
//支持的参数类型(整型或带引号的字符串)
//注意:iter_pos用于保存参数的迭代器,以便生成更详细的错误报告
参数=bsqi_repos::iter_pos>>(bsqi::int_124;bsqi::lexeme[L''>*(bsqi_编码::char_-L'')>L']);
参数名称(“参数”);
//逗号分隔符参数列表(或无参数)
参数=-(参数%L',');
参数。名称(“参数”);
//带参数的操作
action=(actionSymbols>L'('>parameters>L'))[bsqi::\u pass=boost::phoenix::bind(&ScriptGrammar::ValidateAction,this,bsqi::\u 1,bsqi::\u 2)];
行动名称(“行动”);
//动作(..)[->事件(..)->事件(..)->
//eps=强制使用此规则进行解析
//eoi=规则必须使用整个输入
start=bsqi::eps>(操作%L';')>L';'>bsqi::eoi;
}
私人:
bool验证操作(操作、常量参数和参数)
{
返回true;
}
规则参数;
规则参数;
规则行为;
规则启动;
};
//////////////////////////////////////////////////////////////////////////
int _tmain(int argc,_TCHAR*argv[]
{
使用ScriptParser=ScriptGrammar;
脚本解析器;
自动输入=std::wstring(L“\taction0(1,2,3);action1(\'str1\,\'str2\”);action2(\'strix\,0);\t\t”);
auto it=input.begin();
ScriptParser::结果_类型输出;
尝试
{
if(!phrase_parse(it,input.end(),parser,bsqi_coding::space,output))
抛出SyntaxError();
}
捕获(bsqi::期望值、失败和e)
{

std::cout有一个
BOOST\u SPIRIT\u ACTIONS\u ALLOW\u ATTR\u COMPAT
,它应该允许属性兼容性规则在语义操作内部工作,就像它们在自动属性传播期间工作一样

但是,更好的解决方案是在需要时指定所需的转换

最明显的方法是

  • 将中间层包装成
    qi::rule

    顺便说一句,我已经在你之前的问题中以这种方式解决了你的特定问题

    实际上,我假设您希望有一个状态验证程序在运行中,您可以使用它将中间产物转换为所需的AST(例如,如果您不想在AST中实际存储迭代器)

  • 将子表达式包装为一个新的格式

    请注意Boost Spirit某些版本中的一个bug,该bug要求您显式深度复制
    transform\u属性中的子表达式(使用
    qi::copy(p)


添加了一些关于我在回答您之前的问题时显示的第一个解决方案的注释super,thx。我将原始帖子中的示例代码更改为更具意义的代码