2011-12-10 14 views
8

boost::spirit पर tutorials पढ़ने के बाद, मुझे इसे पार्सर संयोजक वाक्यविन्यास के कारण पसंद आया। एक पार्सर बनाना इतना आसान है।बढ़ावा से एएसटी पुनर्प्राप्त :: भावना पार्सर

दुर्भाग्य से, ट्यूटोरियल पार्सर से जटिल डेटा संरचना प्राप्त करने के मामले में सटीक नहीं थे। मैं Kaleidoscope 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 के निर्माता को कॉल करने का प्रयास कर रहे हैं। वे अच्छी तरह से मिश्रण नहीं करते हैं। आपको lazy callast::binary_op कन्स्ट्रक्टर का उपयोग करने की आवश्यकता है। इस फोनिक्स में 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) में बदल रही हैं इस प्रकार कोई विशेषता रही है।

मैं भी varname और number नियमों में लापता कोष्ठक की एक जोड़ी का उल्लेख किया:

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

बूस्ट आत्मा क्यूई बहुत शक्तिशाली है, लेकिन यह भी बहुत मुश्किल डिबग करने के लिए। जब मैंने इसका उपयोग करना शुरू किया, तो मुझे ये Boost Spirit Applications बहुत उपयोगी पाया।

मुझे आशा है कि यह सहायक होगा, क्योंकि मैं बूस्ट स्पिरिट विशेषज्ञ नहीं हूं।

+0

धन्यवाद कि 'निर्माण <>' वास्तव में बहुत सारी त्रुटियों को दूर कर लिया। अब मैं केवल एक के साथ छोड़ दिया गया है: 'parser.hpp: 38: 81: त्रुटि: 'boost :: spirit :: _ 1' का मान निरंतर अभिव्यक्ति में उपयोग करने योग्य नहीं है 'और' नोट: 'boost :: spirit :: _1 'घोषित नहीं किया गया' constexpr '। कोई मदद? – Lanbo

+0

ठीक है स्क्रैप कि, मैंने आपके समाधान को लिखने में गलती की है। धन्यवाद! – Lanbo

+0

उस आत्मा अनुप्रयोग लिंक में सूचीबद्ध कुछ महान उदाहरण स्रोत हैं, धन्यवाद! – rvalue

संबंधित मुद्दे