2011-12-10 3 views
8

boost::spirit에있는 tutorials을 읽은 후에 파서 결합기 구문 때문에 매우 마음에 들었습니다. 파서 만들기가 너무 쉽습니다.boost :: spirit parser에서 AST 가져 오기

불행히도 튜토리얼은 파서에서 복잡한 데이터 구조를 가져 오는 문제와 정확히 일치하지 않았습니다. 나는 Kaleidoscope AST에 도착하려고 노력하고있다.

어쨌든, 여기 내 AST 코드 수 :

#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 

나는 BOOST_FUSION_ADAPT_STRUCT 부분을 생략했지만, 그들은있다.

그리고이 내 표현 파서 :

#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 

내가 가진 문제는 ast::expression을 결과에 문제가있는 것이다. 컴파일하면 복잡한 템플릿 오류가 200 줄 이상 발생합니다. 나는 이것이 내가 binop 규칙에서 정보를 얻으려고하는 방식과 관련이 있다고 의심하지만 확실하지 않다.

아무도 도와 줄 수 있습니까?

답변

7

부스트 피닉스 자리 표시자를 사용하여 ast::binary_op의 생성자를 호출하려고합니다. 그들은 잘 섞이지 않는다. ast::binary_op 생성자에 lazy call을 사용해야합니다. 이 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)] ; 

또한, 당신 만 _1_2 자리 표시자를 필요가 있다고 생각의 '+', '-'이 ... qi::lit (litteral)로 변환으로, 따라서 어떤 속성을 가지고하지 않습니다.

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

부스트 성령 제나라는 매우 강력하지만 또한 매우 어려운 디버깅에 :

는 또한 varnamenumber 규칙에서 누락 된 괄호의 몇 가지를 지적했다. 내가 그것을 사용하기 시작했을 때, 나는이 Boost Spirit Applications이 매우 유용하다는 것을 알았다.

부스트 스피릿 전문가가 아니기 때문에 이것이 도움이되기를 바랍니다.

+0

'construct <>'로 인해 많은 오류가 발생했습니다. 'parser.hpp : 38 : 81 : error : 'boost :: spirit :: _ 1'의 값을 상수 표현식에서 사용할 수 없습니다.''note : 'boost :: spirit :: _1 '은'constexpr '으로 선언되지 않았습니다. 어떤 도움이 필요합니까? – Lanbo

+0

좋아, 그 실수를 저질렀습니다. 감사! – Lanbo

+0

Spirit Applications 링크에는 멋진 예제 소스가 나열되어있어 감사합니다! – rvalue

관련 문제