повышение духа: тип параметра при использовании семантических действий и феникса - PullRequest
2 голосов
/ 03 декабря 2011

Я использую Boost Spirit для разбора математических выражений и столкнулся с проблемой, которую я извлек в следующий код.

Существует простой лексер с одним токеном, имеющий атрибут, содержащий совпадающую строку. Парсер определяет единственное правило, которое предназначено для того, чтобы взять атрибут токена и вызвать с ним функцию. Результатом вызова функции должно быть значение атрибута правила.

Не удается скомпилировать (calc_something: невозможно преобразовать параметр 1 из const boost :: spirit :: _ 1_type в const std :: string &) - очевидно, потому что тип qi :: _ 1 выведен неправильно. Однако изменение действия на простое «cout << qi :: _ 1» работает. </p>

Я новичок в повышении духа, но мне удалось заставить мою грамматику вести себя правильно. Теперь, когда мне нужно получить проанализированные значения, я застрял здесь и был бы признателен за любую помощь, которую я могу получить.

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

Ответы [ 2 ]

2 голосов
/ 15 марта 2012

У меня нет опыта работы с spirit lex, но я предполагаю, что он похож на qi, и поэтому вы хотите использовать phoenix function для этого:

#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;
1 голос
/ 30 апреля 2013

Эдди определил часть проблемы; Мне удалось заставить это работать с двумя другими изменениями:

  • Подпись вашей грамматики и правила должна использовать синтаксис вызова функции для синтезированного атрибута, т.е. <Iterator, int()>
  • Хотя мне не удалось детально описать работу ленивой функции Phoenix (она компилируется, но никогда не вызывается), переключение на Phoenix V3 заставляет ее работать. Добавьте, прежде чем ваш первый Дух включает:

#define BOOST_SPIRIT_USE_PHOENIX_V3 1

...