Using semantic action along with spreading attributes in the spirit

I have been playing around a bit with the code on the link and I have another question. I added a semantic action: action = actions_ >> '(' >> parameters >> ')'[ /* semantic action placed here */];

so I can reuse the rule along with validation in multiple places. The problem is then spirit stops propagating my attribute type to the top rules (which it uses action

as a parser). I read in the link that the operator %=

must be used to re-enable it (have semantic actions and attribute propagation). But then I get a compiler error that cannot be converted boost::fuction::vector2<ast::actionid, ast::parameters>

to ast::action

. Is there a macro infusion

to enable assignment in the other direction? Or what should I do that the rule still exposes the same attribute that is passed to the semantic action, and not where the merge file is?

Sample code:

#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;
}

      

I am trying to get an attribute from a rule start

. I am evaluating the values ​​correctly in semantic action ( ValidateAction

), but the attribute from the rule start

only gets uninitialized values ​​(output size std::vector

is 3, but the values ​​are not initialized). I tried to replace the rule initialization %=

instead of the simple one =

, but then the mentioned compilation error appears.

+1


source to share


1 answer


There is BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT

one that should allow attribute compatibility rules to work within semantic actions as they work during automation attribute propagation.

An excellent solution, however, is to specify the conversions you want whenever you want.



The most obvious approaches are

+2


source







All Articles