views:

126

answers:

1

Hello, everybody.

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/include/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…

A: 

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

hkaiser
Thank you, but nothing has changed. My Visual Studio 2008 still prints the same error.I've made few small corrections in your code. Maybe, this is the correct one: http://dumpz.org/19690/
GooRoo
I have placed all my code in single file and posted it here: http://pastebin.com/R0cdN8x8Thanks in advance.
GooRoo
Ok, seems you found a bug in Spirit.Lex. Thanks! I'll commit a fix later today to the Boost SVN trunk.
hkaiser
I had hoped until very recently that it was my bug. Anyway thank you for helping.
GooRoo
This is fixed in Boost SVN now. It was not a bug in Phoenix, but one in Spirit.Lex.
hkaiser