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

Philipp Schwaha <[email protected]>
Newsgroups gmane.comp.parsers.spirit.general
Message-ID <[email protected]>
Hi Jens,

looking at this again I see that you only build a partial tree.
What I mean is that not all of the rules in the grammar (as well as the 
grammar itself) do not have attributes to expose the collected results.

Take a look at a further modified version of the code you provided. I 
added qi::debug statements and provided operater<< for expression_ast, 
binary_op and unary_op. Running it on the input "2+3" give the following:

<start>
   <try>[2][+][3]</try>
   <symsbols>
     <try>[2][+][3]</try>
     <expression>
       <try>[2][+][3]</try>
       <term>
         <try>[2][+][3]</try>
         <factor>
           <try>[2][+][3]</try>
           <success>[+][3]</success>
           <attributes>[expression_ast int value: 2]</attributes>
         </factor>
         <success>[+][3]</success>
         <attributes>[expression_ast int value: 2]</attributes>
       </term>
       <term>
         <try>[3]</try>
         <factor>
           <try>[3]</try>
           <success></success>
           <attributes>[expression_ast int value: 3]</attributes>
         </factor>
         <success></success>
         <attributes>[expression_ast int value: 3]</attributes>
       </term>
       <success></success>
       <attributes>[expression_ast op:+(int value: 2, int value: 
3)]</attributes>
     </expression>
     <success></success>
     <attributes>[]</attributes>
   </symsbols>
   <symsbols>
     <try></try>
     <expression>
       <try></try>
       <term>
         <try></try>
         <factor>
           <try></try>
           <fail/>
         </factor>
         <fail/>
       </term>
       <fail/>
     </expression>
     <fail/>
   </symsbols>
   <success></success>
   <attributes>[]</attributes>
</start>

So you can see that the values are put into attributes, but the 
'symbols' and 'start' rules do not have attributes. So there is no place 
to accumulate this information.

I think 'start' should have an attribute of std::vector<X> to 
accommodate the parse results, if 'symbols' has attribute type X.
Have a look at 
http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/operator.html 
the attributes due to operators.
The 'symbol' attribute is currently empty and apparently the 
'expression_ast' is not sufficient at this point, since it collides with 
the 'class_definition' attribute 'print_testclass'.

So this is a point where the value of the attribute stops propagating 
leading to the default constructed attribute you get on parsing success.

Hope this is helpful.

Cheers
	Philipp



On 07/17/2016 05:55 PM, Philipp Schwaha wrote:
> Hi Jens,
>
> On 07/15/2016 01:56 AM, Jens Kallup wrote:
>> 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?
>
> I noticed that you define a 'nil' type, but use qi::info::nil in the
> visitor. Is there a particular reason for this?
> I modified the code so it compiles for me (with both g++ and clang++ in
> c++11 mode). The visitor will not crash in this form.
> Did you have a look at
> http://www.boost.org/doc/libs/1_61_0/libs/spirit/doc/html/spirit/support/utree.html
> for representing the ast?
>
> Best regards
>     Philipp
>
>
>>
>> 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
>> _______________________________________________
>> Spirit-general mailing list
>> [email protected]
>> https://lists.sourceforge.net/lists/listinfo/spirit-general
>>
>
>
> ------------------------------------------------------------------------------
> 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
>
>
>
> _______________________________________________
> Spirit-general mailing list
> [email protected]
> https://lists.sourceforge.net/lists/listinfo/spirit-general
>

------------------------------------------------------------------------------
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

_______________________________________________
Spirit-general mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/spirit-general
test.cpp (text/x-c++src, 13.8 KB)

// #include "includes/mainwindow.h"

#define BOOST_SPIRIT_USE_PHOENIX_V3
#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/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/proto/proto.hpp>
//#include <boost/typeof/std/ostream.hpp>

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

//#include <boost/phoenix/bind/bind_member_function.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
                 , int
                 , boost::recursive_wrapper<expression_ast>
                 , boost::recursive_wrapper<binary_op>
                 , boost::recursive_wrapper<unary_op>
             >
         type;
         type expr;

         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);
     };

  
     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;
     }

     // 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()(nil) const {
           std::cerr << " empty " << std::endl ;
         }
         void operator()(int n) const {
           std::cout << "int value: " << n;
         }

         void operator()(expression_ast const& ast) const
         {
           cout << "-> "
                << ast.expr.type().name()
                << endl;

             boost::apply_visitor(*this, ast.expr);
         }

         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 StreamT>
     StreamT& operator<<(StreamT& out, expression_ast const& item) {
       out << "expression_ast " ;
       boost::apply_visitor(ast_print(), item.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 ;
     }

     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);

             qi::debug(start);
             qi::debug(symsbols);
             qi::debug(factor);
             qi::debug(term);
             qi::debug(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(std::string const& text)
{
     // std::string data(text.toStdString().c_str());
     std::string data(text) ;
     if (data.size() < 1) {
         // QMessageBox::information(0,"Error","No Data for parser.\nABORT.");
         std::cerr << "Error\n\tNo Data for parser.\nABORT.\n" ;
         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();

     expression_ast ast;
     ast_print  printer;

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

     if (r && iter == end) {
       // QMessageBox::information(w,"text parser","SUCCESS");
       std::cerr << "success\n\n" ;
       printer(ast);
     } else {
       // QMessageBox::information(w,"text parser","ERROR");
       std::cerr << "fail\n\n" ;
     }
     return 0;
}


int main() {
  parseText("2+3") ;
  return 0 ;
}
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.