2011-12-10 20 views
8

boost::spirit numaralı telefondan tutorials'u okuduktan sonra, çözümleyici birleştirici sözdizimi nedeniyle oldukça beğendim. Bir çözümleyici yapmak çok kolay. Ne yazık ki, eğiticiler ayrıştırıcıdan karmaşık bir veri yapısı elde etme konusunda kesin olarak doğru değildi. Kaleidoscope AST'a ulaşmaya çalışıyorum.AST'den yükseltme AST :: spirit ayrıştırıcı

Neyse, işte benim AST kodu olması:

#ifndef __AST_HPP__ 
#define __AST_HPP__ 

#include <boost/fusion/include/adapt_struct.hpp> 
#include <boost/variant/recursive_variant.hpp> 
#include <boost/lexical_cast.hpp> 
#include <boost/variant/apply_visitor.hpp> 
#include <string> 
#include <vector> 

namespace ast { 

struct add; 
struct sub; 
struct mul; 
struct div; 
struct func_call; 
template<typename OpTag> struct binary_op; 

typedef boost::variant<double, std::string, boost::recursive_wrapper<binary_op< 
     add>>, boost::recursive_wrapper<binary_op<sub>>, 
     boost::recursive_wrapper<binary_op<mul>>, boost::recursive_wrapper< 
       binary_op<div>>, boost::recursive_wrapper<func_call>> 
     expression; 

template<typename OpTag> 
struct binary_op { 
    expression left; 
    expression right; 

    binary_op(const expression & lhs, const expression & rhs) : 
     left(lhs), right(rhs) { 
    } 
}; 

struct func_call { 
    std::string callee; 
    std::vector<expression> args; 

    func_call(const std::string func, const std::vector<expression> &args) : 
     callee(func), args(args) { 
    } 
}; 

struct prototype { 
    std::string name; 
    std::vector<std::string> args; 

    prototype(const std::string &name, const std::vector<std::string> &args) : 
     name(name), args(args) { 
    } 
}; 

struct function { 
    prototype proto; 
    expression body; 

    function(const prototype &proto, const expression &body) : 
     body(body), proto(proto) { 
    } 
}; 

} 
    #endif 

Ben BOOST_FUSION_ADAPT_STRUCT parça ihmal ettik, ama onlar vardır.

Ve bu benim ifade ayrıştırıcı:

#ifndef __PARSER_HPP__ 
#define __PARSER_HPP__ 

#include <boost/config/warning_disable.hpp> 
#include <boost/spirit/include/qi.hpp> 
#include <boost/spirit/include/phoenix.hpp> 
#include <boost/fusion/include/adapt_struct.hpp> 

#include "ast.hpp" 

namespace parser { 

namespace qi = boost::spirit::qi; 
namespace ascii = boost::spirit::ascii; 
namespace phoenix = boost::phoenix; 

template<typename Iterator> 
struct expression: qi::grammar<Iterator, ast::expression(), ascii::space_type> { 
    expression() : 
     expression::base_type(expr) { 
     using qi::lit; 
     using qi::lexeme; 
     using ascii::char_; 
     using ascii::string; 
     using ascii::alnum; 
     using ascii::alpha; 
     using qi::double_; 
     using namespace qi::labels; 

     using phoenix::at_c; 
     using phoenix::push_back; 

     number %= lexeme[double_]; 
     varname %= lexeme[alpha >> *(alnum | '_')]; 

     binop 
       = (expr >> '+' >> expr)[_val = ast::binary_op<ast::add>(_1, _3)] 
         | (expr >> '-' >> expr)[_val 
           = ast::binary_op<ast::sub>(_1, _3)] 
         | (expr >> '*' >> expr)[_val 
           = ast::binary_op<ast::mul>(_1, _3)] 
         | (expr >> '/' >> expr)[_val 
           = ast::binary_op<ast::div>(_1, _3)]; 

     expr %= number | varname | binop; 
    } 

    qi::rule<Iterator, ast::expression(), ascii::space_type> expr; 
    qi::rule<Iterator, ast::expression(), ascii::space_type> binop; 
    qi::rule<Iterator, std::string, ascii::space_type> varname; 
    qi::rule<Iterator, double, ascii::space_type> number; 
}; 

} 

#endif 

Ben sorun ast::expression çıkan bir sorun var gibi görünüyor olmasıdır. Derlenmiş, 200'den fazla karmaşık şablon hatası çıkarır. Ben binop kuralından bilgi almak için çalıştı yolu ile bir şey olduğundan şüpheleniyorum, ama emin değilim.

Herkes yardımcı olabilir mi?

cevap

7

Boost Phoenix yer tutucularını kullanarak ast::binary_op yapıcısını çağırmaya çalışıyorsunuz. İyi karışmıyorlar. ast::binary_op yapıcısına bir lazy call kullanmanız gerekir. Bu construct kullanarak Phoenix sağlanır:

binop = (expr >> '+' >> expr) [_val = construct< ast::binary_op<ast::add> >(_1, _2)] 
     | (expr >> '-' >> expr) [_val = construct< ast::binary_op<ast::sub> >(_1, _2)] 
     | (expr >> '*' >> expr) [_val = construct< ast::binary_op<ast::mul> >(_1, _2)] 
     | (expr >> '/' >> expr) [_val = construct< ast::binary_op<ast::div> >(_1, _2)] ; 

Ayrıca, ben sadece _1 ve _2 tutucuları gerektiğini düşünüyorum, '+', '-' ... qi::lit (edebî) dönüştürülür olarak böylece hiçbir niteliğine sahip.

qi::rule<Iterator, std::string(), ascii::space_type> varname; 
//       ^^   
qi::rule<Iterator, double(), ascii::space_type> number; 
//      ^^ 

Boost Ruh Qi çok güçlüdür, ama aynı zamanda çok sert debug:

Ben de varname ve number kurallarda eksik parantez birkaç kaydetti. Kullanmaya başladığımda, bu Boost Spirit Applications'u çok yararlı buldum.

Umarım Boost Spirit uzmanı olmadığım için bu yardımcı olur.

+0

Yapın <> 'gerçekten çok fazla hata aldı. Şimdi sadece bir tane bırakıyorum: 'parser.hpp: 38: 81: hata: 'boost :: spirit :: _ 1' değeri sabit bir ifadede kullanılamaz ve not: 'boost :: spirit :: _1 '' constexpr 'olarak bildirilmedi. Herhangi bir yardım? – Lanbo

+0

Tamam, bu, çözümünüzü yazarken bir hata yaptım. Teşekkürler! – Lanbo

+0

Bu Ruh Uygulamaları linkinde listelenen bazı harika örnek kaynaklar var, teşekkürler! – rvalue