我正在尝试做的是,在预处理c类文件时 boost :: wave(我实际上是在处理glsl文件),而不是加载 从磁盘中包含文件,我想从地图“加载”它们,其中map.first是文件名,map.second是内容。
我需要为输入策略的内部类提供这些的映射 文件名/文件内容。但是,我不确定我怎么能真正得到一个 映射到内部阶级......
上下文的创建如下:
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 :(得分: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>();
在主要方法之前。
在主要方法中,我补充说:
std::map<std::string, std::string> files;
files["oglre"] = "oglre SOURCE\n";
files["material"] = "material SOURCE\n";
files["light"] = "light SOURCE\n";
然后将files
映射传递给自定义指令对象。
然后,我可以在files_
类中引用inner
变量,如下所示:
...
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>()
);
}
...
希望这对有这样一个问题的其他人有所帮助(虽然这是一个非常具体的问题:))。