lexer, parser, skiper - 3 in one

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

lexer, parser, skiper - 3 in one

Jens Kallup
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
_______________________________________________
Spirit-general mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/spirit-general