2011-12-10 32 views
8

Sau khi tôi đã đọc tutorials trên boost::spirit, tôi rất thích nó vì cú pháp trình kết hợp phân tích cú pháp. Làm cho một trình phân tích cú pháp rất dễ dàng.Lấy AST khỏi tăng :: trình phân tích cú pháp tinh thần

Thật không may, các hướng dẫn không chính xác về vấn đề lấy cấu trúc dữ liệu phức tạp ra khỏi trình phân tích cú pháp. Tôi đang cố gắng truy cập vào Kaleidoscope AST.

Dù sao, đây là mã AST tôi:

#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 

Tôi đã bỏ qua BOOST_FUSION_ADAPT_STRUCT phần, nhưng họ đang có.

Và đây phân tích cú pháp biểu hiện của tôi:

#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 

Tôi có vấn đề là nó dường như có một vấn đề với các kết quả ast::expression. Các biên dịch ném ra hơn 200 dòng lỗi mẫu phức tạp. Tôi nghi ngờ nó là một cái gì đó với cách tôi đã cố gắng để có được thông tin trong số các quy tắc binop, nhưng tôi không chắc chắn.

Có ai giúp được không?

Trả lời

7

Bạn đang cố gắng gọi hàm tạo của ast::binary_op bằng trình giữ chỗ Boost Phoenix. Chúng không trộn đều. Bạn cần sử dụng một số lazy call cho hàm tạo ast::binary_op. Này được cung cấp ở Phoenix bằng cách sử dụng construct:

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

Ngoài ra, tôi nghĩ rằng bạn chỉ cần _1_2 placeholders, như '+', '-' ... được chuyển đổi thành qi::lit (litteral) do đó không có thuộc tính.

Tôi cũng lưu ý một vài ngoặc thiếu trong varnamenumber quy tắc:

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

Boost Thần Qi là rất mạnh mẽ, nhưng cũng rất khó để gỡ lỗi. Khi tôi bắt đầu sử dụng nó, tôi thấy những Boost Spirit Applications rất hữu ích.

Tôi hy vọng điều này sẽ hữu ích vì tôi không phải là chuyên gia về Tăng cường tinh thần.

+0

Cảm ơn 'kiến trúc <>' thực sự đã loại bỏ rất nhiều lỗi. Bây giờ tôi chỉ còn lại một: 'parser.hpp: 38: 81: error: giá trị của 'boost :: spirit :: _ 1' không thể sử dụng trong một biểu thức liên tục' và' note: 'boost :: spirit :: _1 'không được khai báo' constexpr''. Bất kỳ giúp đỡ? – Lanbo

+0

Ok mẩu tin lưu niệm đó, tôi đã nhầm lẫn khi viết ra giải pháp của bạn. Cảm ơn! – Lanbo

+0

Liên kết Ứng dụng Thần linh đó có một số nguồn ví dụ tuyệt vời được liệt kê, cảm ơn! – rvalue

Các vấn đề liên quan