//  Copyright (c) 2001-2011 Hartmut Kaiser
// 
//  Distributed under the Boost Software License, Version 1.0. (See accompanying 
//  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// #define BOOST_SPIRIT_LEXERTL_DEBUG 1

#include <boost/config/warning_disable.hpp>

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

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

///////////////////////////////////////////////////////////////////////////////
template <typename Lexer>
struct language_tokens : lex::lexer<Lexer>
{
    language_tokens()
    {
        tok_float = "float";
        tok_int = "int";
        floatlit = "[0-9]+\\.[0-9]*";
        intlit = "[0-9]+";
        ws = "[ \t\n]+";
        identifier = "[a-zA-Z_][a-zA-Z_0-9]*";
      
        this->self = ws [lex::_pass = lex::pass_flags::pass_ignore];
        this->self += tok_float | tok_int | floatlit | intlit | identifier;
        this->self += lex::char_('=');
    }

    lex::token_def<> tok_float, tok_int;
    lex::token_def<> ws;
    lex::token_def<double> floatlit;
    lex::token_def<int> intlit;
    lex::token_def<> identifier;
};

///////////////////////////////////////////////////////////////////////////////
template <typename Iterator>
struct language_grammar : qi::grammar<Iterator>
{
    template <typename Lexer>
    language_grammar(language_tokens<Lexer> const& tok) 
      : language_grammar::base_type(declarations)
    {
        declarations = +number;
        number = 
                tok.tok_float >> tok.identifier >> '=' >> tok.floatlit
            |   tok.tok_int >> tok.identifier >> '=' >> tok.intlit
            ;

        declarations.name("declarations");
        number.name("number");
        debug(declarations);
        debug(number);
    }

    qi::rule<Iterator> declarations;
    qi::rule<Iterator> number;
};

///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
    // iterator type used to expose the underlying input stream
    typedef std::string::iterator base_iterator_type;

    // lexer type
    typedef lex::lexertl::actor_lexer<
        lex::lexertl::token<
            base_iterator_type, boost::mpl::vector2<double, int> 
        > > lexer_type;

    // iterator type exposed by the lexer 
    typedef language_tokens<lexer_type>::iterator_type iterator_type;

    // now we use the types defined above to create the lexer and grammar
    // object instances needed to invoke the parsing process
    language_tokens<lexer_type> tokenizer;           // Our lexer
    language_grammar<iterator_type> g (tokenizer);   // Our parser 

    // Parsing is done based on the token stream, not the character 
    // stream read from the input.
    std::string str ("float f = 3.4\nint i = 6\n");
    base_iterator_type first = str.begin();

    bool r = lex::tokenize_and_parse(first, str.end(), tokenizer, g);

    if (r) {
        std::cout << "-------------------------\n";
        std::cout << "Parsing succeeded\n";
        std::cout << "-------------------------\n";
    }
    else {
        std::string rest(first, str.end());
        std::cout << "-------------------------\n";
        std::cout << "Parsing failed\n";
        std::cout << "stopped at: \"" << rest << "\"\n";
        std::cout << "-------------------------\n";
    }

    std::cout << "Bye... :-) \n\n";
    return 0;
}
