2013-02-15 93 views
0

我想要做的是,在預處理類似於 boost :: wave(我實際上正在處理glsl文件)的c文件的過程中,而不是從磁盤加載 包含的文件,我想要從map中加載它們,其中map.first是文件名,map.second是內容。Boost Wave自定義輸入策略

我需要爲輸入策略的內部類別提供這些文件名/文件內容的地圖。但是,我不知道我怎樣才能真正得到一個 映射到內部類...

的上下文中創建像這樣:

typedef boost::wave::context< 
       std::string::iterator, 
       lex_iterator_type, 
       custom_directives_hooks::load_file_or_string_to_string, 
       custom_directives_hooks 
      > context_type; 

和自定義指令是像這樣(與自定義輸入策略定義在底部附近):

#if !defined(BOOST_WAVE_CUSTOM_DIRECTIVES_HOOKS_INCLUDED) 
#define BOOST_WAVE_CUSTOM_DIRECTIVES_HOOKS_INCLUDED 

#include <cstdio> 
#include <iostream> 
#include <ostream> 
#include <string> 
#include <algorithm> 
#include <map> 

#include <boost/assert.hpp> 
#include <boost/config.hpp> 

#include <boost/wave/token_ids.hpp> 
#include <boost/wave/util/macro_helpers.hpp> 
#include <boost/wave/preprocessing_hooks.hpp> 
#include <boost/wave/cpp_iteration_context.hpp> 

#include <iterator> 
#include <fstream> 
#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS) 
#include <sstream> 
#endif 

#include <boost/wave/wave_config.hpp> 
#include <boost/wave/cpp_exceptions.hpp> 
#include <boost/wave/language_support.hpp> 
#include <boost/wave/util/file_position.hpp> 

namespace wave = boost::wave; 

class custom_directives_hooks 
: public wave::context_policies::default_preprocessing_hooks 
{ 
public: 

    custom_directives_hooks(std::map<std::string, std::string> files) : files_(files) { 
    } 

    //custom_directives_hooks(std::set<std::string> &files_) : files(files_), include_depth(0) { 
    //} 

    template <typename ContextT, typename ContainerT> 
    bool 
    found_unknown_directive(ContextT const& ctx, ContainerT const& line, 
     ContainerT& pending) 
    { 
     typedef typename ContainerT::const_iterator iterator_type; 
     iterator_type it = line.begin(); 
     wave::token_id id = wave::util::impl::skip_whitespace(it, line.end()); 

     if (id != wave::T_IDENTIFIER) 
      return false;  // nothing we could do 

     if ((*it).get_value() == "version" || (*it).get_value() == "extension") { 
      // Handle #version and #extension directives 
      std::copy(line.begin(), line.end(), std::back_inserter(pending)); 
      return true; 
     } 

     if ((*it).get_value() == "type") { 
      // Handle type directive 
      return true; 
     } 

     // Unknown directive 
     return false; 
    } 


#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 
    void opened_include_file(std::string const &relname, std::string const &filename, 
     std::size_t /*include_depth*/, bool is_system_include) 
#else 
    template <typename ContextT> 
    void opened_include_file(ContextT const& ctx, std::string const& relname, 
     std::string const& filename, bool is_system_include) 
#endif 
    { 
     std::cout << "opened_include_file: " << "relname: " << relname << " filename: " << filename << " is_system_include: " << is_system_include << std::endl; 
     /* 
     std::set<std::string>::iterator it = files.find(filename); 

     if (it == files.end()) { 
      // print indented filename 
      for (std::size_t i = 0; i < include_depth; ++i) 
       std::cout << " "; 
      std::cout << filename << std::endl; 

      files.insert(filename); 
     } 
     ++include_depth; 
     */ 
    } 

#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 
    void returning_from_include_file() 
#else 
    template <typename ContextT> 
    void returning_from_include_file(ContextT const& ctx) 
#endif 
    { 
     //--include_depth; 
    } 

#if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0 
    // old signature 
    void 
    found_include_directive(std::string const& filename, bool include_next) 
    {} 
#else 
    // new signature 
    template <typename ContextT> 
    bool 
    found_include_directive(ContextT const& ctx, std::string const& filename, bool include_next) { 
     std::cout << "found_include_directive:" << filename << std::endl; 

     return false; // ok to include this file 
    } 
#endif 


    template <typename ContextT> 
    bool 
    locate_include_file(ContextT& ctx, std::string &file_path, 
     bool is_system, char const *current_name, std::string &dir_path, 
     std::string &native_name) 
    { 
     // Check if file is in the files map 
     if (files_.find(file_path) != files_.end()) { 
      std::cout << "locate_include_file: file_path:" << file_path << " dir_path:" << dir_path << " native_name:" << native_name << std::endl; 
      native_name = file_path; 
     } else { 
      if (!ctx.find_include_file (file_path, dir_path, is_system, current_name)) 
       return false; // could not locate file 

      namespace fs = boost::filesystem; 

      fs::path native_path(wave::util::create_path(file_path)); 
      if (!fs::exists(native_path)) { 
       //BOOST_WAVE_THROW_CTX(ctx, preprocess_exception, bad_include_file, 
       // file_path.c_str(), ctx.get_main_pos()); 
       std::cout << "error: doesn't exist" << std::endl; 
       return false; 
      } 

      // return the unique full file system path of the located file 
      native_name = wave::util::native_file_string(native_path); 
     } 

     typedef typename ContextT::iterator_type iterator_type; 
     std::streambuf* buffer = nullptr; 
     wave::language_support language(); 

     ctx.instring.assign(
      std::istreambuf_iterator<char>(buffer), 
      std::istreambuf_iterator<char>()); 

     ctx.first = iterator_type(
      ctx.instring.begin(), ctx.instring.end(), 
      PositionT(ctx.filename), language); 
     ctx.last = iterator_type(); 

     return true;  // include file has been located successfully 
    } 

    struct load_file_or_string_to_string 
    {  
     template <typename IterContextT> 
     class inner 
     { 
     public:  
      template <typename PositionT> 
      static void init_iterators(IterContextT &iter_ctx, 
       PositionT const &act_pos, wave::language_support language) 
      { 
       static std::map<std::string, std::string> theFiles; 

       typedef typename IterContextT::iterator_type iterator_type; 

       std::cout << "init_iterators: " << iter_ctx.filename << std::endl; 

       std::streambuf* buffer = nullptr; 

       const char* cString = iter_ctx.filename.c_str(); 

       if (theFiles.find(std::string(cString)) != theFiles.end()) { 
        std::stringstream ss(theFiles[std::string(cString)]); 
        buffer = ss.rdbuf(); 
       } else { 
        // read in the file 
        std::ifstream instream(iter_ctx.filename.c_str()); 
        if (!instream.is_open()) { 
         //BOOST_WAVE_THROW_CTX(iter_ctx.ctx, wave::preprocess_exception, 
         // wave::bad_include_file, iter_ctx.filename.c_str(), act_pos); 
         std::cout << "error: not open" << std::endl; 
         return; 
        } 
        instream.unsetf(std::ios::skipws); 
        buffer = instream.rdbuf(); 
       } 

       iter_ctx.instring.assign(
        std::istreambuf_iterator<char>(buffer), 
        std::istreambuf_iterator<char>()); 

       iter_ctx.first = iterator_type(
        iter_ctx.instring.begin(), iter_ctx.instring.end(), 
        PositionT(iter_ctx.filename), language); 
       iter_ctx.last = iterator_type(); 
      } 

     private: 
      std::string instring; 
     }; 
    }; 

    std::map<std::string, std::string> files_; 
}; 

#endif // !defined(BOOST_WAVE_ADVANCED_PREPROCESSING_HOOKS_INCLUDED) 

有沒有人有任何建議?

回答

0

我能夠通過爲內部類之外的文件創建一個靜態地圖來填充它,然後引用init_iterators方法中的靜態地圖來解決此問題。

首先,我將inner類聲明/實現代碼移動到custom_directives_hooks類中。

然後,我到在自定義指令定義的一個files_可變報頭文件中,像這樣:

... 
class custom_directives_hooks 
: public wave::context_policies::default_preprocessing_hooks 
{ 
public: 
    static std::map<std::string, std::string> files_; 

    custom_directives_hooks(std::map<std::string, std::string> files) { 
     custom_directives_hooks::files_ = files; 
    } 
... 

在我的自定義指令的cpp文件,我初始化地圖像這樣:

std::map<std::string, std::string> custom_directives_hooks::files_ = std::map<std::string, std::string>(); 

主要方法之前。

在main方法,我添加:

std::map<std::string, std::string> files; 

files["oglre"] = "oglre SOURCE\n"; 
files["material"] = "material SOURCE\n"; 
files["light"] = "light SOURCE\n"; 

,然後通過files映射到定製指令對象。

當時我能夠在inner類內指files_變量,像這樣:

... 
if (custom_directives_hooks::files_.find(std::string(cString)) != custom_directives_hooks::files_.end()) { 
    std::stringstream ss(custom_directives_hooks::files_[std::string(cString)]); 
    iter_ctx.instring.assign(
     std::istreambuf_iterator<char>(ss.rdbuf()), 
     std::istreambuf_iterator<char>() 
    ); 
} 
... 

希望這會幫助到其他人,像這樣的問題(雖然,這是一個非常具體問題:))。