boostspirit:使用语义动作和phoenix时的参数类型

发布于 2024-12-19 03:26:00 字数 2351 浏览 2 评论 0原文

我使用 boost Spirit 来解析数学表达式,并遇到了一个问题,我将其提取到以下代码中。

有一个带有一个标记的简单词法分析器,具有一个保存匹配字符串的属性。解析器定义了一个规则,该规则旨在获取令牌的属性并用它调用函数。函数调用的结果应该是规则的属性值。

这无法编译(calc_something:无法将参数 1 从 const boost::spirit::_1_type 转换为 const std::string &) - 显然是因为 qi::_1 的类型未正确推断。但是,将操作更改为简单的“cout << qi::_1”是可行的。

我对提升精神还很陌生,但已经设法让我的语法表现得正确。现在我需要获取解析的值,我被困在这里,希望能得到任何帮助。

// spiritTest.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <tchar.h>

#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>

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

template <typename Lexer>
class TestLexer : public lex::lexer<Lexer>
{
public:
    TestLexer()
    {
        number = "(\\d*\\.)?\\d+([eE][-+]?\\d+)?";      
        self = number;
    }

    lex::token_def<std::string> number;
};

int calc_something(const std::string & s)
{
    return 5;
}

template <typename Iterator>
class Parser : public qi::grammar<Iterator, int>
{
public:
    template <typename TokenDef>
    Parser(const TokenDef& tok) : Parser::base_type(value)
    {   
        // the following line causes error C2664: 'calc_something' : cannot convert parameter 1 from 'const boost::spirit::_1_type' to 'const std::string &'    
        value = tok.number [qi::_val = calc_something(qi::_1)];         

        // the following line works as expected
        //value = tok.number [std::cout << qi::_1 << std::endl];            
    }

    qi::rule<Iterator, int> value;
};

int _tmain(int argc, _TCHAR* argv[])
{
    typedef const char* base_iterator_type;
    typedef lex::lexertl::token<base_iterator_type> token_type;
    typedef lex::lexertl::lexer<token_type> lexer_type;
    typedef TestLexer<lexer_type> TestLexer;
    typedef TestLexer::iterator_type iterator_type;
    typedef Parser<iterator_type> Parser;

    TestLexer lexer;
    Parser parser(lexer);

    const char * formula = "530";
    bool result = lex::tokenize_and_parse(formula, formula + strlen(formula), lexer, parser);

    return 0;
}

I use boost spirit to parse mathematical expressions and have run into a problem that I extracted into the following code.

There is a simple lexer with one token, having an attribute holding the matched string. The parser defines a single rule which is meant to take the token's attribute and call a function with it. The result of the function call should be the attribute value of the rule.

This fails to compile (calc_something: cannot convert parameter 1 from const boost::spirit::_1_type to const std::string &) - clearly because the type of qi::_1 is not inferred correctly. However, changing the action to a simple "cout << qi::_1" works.

I am fairly new to boost spirit, but have managed to get my grammar to behave correctly. Now that I need to get at parsed values, I am stuck here and would appreciate any help I can get.

// spiritTest.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <tchar.h>

#include <string>
#include <iostream>

#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix_core.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>

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

template <typename Lexer>
class TestLexer : public lex::lexer<Lexer>
{
public:
    TestLexer()
    {
        number = "(\\d*\\.)?\\d+([eE][-+]?\\d+)?";      
        self = number;
    }

    lex::token_def<std::string> number;
};

int calc_something(const std::string & s)
{
    return 5;
}

template <typename Iterator>
class Parser : public qi::grammar<Iterator, int>
{
public:
    template <typename TokenDef>
    Parser(const TokenDef& tok) : Parser::base_type(value)
    {   
        // the following line causes error C2664: 'calc_something' : cannot convert parameter 1 from 'const boost::spirit::_1_type' to 'const std::string &'    
        value = tok.number [qi::_val = calc_something(qi::_1)];         

        // the following line works as expected
        //value = tok.number [std::cout << qi::_1 << std::endl];            
    }

    qi::rule<Iterator, int> value;
};

int _tmain(int argc, _TCHAR* argv[])
{
    typedef const char* base_iterator_type;
    typedef lex::lexertl::token<base_iterator_type> token_type;
    typedef lex::lexertl::lexer<token_type> lexer_type;
    typedef TestLexer<lexer_type> TestLexer;
    typedef TestLexer::iterator_type iterator_type;
    typedef Parser<iterator_type> Parser;

    TestLexer lexer;
    Parser parser(lexer);

    const char * formula = "530";
    bool result = lex::tokenize_and_parse(formula, formula + strlen(formula), lexer, parser);

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

温柔一刀 2024-12-26 03:26:00

我没有使用 spirit lex 的经验,但我认为它与 qi 类似,因此您需要使用 phoenix 函数 来这样做:

#include <boost/spirit/include/phoenix_function.hpp>

struct calc_something_impl
{
  template <typename T1>
  struct result { typedef int type; };

  int operator()(const std::string & s) const
  {
    return 5;
  }
};

boost::phoenix::function<calc_something_impl> calc_something;

I don't have experience with spirit lex, but I assume it's similar to qi and so you'd want to use a phoenix function to do that:

#include <boost/spirit/include/phoenix_function.hpp>

struct calc_something_impl
{
  template <typename T1>
  struct result { typedef int type; };

  int operator()(const std::string & s) const
  {
    return 5;
  }
};

boost::phoenix::function<calc_something_impl> calc_something;
傾旎 2024-12-26 03:26:00

eddi 已确定部分问题;我设法通过另外两个更改来实现此目的:

  • 语法和规则的签名必须使用合成属性的函数调用语法,即
  • 虽然我无法要让懒惰的 Phoenix 函数 eddi 详细工作(它可以编译,但永远不会被调用),切换到 Phoenix V3 可以使其工作。在第一个 Spirit 之前添加:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

eddi has identified part of the problem; I managed to get this working with another two changes:

  • The signature of your grammar and rule must use function call syntax for the synthesized attribute, i.e., <Iterator, int()>
  • Although I was unable to get the lazy Phoenix function eddi detailed to work (it compiles, but never gets called), switching to Phoenix V3 makes it work. Add before your first Spirit include:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文