如何用boost::wave关联C代码中嵌套宏的调用位置与展开文本
用Boost.Wave搞定宏调用位置与展开文本的关联
核心思路:靠context_hooks追踪宏调用上下文
Boost.Wave的advanced_hooks只能捕获展开文本,但要绑定原代码中的调用位置,得结合宏调用的进出钩子和位置栈存储——毕竟嵌套宏调用会层层触发钩子,用栈才能保住外层的位置信息不被覆盖。
具体操作步骤
- 自定义钩子类,用栈存储调用位置:
struct MacroTrackingHooks : boost::wave::context_hooks<> { std::stack<boost::wave::token_position> call_pos_stack; // 宏开始展开时,把当前调用位置压栈 void macro_expansion_start( boost::wave::context_type const&, boost::wave::token_type const&, boost::wave::token_position const& call_pos, bool ) override { call_pos_stack.push(call_pos); } // 宏展开结束,弹出栈顶位置(适配嵌套宏场景) void macro_expansion_end( boost::wave::context_type const&, boost::wave::token_type const&, bool ) override { if (!call_pos_stack.empty()) { call_pos_stack.pop(); } } // 在rescanned_macro中绑定位置与展开文本 void rescanned_macro( boost::wave::context_type const&, boost::wave::token_type const&, boost::wave::token_sequence_type const& expansion ) override { if (call_pos_stack.empty()) return; // 提取原调用的行号、列号 auto const& pos = call_pos_stack.top(); int line = pos.get_line(); int col = pos.get_column(); // 拼接完整的展开文本 std::string expanded; for (auto const& tok : expansion) { expanded += tok.get_value(); } // 这里把位置和展开文本存入自定义映射结构即可 // 示例:macro_map[{line, col}] = expanded; } };
- 注入钩子到Wave上下文:
编译时必须定义BOOST_WAVE_SUPPORT_CONTEXT_HOOKS宏(比如编译参数加-DBOOST_WAVE_SUPPORT_CONTEXT_HOOKS),否则钩子接口无法启用。创建上下文时带上自定义钩子:
boost::wave::context< std::string::iterator, boost::wave::cpplexer::lex_iterator<>, boost::wave::context_policies::default_policy, MacroTrackingHooks > ctx(input.begin(), input.end(), "your_source.c"); // 启用钩子功能 ctx.get_hooks().enable();
- 适配嵌套宏参数:
函数式宏参数中的嵌套宏会触发递归展开,此时栈结构会自动保留外层宏的位置——内层展开时栈顶始终是原代码中最外层的宏调用位置,直到内层展开结束弹出栈,完美对应原位置。
额外提醒
- 对象式宏的处理逻辑和函数式一致,
macro_expansion_start同样会触发,无需额外修改 token_position还支持获取文件名,多文件处理场景下也能直接复用
内容的提问来源于stack exchange,提问作者johnco3
相关产品推荐
相关产品推荐

