lexer, parser, skiper - 3 in one

Jens Kallup <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Hello,

what is wrong with the code?

I would like to have
- a lexer
- a parser, and
- a skipper

Is it not possible to get together all?
Thanks for helping.

Jens

#define BOOST_SPIRIT_DEBUG
#define BOOST_SPIRIT_ACTIONS_ALLOW_ATTR_COMPAT

#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <boost/spirit/include/phoenix_container.hpp>
#include <boost/spirit/include/phoenix_function.hpp>
#include <boost/spirit/include/qi_eoi.hpp>
#include <boost/spirit/include/qi_skip.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/fusion/include/std_pair.hpp>
#include <boost/variant/recursive_variant.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/get.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/lexical_cast.hpp>

#include <boost/bind.hpp>
#include <boost/ref.hpp>

#include <iostream>
#include <fstream>
#include <string>
#include <exception>
#include <typeinfo>
#include <set>
#include <utility>
#include <vector>

#define USE_QT
#ifdef USE_QT
#include <QMessageBox>
#endif

using namespace std;
using namespace boost::spirit;

namespace client
{
     namespace fusion = boost::fusion;
     namespace phoenix = boost::phoenix;

     namespace qi = boost::spirit::qi;
     namespace ascii = boost::spirit::ascii;

     struct binary_op;
     struct unary_op;
     struct nil {};

     struct expression_ast
     {
         typedef
             boost::variant<
             nil // can't happen!
             , double
             , std::string
             , boost::recursive_wrapper<expression_ast>
             , boost::recursive_wrapper<binary_op>
             , boost::recursive_wrapper<unary_op>
             >
             type;

         expression_ast()
             : m_expr(nil()) {}

         template <typename Expr>
             expression_ast(Expr const& expr)
             : m_expr(expr) {}

         expression_ast& operator+=(expression_ast const& rhs);
         expression_ast& operator-=(expression_ast const& rhs);
         expression_ast& operator*=(expression_ast const& rhs);
         expression_ast& operator/=(expression_ast const& rhs);

         type m_expr;
     };

     struct binary_op
     {
         binary_op(
                 char op
                 , expression_ast const& left
                 , expression_ast const& right)
             : m_op(op), m_left(left), m_right(right) {}

         char m_op;
         expression_ast m_left;
         expression_ast m_right;
     };

     struct unary_op
     {
         unary_op(
                 char op
                 , expression_ast const& subject)
             : m_op(op), m_subject(subject) {}

         char m_op;
         expression_ast m_subject;
     };

     expression_ast& expression_ast::operator+=(expression_ast const& rhs)
     {
         m_expr = binary_op('+', m_expr, rhs);
         return *this;
     }

     expression_ast& expression_ast::operator-=(expression_ast const& rhs)
     {
         m_expr = binary_op('-', m_expr, rhs);
         return *this;
     }

     expression_ast& expression_ast::operator*=(expression_ast const& rhs)
     {
         m_expr = binary_op('*', m_expr, rhs);
         return *this;
     }

     expression_ast& expression_ast::operator/=(expression_ast const& rhs)
     {
         m_expr = binary_op('/', m_expr, rhs);
         return *this;
     }


     struct ast_print
     {
         typedef std::string result_type;

         std::string operator()(nil()) const
         {
             return "";
         }
         std::string operator()(std::string const& str) const
         {
             return str;
         }
         std::string operator()(double d) const
         {
             std::ostringstream oss;
             oss << d;
             return oss.str();
         }

         std::string operator()(expression_ast const& ast) const
         {
             return boost::apply_visitor(*this, ast.m_expr);
         }

         std::string operator()(binary_op const& expr) const
         {
             std::ostringstream oss;
             oss << "op:" << expr.m_op << "(";
             oss << boost::apply_visitor(*this, expr.m_left.m_expr);
             oss << ", ";
             oss << boost::apply_visitor(*this, expr.m_right.m_expr);
             oss << ')';
             return oss.str();
         }

         std::string operator()(unary_op const& expr) const
         {
             std::ostringstream oss;
             oss << "op:" << expr.m_op << "(";
             oss << boost::apply_visitor(*this, expr.m_subject.m_expr);
             oss << ')';
             return oss.str();
         }
     };

     std::ostream& operator << (std::ostream& stream, const 
expression_ast& expr)
     {
         ast_print printer;
         stream << printer(expr) << std::endl;
         return stream;
     }

     template<typename StreamT>
     StreamT& operator<<(StreamT& out, expression_ast const& item) {
       out << "expression_ast " ;
       boost::apply_visitor(ast_print(), item.m_expr) ;
       return out ;
     }
     template<typename StreamT>
     StreamT& operator<<(StreamT& out, binary_op const& item) {
         out << "binary_op" << std::endl ;
         return out ;
     }
     template<typename StreamT>
     StreamT& operator<<(StreamT& out, unary_op const& item) {
         out << "unary_op" << std::endl ;
         return out ;
     }

     expression_ast expr;

     template <typename Lexer>
     struct dbase_tokens : lex::lexer<Lexer>
     {
         // ----------------------------
         // tokens with no attributes...
         // ----------------------------
         lex::token_def<lex::omit> kw_class;
         lex::token_def<lex::omit> kw_of;
         lex::token_def<lex::omit> kw_endclass;

         lex::token_def<lex::omit> kw_this;
         lex::token_def<lex::omit> kw_ident;

         dbase_tokens()
         {
             // ------------
             // keywords ...
             // ------------
             kw_class        = "(?i:class)";
             kw_endclass     = "(?i:endclass)";
             kw_of           = "(?i:of)";

             kw_this         = "(?i:this)";

             kw_ident        = "(?i:[a-z0-9_])";

             this->self +=
                 kw_class | kw_of | kw_endclass | kw_this | kw_ident
                 ;
         }
     };

     template <typename Iterator>
     struct dbase_skipper : public qi::grammar<Iterator>
     {
         dbase_skipper() : dbase_skipper::base_type(my_skip, "dBase")
         {
             using qi::ascii::char_;
             using qi::ascii::space;
             using qi::eol;
             using qi::eoi;

             my_skip = (char_("[ \t\n\r]"))                            |
             ("**" >> *(char_ - eol) >> (eol | eoi | char_("[\n\r]"))) |
             ("&&" >> *(char_ - eol) >> (eol | eoi | char_("[\n\r]"))) |
             ("//" >> *(char_ - eol) >> (eol | eoi | char_("[\n\r]"))) |
             ("/*" >> *(char_ - "*/") >> "*/")
             ;

             BOOST_SPIRIT_DEBUG_NODE((my_skip));
         }
         qi::rule<Iterator> my_skip;
     };

     template <
             typename Iterator,
             typename Lexer,
             typename Skipper = dbase_skipper<Iterator>
             >
     struct dbase_grammar : public qi::grammar<Iterator, Skipper>
     {
         qi::rule<Iterator, Skipper> start;
         qi::rule<Iterator, Skipper> block;
         qi::rule<Iterator, Skipper> statement;

         template <typename TokenDef>
         dbase_grammar(TokenDef const& tok) :
         dbase_grammar::base_type(start, "start")
         {
             using qi::lit;
             using qi::char_;
             using qi::lexeme;

             using qi::on_error;
             using qi::fail;

             using phoenix::construct;
             using phoenix::val;


             start = +symbol;

             expression =
                     term
                     >> *(
                       ('+' >> term )
                     | ('-' >> term ))
                     ;
             term =
                     factor
                     >> *(
                       ('*' >> factor )
                     | ('/' >> factor ))
                     ;

             factor =
                     '(';
             /*
                     ( symbol_digit
                     ///| symbol_alpha
                     )
                     >> *(
                     ('('   >> expression >> ')')
                     | ('-' >> factor     )
                     | ('+' >> factor     ))
                     ;*/

             symbol =
                 (tok.kw_class >> tok.kw_ident >>
                  tok.kw_of    >> tok.kw_ident >> tok.kw_endclass)
                 //|
                 //(symbol_alpha >> qi::char_('=') >> expression)
                 ;

             on_error<fail>
             (
                 start
               , std::cout
                     << val("Error! Expecting ")
                     << std::endl

                     //<< _4                               // what failed?
                     //<< val(" here: \"")
                     //<< construct<std::string>(_3, _2)   // iterators 
to error-pos, end
                     ///<< val("\"")
                     //<< std::endl
             );


             BOOST_SPIRIT_DEBUG_NODE(start);
             BOOST_SPIRIT_DEBUG_NODE(symbol);
             BOOST_SPIRIT_DEBUG_NODE(symbol_space);
             BOOST_SPIRIT_DEBUG_NODE(symbol_alpha);

             BOOST_SPIRIT_DEBUG_NODE(expression);
             BOOST_SPIRIT_DEBUG_NODE(term);
             BOOST_SPIRIT_DEBUG_NODE(factor);
         }

         qi::rule<Iterator, Skipper>
         symbol,
         symbol_alpha,
         symbol_space;

         qi::rule<Iterator, expression_ast(), Skipper> expression, term, 
factor;
     };
}

bool my_parser(std::string &str)
{
     namespace qi = boost::spirit::qi;

     using namespace client;

     typedef std::string::iterator base_iterator_type;
     typedef lex::lexertl::token<  base_iterator_type, 
boost::mpl::vector<char, int, std::size_t, std::string>> token_type;
     typedef lex::lexertl::actor_lexer<token_type> lexer_type;

     typedef dbase_tokens<lexer_type>     dbase_tokens;
     typedef dbase_tokens::iterator_type iterator_type;
     typedef dbase_skipper<iterator_type> dbase_skipper;
     typedef dbase_grammar<iterator_type, dbase_tokens::lexer_def, 
dbase_skipper> dbase_grammar;


     dbase_tokens  tokens;
     dbase_grammar pg(tokens);

     base_iterator_type it = str.begin();
     iterator_type iter    = tokens.begin(it, str.end());
     iterator_type end     = tokens.end();

     expression_ast ast;

     bool r = qi::parse(iter, end, pg, ast);
     if (r == true) {
         #ifdef USE_QT
         QMessageBox::information(0,"Parser", "Parsing SUCCESS.");
         #else
         std::cout << "SUCCESS" << std::endl;
         #endif
         return true;
     }

     if (iter != end) {
         std::cout << "Remaining: '" << std::string(iter, end) << std::endl;
         #ifdef USE_QT
         QMessageBox::information(0,"Parser", "Parsing ERROR.");
         #else
         std::cout << "ERROR" << std::endl;
         #endif
         return false;
     }   return false;
}

bool parseText(std::string str, int mode)
{
     return my_parser(str);
}

------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most 
engaging tech sites, SlashDot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.