boost::spirit - parser bau


jkallup

Erfahrenes Mitglied
Hallo,
ich habe Probleme beim Übersetzen dieses Codes.
was ist daran falsch?

C++:
#include <stdio.h>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <typeinfo>
#include <set>
#include <utility>

using namespace std;

#define  BOOST_VARIANT_USE_RELAXED_GET_BY_DEFAULT
#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/bind.hpp>
#include <boost/ref.hpp>

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;

#include <QString>
#include <QVariant>
#include <QMessageBox>

// ------------------------------------------------------
// namespace to avoid conflicts with other frameworks ...
// ------------------------------------------------------
namespace kallup
{
    int line_no  = 1;
    QString number, ident;
    double value = 0.00;    // math

    struct class_op;
    struct binary_op;
    struct unary_op;
    struct nil { };

    struct expression_ast
    {
        typedef
        boost::variant<
              nil
            , int
            , double
            , std::string
            , boost::recursive_wrapper<expression_ast>
            , boost::recursive_wrapper<binary_op>
            , boost::recursive_wrapper<unary_op>
            , boost::recursive_wrapper<class_op>
        >
        type;
        type expr;

        template <typename Expr>
        expression_ast(Expr const & expr)
            : expr(expr) {  }

        expression_ast() {}
        expression_ast(
                  std::string const& name
                , std::string const& str1
                , std::string const& str2
                , expression_ast const& rhs);

        expression_ast(expression_ast const & rhs, std::string const & name);

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

    expression_ast dast;
    struct binary_op
    {
        binary_op(
              char op
            , expression_ast const & left
            , expression_ast const & right)
            : op(op)
            , left(left)
            , right(right)
        {
            std::cout << "Math2: " << std::endl;
        }

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

    struct class_op
    {
        class_op(
              std::string const& op
            , std::string const& cname
            , std::string const& oname
            , expression_ast const& left
            , expression_ast const& right)
            : op(op)
            , class_cname(cname)
            , class_oname(oname)
            , left(left)
            , right(right) { }

        std::string op;
        std::string class_cname;
        std::string class_oname;

        expression_ast left;
        expression_ast right;
    };

    expression_ast::expression_ast(expression_ast const & rhs, std::string const & name) {
        cout << "dinit" << endl;
        cout << name << endl;
        cout << rhs.expr.type().name() << endl;

        expr = rhs;
    }

    expression_ast::expression_ast  (
              std::string const& name
            , std::string const& str1
            , std::string const& str2, expression_ast const& rhs) {
        expr = class_op(name, str1, str2, *this, rhs);
    }

    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 & expr) const {
            cout << "lllllllllllllllll\n";
            return expression_ast(unary_op('-', expr));
        }
    };

    phx::function<negate_expr> neg;

#if 0
    struct __addnumber
    {
        template <typename T>
        struct result { typedef T type; };

        expression_ast operator()(expression_ast const &_expr, std::string &namber) const
        {
            cout << "scene: " << endl;

            //dast = int(1);

            cout << "add number ok." << endl;

            //cout << _expr.expr.type().name() << endl;
            return expression_ast(int(1)); //binary_op('+', _expr, _expr));
        }
    };

    phx::function<__addnumber> _addnumber;
#endif

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

        void operator()(int const value)
        {
            cout << "const int = " << value << endl;
            dast = value;
            cout << dast.expr.type().name() << endl;
        }

        void operator()(expression_ast const& ast) const
        {
            //if (!(ast.expr.type().name() == std::string("N11dBaseParser3nilE")))
            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 << ')';
        }

        void operator()(class_op const& expr) const
        {
            std::cout << "class:"
                      << expr.class_cname << ":"
                      << expr.class_oname
                      << "(null)"
                      << std::endl;
            boost::apply_visitor(*this, expr.left.expr);
        }
    };

    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<lex::omit> my_assign;

        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   = "\\\?";
            my_assign = "\\=";

            // 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
                | my_assign
                | 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 & 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
                | h_expression
                ;

            h_expression
                = (tok.identifier   >> *comments
                >> tok.my_assign    >> *comments
                >> tok.number_digit >> *comments)
                ;

            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)
                ;
            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");
            h_expression.name("h_expression");
        }

        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, expression_ast()>
             expression, term, factor
           , h_expression
           , class_definition;
    };

    class expression { public:
          expression() { }

        typedef boost::variant<
          double
        , std::string
        >
        expression_type;
        expression_type expr;
    };


    class mystream {
    public:
        mystream() {
            m_filePtr = nullptr;
        }
        mystream(char* fileName, int mode) {
            try {
                m_filePtr = nullptr;
                open(fileName,mode);
            } catch (...) {
                std::cout << "can not open mem file.\n";
            }
        }
        ~mystream() {
            close();
        }
        void open(char* fileName, int mode) {
            if (m_filePtr != nullptr)
            fclose(m_filePtr);

            switch (mode)
            {
            case 0:
                m_filePtr = fopen(fileName, "wb");
                break;
            case 1:
                m_filePtr = fopen(fileName, "rb");
                break;
            }
        }

        void close() {
            if (!m_filePtr)
            fclose(m_filePtr);
        }

        void read(void *data, unsigned long size) {
            if (m_filePtr) {
                fread(data,1,size,m_filePtr);
            }
        }

        void write(const void *data, unsigned long size) {
            if (m_filePtr) {
                fwrite(data,1,size,m_filePtr);
            }
        }

    private:
        FILE *m_filePtr;
    };

    template <class T>
    inline mystream & operator << (mystream & s, T val) {
        s.write(&val,sizeof(T));
        return s;
    }

    template <class T>
    inline mystream & operator >> (mystream & s, T val) {
        s.read(&val,sizeof(T));
        return s;
    }

    template<class T>
    inline mystream & operator<<(mystream & s, const vector<T>& _arr)
    {
        s << (long)_arr.size();
        if (_arr.size() > 0) s.write(&_arr.front(), (unsigned long)sizeof(T)*_arr.size());
        return s;
    }

    template<class T>
    inline mystream & operator>>(mystream & s, vector<T>& _arr)
    {
        long size;
        s >> size;
        if (size > 0) {
            _arr.resize(size);
            s.read(&_arr.front(), (unsigned long)sizeof(T)*_arr.size());
        }
        return s;
    }

    // -----------------------------------
    // parser oode for an dBase parser ...
    // -----------------------------------
    class dBase {
    public:
        dBase() {
            std::cout << "handle dbase grammar..."
                      << std::endl;
        }
        bool InitParseText(QString text)
        {
            std::string data(text.toLatin1().data());
            if (data.size() < 1) {
                throw QString("No data for parser.");
                return false;
            }

            typedef std::string::iterator base_iterator_type;
            typedef lex::lexertl::token<  base_iterator_type, boost::mpl::vector<char, int, std::size_t, std::string> > tokentype;
            typedef lex::lexertl::actor_lexer<tokentype> lexer_type;

            typedef dbase_tokens<lexer_type> dbase_tokens;
            typedef dbase_tokens::iterator_type iterator_type;
            typedef 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;
            return qi::parse(iter, end, dbase, ast);
        }
        void start(QString src)  {
            if (InitParseText(src)) {
                QMessageBox::information(0,"Info","SUCCESS");
                //ast_print printer;
                //printer(dast);
            } else {
                QMessageBox::critical(0,"Error","ERROR");
            }
        }
    };

    template   <typename T>
    class Parser: public T {
    public:
        Parser() {
            std::cout << "parser init." << std::endl;
            line_no = 1;

            ident .clear();
            number.clear();
        }
    };
}

// int main() {
bool parseText(QString src)
{
    using namespace kallup;

    try {
        Parser<dBase> p;
        p.start(src);

        QMessageBox::information(0,"Info","SUCCESS");
        return true;
    }
    catch (QString &e) {
        QMessageBox::critical(0,"Error",
        QString("Error in line: %1\n%2")
        .arg(line_no)
        .arg(e));
    }
    return false;
}
 
Zuletzt bearbeitet von einem Moderator:

Neue Beiträge

Forum-Statistiken

Themen
272.361
Beiträge
1.558.639
Mitglieder
187.834
Neuestes Mitglied
jordanx0206