开发者

Error with Phoenix placeholder _val in Boost.Spirit.Lex :(

I'm newbie in Boost.Spirit.Lex. Some strange error appears every time I try to use lex::_val in semantics actions in my simple lexer:

#ifndef _TOKENS_H_
#define _TOKENS_H_

#include <iostream>
#include <string>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_statement.hpp>
#include <boost/spirit/i开发者_开发百科nclude/phoenix_container.hpp>


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


enum tokenids 
{
    ID_IDENTIFICATOR = 1,
    ID_CONSTANT,
    ID_OPERATION,
    ID_BRACKET,
    ID_WHITESPACES
};

template <typename Lexer>
struct mega_tokens
    : lex::lexer<Lexer>
{

    mega_tokens()
        : identifier(L"[a-zA-Z_][a-zA-Z0-9_]*", ID_IDENTIFICATOR)
        , constant  (L"[0-9]+(\\.[0-9]+)?",     ID_CONSTANT     )
        , operation (L"[\\+\\-\\*/]",           ID_OPERATION    )
        , bracket   (L"[\\(\\)\\[\\]]",         ID_BRACKET      )
    {
        using lex::_tokenid;
        using lex::_val;
        using phx::val;

        this->self
                    = operation  [ std::wcout
                                       << val(L'<') << _tokenid
//                                     << val(L':') << lex::_val
                                       << val(L'>')
                                 ]
                    | identifier [ std::wcout
                                       << val(L'<') << _tokenid
                                       << val(L':') << _val
                                       << val(L'>')
                                 ]
                    | constant   [ std::wcout
                                       << val(L'<') << _tokenid
//                                     << val(L':') << _val
                                       << val(L'>')
                                 ]
                    | bracket    [ std::wcout
                                       << val(L'<') << _tokenid
//                                     << val(L':') << lex::_val
                                       << val(L'>')
                                 ]
            ;

    }

    lex::token_def<wchar_t,      wchar_t> operation;
    lex::token_def<std::wstring, wchar_t> identifier;
    lex::token_def<double,       wchar_t> constant;
    lex::token_def<wchar_t,      wchar_t> bracket;
};

#endif // _TOKENS_H_

and

#include <cstdlib>
#include <iostream>
#include <locale>
#include <boost/spirit/include/lex_lexertl.hpp>

#include "tokens.h"

int main()
{
    setlocale(LC_ALL, "Russian");

    namespace lex = boost::spirit::lex;

    typedef std::wstring::iterator base_iterator;
    typedef lex::lexertl::token <
        base_iterator,
        boost::mpl::vector<wchar_t, std::wstring, double, wchar_t>,
        boost::mpl::true_
    > token_type;
    typedef lex::lexertl::actor_lexer<token_type> lexer_type;
    typedef mega_tokens<lexer_type>::iterator_type iterator_type;

    mega_tokens<lexer_type> mega_lexer;

    std::wstring str = L"alfa+x1*(2.836-x2[i])";
    base_iterator first = str.begin();

    bool r = lex::tokenize(first, str.end(), mega_lexer);

    if (r) {
        std::wcout << L"Success" << std::endl;
    }
    else {
        std::wstring rest(first, str.end());
        std::wcerr << L"Lexical analysis failed\n" << L"stopped at: \"" 
            << rest << L"\"\n";
    }

    return EXIT_SUCCESS;
}

This code causes an error in Boost header 'boost/spirit/home/lex/argument.hpp' on line 167 while compiling:

return: can't convert 'const boost::variant' to 'boost::variant &'

When I don't use lex::_val program compiles with no errors.

Obviously, I use _val in wrong way, but I do not know how to do this correctly. Help, please! :)

P.S. And sorry for my terrible English…


I believe this is a problem in the current Phoenix related to using iostreams. As a workaround I suggest to define a custom (Phoenix) function doing the actual output:

struct output_operation_impl
{
    template <typename TokenId, typename Val>
    struct result { typedef void type; };

    template <typename TokenId, typename Val>
    void operator()(T1 const& tokenid, T2 const& val) const
    {
        std::wcout << L'<' << tokenid << L':' << val << L'>';
    }
};
boost::phoenix::function<output_operation_impl> const output_operation =
    output_operation_impl();

calling it as:

this->self = operation[ output_operation(_tokenid, _val) ] ... ;

Regards Hartmut

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜