Boost::Spirit: Application SUCCESS, crash at: printer(ast) ... why?

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

I have the problem, that the visitor does endless
loop, and crash after a while.
The problem is on:

void operator()(expression_ast const& ast) const
{
   boost::apply_visitor(*this, ast.expr);
}

How can this be fixed?

Thanks for helping
Jens

here the run/compileable source:

#include "includes/mainwindow.h"

#define BOOST_SPIRIT_USE_PHOENIX_V3
#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/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 <set>
#include <utility>

int lineno = 1;


using namespace std;
using namespace boost::spirit;

namespace bs    = boost::spirit;
namespace phx   = boost::phoenix;
namespace ascii = boost::spirit::ascii;

using boost::spirit::ascii::space; // use the ASCII space parser
using boost::spirit::ascii::char_;
using boost::spirit::_val;

using boost::phoenix::val;

struct print_testclass
{
     print_testclass() {}
     print_testclass(std::string str1, std::string str2)
     {
         cout << str1 << " = " << str2 << endl;
     }
};

namespace dBaseParser
{
     // -----------------
     // AST for dBase ...
     // -----------------
     struct binary_op;
     struct unary_op;
     struct nil {};

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

         expression_ast()
           : expr(nil()) {}

         template <typename Expr>
         expression_ast(Expr const& expr) : 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 expr;
     };

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

         char op;
         expression_ast left;
         expression_ast right;
     };

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

         char op;
         expression_ast subject;
     };

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

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

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

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

     std::ostream& operator << (std::ostream& os, const expression_ast& as)
     {
         return os
                 << boost::get<binary_op>(as.expr).left
                 //<< " = "
                 //<< boost::get<binary_op>(as.expr).right;
                 << endl;
     }

     // ------------------------------------------------------------
     // We should be using expression_ast::operator-. There's a bug
     // in phoenix type deduction mechanism that prevents us from
     // doing so. Phoenix will be switching to BOOST_TYPEOF. In the
     // meantime, we will use a phoenix::function below:
     // ------------------------------------------------------------
     struct negate_expr
     {
         template <typename T>
         struct result { typedef T type; };

         expression_ast operator()(expression_ast const& expr) const
         {
             return expression_ast(unary_op('-', expr));
         }
     };

     boost::phoenix::function<negate_expr> neg;

     // -----------------------
     // walk throug the AST ...
     // -----------------------
     struct ast_print
     {
         typedef void result_type;

         void operator()(qi::info::nil) const {}
         void operator()(int n) const { std::cout << n; }

         void operator()(expression_ast const& ast) const
         {
             boost::apply_visitor(*this, ast.expr);

             //int i = boost::get<int>(ast.expr);
             //cout << "1 = " << (int)i << endl;
         }

         void operator()(binary_op const& expr) const
         {
             std::cout << "op:" << expr.op << "(";
             boost::apply_visitor(*this, expr.left.expr);
             std::cout << ", ";
             boost::apply_visitor(*this, expr.right.expr);
             std::cout << ')';
         }

         void operator()(unary_op const& expr) const
         {
             std::cout << "op:" << expr.op << "(";
             boost::apply_visitor(*this, expr.subject.expr);
             std::cout << ')';
         }
     };

     template <typename Lexer>
     struct dbase_tokens : lex::lexer<Lexer>
     {
         // ----------------------------
         // tokens with no attributes...
         // ----------------------------
         lex::token_def<lex::omit> whitespace;
         lex::token_def<lex::omit> cpcomment;
         lex::token_def<lex::omit> d_comment;
         lex::token_def<lex::omit> c_comment;

         lex::token_def<lex::omit> kw_class;
         lex::token_def<lex::omit> kw_of;
         lex::token_def<lex::omit> kw_endclass;

         // --------------------------
         // tokens with attributes ...
         // --------------------------
         lex::token_def<char> printLn;

         lex::token_def<int>         number_digit;
         lex::token_def<std::string> identifier;
         lex::token_def<std::string> quoted_string;

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

             printLn   = "\\\?";

             // Values.
             number_digit      = "[0-9]+";
             quoted_string     = "\\\"(\\\\.|[^\\\"])*\\\""; // 
\"(\\.|[^\"])*\"

             // Identifier.
             identifier        = "[a-zA-Z][a-zA-Z0-9_]*";

             cpcomment = "\\/\\/[^\\n]*\\n";                    // 
single line comment
             d_comment = "\\*\\*[^\\n]*\\n";                    // 
dBase  line comment
             c_comment = "\\/\\*[^*]*\\*+([^/*][^*]*\\*+)*\\/"; // 
c-style comments

             whitespace = "[ \\t\\n]+";

             this->self += lex::token_def<>
                     ('(') | ')'
                     | '+' | '-'
                     | '*' | '/'
                     | ',' | '.';
             this->self +=
                 printLn
                 ;
             this->self +=
                 kw_class | kw_of | kw_endclass
                 ;
             this->self +=
                   identifier
                 | number_digit
                 | quoted_string
                 ;

             this->self +=
                   whitespace [ lex::_pass = lex::pass_flags::pass_ignore ]
                 | cpcomment
                 | c_comment
                 | d_comment
                 ;
         }
     };

     template <typename Iterator, typename Lexer>
     struct dbase_grammar
     :   public qi::grammar<Iterator>
     {   template <typename TokenDef>

         dbase_grammar(TokenDef const& tok) :
         dbase_grammar::base_type(start, "start")
         {
             using qi::_val;

             start
                 = +symsbols
                 ;

             expression =
                 term                            [_val  = qi::_1]
                 >> *(   ('+' >> term            [_val += qi::_1])
                     |   ('-' >> term            [_val -= qi::_1])
                     )
                 ;

             term =
                 factor                          [_val  = qi::_1]
                 >> *(   ('*' >> factor          [_val *= qi::_1])
                     |   ('/' >> factor          [_val /= qi::_1])
                     )
                 ;

             factor =
                 tok.number_digit                [_val = qi::_1]
                 |  '('   >> expression          [_val = qi::_1] >> ')'
                 |   ('-' >> factor              [_val = neg(qi::_1)])
                 |   ('+' >> factor              [_val = qi::_1])
                 ;

             symsbols
                 = printLn
                 | comments
                 | class_definition
                 | expression
                 ;

             comments
                 = tok.cpcomment
                 | tok.c_comment
                 | tok.d_comment
                 ;

             printLn
                 = tok.printLn >> *comments >> tok.quoted_string
                 | tok.printLn >> tok.quoted_string
                 ;

             class_definition
                 = (tok.kw_class          >> *comments
                     >> tok.identifier    >> *comments
                     >> tok.kw_of         >> *comments
                     >> tok.identifier    >> *comments >> class_body
                     >> tok.kw_endclass)
                     [
                         qi::_val = phx::construct<print_testclass>(
                         phx::construct<std::string>(qi::_1),
                         phx::construct<std::string>(qi::_2))
                     ]
                 ;
             class_body
                 = *comments
                 ;

             start.name("start");
             symsbols.name("symsbols");
             comments.name("comments");
             expression.name("expression");
             term.name("term");
             factor.name("factor");
             printLn.name("printLn");
             class_definition.name("class_definition");
             class_body.name("class_body");

             BOOST_SPIRIT_DEBUG_NODE(start);
             BOOST_SPIRIT_DEBUG_NODE(symsbols);
             BOOST_SPIRIT_DEBUG_NODE(comments);
             BOOST_SPIRIT_DEBUG_NODE(printLn);
             BOOST_SPIRIT_DEBUG_NODE(class_definition);
             BOOST_SPIRIT_DEBUG_NODE(class_body);
             BOOST_SPIRIT_DEBUG_NODE(factor);
             BOOST_SPIRIT_DEBUG_NODE(term);
             BOOST_SPIRIT_DEBUG_NODE(expression);

             using namespace qi::labels;
             qi::on_error<qi::fail>
             (
                 start,
                 std::cout
                     << phx::val("Error! Expecting ")
                     << bs::_4 // what failed?
                     << phx::val(" here: \"")
                     << phx::construct<std::string>(bs::_3, bs::_2)   // 
iterators to error-pos, end
                     << phx::val("\"")
                     << std::endl
             );
         }

         typedef qi::unused_type skipper_type;
         typedef qi::rule<Iterator, skipper_type> simple_rule;

         simple_rule start, symsbols, comments, printLn;
         simple_rule class_body;

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

bool parseText(QString text)
{
     std::string data(text.toStdString().c_str());
     if (data.size() < 1) {
         QMessageBox::information(0,"Error","No Data for parser.\nABORT.");
         return false;
     }

     using dBaseParser::expression_ast;
     using dBaseParser::ast_print;

     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 dBaseParser::dbase_tokens<lexer_type> dbase_tokens;
     typedef dbase_tokens::iterator_type iterator_type;
     typedef dBaseParser::dbase_grammar<iterator_type, 
dbase_tokens::lexer_def> dbase_grammar;

     dbase_tokens  tokens;
     dbase_grammar dbase(tokens);

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

     dBaseParser::expression_ast ast;
     dBaseParser::ast_print  printer;

     bool r = qi::parse(iter, end, dbase, ast);

     if (r && iter == end) {
         QMessageBox::information(w,"text parser","SUCCESS"); 
printer(ast); } else
         QMessageBox::information(w,"text parser","ERROR");

     return 0;
}


------------------------------------------------------------------------------
What NetFlow Analyzer can do for you? Monitors network bandwidth and traffic
patterns at an interface-level. Reveals which users, apps, and protocols are 
consuming the most bandwidth. Provides multi-vendor support for NetFlow, 
J-Flow, sFlow and other flows. Make informed decisions using capacity planning
reports.http://sdm.link/zohodev2dev
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.