trace_macro_expansion.hpp 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. http://www.boost.org/
  4. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  5. Software License, Version 1.0. (See accompanying file
  6. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #if !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)
  9. #define TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED
  10. #include <cstdio>
  11. #include <cstdlib>
  12. #include <ctime>
  13. #include <ostream>
  14. #include <string>
  15. #include <stack>
  16. #include <set>
  17. #include <boost/assert.hpp>
  18. #include <boost/config.hpp>
  19. #include <boost/filesystem/path.hpp>
  20. #include <boost/filesystem/operations.hpp>
  21. #include <boost/filesystem/convenience.hpp>
  22. #include <boost/wave/token_ids.hpp>
  23. #include <boost/wave/util/macro_helpers.hpp>
  24. #include <boost/wave/util/filesystem_compatibility.hpp>
  25. #include <boost/wave/preprocessing_hooks.hpp>
  26. #include <boost/wave/whitespace_handling.hpp>
  27. #include <boost/wave/language_support.hpp>
  28. #include <boost/wave/cpp_exceptions.hpp>
  29. #include "stop_watch.hpp"
  30. #ifdef BOOST_NO_STRINGSTREAM
  31. #include <strstream>
  32. #define BOOST_WAVE_OSSTREAM std::ostrstream
  33. std::string BOOST_WAVE_GETSTRING(std::ostrstream& ss)
  34. {
  35. ss << std::ends;
  36. std::string rval = ss.str();
  37. ss.freeze(false);
  38. return rval;
  39. }
  40. #else
  41. #include <sstream>
  42. #define BOOST_WAVE_GETSTRING(ss) ss.str()
  43. #define BOOST_WAVE_OSSTREAM std::ostringstream
  44. #endif
  45. // trace_flags: enable single tracing functionality
  46. enum trace_flags {
  47. trace_nothing = 0, // disable tracing
  48. trace_macros = 1, // enable macro tracing
  49. trace_macro_counts = 2, // enable invocation counting
  50. trace_includes = 4, // enable include file tracing
  51. trace_guards = 8 // enable include guard tracing
  52. };
  53. ///////////////////////////////////////////////////////////////////////////////
  54. //
  55. // Special error thrown whenever the #pragma wave system() directive is
  56. // disabled
  57. //
  58. ///////////////////////////////////////////////////////////////////////////////
  59. class bad_pragma_exception :
  60. public boost::wave::preprocess_exception
  61. {
  62. public:
  63. enum error_code {
  64. pragma_system_not_enabled =
  65. boost::wave::preprocess_exception::last_error_number + 1,
  66. pragma_mismatched_push_pop,
  67. };
  68. bad_pragma_exception(char const *what_, error_code code, std::size_t line_,
  69. std::size_t column_, char const *filename_) throw()
  70. : boost::wave::preprocess_exception(what_,
  71. (boost::wave::preprocess_exception::error_code)code, line_,
  72. column_, filename_)
  73. {
  74. }
  75. ~bad_pragma_exception() throw() {}
  76. virtual char const *what() const throw()
  77. {
  78. return "boost::wave::bad_pragma_exception";
  79. }
  80. virtual bool is_recoverable() const throw()
  81. {
  82. return true;
  83. }
  84. virtual int get_severity() const throw()
  85. {
  86. return boost::wave::util::severity_remark;
  87. }
  88. static char const *error_text(int code)
  89. {
  90. switch(code) {
  91. case pragma_system_not_enabled:
  92. return "the directive '#pragma wave system()' was not enabled, use the "
  93. "-x command line argument to enable the execution of";
  94. case pragma_mismatched_push_pop:
  95. return "unbalanced #pragma push/pop in input file(s) for option";
  96. }
  97. return "Unknown exception";
  98. }
  99. static boost::wave::util::severity severity_level(int code)
  100. {
  101. switch(code) {
  102. case pragma_system_not_enabled:
  103. return boost::wave::util::severity_remark;
  104. case pragma_mismatched_push_pop:
  105. return boost::wave::util::severity_error;
  106. }
  107. return boost::wave::util::severity_fatal;
  108. }
  109. static char const *severity_text(int code)
  110. {
  111. return boost::wave::util::get_severity(boost::wave::util::severity_remark);
  112. }
  113. };
  114. ///////////////////////////////////////////////////////////////////////////////
  115. //
  116. // The trace_macro_expansion policy is used to trace the macro expansion of
  117. // macros whenever it is requested from inside the input stream to preprocess
  118. // through the '#pragma wave_option(trace: enable)' directive. The macro
  119. // tracing is disabled with the help of a '#pragma wave_option(trace: disable)'
  120. // directive.
  121. //
  122. // This policy type is used as a template parameter to the boost::wave::context<>
  123. // object.
  124. //
  125. ///////////////////////////////////////////////////////////////////////////////
  126. template <typename TokenT>
  127. class trace_macro_expansion
  128. : public boost::wave::context_policies::eat_whitespace<TokenT>
  129. {
  130. typedef boost::wave::context_policies::eat_whitespace<TokenT> base_type;
  131. public:
  132. trace_macro_expansion(
  133. bool preserve_whitespace_, bool preserve_bol_whitespace_,
  134. std::ofstream &output_, std::ostream &tracestrm_,
  135. std::ostream &includestrm_, std::ostream &guardstrm_,
  136. trace_flags flags_, bool enable_system_command_,
  137. bool& generate_output_, std::string const& default_outfile_)
  138. : outputstrm(output_), tracestrm(tracestrm_),
  139. includestrm(includestrm_), guardstrm(guardstrm_),
  140. level(0), flags(flags_), logging_flags(trace_nothing),
  141. enable_system_command(enable_system_command_),
  142. preserve_whitespace(preserve_whitespace_),
  143. preserve_bol_whitespace(preserve_bol_whitespace_),
  144. generate_output(generate_output_),
  145. default_outfile(default_outfile_),
  146. emit_relative_filenames(false)
  147. {
  148. }
  149. ~trace_macro_expansion()
  150. {
  151. }
  152. void enable_macro_counting()
  153. {
  154. logging_flags = trace_flags(logging_flags | trace_macro_counts);
  155. }
  156. std::map<std::string, std::size_t> const& get_macro_counts() const
  157. {
  158. return counts;
  159. }
  160. void enable_relative_names_in_line_directives(bool flag)
  161. {
  162. emit_relative_filenames = flag;
  163. }
  164. bool enable_relative_names_in_line_directives() const
  165. {
  166. return emit_relative_filenames;
  167. }
  168. // add a macro name, which should not be expanded at all (left untouched)
  169. void add_noexpandmacro(std::string const& name)
  170. {
  171. noexpandmacros.insert(name);
  172. }
  173. void set_license_info(std::string const& info)
  174. {
  175. license_info = info;
  176. }
  177. ///////////////////////////////////////////////////////////////////////////
  178. //
  179. // The function 'expanding_function_like_macro' is called whenever a
  180. // function-like macro is to be expanded.
  181. //
  182. // The parameter 'ctx' is a reference to the context object used for
  183. // instantiating the preprocessing iterators by the user.
  184. //
  185. // The parameter 'macrodef' marks the position, where the macro to expand
  186. // is defined.
  187. //
  188. // The parameter 'formal_args' holds the formal arguments used during the
  189. // definition of the macro.
  190. //
  191. // The parameter 'definition' holds the macro definition for the macro to
  192. // trace.
  193. //
  194. // The parameter 'macro_call' marks the position, where this macro invoked.
  195. //
  196. // The parameter 'arguments' holds the macro arguments used during the
  197. // invocation of the macro
  198. //
  199. // The parameters 'seqstart' and 'seqend' point into the input token
  200. // stream allowing to access the whole token sequence comprising the macro
  201. // invocation (starting with the opening parenthesis and ending after the
  202. // closing one).
  203. //
  204. // The return value defines whether the corresponding macro will be
  205. // expanded (return false) or will be copied to the output (return true).
  206. // Note: the whole argument list is copied unchanged to the output as well
  207. // without any further processing.
  208. //
  209. ///////////////////////////////////////////////////////////////////////////
  210. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
  211. // old signature
  212. template <typename ContainerT>
  213. void expanding_function_like_macro(
  214. TokenT const &macrodef, std::vector<TokenT> const &formal_args,
  215. ContainerT const &definition,
  216. TokenT const &macrocall, std::vector<ContainerT> const &arguments)
  217. {
  218. if (enabled_macro_counting())
  219. count_invocation(macrodef.get_value().c_str());
  220. if (!enabled_macro_tracing())
  221. return;
  222. #else
  223. // new signature
  224. template <typename ContextT, typename ContainerT, typename IteratorT>
  225. bool
  226. expanding_function_like_macro(ContextT const& ctx,
  227. TokenT const &macrodef, std::vector<TokenT> const &formal_args,
  228. ContainerT const &definition,
  229. TokenT const &macrocall, std::vector<ContainerT> const &arguments,
  230. IteratorT const& seqstart, IteratorT const& seqend)
  231. {
  232. if (enabled_macro_counting() || !noexpandmacros.empty()) {
  233. std::string name (macrodef.get_value().c_str());
  234. if (noexpandmacros.find(name.c_str()) != noexpandmacros.end())
  235. return true; // do not expand this macro
  236. if (enabled_macro_counting())
  237. count_invocation(name.c_str());
  238. }
  239. if (!enabled_macro_tracing())
  240. return false;
  241. #endif
  242. if (0 == get_level()) {
  243. // output header line
  244. BOOST_WAVE_OSSTREAM stream;
  245. stream
  246. << macrocall.get_position() << ": "
  247. << macrocall.get_value() << "(";
  248. // argument list
  249. for (typename ContainerT::size_type i = 0; i < arguments.size(); ++i) {
  250. stream << boost::wave::util::impl::as_string(arguments[i]);
  251. if (i < arguments.size()-1)
  252. stream << ", ";
  253. }
  254. stream << ")" << std::endl;
  255. output(BOOST_WAVE_GETSTRING(stream));
  256. increment_level();
  257. }
  258. // output definition reference
  259. {
  260. BOOST_WAVE_OSSTREAM stream;
  261. stream
  262. << macrodef.get_position() << ": see macro definition: "
  263. << macrodef.get_value() << "(";
  264. // formal argument list
  265. for (typename std::vector<TokenT>::size_type i = 0;
  266. i < formal_args.size(); ++i)
  267. {
  268. stream << formal_args[i].get_value();
  269. if (i < formal_args.size()-1)
  270. stream << ", ";
  271. }
  272. stream << ")" << std::endl;
  273. output(BOOST_WAVE_GETSTRING(stream));
  274. }
  275. if (formal_args.size() > 0) {
  276. // map formal and real arguments
  277. open_trace_body("invoked with\n");
  278. for (typename std::vector<TokenT>::size_type j = 0;
  279. j < formal_args.size(); ++j)
  280. {
  281. using namespace boost::wave;
  282. BOOST_WAVE_OSSTREAM stream;
  283. stream << formal_args[j].get_value() << " = ";
  284. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  285. if (T_ELLIPSIS == token_id(formal_args[j])) {
  286. // ellipsis
  287. for (typename ContainerT::size_type k = j;
  288. k < arguments.size(); ++k)
  289. {
  290. stream << boost::wave::util::impl::as_string(arguments[k]);
  291. if (k < arguments.size()-1)
  292. stream << ", ";
  293. }
  294. }
  295. else
  296. #endif
  297. {
  298. stream << boost::wave::util::impl::as_string(arguments[j]);
  299. }
  300. stream << std::endl;
  301. output(BOOST_WAVE_GETSTRING(stream));
  302. }
  303. close_trace_body();
  304. }
  305. open_trace_body();
  306. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
  307. return false;
  308. #endif
  309. }
  310. ///////////////////////////////////////////////////////////////////////////
  311. //
  312. // The function 'expanding_object_like_macro' is called whenever a
  313. // object-like macro is to be expanded .
  314. //
  315. // The parameter 'ctx' is a reference to the context object used for
  316. // instantiating the preprocessing iterators by the user.
  317. //
  318. // The parameter 'macrodef' marks the position, where the macro to expand
  319. // is defined.
  320. //
  321. // The definition 'definition' holds the macro definition for the macro to
  322. // trace.
  323. //
  324. // The parameter 'macrocall' marks the position, where this macro invoked.
  325. //
  326. ///////////////////////////////////////////////////////////////////////////
  327. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
  328. // old signature
  329. template <typename ContainerT>
  330. void expanding_object_like_macro(TokenT const &macrodef,
  331. ContainerT const &definition, TokenT const &macrocall)
  332. {
  333. if (enabled_macro_counting())
  334. count_invocation(macrodef.get_value().c_str());
  335. if (!enabled_macro_tracing())
  336. return;
  337. #else
  338. // new signature
  339. template <typename ContextT, typename ContainerT>
  340. bool
  341. expanding_object_like_macro(ContextT const& ctx,
  342. TokenT const &macrodef, ContainerT const &definition,
  343. TokenT const &macrocall)
  344. {
  345. if (enabled_macro_counting() || !noexpandmacros.empty()) {
  346. std::string name (macrodef.get_value().c_str());
  347. if (noexpandmacros.find(name.c_str()) != noexpandmacros.end())
  348. return true; // do not expand this macro
  349. if (enabled_macro_counting())
  350. count_invocation(name.c_str());
  351. }
  352. if (!enabled_macro_tracing())
  353. return false;
  354. #endif
  355. if (0 == get_level()) {
  356. // output header line
  357. BOOST_WAVE_OSSTREAM stream;
  358. stream
  359. << macrocall.get_position() << ": "
  360. << macrocall.get_value() << std::endl;
  361. output(BOOST_WAVE_GETSTRING(stream));
  362. increment_level();
  363. }
  364. // output definition reference
  365. {
  366. BOOST_WAVE_OSSTREAM stream;
  367. stream
  368. << macrodef.get_position() << ": see macro definition: "
  369. << macrodef.get_value() << std::endl;
  370. output(BOOST_WAVE_GETSTRING(stream));
  371. }
  372. open_trace_body();
  373. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
  374. return false;
  375. #endif
  376. }
  377. ///////////////////////////////////////////////////////////////////////////
  378. //
  379. // The function 'expanded_macro' is called whenever the expansion of a
  380. // macro is finished but before the rescanning process starts.
  381. //
  382. // The parameter 'ctx' is a reference to the context object used for
  383. // instantiating the preprocessing iterators by the user.
  384. //
  385. // The parameter 'result' contains the token sequence generated as the
  386. // result of the macro expansion.
  387. //
  388. ///////////////////////////////////////////////////////////////////////////
  389. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
  390. // old signature
  391. template <typename ContainerT>
  392. void expanded_macro(ContainerT const &result)
  393. #else
  394. // new signature
  395. template <typename ContextT, typename ContainerT>
  396. void expanded_macro(ContextT const& ctx,ContainerT const &result)
  397. #endif
  398. {
  399. if (!enabled_macro_tracing()) return;
  400. BOOST_WAVE_OSSTREAM stream;
  401. stream << boost::wave::util::impl::as_string(result) << std::endl;
  402. output(BOOST_WAVE_GETSTRING(stream));
  403. open_trace_body("rescanning\n");
  404. }
  405. ///////////////////////////////////////////////////////////////////////////
  406. //
  407. // The function 'rescanned_macro' is called whenever the rescanning of a
  408. // macro is finished.
  409. //
  410. // The parameter 'ctx' is a reference to the context object used for
  411. // instantiating the preprocessing iterators by the user.
  412. //
  413. // The parameter 'result' contains the token sequence generated as the
  414. // result of the rescanning.
  415. //
  416. ///////////////////////////////////////////////////////////////////////////
  417. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
  418. // old signature
  419. template <typename ContainerT>
  420. void rescanned_macro(ContainerT const &result)
  421. #else
  422. // new signature
  423. template <typename ContextT, typename ContainerT>
  424. void rescanned_macro(ContextT const& ctx,ContainerT const &result)
  425. #endif
  426. {
  427. if (!enabled_macro_tracing() || get_level() == 0)
  428. return;
  429. BOOST_WAVE_OSSTREAM stream;
  430. stream << boost::wave::util::impl::as_string(result) << std::endl;
  431. output(BOOST_WAVE_GETSTRING(stream));
  432. close_trace_body();
  433. close_trace_body();
  434. if (1 == get_level())
  435. decrement_level();
  436. }
  437. ///////////////////////////////////////////////////////////////////////////
  438. //
  439. // The function 'interpret_pragma' is called whenever a #pragma command
  440. // directive is found which isn't known to the core Wave library, where
  441. // command is the value defined as the BOOST_WAVE_PRAGMA_KEYWORD constant
  442. // which defaults to "wave".
  443. //
  444. // The parameter 'ctx' is a reference to the context object used for
  445. // instantiating the preprocessing iterators by the user.
  446. //
  447. // The parameter 'pending' may be used to push tokens back into the input
  448. // stream, which are to be used as the replacement text for the whole
  449. // #pragma directive.
  450. //
  451. // The parameter 'option' contains the name of the interpreted pragma.
  452. //
  453. // The parameter 'values' holds the values of the parameter provided to
  454. // the pragma operator.
  455. //
  456. // The parameter 'act_token' contains the actual #pragma token, which may
  457. // be used for error output.
  458. //
  459. // If the return value is 'false', the whole #pragma directive is
  460. // interpreted as unknown and a corresponding error message is issued. A
  461. // return value of 'true' signs a successful interpretation of the given
  462. // #pragma.
  463. //
  464. ///////////////////////////////////////////////////////////////////////////
  465. template <typename ContextT, typename ContainerT>
  466. bool
  467. interpret_pragma(ContextT &ctx, ContainerT &pending,
  468. typename ContextT::token_type const &option, ContainerT const &valuetokens,
  469. typename ContextT::token_type const &act_token)
  470. {
  471. typedef typename ContextT::token_type token_type;
  472. ContainerT values(valuetokens);
  473. boost::wave::util::impl::trim_sequence(values); // trim whitespace
  474. if (option.get_value() == "timer") {
  475. // #pragma wave timer(value)
  476. if (0 == values.size()) {
  477. // no value means '1'
  478. using namespace boost::wave;
  479. timer(token_type(T_INTLIT, "1", act_token.get_position()));
  480. }
  481. else {
  482. timer(values.front());
  483. }
  484. return true;
  485. }
  486. if (option.get_value() == "trace") {
  487. // enable/disable tracing option
  488. return interpret_pragma_trace(ctx, values, act_token);
  489. }
  490. if (option.get_value() == "system") {
  491. if (!enable_system_command) {
  492. // if the #pragma wave system() directive is not enabled, throw
  493. // a corresponding error (actually its a remark),
  494. typename ContextT::string_type msg(
  495. boost::wave::util::impl::as_string(values));
  496. BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
  497. pragma_system_not_enabled,
  498. msg.c_str(), act_token.get_position());
  499. return false;
  500. }
  501. // try to spawn the given argument as a system command and return the
  502. // std::cout of this process as the replacement of this _Pragma
  503. return interpret_pragma_system(ctx, pending, values, act_token);
  504. }
  505. if (option.get_value() == "stop") {
  506. // stop the execution and output the argument
  507. typename ContextT::string_type msg(
  508. boost::wave::util::impl::as_string(values));
  509. BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
  510. error_directive, msg.c_str(), act_token.get_position());
  511. return false;
  512. }
  513. if (option.get_value() == "option") {
  514. // handle different options
  515. return interpret_pragma_option(ctx, values, act_token);
  516. }
  517. return false;
  518. }
  519. ///////////////////////////////////////////////////////////////////////////
  520. //
  521. // The function 'emit_line_directive' is called whenever a #line directive
  522. // has to be emitted into the generated output.
  523. //
  524. // The parameter 'ctx' is a reference to the context object used for
  525. // instantiating the preprocessing iterators by the user.
  526. //
  527. // The parameter 'pending' may be used to push tokens back into the input
  528. // stream, which are to be used instead of the default output generated
  529. // for the #line directive.
  530. //
  531. // The parameter 'act_token' contains the actual #pragma token, which may
  532. // be used for error output. The line number stored in this token can be
  533. // used as the line number emitted as part of the #line directive.
  534. //
  535. // If the return value is 'false', a default #line directive is emitted
  536. // by the library. A return value of 'true' will inhibit any further
  537. // actions, the tokens contained in 'pending' will be copied verbatim
  538. // to the output.
  539. //
  540. ///////////////////////////////////////////////////////////////////////////
  541. template <typename ContextT, typename ContainerT>
  542. bool
  543. emit_line_directive(ContextT const& ctx, ContainerT &pending,
  544. typename ContextT::token_type const& act_token)
  545. {
  546. if (!need_emit_line_directives(ctx.get_language()) ||
  547. !enable_relative_names_in_line_directives())
  548. {
  549. return false;
  550. }
  551. // emit a #line directive showing the relative filename instead
  552. typename ContextT::position_type pos = act_token.get_position();
  553. unsigned int column = 6;
  554. typedef typename ContextT::token_type result_type;
  555. using namespace boost::wave;
  556. pos.set_column(1);
  557. pending.push_back(result_type(T_PP_LINE, "#line", pos));
  558. pos.set_column(column); // account for '#line'
  559. pending.push_back(result_type(T_SPACE, " ", pos));
  560. // 21 is the max required size for a 64 bit integer represented as a
  561. // string
  562. char buffer[22];
  563. using namespace std; // for some systems sprintf is in namespace std
  564. sprintf (buffer, "%zd", pos.get_line());
  565. pos.set_column(++column); // account for ' '
  566. pending.push_back(result_type(T_INTLIT, buffer, pos));
  567. pos.set_column(column += (unsigned int)strlen(buffer)); // account for <number>
  568. pending.push_back(result_type(T_SPACE, " ", pos));
  569. pos.set_column(++column); // account for ' '
  570. std::string file("\"");
  571. boost::filesystem::path filename(
  572. boost::wave::util::create_path(ctx.get_current_relative_filename().c_str()));
  573. using boost::wave::util::impl::escape_lit;
  574. file += escape_lit(boost::wave::util::native_file_string(filename)) + "\"";
  575. pending.push_back(result_type(T_STRINGLIT, file.c_str(), pos));
  576. pos.set_column(column += (unsigned int)file.size()); // account for filename
  577. pending.push_back(result_type(T_GENERATEDNEWLINE, "\n", pos));
  578. return true;
  579. }
  580. ///////////////////////////////////////////////////////////////////////////
  581. //
  582. // The function 'opened_include_file' is called whenever a file referred
  583. // by an #include directive was successfully located and opened.
  584. //
  585. // The parameter 'ctx' is a reference to the context object used for
  586. // instantiating the preprocessing iterators by the user.
  587. //
  588. // The parameter 'filename' contains the file system path of the
  589. // opened file (this is relative to the directory of the currently
  590. // processed file or a absolute path depending on the paths given as the
  591. // include search paths).
  592. //
  593. // The include_depth parameter contains the current include file depth.
  594. //
  595. // The is_system_include parameter denotes, whether the given file was
  596. // found as a result of a #include <...> directive.
  597. //
  598. ///////////////////////////////////////////////////////////////////////////
  599. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS != 0
  600. // old signature
  601. void
  602. opened_include_file(std::string const &relname, std::string const &absname,
  603. std::size_t include_depth, bool is_system_include)
  604. {
  605. #else
  606. // new signature
  607. template <typename ContextT>
  608. void
  609. opened_include_file(ContextT const& ctx, std::string const &relname,
  610. std::string const &absname, bool is_system_include)
  611. {
  612. std::size_t include_depth = ctx.get_iteration_depth();
  613. #endif
  614. if (enabled_include_tracing()) {
  615. // print indented filename
  616. for (std::size_t i = 0; i < include_depth; ++i)
  617. includestrm << " ";
  618. if (is_system_include)
  619. includestrm << "<" << relname << "> (" << absname << ")";
  620. else
  621. includestrm << "\"" << relname << "\" (" << absname << ")";
  622. includestrm << std::endl;
  623. }
  624. }
  625. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  626. ///////////////////////////////////////////////////////////////////////////
  627. //
  628. // The function 'detected_include_guard' is called whenever either a
  629. // include file is about to be added to the list of #pragma once headers.
  630. // That means this header file will not be opened and parsed again even
  631. // if it is specified in a later #include directive.
  632. // This function is called as the result of a detected include guard
  633. // scheme.
  634. //
  635. // The implemented heuristics for include guards detects two forms of
  636. // include guards:
  637. //
  638. // #ifndef INCLUDE_GUARD_MACRO
  639. // #define INCLUDE_GUARD_MACRO
  640. // ...
  641. // #endif
  642. //
  643. // or
  644. //
  645. // if !defined(INCLUDE_GUARD_MACRO)
  646. // #define INCLUDE_GUARD_MACRO
  647. // ...
  648. // #endif
  649. //
  650. // note, that the parenthesis are optional (i.e. !defined INCLUDE_GUARD_MACRO
  651. // will work as well). The code allows for any whitespace, newline and single
  652. // '#' tokens before the #if/#ifndef and after the final #endif.
  653. //
  654. // The parameter 'ctx' is a reference to the context object used for
  655. // instantiating the preprocessing iterators by the user.
  656. //
  657. // The parameter 'filename' contains the file system path of the
  658. // opened file (this is relative to the directory of the currently
  659. // processed file or a absolute path depending on the paths given as the
  660. // include search paths).
  661. //
  662. // The parameter contains the name of the detected include guard.
  663. //
  664. ///////////////////////////////////////////////////////////////////////////
  665. template <typename ContextT>
  666. void
  667. detected_include_guard(ContextT const& ctx, std::string const& filename,
  668. std::string const& include_guard)
  669. {
  670. if (enabled_guard_tracing()) {
  671. guardstrm << include_guard << ":" << std::endl
  672. << " " << filename << std::endl;
  673. }
  674. }
  675. #endif
  676. ///////////////////////////////////////////////////////////////////////////
  677. //
  678. // The function 'may_skip_whitespace' will be called by the
  679. // library whenever a token is about to be returned to the calling
  680. // application.
  681. //
  682. // The parameter 'ctx' is a reference to the context object used for
  683. // instantiating the preprocessing iterators by the user.
  684. //
  685. // The 'token' parameter holds a reference to the current token. The policy
  686. // is free to change this token if needed.
  687. //
  688. // The 'skipped_newline' parameter holds a reference to a boolean value
  689. // which should be set to true by the policy function whenever a newline
  690. // is going to be skipped.
  691. //
  692. // If the return value is true, the given token is skipped and the
  693. // preprocessing continues to the next token. If the return value is
  694. // false, the given token is returned to the calling application.
  695. //
  696. // ATTENTION!
  697. // Caution has to be used, because by returning true the policy function
  698. // is able to force skipping even significant tokens, not only whitespace.
  699. //
  700. ///////////////////////////////////////////////////////////////////////////
  701. template <typename ContextT>
  702. bool may_skip_whitespace(ContextT const &ctx, TokenT &token,
  703. bool &skipped_newline)
  704. {
  705. return this->base_type::may_skip_whitespace(
  706. ctx, token, need_preserve_comments(ctx.get_language()),
  707. preserve_bol_whitespace, skipped_newline) ?
  708. !preserve_whitespace : false;
  709. }
  710. ///////////////////////////////////////////////////////////////////////////
  711. //
  712. // The function 'throw_exception' will be called by the library whenever a
  713. // preprocessing exception occurs.
  714. //
  715. // The parameter 'ctx' is a reference to the context object used for
  716. // instantiating the preprocessing iterators by the user.
  717. //
  718. // The parameter 'e' is the exception object containing detailed error
  719. // information.
  720. //
  721. // The default behavior is to call the function boost::throw_exception.
  722. //
  723. ///////////////////////////////////////////////////////////////////////////
  724. template <typename ContextT>
  725. void
  726. throw_exception(ContextT const& ctx, boost::wave::preprocess_exception const& e)
  727. {
  728. #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
  729. if (!is_import_directive_error(e))
  730. boost::throw_exception(e);
  731. #else
  732. boost::throw_exception(e);
  733. #endif
  734. }
  735. using base_type::throw_exception;
  736. protected:
  737. #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
  738. ///////////////////////////////////////////////////////////////////////////
  739. // Avoid throwing an error from a #import directive
  740. bool is_import_directive_error(boost::wave::preprocess_exception const& e)
  741. {
  742. using namespace boost::wave;
  743. if (e.get_errorcode() != preprocess_exception::ill_formed_directive)
  744. return false;
  745. // the error string is formatted as 'severity: error: directive'
  746. std::string error(e.description());
  747. std::string::size_type p = error.find_last_of(":");
  748. return p != std::string::npos && error.substr(p+2) == "import";
  749. }
  750. #endif
  751. ///////////////////////////////////////////////////////////////////////////
  752. // Interpret the different Wave specific pragma directives/operators
  753. template <typename ContextT, typename ContainerT>
  754. bool
  755. interpret_pragma_trace(ContextT& ctx, ContainerT const &values,
  756. typename ContextT::token_type const &act_token)
  757. {
  758. typedef typename ContextT::token_type token_type;
  759. typedef typename token_type::string_type string_type;
  760. bool valid_option = false;
  761. if (1 == values.size()) {
  762. token_type const &value = values.front();
  763. if (value.get_value() == "enable" ||
  764. value.get_value() == "on" ||
  765. value.get_value() == "1")
  766. {
  767. // #pragma wave trace(enable)
  768. enable_tracing(static_cast<trace_flags>(
  769. tracing_enabled() | trace_macros));
  770. valid_option = true;
  771. }
  772. else if (value.get_value() == "disable" ||
  773. value.get_value() == "off" ||
  774. value.get_value() == "0")
  775. {
  776. // #pragma wave trace(disable)
  777. enable_tracing(static_cast<trace_flags>(
  778. tracing_enabled() & ~trace_macros));
  779. valid_option = true;
  780. }
  781. }
  782. if (!valid_option) {
  783. // unknown option value
  784. string_type option_str ("trace");
  785. if (values.size() > 0) {
  786. option_str += "(";
  787. option_str += boost::wave::util::impl::as_string(values);
  788. option_str += ")";
  789. }
  790. BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
  791. ill_formed_pragma_option, option_str.c_str(),
  792. act_token.get_position());
  793. return false;
  794. }
  795. return true;
  796. }
  797. ///////////////////////////////////////////////////////////////////////////
  798. // interpret the pragma wave option(preserve: [0|1|2|3|push|pop]) directive
  799. template <typename ContextT>
  800. static bool
  801. interpret_pragma_option_preserve_set(int mode, bool &preserve_whitespace,
  802. bool& preserve_bol_whitespace, ContextT &ctx)
  803. {
  804. switch(mode) {
  805. // preserve no whitespace
  806. case 0:
  807. preserve_whitespace = false;
  808. preserve_bol_whitespace = false;
  809. ctx.set_language(
  810. enable_preserve_comments(ctx.get_language(), false),
  811. false);
  812. break;
  813. // preserve BOL whitespace only
  814. case 1:
  815. preserve_whitespace = false;
  816. preserve_bol_whitespace = true;
  817. ctx.set_language(
  818. enable_preserve_comments(ctx.get_language(), false),
  819. false);
  820. break;
  821. // preserve comments and BOL whitespace only
  822. case 2:
  823. preserve_whitespace = false;
  824. preserve_bol_whitespace = true;
  825. ctx.set_language(
  826. enable_preserve_comments(ctx.get_language()),
  827. false);
  828. break;
  829. // preserve all whitespace
  830. case 3:
  831. preserve_whitespace = true;
  832. preserve_bol_whitespace = true;
  833. ctx.set_language(
  834. enable_preserve_comments(ctx.get_language()),
  835. false);
  836. break;
  837. default:
  838. return false;
  839. }
  840. return true;
  841. }
  842. template <typename ContextT, typename IteratorT>
  843. bool
  844. interpret_pragma_option_preserve(ContextT &ctx, IteratorT &it,
  845. IteratorT end, typename ContextT::token_type const &act_token)
  846. {
  847. using namespace boost::wave;
  848. token_id id = util::impl::skip_whitespace(it, end);
  849. if (T_COLON == id)
  850. id = util::impl::skip_whitespace(it, end);
  851. // implement push/pop
  852. if (T_IDENTIFIER == id) {
  853. if ((*it).get_value() == "push") {
  854. // push current preserve option onto the internal option stack
  855. if (need_preserve_comments(ctx.get_language())) {
  856. if (preserve_whitespace)
  857. preserve_options.push(3);
  858. else
  859. preserve_options.push(2);
  860. }
  861. else if (preserve_bol_whitespace) {
  862. preserve_options.push(1);
  863. }
  864. else {
  865. preserve_options.push(0);
  866. }
  867. return true;
  868. }
  869. else if ((*it).get_value() == "pop") {
  870. // test for mismatched push/pop #pragmas
  871. if (preserve_options.empty()) {
  872. BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
  873. pragma_mismatched_push_pop, "preserve",
  874. act_token.get_position());
  875. }
  876. // pop output preserve from the internal option stack
  877. bool result = interpret_pragma_option_preserve_set(
  878. preserve_options.top(), preserve_whitespace,
  879. preserve_bol_whitespace, ctx);
  880. preserve_options.pop();
  881. return result;
  882. }
  883. return false;
  884. }
  885. if (T_PP_NUMBER != id)
  886. return false;
  887. using namespace std; // some platforms have atoi in namespace std
  888. return interpret_pragma_option_preserve_set(
  889. atoi((*it).get_value().c_str()), preserve_whitespace,
  890. preserve_bol_whitespace, ctx);
  891. }
  892. // interpret the pragma wave option(line: [0|1|2|push|pop]) directive
  893. template <typename ContextT, typename IteratorT>
  894. bool
  895. interpret_pragma_option_line(ContextT &ctx, IteratorT &it,
  896. IteratorT end, typename ContextT::token_type const &act_token)
  897. {
  898. using namespace boost::wave;
  899. token_id id = util::impl::skip_whitespace(it, end);
  900. if (T_COLON == id)
  901. id = util::impl::skip_whitespace(it, end);
  902. // implement push/pop
  903. if (T_IDENTIFIER == id) {
  904. if ((*it).get_value() == "push") {
  905. // push current line option onto the internal option stack
  906. int mode = 0;
  907. if (need_emit_line_directives(ctx.get_language())) {
  908. mode = 1;
  909. if (enable_relative_names_in_line_directives())
  910. mode = 2;
  911. }
  912. line_options.push(mode);
  913. return true;
  914. }
  915. else if ((*it).get_value() == "pop") {
  916. // test for mismatched push/pop #pragmas
  917. if (line_options.empty()) {
  918. BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
  919. pragma_mismatched_push_pop, "line",
  920. act_token.get_position());
  921. }
  922. // pop output line from the internal option stack
  923. ctx.set_language(
  924. enable_emit_line_directives(ctx.get_language(), 0 != line_options.top()),
  925. false);
  926. enable_relative_names_in_line_directives(2 == line_options.top());
  927. line_options.pop();
  928. return true;
  929. }
  930. return false;
  931. }
  932. if (T_PP_NUMBER != id)
  933. return false;
  934. using namespace std; // some platforms have atoi in namespace std
  935. int emit_lines = atoi((*it).get_value().c_str());
  936. if (0 == emit_lines || 1 == emit_lines || 2 == emit_lines) {
  937. // set the new emit #line directive mode
  938. ctx.set_language(
  939. enable_emit_line_directives(ctx.get_language(), emit_lines),
  940. false);
  941. return true;
  942. }
  943. return false;
  944. }
  945. // interpret the pragma wave option(output: ["filename"|null|default|push|pop])
  946. // directive
  947. template <typename ContextT>
  948. bool
  949. interpret_pragma_option_output_open(boost::filesystem::path &fpath,
  950. ContextT& ctx, typename ContextT::token_type const &act_token)
  951. {
  952. namespace fs = boost::filesystem;
  953. // ensure all directories for this file do exist
  954. boost::wave::util::create_directories(
  955. boost::wave::util::branch_path(fpath));
  956. // figure out, whether the file has been written to by us, if yes, we
  957. // append any output to this file, otherwise we overwrite it
  958. std::ios::openmode mode = std::ios::out;
  959. if (fs::exists(fpath) && written_by_us.find(fpath) != written_by_us.end())
  960. mode = (std::ios::openmode)(std::ios::out | std::ios::app);
  961. written_by_us.insert(fpath);
  962. // close the current file
  963. if (outputstrm.is_open())
  964. outputstrm.close();
  965. // open the new file
  966. outputstrm.open(fpath.string().c_str(), mode);
  967. if (!outputstrm.is_open()) {
  968. BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
  969. could_not_open_output_file,
  970. fpath.string().c_str(), act_token.get_position());
  971. return false;
  972. }
  973. // write license text, if file was created and if requested
  974. if (mode == std::ios::out && !license_info.empty())
  975. outputstrm << license_info;
  976. generate_output = true;
  977. current_outfile = fpath;
  978. return true;
  979. }
  980. bool interpret_pragma_option_output_close(bool generate)
  981. {
  982. if (outputstrm.is_open())
  983. outputstrm.close();
  984. current_outfile = boost::filesystem::path();
  985. generate_output = generate;
  986. return true;
  987. }
  988. template <typename ContextT, typename IteratorT>
  989. bool
  990. interpret_pragma_option_output(ContextT &ctx, IteratorT &it,
  991. IteratorT end, typename ContextT::token_type const &act_token)
  992. {
  993. using namespace boost::wave;
  994. namespace fs = boost::filesystem;
  995. typedef typename ContextT::token_type token_type;
  996. typedef typename token_type::string_type string_type;
  997. token_id id = util::impl::skip_whitespace(it, end);
  998. if (T_COLON == id)
  999. id = util::impl::skip_whitespace(it, end);
  1000. bool result = false;
  1001. if (T_STRINGLIT == id) {
  1002. namespace fs = boost::filesystem;
  1003. string_type fname ((*it).get_value());
  1004. fs::path fpath (boost::wave::util::create_path(
  1005. util::impl::unescape_lit(fname.substr(1, fname.size()-2)).c_str()));
  1006. fpath = boost::wave::util::complete_path(fpath, ctx.get_current_directory());
  1007. result = interpret_pragma_option_output_open(fpath, ctx, act_token);
  1008. }
  1009. else if (T_IDENTIFIER == id) {
  1010. if ((*it).get_value() == "null") {
  1011. // suppress all output from this point on
  1012. result = interpret_pragma_option_output_close(false);
  1013. }
  1014. else if ((*it).get_value() == "push") {
  1015. // initialize the current_outfile, if appropriate
  1016. if (output_options.empty() && current_outfile.empty() &&
  1017. !default_outfile.empty() && default_outfile != "-")
  1018. {
  1019. current_outfile = boost::wave::util::complete_path(
  1020. default_outfile, ctx.get_current_directory());
  1021. }
  1022. // push current output option onto the internal option stack
  1023. output_options.push(
  1024. output_option_type(generate_output, current_outfile));
  1025. result = true;
  1026. }
  1027. else if ((*it).get_value() == "pop") {
  1028. // test for mismatched push/pop #pragmas
  1029. if (output_options.empty()) {
  1030. BOOST_WAVE_THROW_CTX(ctx, bad_pragma_exception,
  1031. pragma_mismatched_push_pop, "output",
  1032. act_token.get_position());
  1033. return false;
  1034. }
  1035. // pop output option from the internal option stack
  1036. output_option_type const& opts = output_options.top();
  1037. generate_output = opts.first;
  1038. current_outfile = opts.second;
  1039. if (!current_outfile.empty()) {
  1040. // re-open the last file
  1041. result = interpret_pragma_option_output_open(current_outfile,
  1042. ctx, act_token);
  1043. }
  1044. else {
  1045. // either no output or generate to std::cout
  1046. result = interpret_pragma_option_output_close(generate_output);
  1047. }
  1048. output_options.pop();
  1049. }
  1050. }
  1051. else if (T_DEFAULT == id) {
  1052. // re-open the default output given on command line
  1053. if (!default_outfile.empty()) {
  1054. if (default_outfile == "-") {
  1055. // the output was suppressed on the command line
  1056. result = interpret_pragma_option_output_close(false);
  1057. }
  1058. else {
  1059. // there was a file name on the command line
  1060. fs::path fpath(boost::wave::util::create_path(default_outfile));
  1061. result = interpret_pragma_option_output_open(fpath, ctx,
  1062. act_token);
  1063. }
  1064. }
  1065. else {
  1066. // generate the output to std::cout
  1067. result = interpret_pragma_option_output_close(true);
  1068. }
  1069. }
  1070. return result;
  1071. }
  1072. ///////////////////////////////////////////////////////////////////////////
  1073. // join all adjacent string tokens into the first one
  1074. template <typename StringT>
  1075. StringT unlit(StringT const& str)
  1076. {
  1077. return str.substr(1, str.size()-2);
  1078. }
  1079. template <typename StringT>
  1080. StringT merge_string_lits(StringT const& lhs, StringT const& rhs)
  1081. {
  1082. StringT result ("\"");
  1083. result += unlit(lhs);
  1084. result += unlit(rhs);
  1085. result += "\"";
  1086. return result;
  1087. }
  1088. template <typename ContextT, typename ContainerT>
  1089. void join_adjacent_string_tokens(ContextT &ctx, ContainerT const& values,
  1090. ContainerT& joined_values)
  1091. {
  1092. using namespace boost::wave;
  1093. typedef typename ContextT::token_type token_type;
  1094. typedef typename token_type::string_type string_type;
  1095. typedef typename ContainerT::const_iterator const_iterator;
  1096. typedef typename ContainerT::iterator iterator;
  1097. token_type* current = 0;
  1098. const_iterator end = values.end();
  1099. for (const_iterator it = values.begin(); it != end; ++it) {
  1100. token_id id(*it);
  1101. if (id == T_STRINGLIT) {
  1102. if (!current) {
  1103. joined_values.push_back(*it);
  1104. current = &joined_values.back();
  1105. }
  1106. else {
  1107. current->set_value(merge_string_lits(
  1108. current->get_value(), (*it).get_value()));
  1109. }
  1110. }
  1111. else if (current) {
  1112. typedef util::impl::next_token<const_iterator> next_token_type;
  1113. token_id next_id (next_token_type::peek(it, end, true));
  1114. if (next_id != T_STRINGLIT) {
  1115. current = 0;
  1116. joined_values.push_back(*it);
  1117. }
  1118. }
  1119. else {
  1120. joined_values.push_back(*it);
  1121. }
  1122. }
  1123. }
  1124. ///////////////////////////////////////////////////////////////////////////
  1125. // interpret the pragma wave option() directives
  1126. template <typename ContextT, typename ContainerT>
  1127. bool
  1128. interpret_pragma_option(ContextT &ctx, ContainerT const &cvalues,
  1129. typename ContextT::token_type const &act_token)
  1130. {
  1131. using namespace boost::wave;
  1132. typedef typename ContextT::token_type token_type;
  1133. typedef typename token_type::string_type string_type;
  1134. typedef typename ContainerT::const_iterator const_iterator;
  1135. ContainerT values;
  1136. join_adjacent_string_tokens(ctx, cvalues, values);
  1137. const_iterator end = values.end();
  1138. for (const_iterator it = values.begin(); it != end; /**/) {
  1139. bool valid_option = false;
  1140. token_type const &value = *it;
  1141. if (value.get_value() == "preserve") {
  1142. // #pragma wave option(preserve: [0|1|2|3|push|pop])
  1143. valid_option = interpret_pragma_option_preserve(ctx, it, end,
  1144. act_token);
  1145. }
  1146. else if (value.get_value() == "line") {
  1147. // #pragma wave option(line: [0|1|2|push|pop])
  1148. valid_option = interpret_pragma_option_line(ctx, it, end,
  1149. act_token);
  1150. }
  1151. else if (value.get_value() == "output") {
  1152. // #pragma wave option(output: ["filename"|null|default|push|pop])
  1153. valid_option = interpret_pragma_option_output(ctx, it, end,
  1154. act_token);
  1155. }
  1156. if (!valid_option) {
  1157. // unknown option value
  1158. string_type option_str ("option");
  1159. if (values.size() > 0) {
  1160. option_str += "(";
  1161. option_str += util::impl::as_string(values);
  1162. option_str += ")";
  1163. }
  1164. BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
  1165. ill_formed_pragma_option,
  1166. option_str.c_str(), act_token.get_position());
  1167. return false;
  1168. }
  1169. token_id id = util::impl::skip_whitespace(it, end);
  1170. if (id == T_COMMA)
  1171. util::impl::skip_whitespace(it, end);
  1172. }
  1173. return true;
  1174. }
  1175. ///////////////////////////////////////////////////////////////////////////
  1176. // interpret the #pragma wave system() directive
  1177. template <typename ContextT, typename ContainerT>
  1178. bool
  1179. interpret_pragma_system(ContextT& ctx, ContainerT &pending,
  1180. ContainerT const &values,
  1181. typename ContextT::token_type const &act_token)
  1182. {
  1183. typedef typename ContextT::token_type token_type;
  1184. typedef typename token_type::string_type string_type;
  1185. if (0 == values.size()) return false; // ill_formed_pragma_option
  1186. string_type stdout_file(std::tmpnam(0));
  1187. string_type stderr_file(std::tmpnam(0));
  1188. string_type system_str(boost::wave::util::impl::as_string(values));
  1189. string_type native_cmd(system_str);
  1190. system_str += " >" + stdout_file + " 2>" + stderr_file;
  1191. if (0 != std::system(system_str.c_str())) {
  1192. // unable to spawn the command
  1193. string_type error_str("unable to spawn command: ");
  1194. error_str += native_cmd;
  1195. BOOST_WAVE_THROW_CTX(ctx, boost::wave::preprocess_exception,
  1196. ill_formed_pragma_option,
  1197. error_str.c_str(), act_token.get_position());
  1198. return false;
  1199. }
  1200. // rescan the content of the stdout_file and insert it as the
  1201. // _Pragma replacement
  1202. typedef typename ContextT::lexer_type lexer_type;
  1203. typedef typename ContextT::input_policy_type input_policy_type;
  1204. typedef boost::wave::iteration_context<
  1205. ContextT, lexer_type, input_policy_type>
  1206. iteration_context_type;
  1207. iteration_context_type iter_ctx(ctx, stdout_file.c_str(),
  1208. act_token.get_position(), ctx.get_language());
  1209. ContainerT pragma;
  1210. for (/**/; iter_ctx.first != iter_ctx.last; ++iter_ctx.first)
  1211. pragma.push_back(*iter_ctx.first);
  1212. // prepend the newly generated token sequence to the 'pending' container
  1213. pending.splice(pending.begin(), pragma);
  1214. // erase the created tempfiles
  1215. std::remove(stdout_file.c_str());
  1216. std::remove(stderr_file.c_str());
  1217. return true;
  1218. }
  1219. ///////////////////////////////////////////////////////////////////////////
  1220. // The function enable_tracing is called, whenever the status of the
  1221. // tracing was changed.
  1222. // The parameter 'enable' is to be used as the new tracing status.
  1223. void enable_tracing(trace_flags flags)
  1224. { logging_flags = flags; }
  1225. // The function tracing_enabled should return the current tracing status.
  1226. trace_flags tracing_enabled()
  1227. { return logging_flags; }
  1228. // Helper functions for generating the trace output
  1229. void open_trace_body(char const *label = 0)
  1230. {
  1231. if (label)
  1232. output(label);
  1233. output("[\n");
  1234. increment_level();
  1235. }
  1236. void close_trace_body()
  1237. {
  1238. if (get_level() > 0) {
  1239. decrement_level();
  1240. output("]\n");
  1241. tracestrm << std::flush; // flush the stream buffer
  1242. }
  1243. }
  1244. template <typename StringT>
  1245. void output(StringT const &outstr) const
  1246. {
  1247. indent(get_level());
  1248. tracestrm << outstr; // output the given string
  1249. }
  1250. void indent(int level) const
  1251. {
  1252. for (int i = 0; i < level; ++i)
  1253. tracestrm << " "; // indent
  1254. }
  1255. int increment_level() { return ++level; }
  1256. int decrement_level() { BOOST_ASSERT(level > 0); return --level; }
  1257. int get_level() const { return level; }
  1258. bool enabled_macro_tracing() const
  1259. {
  1260. return (flags & trace_macros) && (logging_flags & trace_macros);
  1261. }
  1262. bool enabled_include_tracing() const
  1263. {
  1264. return (flags & trace_includes);
  1265. }
  1266. bool enabled_guard_tracing() const
  1267. {
  1268. return (flags & trace_guards);
  1269. }
  1270. bool enabled_macro_counting() const
  1271. {
  1272. return logging_flags & trace_macro_counts;
  1273. }
  1274. void count_invocation(std::string const& name)
  1275. {
  1276. typedef std::map<std::string, std::size_t>::iterator iterator;
  1277. typedef std::map<std::string, std::size_t>::value_type value_type;
  1278. iterator it = counts.find(name);
  1279. if (it == counts.end())
  1280. {
  1281. std::pair<iterator, bool> p = counts.insert(value_type(name, 0));
  1282. if (p.second)
  1283. it = p.first;
  1284. }
  1285. if (it != counts.end())
  1286. ++(*it).second;
  1287. }
  1288. void timer(TokenT const &value)
  1289. {
  1290. if (value.get_value() == "0" || value.get_value() == "restart") {
  1291. // restart the timer
  1292. elapsed_time.restart();
  1293. }
  1294. else if (value.get_value() == "1") {
  1295. // print out the current elapsed time
  1296. std::cerr
  1297. << value.get_position() << ": "
  1298. << elapsed_time.format_elapsed_time()
  1299. << std::endl;
  1300. }
  1301. else if (value.get_value() == "suspend") {
  1302. // suspend the timer
  1303. elapsed_time.suspend();
  1304. }
  1305. else if (value.get_value() == "resume") {
  1306. // resume the timer
  1307. elapsed_time.resume();
  1308. }
  1309. }
  1310. private:
  1311. std::ofstream &outputstrm; // main output stream
  1312. std::ostream &tracestrm; // trace output stream
  1313. std::ostream &includestrm; // included list output stream
  1314. std::ostream &guardstrm; // include guard output stream
  1315. int level; // indentation level
  1316. trace_flags flags; // enabled globally
  1317. trace_flags logging_flags; // enabled by a #pragma
  1318. bool enable_system_command; // enable #pragma wave system() command
  1319. bool preserve_whitespace; // enable whitespace preservation
  1320. bool preserve_bol_whitespace; // enable begin of line whitespace preservation
  1321. bool& generate_output; // allow generated tokens to be streamed to output
  1322. std::string const& default_outfile; // name of the output file given on command line
  1323. boost::filesystem::path current_outfile; // name of the current output file
  1324. stop_watch elapsed_time; // trace timings
  1325. std::set<boost::filesystem::path> written_by_us; // all files we have written to
  1326. typedef std::pair<bool, boost::filesystem::path> output_option_type;
  1327. std::stack<output_option_type> output_options; // output option stack
  1328. std::stack<int> line_options; // line option stack
  1329. std::stack<int> preserve_options; // preserve option stack
  1330. std::map<std::string, std::size_t> counts; // macro invocation counts
  1331. bool emit_relative_filenames; // emit relative names in #line directives
  1332. std::set<std::string> noexpandmacros; // list of macros not to expand
  1333. std::string license_info; // text to pre-pend to all generated output files
  1334. };
  1335. #undef BOOST_WAVE_GETSTRING
  1336. #undef BOOST_WAVE_OSSTREAM
  1337. #endif // !defined(TRACE_MACRO_EXPANSION_HPP_D8469318_8407_4B9D_A19F_13CA60C1661F_INCLUDED)