Chris@16
|
1 /*=============================================================================
|
Chris@16
|
2 Boost.Wave: A Standard compliant C++ preprocessor library
|
Chris@16
|
3
|
Chris@16
|
4 http://www.boost.org/
|
Chris@16
|
5
|
Chris@16
|
6 Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
|
Chris@16
|
7 Software License, Version 1.0. (See accompanying file
|
Chris@16
|
8 LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
9 =============================================================================*/
|
Chris@16
|
10
|
Chris@16
|
11 #if !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
|
Chris@16
|
12 #define CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED
|
Chris@16
|
13
|
Chris@16
|
14 #include <boost/spirit/include/classic_core.hpp>
|
Chris@16
|
15 #include <boost/spirit/include/classic_parse_tree.hpp>
|
Chris@16
|
16 #include <boost/spirit/include/classic_parse_tree_utils.hpp>
|
Chris@16
|
17 #include <boost/spirit/include/classic_confix.hpp>
|
Chris@16
|
18 #include <boost/spirit/include/classic_lists.hpp>
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/wave/wave_config.hpp>
|
Chris@16
|
21 #include <boost/pool/pool_alloc.hpp>
|
Chris@16
|
22
|
Chris@16
|
23 #if BOOST_WAVE_DUMP_PARSE_TREE != 0
|
Chris@16
|
24 #include <map>
|
Chris@16
|
25 #include <boost/spirit/include/classic_tree_to_xml.hpp>
|
Chris@16
|
26 #endif
|
Chris@16
|
27
|
Chris@16
|
28 #include <boost/wave/token_ids.hpp>
|
Chris@16
|
29 #include <boost/wave/grammars/cpp_grammar_gen.hpp>
|
Chris@16
|
30 #include <boost/wave/util/pattern_parser.hpp>
|
Chris@16
|
31
|
Chris@16
|
32 #include <boost/wave/cpp_exceptions.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 // this must occur after all of the includes and before any code appears
|
Chris@16
|
35 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
36 #include BOOST_ABI_PREFIX
|
Chris@16
|
37 #endif
|
Chris@16
|
38
|
Chris@16
|
39 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
40 namespace boost {
|
Chris@16
|
41 namespace wave {
|
Chris@16
|
42 namespace grammars {
|
Chris@16
|
43
|
Chris@16
|
44 namespace impl {
|
Chris@16
|
45
|
Chris@16
|
46 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
47 //
|
Chris@16
|
48 // store_found_eof
|
Chris@16
|
49 //
|
Chris@16
|
50 // The store_found_eof functor sets a given flag if the T_EOF token was
|
Chris@16
|
51 // found during the parsing process
|
Chris@16
|
52 //
|
Chris@16
|
53 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
54
|
Chris@16
|
55 struct store_found_eof {
|
Chris@16
|
56
|
Chris@16
|
57 store_found_eof(bool &found_eof_) : found_eof(found_eof_) {}
|
Chris@16
|
58
|
Chris@16
|
59 template <typename TokenT>
|
Chris@16
|
60 void operator()(TokenT const &/*token*/) const
|
Chris@16
|
61 {
|
Chris@16
|
62 found_eof = true;
|
Chris@16
|
63 }
|
Chris@16
|
64
|
Chris@16
|
65 bool &found_eof;
|
Chris@16
|
66 };
|
Chris@16
|
67
|
Chris@16
|
68 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
69 //
|
Chris@16
|
70 // store_found_directive
|
Chris@16
|
71 //
|
Chris@16
|
72 // The store_found_directive functor stores the token_id of the recognized
|
Chris@16
|
73 // pp directive
|
Chris@16
|
74 //
|
Chris@16
|
75 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
76
|
Chris@16
|
77 template <typename TokenT>
|
Chris@16
|
78 struct store_found_directive {
|
Chris@16
|
79
|
Chris@16
|
80 store_found_directive(TokenT &found_directive_)
|
Chris@16
|
81 : found_directive(found_directive_) {}
|
Chris@16
|
82
|
Chris@16
|
83 void operator()(TokenT const &token) const
|
Chris@16
|
84 {
|
Chris@16
|
85 found_directive = token;
|
Chris@16
|
86 }
|
Chris@16
|
87
|
Chris@16
|
88 TokenT &found_directive;
|
Chris@16
|
89 };
|
Chris@16
|
90
|
Chris@16
|
91 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
92 //
|
Chris@16
|
93 // store_found_eoltokens
|
Chris@16
|
94 //
|
Chris@16
|
95 // The store_found_eoltokens functor stores the token sequence of the
|
Chris@16
|
96 // line ending for a particular pp directive
|
Chris@16
|
97 //
|
Chris@16
|
98 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
99
|
Chris@16
|
100 template <typename ContainerT>
|
Chris@16
|
101 struct store_found_eoltokens {
|
Chris@16
|
102
|
Chris@16
|
103 store_found_eoltokens(ContainerT &found_eoltokens_)
|
Chris@16
|
104 : found_eoltokens(found_eoltokens_) {}
|
Chris@16
|
105
|
Chris@16
|
106 template <typename IteratorT>
|
Chris@16
|
107 void operator()(IteratorT const &first, IteratorT const& last) const
|
Chris@16
|
108 {
|
Chris@16
|
109 std::copy(first, last,
|
Chris@16
|
110 std::inserter(found_eoltokens, found_eoltokens.end()));
|
Chris@16
|
111 }
|
Chris@16
|
112
|
Chris@16
|
113 ContainerT &found_eoltokens;
|
Chris@16
|
114 };
|
Chris@16
|
115
|
Chris@16
|
116 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
117 //
|
Chris@16
|
118 // flush_underlying_parser
|
Chris@16
|
119 //
|
Chris@16
|
120 // The flush_underlying_parser flushes the underlying
|
Chris@16
|
121 // multi_pass_iterator during the normal parsing process. This is
|
Chris@16
|
122 // used at certain points during the parsing process, when it is
|
Chris@16
|
123 // clear, that no backtracking is needed anymore and the input
|
Chris@16
|
124 // gathered so far may be discarded.
|
Chris@16
|
125 //
|
Chris@16
|
126 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
127 struct flush_underlying_parser
|
Chris@16
|
128 : public boost::spirit::classic::parser<flush_underlying_parser>
|
Chris@16
|
129 {
|
Chris@16
|
130 typedef flush_underlying_parser this_t;
|
Chris@16
|
131
|
Chris@16
|
132 template <typename ScannerT>
|
Chris@16
|
133 typename boost::spirit::classic::parser_result<this_t, ScannerT>::type
|
Chris@16
|
134 parse(ScannerT const& scan) const
|
Chris@16
|
135 {
|
Chris@16
|
136 scan.first.clear_queue();
|
Chris@16
|
137 return scan.empty_match();
|
Chris@16
|
138 }
|
Chris@16
|
139 };
|
Chris@16
|
140
|
Chris@16
|
141 flush_underlying_parser const
|
Chris@16
|
142 flush_underlying_parser_p = flush_underlying_parser();
|
Chris@16
|
143
|
Chris@16
|
144 } // anonymous namespace
|
Chris@16
|
145
|
Chris@16
|
146 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
147 // define, whether the rule's should generate some debug output
|
Chris@16
|
148 #define TRACE_CPP_GRAMMAR \
|
Chris@16
|
149 bool(BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
|
Chris@16
|
150 /**/
|
Chris@16
|
151
|
Chris@16
|
152 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
153 // Encapsulation of the C++ preprocessor grammar.
|
Chris@16
|
154 template <typename TokenT, typename ContainerT>
|
Chris@16
|
155 struct cpp_grammar :
|
Chris@16
|
156 public boost::spirit::classic::grammar<cpp_grammar<TokenT, ContainerT> >
|
Chris@16
|
157 {
|
Chris@16
|
158 typedef typename TokenT::position_type position_type;
|
Chris@16
|
159 typedef cpp_grammar<TokenT, ContainerT> grammar_type;
|
Chris@16
|
160 typedef impl::store_found_eof store_found_eof_type;
|
Chris@16
|
161 typedef impl::store_found_directive<TokenT> store_found_directive_type;
|
Chris@16
|
162 typedef impl::store_found_eoltokens<ContainerT> store_found_eoltokens_type;
|
Chris@16
|
163
|
Chris@16
|
164 template <typename ScannerT>
|
Chris@16
|
165 struct definition
|
Chris@16
|
166 {
|
Chris@16
|
167 // non-parse_tree generating rule type
|
Chris@16
|
168 typedef typename ScannerT::iteration_policy_t iteration_policy_t;
|
Chris@16
|
169 typedef boost::spirit::classic::match_policy match_policy_t;
|
Chris@16
|
170 typedef typename ScannerT::action_policy_t action_policy_t;
|
Chris@16
|
171 typedef
|
Chris@16
|
172 boost::spirit::classic::scanner_policies<
|
Chris@16
|
173 iteration_policy_t, match_policy_t, action_policy_t>
|
Chris@16
|
174 policies_t;
|
Chris@16
|
175 typedef
|
Chris@16
|
176 boost::spirit::classic::scanner<typename ScannerT::iterator_t, policies_t>
|
Chris@16
|
177 non_tree_scanner_t;
|
Chris@16
|
178 typedef
|
Chris@16
|
179 boost::spirit::classic::rule<
|
Chris@16
|
180 non_tree_scanner_t, boost::spirit::classic::dynamic_parser_tag>
|
Chris@16
|
181 no_tree_rule_type;
|
Chris@16
|
182
|
Chris@16
|
183 // 'normal' (parse_tree generating) rule type
|
Chris@16
|
184 typedef
|
Chris@16
|
185 boost::spirit::classic::rule<
|
Chris@16
|
186 ScannerT, boost::spirit::classic::dynamic_parser_tag>
|
Chris@16
|
187 rule_type;
|
Chris@16
|
188
|
Chris@16
|
189 rule_type pp_statement, macro_include_file;
|
Chris@16
|
190 // rule_type include_file, system_include_file;
|
Chris@16
|
191 rule_type plain_define, macro_definition, macro_parameters;
|
Chris@16
|
192 rule_type undefine;
|
Chris@16
|
193 rule_type ppifdef, ppifndef, ppif, ppelif;
|
Chris@16
|
194 // rule_type ppelse, ppendif;
|
Chris@16
|
195 rule_type ppline;
|
Chris@16
|
196 rule_type pperror;
|
Chris@16
|
197 rule_type ppwarning;
|
Chris@16
|
198 rule_type pppragma;
|
Chris@16
|
199 rule_type illformed;
|
Chris@16
|
200 rule_type ppqualifiedname;
|
Chris@16
|
201 rule_type eol_tokens;
|
Chris@16
|
202 no_tree_rule_type ppsp;
|
Chris@16
|
203 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
204 rule_type ppregion;
|
Chris@16
|
205 rule_type ppendregion;
|
Chris@16
|
206 #endif
|
Chris@16
|
207
|
Chris@16
|
208 definition(cpp_grammar const &self)
|
Chris@16
|
209 {
|
Chris@16
|
210 // import the spirit and cpplexer namespaces here
|
Chris@16
|
211 using namespace boost::spirit::classic;
|
Chris@16
|
212 using namespace boost::wave;
|
Chris@16
|
213 using namespace boost::wave::util;
|
Chris@16
|
214
|
Chris@16
|
215 // set the rule id's for later use
|
Chris@16
|
216 pp_statement.set_id(BOOST_WAVE_PP_STATEMENT_ID);
|
Chris@16
|
217 // include_file.set_id(BOOST_WAVE_INCLUDE_FILE_ID);
|
Chris@16
|
218 // system_include_file.set_id(BOOST_WAVE_SYSINCLUDE_FILE_ID);
|
Chris@16
|
219 macro_include_file.set_id(BOOST_WAVE_MACROINCLUDE_FILE_ID);
|
Chris@16
|
220 plain_define.set_id(BOOST_WAVE_PLAIN_DEFINE_ID);
|
Chris@16
|
221 macro_parameters.set_id(BOOST_WAVE_MACRO_PARAMETERS_ID);
|
Chris@16
|
222 macro_definition.set_id(BOOST_WAVE_MACRO_DEFINITION_ID);
|
Chris@16
|
223 undefine.set_id(BOOST_WAVE_UNDEFINE_ID);
|
Chris@16
|
224 ppifdef.set_id(BOOST_WAVE_IFDEF_ID);
|
Chris@16
|
225 ppifndef.set_id(BOOST_WAVE_IFNDEF_ID);
|
Chris@16
|
226 ppif.set_id(BOOST_WAVE_IF_ID);
|
Chris@16
|
227 ppelif.set_id(BOOST_WAVE_ELIF_ID);
|
Chris@16
|
228 // ppelse.set_id(BOOST_WAVE_ELSE_ID);
|
Chris@16
|
229 // ppendif.set_id(BOOST_WAVE_ENDIF_ID);
|
Chris@16
|
230 ppline.set_id(BOOST_WAVE_LINE_ID);
|
Chris@16
|
231 pperror.set_id(BOOST_WAVE_ERROR_ID);
|
Chris@16
|
232 ppwarning.set_id(BOOST_WAVE_WARNING_ID);
|
Chris@16
|
233 pppragma.set_id(BOOST_WAVE_PRAGMA_ID);
|
Chris@16
|
234 illformed.set_id(BOOST_WAVE_ILLFORMED_ID);
|
Chris@16
|
235 ppsp.set_id(BOOST_WAVE_PPSPACE_ID);
|
Chris@16
|
236 ppqualifiedname.set_id(BOOST_WAVE_PPQUALIFIEDNAME_ID);
|
Chris@16
|
237 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
238 ppregion.set_id(BOOST_WAVE_REGION_ID);
|
Chris@16
|
239 ppendregion.set_id(BOOST_WAVE_ENDREGION_ID);
|
Chris@16
|
240 #endif
|
Chris@16
|
241
|
Chris@16
|
242 #if BOOST_WAVE_DUMP_PARSE_TREE != 0
|
Chris@16
|
243 self.map_rule_id_to_name.init_rule_id_to_name_map(self);
|
Chris@16
|
244 #endif
|
Chris@16
|
245
|
Chris@16
|
246 // recognizes preprocessor directives only
|
Chris@16
|
247
|
Chris@16
|
248 // C++ standard 16.1: A preprocessing directive consists of a sequence
|
Chris@16
|
249 // of preprocessing tokens. The first token in the sequence is #
|
Chris@16
|
250 // preprocessing token that is either the first character in the source
|
Chris@16
|
251 // file (optionally after white space containing no new-line
|
Chris@16
|
252 // characters) or that follows white space containing at least one
|
Chris@16
|
253 // new-line character. The last token in the sequence is the first
|
Chris@16
|
254 // new-line character that follows the first token in the sequence.
|
Chris@16
|
255
|
Chris@16
|
256 pp_statement
|
Chris@16
|
257 = ( plain_define
|
Chris@16
|
258 // | include_file
|
Chris@16
|
259 // | system_include_file
|
Chris@16
|
260 | ppif
|
Chris@16
|
261 | ppelif
|
Chris@16
|
262 | ppifndef
|
Chris@16
|
263 | ppifdef
|
Chris@16
|
264 | undefine
|
Chris@16
|
265 // | ppelse
|
Chris@16
|
266 | macro_include_file
|
Chris@16
|
267 | ppline
|
Chris@16
|
268 | pppragma
|
Chris@16
|
269 | pperror
|
Chris@16
|
270 | ppwarning
|
Chris@16
|
271 // | ppendif
|
Chris@16
|
272 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
273 | ppregion
|
Chris@16
|
274 | ppendregion
|
Chris@16
|
275 #endif
|
Chris@16
|
276 | illformed
|
Chris@16
|
277 )
|
Chris@16
|
278 >> eol_tokens
|
Chris@16
|
279 [ store_found_eoltokens_type(self.found_eoltokens) ]
|
Chris@16
|
280 // In parser debug mode it is useful not to flush the underlying stream
|
Chris@16
|
281 // to allow its investigation in the debugger and to see the correct
|
Chris@16
|
282 // output in the printed debug log..
|
Chris@16
|
283 // Note: this may break the parser, though.
|
Chris@16
|
284 #if !(defined(BOOST_SPIRIT_DEBUG) && \
|
Chris@16
|
285 (BOOST_SPIRIT_DEBUG_FLAGS_CPP & BOOST_SPIRIT_DEBUG_FLAGS_CPP_GRAMMAR) \
|
Chris@16
|
286 )
|
Chris@16
|
287 >> impl::flush_underlying_parser_p
|
Chris@16
|
288 #endif // !(defined(BOOST_SPIRIT_DEBUG) &&
|
Chris@16
|
289 ;
|
Chris@16
|
290
|
Chris@16
|
291 // // #include ...
|
Chris@16
|
292 // include_file // include "..."
|
Chris@16
|
293 // = ch_p(T_PP_QHEADER)
|
Chris@16
|
294 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
295 // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
|
Chris@16
|
296 // | ch_p(T_PP_QHEADER_NEXT)
|
Chris@16
|
297 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
298 // #endif
|
Chris@16
|
299 // ;
|
Chris@16
|
300
|
Chris@16
|
301 // system_include_file // include <...>
|
Chris@16
|
302 // = ch_p(T_PP_HHEADER)
|
Chris@16
|
303 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
304 // #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
|
Chris@16
|
305 // | ch_p(T_PP_HHEADER_NEXT)
|
Chris@16
|
306 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
307 // #endif
|
Chris@16
|
308 // ;
|
Chris@16
|
309
|
Chris@16
|
310 macro_include_file // include ...anything else...
|
Chris@16
|
311 = no_node_d
|
Chris@16
|
312 [
|
Chris@16
|
313 ch_p(T_PP_INCLUDE)
|
Chris@16
|
314 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
315 #if BOOST_WAVE_SUPPORT_INCLUDE_NEXT != 0
|
Chris@16
|
316 | ch_p(T_PP_INCLUDE_NEXT)
|
Chris@16
|
317 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
318 #endif
|
Chris@16
|
319 ]
|
Chris@16
|
320 >> *( anychar_p -
|
Chris@16
|
321 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
322 )
|
Chris@16
|
323 ;
|
Chris@16
|
324
|
Chris@16
|
325 // #define FOO foo (with optional parameters)
|
Chris@16
|
326 plain_define
|
Chris@16
|
327 = no_node_d
|
Chris@16
|
328 [
|
Chris@16
|
329 ch_p(T_PP_DEFINE)
|
Chris@16
|
330 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
331 >> +ppsp
|
Chris@16
|
332 ]
|
Chris@16
|
333 >> ( ch_p(T_IDENTIFIER)
|
Chris@16
|
334 | pattern_p(KeywordTokenType,
|
Chris@16
|
335 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
336 | pattern_p(OperatorTokenType|AltExtTokenType,
|
Chris@16
|
337 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
|
Chris@16
|
338 | pattern_p(BoolLiteralTokenType,
|
Chris@16
|
339 TokenTypeMask|PPTokenFlag) // true/false
|
Chris@16
|
340 )
|
Chris@16
|
341 >> ( ( no_node_d[eps_p(ch_p(T_LEFTPAREN))]
|
Chris@16
|
342 >> macro_parameters
|
Chris@16
|
343 >> !macro_definition
|
Chris@16
|
344 )
|
Chris@16
|
345 | !( no_node_d[+ppsp]
|
Chris@16
|
346 >> macro_definition
|
Chris@16
|
347 )
|
Chris@16
|
348 )
|
Chris@16
|
349 ;
|
Chris@16
|
350
|
Chris@16
|
351 // parameter list
|
Chris@16
|
352 // normal C++ mode
|
Chris@16
|
353 macro_parameters
|
Chris@16
|
354 = confix_p(
|
Chris@16
|
355 no_node_d[ch_p(T_LEFTPAREN) >> *ppsp],
|
Chris@16
|
356 !list_p(
|
Chris@16
|
357 ( ch_p(T_IDENTIFIER)
|
Chris@16
|
358 | pattern_p(KeywordTokenType,
|
Chris@16
|
359 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
360 | pattern_p(OperatorTokenType|AltExtTokenType,
|
Chris@16
|
361 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
|
Chris@16
|
362 | pattern_p(BoolLiteralTokenType,
|
Chris@16
|
363 TokenTypeMask|PPTokenFlag) // true/false
|
Chris@16
|
364 #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
|
Chris@16
|
365 | ch_p(T_ELLIPSIS)
|
Chris@16
|
366 #endif
|
Chris@16
|
367 ),
|
Chris@16
|
368 no_node_d[*ppsp >> ch_p(T_COMMA) >> *ppsp]
|
Chris@16
|
369 ),
|
Chris@16
|
370 no_node_d[*ppsp >> ch_p(T_RIGHTPAREN)]
|
Chris@16
|
371 )
|
Chris@16
|
372 ;
|
Chris@16
|
373
|
Chris@16
|
374 // macro body (anything left until eol)
|
Chris@16
|
375 macro_definition
|
Chris@16
|
376 = no_node_d[*ppsp]
|
Chris@16
|
377 >> *( anychar_p -
|
Chris@16
|
378 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
379 )
|
Chris@16
|
380 ;
|
Chris@16
|
381
|
Chris@16
|
382 // #undef FOO
|
Chris@16
|
383 undefine
|
Chris@16
|
384 = no_node_d
|
Chris@16
|
385 [
|
Chris@16
|
386 ch_p(T_PP_UNDEF)
|
Chris@16
|
387 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
388 >> +ppsp
|
Chris@16
|
389 ]
|
Chris@16
|
390 >> ( ch_p(T_IDENTIFIER)
|
Chris@16
|
391 | pattern_p(KeywordTokenType,
|
Chris@16
|
392 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
393 | pattern_p(OperatorTokenType|AltExtTokenType,
|
Chris@16
|
394 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
|
Chris@16
|
395 | pattern_p(BoolLiteralTokenType,
|
Chris@16
|
396 TokenTypeMask|PPTokenFlag) // true/false
|
Chris@16
|
397 )
|
Chris@16
|
398 ;
|
Chris@16
|
399
|
Chris@16
|
400 // #ifdef et.al.
|
Chris@16
|
401 ppifdef
|
Chris@16
|
402 = no_node_d
|
Chris@16
|
403 [
|
Chris@16
|
404 ch_p(T_PP_IFDEF)
|
Chris@16
|
405 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
406 >> +ppsp
|
Chris@16
|
407 ]
|
Chris@16
|
408 >> ppqualifiedname
|
Chris@16
|
409 ;
|
Chris@16
|
410
|
Chris@16
|
411 ppifndef
|
Chris@16
|
412 = no_node_d
|
Chris@16
|
413 [
|
Chris@16
|
414 ch_p(T_PP_IFNDEF)
|
Chris@16
|
415 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
416 >> +ppsp
|
Chris@16
|
417 ]
|
Chris@16
|
418 >> ppqualifiedname
|
Chris@16
|
419 ;
|
Chris@16
|
420
|
Chris@16
|
421 ppif
|
Chris@16
|
422 = no_node_d
|
Chris@16
|
423 [
|
Chris@16
|
424 ch_p(T_PP_IF)
|
Chris@16
|
425 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
426 // >> *ppsp
|
Chris@16
|
427 ]
|
Chris@16
|
428 >> +( anychar_p -
|
Chris@16
|
429 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
430 )
|
Chris@16
|
431 ;
|
Chris@16
|
432
|
Chris@16
|
433 // ppelse
|
Chris@16
|
434 // = no_node_d
|
Chris@16
|
435 // [
|
Chris@16
|
436 // ch_p(T_PP_ELSE)
|
Chris@16
|
437 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
438 // ]
|
Chris@16
|
439 // ;
|
Chris@16
|
440
|
Chris@16
|
441 ppelif
|
Chris@16
|
442 = no_node_d
|
Chris@16
|
443 [
|
Chris@16
|
444 ch_p(T_PP_ELIF)
|
Chris@16
|
445 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
446 // >> *ppsp
|
Chris@16
|
447 ]
|
Chris@16
|
448 >> +( anychar_p -
|
Chris@16
|
449 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
450 )
|
Chris@16
|
451 ;
|
Chris@16
|
452
|
Chris@16
|
453 // ppendif
|
Chris@16
|
454 // = no_node_d
|
Chris@16
|
455 // [
|
Chris@16
|
456 // ch_p(T_PP_ENDIF)
|
Chris@16
|
457 // [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
458 // ]
|
Chris@16
|
459 // ;
|
Chris@16
|
460
|
Chris@16
|
461 // #line ...
|
Chris@16
|
462 ppline
|
Chris@16
|
463 = no_node_d
|
Chris@16
|
464 [
|
Chris@16
|
465 ch_p(T_PP_LINE)
|
Chris@16
|
466 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
467 >> *ppsp
|
Chris@16
|
468 ]
|
Chris@16
|
469 >> +( anychar_p -
|
Chris@16
|
470 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
471 )
|
Chris@16
|
472 ;
|
Chris@16
|
473
|
Chris@16
|
474 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
475 // #region ...
|
Chris@16
|
476 ppregion
|
Chris@16
|
477 = no_node_d
|
Chris@16
|
478 [
|
Chris@16
|
479 ch_p(T_MSEXT_PP_REGION)
|
Chris@16
|
480 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
481 >> +ppsp
|
Chris@16
|
482 ]
|
Chris@16
|
483 >> ppqualifiedname
|
Chris@16
|
484 ;
|
Chris@16
|
485
|
Chris@16
|
486 // #endregion
|
Chris@16
|
487 ppendregion
|
Chris@16
|
488 = no_node_d
|
Chris@16
|
489 [
|
Chris@16
|
490 ch_p(T_MSEXT_PP_ENDREGION)
|
Chris@16
|
491 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
492 ]
|
Chris@16
|
493 ;
|
Chris@16
|
494 #endif
|
Chris@16
|
495
|
Chris@16
|
496 // # something else (ill formed preprocessor directive)
|
Chris@16
|
497 illformed // for error reporting
|
Chris@16
|
498 = no_node_d
|
Chris@16
|
499 [
|
Chris@16
|
500 pattern_p(T_POUND, MainTokenMask)
|
Chris@16
|
501 >> *ppsp
|
Chris@16
|
502 ]
|
Chris@16
|
503 >> ( anychar_p -
|
Chris@16
|
504 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
505 )
|
Chris@16
|
506 >> no_node_d
|
Chris@16
|
507 [
|
Chris@16
|
508 *( anychar_p -
|
Chris@16
|
509 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
510 )
|
Chris@16
|
511 ]
|
Chris@16
|
512 ;
|
Chris@16
|
513
|
Chris@16
|
514 // #error
|
Chris@16
|
515 pperror
|
Chris@16
|
516 = no_node_d
|
Chris@16
|
517 [
|
Chris@16
|
518 ch_p(T_PP_ERROR)
|
Chris@16
|
519 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
520 >> *ppsp
|
Chris@16
|
521 ]
|
Chris@16
|
522 >> *( anychar_p -
|
Chris@16
|
523 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
524 )
|
Chris@16
|
525 ;
|
Chris@16
|
526
|
Chris@16
|
527 // #warning
|
Chris@16
|
528 ppwarning
|
Chris@16
|
529 = no_node_d
|
Chris@16
|
530 [
|
Chris@16
|
531 ch_p(T_PP_WARNING)
|
Chris@16
|
532 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
533 >> *ppsp
|
Chris@16
|
534 ]
|
Chris@16
|
535 >> *( anychar_p -
|
Chris@16
|
536 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
537 )
|
Chris@16
|
538 ;
|
Chris@16
|
539
|
Chris@16
|
540 // #pragma ...
|
Chris@16
|
541 pppragma
|
Chris@16
|
542 = no_node_d
|
Chris@16
|
543 [
|
Chris@16
|
544 ch_p(T_PP_PRAGMA)
|
Chris@16
|
545 [ store_found_directive_type(self.found_directive) ]
|
Chris@16
|
546 ]
|
Chris@16
|
547 >> *( anychar_p -
|
Chris@16
|
548 (ch_p(T_NEWLINE) | ch_p(T_CPPCOMMENT) | ch_p(T_EOF))
|
Chris@16
|
549 )
|
Chris@16
|
550 ;
|
Chris@16
|
551
|
Chris@16
|
552 ppqualifiedname
|
Chris@16
|
553 = no_node_d[*ppsp]
|
Chris@16
|
554 >> ( ch_p(T_IDENTIFIER)
|
Chris@16
|
555 | pattern_p(KeywordTokenType,
|
Chris@16
|
556 TokenTypeMask|PPTokenFlag)
|
Chris@16
|
557 | pattern_p(OperatorTokenType|AltExtTokenType,
|
Chris@16
|
558 ExtTokenTypeMask|PPTokenFlag) // and, bit_and etc.
|
Chris@16
|
559 | pattern_p(BoolLiteralTokenType,
|
Chris@16
|
560 TokenTypeMask|PPTokenFlag) // true/false
|
Chris@16
|
561 )
|
Chris@16
|
562 ;
|
Chris@16
|
563
|
Chris@16
|
564 // auxiliary helper rules
|
Chris@16
|
565 ppsp // valid space in a line with a preprocessor directive
|
Chris@16
|
566 = ch_p(T_SPACE) | ch_p(T_CCOMMENT)
|
Chris@16
|
567 ;
|
Chris@16
|
568
|
Chris@16
|
569 // end of line tokens
|
Chris@16
|
570 eol_tokens
|
Chris@16
|
571 = no_node_d
|
Chris@16
|
572 [
|
Chris@16
|
573 *( ch_p(T_SPACE)
|
Chris@16
|
574 | ch_p(T_CCOMMENT)
|
Chris@16
|
575 )
|
Chris@16
|
576 >> ( ch_p(T_NEWLINE)
|
Chris@16
|
577 | ch_p(T_CPPCOMMENT)
|
Chris@16
|
578 | ch_p(T_EOF)
|
Chris@16
|
579 [ store_found_eof_type(self.found_eof) ]
|
Chris@16
|
580 )
|
Chris@16
|
581 ]
|
Chris@16
|
582 ;
|
Chris@16
|
583
|
Chris@16
|
584 BOOST_SPIRIT_DEBUG_TRACE_RULE(pp_statement, TRACE_CPP_GRAMMAR);
|
Chris@16
|
585 // BOOST_SPIRIT_DEBUG_TRACE_RULE(include_file, TRACE_CPP_GRAMMAR);
|
Chris@16
|
586 // BOOST_SPIRIT_DEBUG_TRACE_RULE(system_include_file, TRACE_CPP_GRAMMAR);
|
Chris@16
|
587 BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_include_file, TRACE_CPP_GRAMMAR);
|
Chris@16
|
588 BOOST_SPIRIT_DEBUG_TRACE_RULE(plain_define, TRACE_CPP_GRAMMAR);
|
Chris@16
|
589 BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_definition, TRACE_CPP_GRAMMAR);
|
Chris@16
|
590 BOOST_SPIRIT_DEBUG_TRACE_RULE(macro_parameters, TRACE_CPP_GRAMMAR);
|
Chris@16
|
591 BOOST_SPIRIT_DEBUG_TRACE_RULE(undefine, TRACE_CPP_GRAMMAR);
|
Chris@16
|
592 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifdef, TRACE_CPP_GRAMMAR);
|
Chris@16
|
593 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppifndef, TRACE_CPP_GRAMMAR);
|
Chris@16
|
594 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppif, TRACE_CPP_GRAMMAR);
|
Chris@16
|
595 // BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelse, TRACE_CPP_GRAMMAR);
|
Chris@16
|
596 // BOOST_SPIRIT_DEBUG_TRACE_RULE(ppelif, TRACE_CPP_GRAMMAR);
|
Chris@16
|
597 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendif, TRACE_CPP_GRAMMAR);
|
Chris@16
|
598 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppline, TRACE_CPP_GRAMMAR);
|
Chris@16
|
599 BOOST_SPIRIT_DEBUG_TRACE_RULE(pperror, TRACE_CPP_GRAMMAR);
|
Chris@16
|
600 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppwarning, TRACE_CPP_GRAMMAR);
|
Chris@16
|
601 BOOST_SPIRIT_DEBUG_TRACE_RULE(illformed, TRACE_CPP_GRAMMAR);
|
Chris@16
|
602 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppsp, TRACE_CPP_GRAMMAR);
|
Chris@16
|
603 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppqualifiedname, TRACE_CPP_GRAMMAR);
|
Chris@16
|
604 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
605 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppregion, TRACE_CPP_GRAMMAR);
|
Chris@16
|
606 BOOST_SPIRIT_DEBUG_TRACE_RULE(ppendregion, TRACE_CPP_GRAMMAR);
|
Chris@16
|
607 #endif
|
Chris@16
|
608 }
|
Chris@16
|
609
|
Chris@16
|
610 // start rule of this grammar
|
Chris@16
|
611 rule_type const& start() const
|
Chris@16
|
612 { return pp_statement; }
|
Chris@16
|
613 };
|
Chris@16
|
614
|
Chris@16
|
615 bool &found_eof;
|
Chris@16
|
616 TokenT &found_directive;
|
Chris@16
|
617 ContainerT &found_eoltokens;
|
Chris@16
|
618
|
Chris@16
|
619 cpp_grammar(bool &found_eof_, TokenT &found_directive_,
|
Chris@16
|
620 ContainerT &found_eoltokens_)
|
Chris@16
|
621 : found_eof(found_eof_),
|
Chris@16
|
622 found_directive(found_directive_),
|
Chris@16
|
623 found_eoltokens(found_eoltokens_)
|
Chris@16
|
624 {
|
Chris@16
|
625 BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME(*this, "cpp_grammar",
|
Chris@16
|
626 TRACE_CPP_GRAMMAR);
|
Chris@16
|
627 }
|
Chris@16
|
628
|
Chris@16
|
629 #if BOOST_WAVE_DUMP_PARSE_TREE != 0
|
Chris@16
|
630 // helper function and data to get readable names of the rules known to us
|
Chris@16
|
631 struct map_ruleid_to_name :
|
Chris@16
|
632 public std::map<boost::spirit::classic::parser_id, std::string>
|
Chris@16
|
633 {
|
Chris@16
|
634 typedef std::map<boost::spirit::classic::parser_id, std::string> base_type;
|
Chris@16
|
635
|
Chris@16
|
636 void init_rule_id_to_name_map(cpp_grammar const &self)
|
Chris@16
|
637 {
|
Chris@16
|
638 struct {
|
Chris@16
|
639 int parser_id;
|
Chris@16
|
640 char const *rule_name;
|
Chris@16
|
641 }
|
Chris@16
|
642 init_ruleid_name_map[] = {
|
Chris@16
|
643 { BOOST_WAVE_PP_STATEMENT_ID, "pp_statement" },
|
Chris@16
|
644 // { BOOST_WAVE_INCLUDE_FILE_ID, "include_file" },
|
Chris@16
|
645 // { BOOST_WAVE_SYSINCLUDE_FILE_ID, "system_include_file" },
|
Chris@16
|
646 { BOOST_WAVE_MACROINCLUDE_FILE_ID, "macro_include_file" },
|
Chris@16
|
647 { BOOST_WAVE_PLAIN_DEFINE_ID, "plain_define" },
|
Chris@16
|
648 { BOOST_WAVE_MACRO_PARAMETERS_ID, "macro_parameters" },
|
Chris@16
|
649 { BOOST_WAVE_MACRO_DEFINITION_ID, "macro_definition" },
|
Chris@16
|
650 { BOOST_WAVE_UNDEFINE_ID, "undefine" },
|
Chris@16
|
651 { BOOST_WAVE_IFDEF_ID, "ppifdef" },
|
Chris@16
|
652 { BOOST_WAVE_IFNDEF_ID, "ppifndef" },
|
Chris@16
|
653 { BOOST_WAVE_IF_ID, "ppif" },
|
Chris@16
|
654 { BOOST_WAVE_ELIF_ID, "ppelif" },
|
Chris@16
|
655 // { BOOST_WAVE_ELSE_ID, "ppelse" },
|
Chris@16
|
656 // { BOOST_WAVE_ENDIF_ID, "ppendif" },
|
Chris@16
|
657 { BOOST_WAVE_LINE_ID, "ppline" },
|
Chris@16
|
658 { BOOST_WAVE_ERROR_ID, "pperror" },
|
Chris@16
|
659 { BOOST_WAVE_WARNING_ID, "ppwarning" },
|
Chris@16
|
660 { BOOST_WAVE_PRAGMA_ID, "pppragma" },
|
Chris@16
|
661 { BOOST_WAVE_ILLFORMED_ID, "illformed" },
|
Chris@16
|
662 { BOOST_WAVE_PPSPACE_ID, "ppspace" },
|
Chris@16
|
663 { BOOST_WAVE_PPQUALIFIEDNAME_ID, "ppqualifiedname" },
|
Chris@16
|
664 #if BOOST_WAVE_SUPPORT_MS_EXTENSIONS != 0
|
Chris@16
|
665 { BOOST_WAVE_REGION_ID, "ppregion" },
|
Chris@16
|
666 { BOOST_WAVE_ENDREGION_ID, "ppendregion" },
|
Chris@16
|
667 #endif
|
Chris@16
|
668 { 0 }
|
Chris@16
|
669 };
|
Chris@16
|
670
|
Chris@16
|
671 // initialize parser_id to rule_name map
|
Chris@16
|
672 for (int i = 0; 0 != init_ruleid_name_map[i].parser_id; ++i)
|
Chris@16
|
673 base_type::insert(base_type::value_type(
|
Chris@16
|
674 boost::spirit::classic::parser_id(init_ruleid_name_map[i].parser_id),
|
Chris@16
|
675 std::string(init_ruleid_name_map[i].rule_name))
|
Chris@16
|
676 );
|
Chris@16
|
677 }
|
Chris@16
|
678 };
|
Chris@16
|
679 mutable map_ruleid_to_name map_rule_id_to_name;
|
Chris@16
|
680 #endif // WAVE_DUMP_PARSE_TREE != 0
|
Chris@16
|
681 };
|
Chris@16
|
682
|
Chris@16
|
683 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
684 #undef TRACE_CPP_GRAMMAR
|
Chris@16
|
685
|
Chris@16
|
686 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
687 //
|
Chris@16
|
688 // Special parse function generating a parse tree using a given node_factory.
|
Chris@16
|
689 //
|
Chris@16
|
690 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
691 template <typename NodeFactoryT, typename IteratorT, typename ParserT>
|
Chris@16
|
692 inline boost::spirit::classic::tree_parse_info<IteratorT, NodeFactoryT>
|
Chris@16
|
693 parsetree_parse(IteratorT const& first_, IteratorT const& last,
|
Chris@16
|
694 boost::spirit::classic::parser<ParserT> const& p)
|
Chris@16
|
695 {
|
Chris@16
|
696 using namespace boost::spirit::classic;
|
Chris@16
|
697
|
Chris@16
|
698 typedef pt_match_policy<IteratorT, NodeFactoryT> pt_match_policy_type;
|
Chris@16
|
699 typedef scanner_policies<iteration_policy, pt_match_policy_type>
|
Chris@16
|
700 scanner_policies_type;
|
Chris@16
|
701 typedef scanner<IteratorT, scanner_policies_type> scanner_type;
|
Chris@16
|
702
|
Chris@16
|
703 scanner_policies_type policies;
|
Chris@16
|
704 IteratorT first = first_;
|
Chris@16
|
705 scanner_type scan(first, last, policies);
|
Chris@16
|
706 tree_match<IteratorT, NodeFactoryT> hit = p.derived().parse(scan);
|
Chris@16
|
707 return tree_parse_info<IteratorT, NodeFactoryT>(
|
Chris@16
|
708 first, hit, hit && (first == last), hit.length(), hit.trees);
|
Chris@16
|
709 }
|
Chris@16
|
710
|
Chris@16
|
711 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
712 //
|
Chris@16
|
713 // The following parse function is defined here, to allow the separation of
|
Chris@16
|
714 // the compilation of the cpp_grammar from the function using it.
|
Chris@16
|
715 //
|
Chris@16
|
716 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
717
|
Chris@16
|
718 #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION != 0
|
Chris@16
|
719 #define BOOST_WAVE_GRAMMAR_GEN_INLINE
|
Chris@16
|
720 #else
|
Chris@16
|
721 #define BOOST_WAVE_GRAMMAR_GEN_INLINE inline
|
Chris@16
|
722 #endif
|
Chris@16
|
723
|
Chris@16
|
724 template <typename LexIteratorT, typename TokenContainerT>
|
Chris@16
|
725 BOOST_WAVE_GRAMMAR_GEN_INLINE
|
Chris@16
|
726 boost::spirit::classic::tree_parse_info<
|
Chris@16
|
727 LexIteratorT,
|
Chris@16
|
728 typename cpp_grammar_gen<LexIteratorT, TokenContainerT>::node_factory_type
|
Chris@16
|
729 >
|
Chris@16
|
730 cpp_grammar_gen<LexIteratorT, TokenContainerT>::parse_cpp_grammar (
|
Chris@16
|
731 LexIteratorT const &first, LexIteratorT const &last,
|
Chris@16
|
732 position_type const &act_pos, bool &found_eof,
|
Chris@16
|
733 token_type &found_directive, token_container_type &found_eoltokens)
|
Chris@16
|
734 {
|
Chris@16
|
735 using namespace boost::spirit::classic;
|
Chris@16
|
736 using namespace boost::wave;
|
Chris@16
|
737
|
Chris@16
|
738 cpp_grammar<token_type, TokenContainerT> g(found_eof, found_directive, found_eoltokens);
|
Chris@16
|
739 tree_parse_info<LexIteratorT, node_factory_type> hit =
|
Chris@16
|
740 parsetree_parse<node_factory_type>(first, last, g);
|
Chris@16
|
741
|
Chris@16
|
742 #if BOOST_WAVE_DUMP_PARSE_TREE != 0
|
Chris@16
|
743 if (hit.match) {
|
Chris@16
|
744 tree_to_xml (BOOST_WAVE_DUMP_PARSE_TREE_OUT, hit.trees, "",
|
Chris@16
|
745 g.map_rule_id_to_name, &token_type::get_token_id,
|
Chris@16
|
746 &token_type::get_token_value);
|
Chris@16
|
747 }
|
Chris@16
|
748 #endif
|
Chris@16
|
749
|
Chris@16
|
750 return hit;
|
Chris@16
|
751 }
|
Chris@16
|
752
|
Chris@16
|
753 #undef BOOST_WAVE_GRAMMAR_GEN_INLINE
|
Chris@16
|
754
|
Chris@16
|
755 ///////////////////////////////////////////////////////////////////////////////
|
Chris@16
|
756 } // namespace grammars
|
Chris@16
|
757 } // namespace wave
|
Chris@16
|
758 } // namespace boost
|
Chris@16
|
759
|
Chris@16
|
760 // the suffix header occurs after all of the code
|
Chris@16
|
761 #ifdef BOOST_HAS_ABI_HEADERS
|
Chris@16
|
762 #include BOOST_ABI_SUFFIX
|
Chris@16
|
763 #endif
|
Chris@16
|
764
|
Chris@16
|
765 #endif // !defined(CPP_GRAMMAR_HPP_FEAEBC2E_2734_428B_A7CA_85E5A415E23E_INCLUDED)
|