Boost :: spirit如何解析和调用c ++函数式表达式 [英] Boost::spirit how to parse and call c++ function-like expressions

查看:155
本文介绍了Boost :: spirit如何解析和调用c ++函数式表达式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用boost精灵来解析一个表达式

I want to use boost spirit to parse an expression like


function1(arg1,arg2,function2(arg1,arg2,arg3) ,
function3(arg1,arg2))

function1(arg1, arg2, function2(arg1, arg2, arg3), function3(arg1,arg2))

并调用相应的c ++函数。应该是什么语法解析上面的表达式,并通过phoneix :: bind()调用相应的c ++函数?

and call corresponding c++ functions. What should be the grammar to parse above expression and call the corresponding c++ function by phoneix::bind()?

我有两种类型的函数调用

I have 2 types of functions to call

1)字符串函数;


wstring GetSubString(wstring stringToCut,int position,int length) ;
wstring GetStringToken(wstring stringToTokenize,wstring seperators,
int tokenNumber);

wstring GetSubString(wstring stringToCut, int position, int length); wstring GetStringToken(wstring stringToTokenize, wstring seperators, int tokenNumber );

;


int GetCount();

int GetCount();

int GetId(wstring srcId,wstring srcType);

int GetId(wstring srcId, wstring srcType);


推荐答案

第二个答案(更务实)



这是第二个例子,用于比较:

Second Answer (more pragmatic)

Here's a second take, for comparison:

为了防止你真的不想解析为抽象语法树表示,而是在解析过程中评估函数,你可以简化语法。

Just in case you really didn't want to parse into an abstract syntax tree representation, but rather evaluate the functions on-the-fly during parsing, you can simplify the grammar.

它来自92行,而不是第一个答案中的209行。

It comes in at 92 lines as opposed to 209 lines in the first answer. It really depends on what you're implementing which approach is more suitable.

这种较短的方法有一些缺点:

This shorter approach has some downsides:


  • 不太灵活(不可重复使用)

  • 不太稳健(如果函数有副作用,即使解析失败,它们也会发生)

  • 不太可扩展(支持的功能硬连接到语法 1

  • less flexible (not reusable)
  • less robust (if functions have side effects, they will happen even if parsing fails halfway)
  • less extensible (the supported functions are hardwired into the grammar1)

//#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/phoenix/function.hpp>

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

typedef boost::variant<int, std::string> value;

//////////////////////////////////////////////////
// Demo functions:
value AnswerToLTUAE() {
    return 42;
}

value ReverseString(value const& input) {
    auto& as_string = boost::get<std::string>(input);
    return std::string(as_string.rbegin(), as_string.rend());
}

value Concatenate(value const& a, value const& b) {
    std::ostringstream oss;
    oss << a << b;
    return oss.str();
}

BOOST_PHOENIX_ADAPT_FUNCTION_NULLARY(value, AnswerToLTUAE_, AnswerToLTUAE)
BOOST_PHOENIX_ADAPT_FUNCTION(value, ReverseString_, ReverseString, 1)
BOOST_PHOENIX_ADAPT_FUNCTION(value, Concatenate_, Concatenate, 2)

//////////////////////////////////////////////////
// Parser grammar
template <typename It, typename Skipper = qi::space_type>
    struct parser : qi::grammar<It, value(), Skipper>
{
    parser() : parser::base_type(expr_)
    {
        using namespace qi;

        function_call_ = 
                (lit("AnswerToLTUAE")   > '(' > ')')                     
                     [ _val = AnswerToLTUAE_() ]
              | (lit("ReverseString") > '(' > expr_ > ')')               
                     [ _val = ReverseString_(_1) ]
              | (lit("Concatenate")   > '(' > expr_ > ',' > expr_ > ')') 
                     [ _val = Concatenate_(_1, _2) ]
            ;
        string_        = as_string [ 
                            lexeme [ "'" >> *~char_("'") >> "'" ] 
                         ];
        value_         = int_ | string_;

        expr_          = function_call_ | value_;

        on_error<fail> ( expr_, std::cout
             << phx::val("Error! Expecting ") << _4 << phx::val(" here: \"")
             << phx::construct<std::string>(_3, _2) << phx::val("\"\n"));

        BOOST_SPIRIT_DEBUG_NODES((expr_)(function_call_)(value_)(string_))
    }

  private:
    qi::rule<It, value(), Skipper> value_, function_call_, expr_, string_;
};

int main()
{
    for (const std::string input: std::vector<std::string> { 
            "-99",
            "'string'",
            "AnswerToLTUAE()",
            "ReverseString('string')",
            "Concatenate('string', 987)",
            "Concatenate('The Answer Is ', AnswerToLTUAE())",
            })
    {
        auto f(std::begin(input)), l(std::end(input));
        const static parser<decltype(f)> p;

        value direct_eval;
        bool ok = qi::phrase_parse(f,l,p,qi::space,direct_eval);

        if (!ok)
            std::cout << "invalid input\n";
        else
        {
            std::cout << "input:\t" << input       << "\n";
            std::cout << "eval:\t"  << direct_eval << "\n\n";
        }

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

注意如何使用BOOST_PHOENIX_ADAPT_FUNCTION *直接使用 boost :: phoenix :: bind

Note how, instead of using BOOST_PHOENIX_ADAPT_FUNCTION* we could have directly used boost::phoenix::bind.

输出仍然相同:

input:  -99
eval:   -99

input:  'string'
eval:   string

input:  AnswerToLTUAE()
eval:   42

input:  ReverseString('string')
eval:   gnirts

input:  Concatenate('string', 987)
eval:   string987

input:  Concatenate('The Answer Is ', AnswerToLTUAE())
eval:   The Answer Is 42






1 这最后的缺点很容易通过使用'Nabialek Trick'


1 This last downside is easily remedied by using the 'Nabialek Trick'

这篇关于Boost :: spirit如何解析和调用c ++函数式表达式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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