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