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