Mercurial > projects > qtd
comparison generator/parser/rpp/pp-engine-bits.h @ 1:e78566595089
initial import
author | mandel |
---|---|
date | Mon, 11 May 2009 16:01:50 +0000 |
parents | |
children | 09a0f1d048f2 |
comparison
equal
deleted
inserted
replaced
0:36fb74dc547d | 1:e78566595089 |
---|---|
1 /**************************************************************************** | |
2 ** | |
3 ** Copyright (C) 1992-2008 Nokia. All rights reserved. | |
4 ** Copyright 2005 Roberto Raggi <roberto@kdevelop.org> | |
5 ** | |
6 ** This file is part of Qt Jambi. | |
7 ** | |
8 ** * Commercial Usage | |
9 * Licensees holding valid Qt Commercial licenses may use this file in | |
10 * accordance with the Qt Commercial License Agreement provided with the | |
11 * Software or, alternatively, in accordance with the terms contained in | |
12 * a written agreement between you and Nokia. | |
13 * | |
14 * | |
15 * GNU General Public License Usage | |
16 * Alternatively, this file may be used under the terms of the GNU | |
17 * General Public License versions 2.0 or 3.0 as published by the Free | |
18 * Software Foundation and appearing in the file LICENSE.GPL included in | |
19 * the packaging of this file. Please review the following information | |
20 * to ensure GNU General Public Licensing requirements will be met: | |
21 * http://www.fsf.org/licensing/licenses/info/GPLv2.html and | |
22 * http://www.gnu.org/copyleft/gpl.html. In addition, as a special | |
23 * exception, Nokia gives you certain additional rights. These rights | |
24 * are described in the Nokia Qt GPL Exception version 1.2, included in | |
25 * the file GPL_EXCEPTION.txt in this package. | |
26 * | |
27 * Qt for Windows(R) Licensees | |
28 * As a special exception, Nokia, as the sole copyright holder for Qt | |
29 * Designer, grants users of the Qt/Eclipse Integration plug-in the | |
30 * right for the Qt/Eclipse Integration to link to functionality | |
31 * provided by Qt Designer and its related libraries. | |
32 * | |
33 * | |
34 * If you are unsure which license is appropriate for your use, please | |
35 * contact the sales department at qt-sales@nokia.com. | |
36 | |
37 ** | |
38 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE | |
39 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
40 ** | |
41 ****************************************************************************/ | |
42 | |
43 #ifndef PP_ENGINE_BITS_H | |
44 #define PP_ENGINE_BITS_H | |
45 | |
46 namespace rpp { | |
47 | |
48 inline std::string pp::fix_file_path(std::string const &filename) const | |
49 { | |
50 #if defined (PP_OS_WIN) | |
51 std::string s = filename; | |
52 for (std::string::iterator it = s.begin(); it != s.end(); ++it) | |
53 { | |
54 if (*it == '/') | |
55 *it = '\\'; | |
56 } | |
57 return s; | |
58 #else | |
59 return filename; | |
60 #endif | |
61 } | |
62 | |
63 inline bool pp::is_absolute(std::string const &filename) const | |
64 { | |
65 #if defined(PP_OS_WIN) | |
66 return filename.length() >= 3 | |
67 && filename.at(1) == ':' | |
68 && (filename.at(2) == '\\' || filename.at(2) == '/'); | |
69 #else | |
70 return filename.length() >= 1 | |
71 && filename.at(0) == '/'; | |
72 #endif | |
73 } | |
74 | |
75 template <typename _OutputIterator> | |
76 void pp::file (std::string const &filename, _OutputIterator __result) | |
77 { | |
78 FILE *fp = fopen (filename.c_str(), "rb"); | |
79 if (fp != 0) | |
80 { | |
81 std::string was = env.current_file; | |
82 env.current_file = filename; | |
83 file (fp, __result); | |
84 env.current_file = was; | |
85 } | |
86 //else | |
87 //std::cerr << "** WARNING file ``" << filename << " not found!" << std::endl; | |
88 } | |
89 | |
90 template <typename _OutputIterator> | |
91 void pp::file (FILE *fp, _OutputIterator __result) | |
92 { | |
93 assert (fp != 0); | |
94 | |
95 #if defined (HAVE_MMAP) | |
96 struct stat st; | |
97 fstat(FILENO (fp), &st); | |
98 std::size_t size = st.st_size; | |
99 char *buffer = 0; | |
100 buffer = (char *) ::mmap(0, size, PROT_READ, MAP_SHARED, FILENO (fp), 0); | |
101 fclose (fp); | |
102 if (!buffer || buffer == (char*) -1) | |
103 return; | |
104 this->operator () (buffer, buffer + size, __result); | |
105 ::munmap(buffer, size); | |
106 #else | |
107 std::string buffer; | |
108 while (!feof(fp)) { | |
109 char tmp[1024]; | |
110 int read = (int) fread (tmp, sizeof(char), 1023, fp); | |
111 tmp[read] = '\0'; | |
112 buffer += tmp; | |
113 } | |
114 fclose (fp); | |
115 this->operator () (buffer.c_str(), buffer.c_str() + buffer.size(), __result); | |
116 #endif | |
117 } | |
118 | |
119 template <typename _InputIterator> | |
120 bool pp::find_header_protection (_InputIterator __first, _InputIterator __last, std::string *__prot) | |
121 { | |
122 int was = env.current_line; | |
123 | |
124 while (__first != __last) | |
125 { | |
126 if (pp_isspace (*__first)) | |
127 { | |
128 if (*__first == '\n') | |
129 ++env.current_line; | |
130 | |
131 ++__first; | |
132 } | |
133 else if (_PP_internal::comment_p (__first, __last)) | |
134 { | |
135 __first = skip_comment_or_divop (__first, __last); | |
136 env.current_line += skip_comment_or_divop.lines; | |
137 } | |
138 else if (*__first == '#') | |
139 { | |
140 __first = skip_blanks (++__first, __last); | |
141 env.current_line += skip_blanks.lines; | |
142 | |
143 if (__first != __last && *__first == 'i') | |
144 { | |
145 _InputIterator __begin = __first; | |
146 __first = skip_identifier (__begin, __last); | |
147 env.current_line += skip_identifier.lines; | |
148 | |
149 std::string __directive (__begin, __first); | |
150 | |
151 if (__directive == "ifndef") | |
152 { | |
153 __first = skip_blanks (__first, __last); | |
154 env.current_line += skip_blanks.lines; | |
155 | |
156 __begin = __first; | |
157 __first = skip_identifier (__first, __last); | |
158 env.current_line += skip_identifier.lines; | |
159 | |
160 if (__begin != __first && __first != __last) | |
161 { | |
162 __prot->assign (__begin, __first); | |
163 return true; | |
164 } | |
165 } | |
166 } | |
167 break; | |
168 } | |
169 else | |
170 break; | |
171 } | |
172 | |
173 env.current_line = was; | |
174 return false; | |
175 } | |
176 | |
177 inline pp::PP_DIRECTIVE_TYPE pp::find_directive (char const *__directive, std::size_t __size) const | |
178 { | |
179 switch (__size) | |
180 { | |
181 case 2: | |
182 if (__directive[0] == 'i' | |
183 && __directive[1] == 'f') | |
184 return PP_IF; | |
185 break; | |
186 | |
187 case 4: | |
188 if (__directive[0] == 'e' && !strcmp (__directive, "elif")) | |
189 return PP_ELIF; | |
190 else if (__directive[0] == 'e' && !strcmp (__directive, "else")) | |
191 return PP_ELSE; | |
192 break; | |
193 | |
194 case 5: | |
195 if (__directive[0] == 'i' && !strcmp (__directive, "ifdef")) | |
196 return PP_IFDEF; | |
197 else if (__directive[0] == 'u' && !strcmp (__directive, "undef")) | |
198 return PP_UNDEF; | |
199 else if (__directive[0] == 'e') { | |
200 if (!strcmp (__directive, "endif")) | |
201 return PP_ENDIF; | |
202 else if (!strcmp (__directive, "error")) | |
203 return PP_ERROR; | |
204 } | |
205 break; | |
206 | |
207 case 6: | |
208 if (__directive[0] == 'i' && !strcmp (__directive, "ifndef")) | |
209 return PP_IFNDEF; | |
210 else if (__directive[0] == 'd' && !strcmp (__directive, "define")) | |
211 return PP_DEFINE; | |
212 else if (__directive[0] == 'p' && !strcmp (__directive, "pragma")) | |
213 return PP_PRAGMA; | |
214 break; | |
215 | |
216 case 7: | |
217 if (__directive[0] == 'i' && !strcmp (__directive, "include")) | |
218 return PP_INCLUDE; | |
219 break; | |
220 | |
221 case 12: | |
222 if (__directive[0] == 'i' && !strcmp (__directive, "include_next")) | |
223 return PP_INCLUDE_NEXT; | |
224 break; | |
225 | |
226 default: | |
227 break; | |
228 } | |
229 std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl; | |
230 return PP_UNKNOWN_DIRECTIVE; | |
231 } | |
232 | |
233 inline bool pp::file_isdir (std::string const &__filename) const | |
234 { | |
235 struct stat __st; | |
236 #if defined(PP_OS_WIN) | |
237 if (stat(__filename.c_str (), &__st) == 0) | |
238 return (__st.st_mode & _S_IFDIR) == _S_IFDIR; | |
239 else | |
240 return false; | |
241 #else | |
242 if (lstat (__filename.c_str (), &__st) == 0) | |
243 return (__st.st_mode & S_IFDIR) == S_IFDIR; | |
244 else | |
245 return false; | |
246 #endif | |
247 } | |
248 | |
249 inline bool pp::file_exists (std::string const &__filename) const | |
250 { | |
251 struct stat __st; | |
252 #if defined(PP_OS_WIN) | |
253 return stat(__filename.c_str (), &__st) == 0; | |
254 #else | |
255 return lstat (__filename.c_str (), &__st) == 0; | |
256 #endif | |
257 } | |
258 | |
259 inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath, | |
260 INCLUDE_POLICY __include_policy, bool __skip_current_path) const | |
261 { | |
262 assert (__filepath != 0); | |
263 assert (! __input_filename.empty()); | |
264 | |
265 __filepath->assign (__input_filename); | |
266 | |
267 if (is_absolute (*__filepath)) | |
268 return fopen (__filepath->c_str(), "r"); | |
269 | |
270 if (! env.current_file.empty ()) | |
271 _PP_internal::extract_file_path (env.current_file, __filepath); | |
272 | |
273 if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) | |
274 { | |
275 std::string __tmp (*__filepath); | |
276 __tmp += __input_filename; | |
277 | |
278 if (file_exists (__tmp) && !file_isdir(__tmp)) | |
279 { | |
280 __filepath->append (__input_filename); | |
281 return fopen (__filepath->c_str (), "r"); | |
282 } | |
283 } | |
284 | |
285 std::vector<std::string>::const_iterator it = include_paths.begin (); | |
286 | |
287 if (__skip_current_path) | |
288 { | |
289 it = std::find (include_paths.begin (), include_paths.end (), *__filepath); | |
290 | |
291 if (it != include_paths.end ()) | |
292 ++it; | |
293 | |
294 else | |
295 it = include_paths.begin (); | |
296 } | |
297 | |
298 for (; it != include_paths.end (); ++it) | |
299 { | |
300 if (__skip_current_path && it == include_paths.begin()) | |
301 continue; | |
302 | |
303 __filepath->assign (*it); | |
304 __filepath->append (__input_filename); | |
305 | |
306 if (file_exists (*__filepath) && !file_isdir(*__filepath)) | |
307 return fopen (__filepath->c_str(), "r"); | |
308 } | |
309 | |
310 return 0; | |
311 } | |
312 | |
313 template <typename _InputIterator, typename _OutputIterator> | |
314 _InputIterator pp::handle_directive(char const *__directive, std::size_t __size, | |
315 _InputIterator __first, _InputIterator __last, _OutputIterator __result) | |
316 { | |
317 __first = skip_blanks (__first, __last); | |
318 | |
319 PP_DIRECTIVE_TYPE d = find_directive (__directive, __size); | |
320 switch (d) | |
321 { | |
322 case PP_DEFINE: | |
323 if (! skipping ()) | |
324 return handle_define (__first, __last); | |
325 break; | |
326 | |
327 case PP_INCLUDE: | |
328 case PP_INCLUDE_NEXT: | |
329 if (! skipping ()) | |
330 return handle_include (d == PP_INCLUDE_NEXT, __first, __last, __result); | |
331 break; | |
332 | |
333 case PP_UNDEF: | |
334 if (! skipping ()) | |
335 return handle_undef(__first, __last); | |
336 break; | |
337 | |
338 case PP_ELIF: | |
339 return handle_elif (__first, __last); | |
340 | |
341 case PP_ELSE: | |
342 return handle_else (__first, __last); | |
343 | |
344 case PP_ENDIF: | |
345 return handle_endif (__first, __last); | |
346 | |
347 case PP_IF: | |
348 return handle_if (__first, __last); | |
349 | |
350 case PP_IFDEF: | |
351 return handle_ifdef (false, __first, __last); | |
352 | |
353 case PP_IFNDEF: | |
354 return handle_ifdef (true, __first, __last); | |
355 | |
356 default: | |
357 break; | |
358 } | |
359 | |
360 return __first; | |
361 } | |
362 | |
363 template <typename _InputIterator, typename _OutputIterator> | |
364 _InputIterator pp::handle_include (bool __skip_current_path, _InputIterator __first, _InputIterator __last, | |
365 _OutputIterator __result) | |
366 { | |
367 if (pp_isalpha (*__first) || *__first == '_') | |
368 { | |
369 pp_macro_expander expand_include (env); | |
370 std::string name; | |
371 name.reserve (255); | |
372 expand_include (__first, __last, std::back_inserter (name)); | |
373 std::string::iterator it = skip_blanks (name.begin (), name.end ()); | |
374 assert (it != name.end () && (*it == '<' || *it == '"')); | |
375 handle_include (__skip_current_path, it, name.end (), __result); | |
376 return __first; | |
377 } | |
378 | |
379 assert (*__first == '<' || *__first == '"'); | |
380 int quote = (*__first == '"') ? '"' : '>'; | |
381 ++__first; | |
382 | |
383 _InputIterator end_name = __first; | |
384 for (; end_name != __last; ++end_name) | |
385 { | |
386 assert (*end_name != '\n'); | |
387 | |
388 if (*end_name == quote) | |
389 break; | |
390 } | |
391 | |
392 std::string filename (__first, end_name); | |
393 | |
394 #ifdef PP_OS_WIN | |
395 std::replace(filename.begin(), filename.end(), '/', '\\'); | |
396 #endif | |
397 | |
398 std::string filepath; | |
399 FILE *fp = find_include_file (filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path); | |
400 | |
401 #if defined (PP_HOOK_ON_FILE_INCLUDED) | |
402 PP_HOOK_ON_FILE_INCLUDED (env.current_file, fp ? filepath : filename, fp); | |
403 #endif | |
404 | |
405 if (fp != 0) | |
406 { | |
407 std::string old_file = env.current_file; | |
408 env.current_file = filepath; | |
409 int __saved_lines = env.current_line; | |
410 | |
411 env.current_line = 1; | |
412 //output_line (env.current_file, 1, __result); | |
413 | |
414 file (fp, __result); | |
415 | |
416 // restore the file name and the line position | |
417 env.current_file = old_file; | |
418 env.current_line = __saved_lines; | |
419 | |
420 // sync the buffer | |
421 _PP_internal::output_line (env.current_file, env.current_line, __result); | |
422 } | |
423 #ifndef RPP_JAMBI | |
424 // else | |
425 // std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl; | |
426 #endif | |
427 | |
428 return __first; | |
429 } | |
430 | |
431 template <typename _InputIterator, typename _OutputIterator> | |
432 void pp::operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) | |
433 { | |
434 #ifndef PP_NO_SMART_HEADER_PROTECTION | |
435 std::string __prot; | |
436 __prot.reserve (255); | |
437 pp_fast_string __tmp (__prot.c_str (), __prot.size ()); | |
438 | |
439 if (find_header_protection (__first, __last, &__prot) | |
440 && env.resolve (&__tmp) != 0) | |
441 { | |
442 // std::cerr << "** DEBUG found header protection:" << __prot << std::endl; | |
443 return; | |
444 } | |
445 #endif | |
446 | |
447 env.current_line = 1; | |
448 char __buffer[512]; | |
449 | |
450 while (true) | |
451 { | |
452 __first = skip_blanks (__first, __last); | |
453 env.current_line += skip_blanks.lines; | |
454 | |
455 if (__first == __last) | |
456 break; | |
457 else if (*__first == '#') | |
458 { | |
459 assert (*__first == '#'); | |
460 __first = skip_blanks (++__first, __last); | |
461 env.current_line += skip_blanks.lines; | |
462 | |
463 _InputIterator end_id = skip_identifier (__first, __last); | |
464 env.current_line += skip_identifier.lines; | |
465 std::size_t __size = end_id - __first; | |
466 | |
467 assert (__size < 512); | |
468 char *__cp = __buffer; | |
469 std::copy (__first, end_id, __cp); | |
470 __cp[__size] = '\0'; | |
471 | |
472 end_id = skip_blanks (end_id, __last); | |
473 __first = skip (end_id, __last); | |
474 | |
475 int was = env.current_line; | |
476 (void) handle_directive (__buffer, __size, end_id, __first, __result); | |
477 | |
478 if (env.current_line != was) | |
479 { | |
480 env.current_line = was; | |
481 _PP_internal::output_line (env.current_file, env.current_line, __result); | |
482 } | |
483 } | |
484 else if (*__first == '\n') | |
485 { | |
486 // ### compress the line | |
487 *__result++ = *__first++; | |
488 ++env.current_line; | |
489 } | |
490 else if (skipping ()) | |
491 __first = skip (__first, __last); | |
492 else | |
493 { | |
494 _PP_internal::output_line (env.current_file, env.current_line, __result); | |
495 __first = expand (__first, __last, __result); | |
496 env.current_line += expand.lines; | |
497 | |
498 if (expand.generated_lines) | |
499 _PP_internal::output_line (env.current_file, env.current_line, __result); | |
500 } | |
501 } | |
502 } | |
503 | |
504 inline pp::pp (pp_environment &__env): | |
505 env (__env), expand (env) | |
506 { | |
507 iflevel = 0; | |
508 _M_skipping[iflevel] = 0; | |
509 _M_true_test[iflevel] = 0; | |
510 } | |
511 | |
512 inline std::back_insert_iterator<std::vector<std::string> > pp::include_paths_inserter () | |
513 { return std::back_inserter (include_paths); } | |
514 | |
515 inline std::vector<std::string>::iterator pp::include_paths_begin () | |
516 { return include_paths.begin (); } | |
517 | |
518 inline std::vector<std::string>::iterator pp::include_paths_end () | |
519 { return include_paths.end (); } | |
520 | |
521 inline std::vector<std::string>::const_iterator pp::include_paths_begin () const | |
522 { return include_paths.begin (); } | |
523 | |
524 inline std::vector<std::string>::const_iterator pp::include_paths_end () const | |
525 { return include_paths.end (); } | |
526 | |
527 inline void pp::push_include_path (std::string const &__path) | |
528 { | |
529 if (__path.empty () || __path [__path.size () - 1] != PATH_SEPARATOR) | |
530 { | |
531 std::string __tmp (__path); | |
532 __tmp += PATH_SEPARATOR; | |
533 include_paths.push_back (__tmp); | |
534 } | |
535 | |
536 else | |
537 include_paths.push_back (__path); | |
538 } | |
539 | |
540 template <typename _InputIterator> | |
541 _InputIterator pp::handle_define (_InputIterator __first, _InputIterator __last) | |
542 { | |
543 pp_macro macro; | |
544 #if defined (PP_WITH_MACRO_POSITION) | |
545 macro.file = pp_symbol::get (env.current_file); | |
546 #endif | |
547 std::string definition; | |
548 | |
549 __first = skip_blanks (__first, __last); | |
550 _InputIterator end_macro_name = skip_identifier (__first, __last); | |
551 pp_fast_string const *macro_name = pp_symbol::get (__first, end_macro_name); | |
552 __first = end_macro_name; | |
553 | |
554 if (__first != __last && *__first == '(') | |
555 { | |
556 macro.function_like = true; | |
557 macro.formals.reserve (5); | |
558 | |
559 __first = skip_blanks (++__first, __last); // skip '(' | |
560 _InputIterator arg_end = skip_identifier (__first, __last); | |
561 if (__first != arg_end) | |
562 macro.formals.push_back (pp_symbol::get (__first, arg_end)); | |
563 | |
564 __first = skip_blanks (arg_end, __last); | |
565 | |
566 if (*__first == '.') | |
567 { | |
568 macro.variadics = true; | |
569 while (*__first == '.') | |
570 ++__first; | |
571 } | |
572 | |
573 while (__first != __last && *__first == ',') | |
574 { | |
575 __first = skip_blanks (++__first, __last); | |
576 | |
577 arg_end = skip_identifier (__first, __last); | |
578 if (__first != arg_end) | |
579 macro.formals.push_back (pp_symbol::get (__first, arg_end)); | |
580 | |
581 __first = skip_blanks (arg_end, __last); | |
582 | |
583 if (*__first == '.') | |
584 { | |
585 macro.variadics = true; | |
586 while (*__first == '.') | |
587 ++__first; | |
588 } | |
589 } | |
590 | |
591 assert (*__first == ')'); | |
592 ++__first; | |
593 } | |
594 | |
595 __first = skip_blanks (__first, __last); | |
596 | |
597 while (__first != __last && *__first != '\n') | |
598 { | |
599 if (*__first == '/') { | |
600 __first = skip_comment_or_divop(__first, __last); | |
601 env.current_line += skip_comment_or_divop.lines; | |
602 } | |
603 | |
604 if (*__first == '\\') | |
605 { | |
606 _InputIterator __begin = __first; | |
607 __begin = skip_blanks (++__begin, __last); | |
608 | |
609 if (__begin != __last && *__begin == '\n') | |
610 { | |
611 ++macro.lines; | |
612 __first = skip_blanks (++__begin, __last); | |
613 definition += ' '; | |
614 continue; | |
615 } | |
616 } | |
617 | |
618 definition += *__first++; | |
619 } | |
620 | |
621 macro.definition = pp_symbol::get (definition); | |
622 env.bind (macro_name, macro); | |
623 | |
624 return __first; | |
625 } | |
626 | |
627 template <typename _InputIterator> | |
628 _InputIterator pp::skip (_InputIterator __first, _InputIterator __last) | |
629 { | |
630 pp_skip_string_literal skip_string_literal; | |
631 pp_skip_char_literal skip_char_literal; | |
632 | |
633 while (__first != __last && *__first != '\n') | |
634 { | |
635 if (*__first == '/') | |
636 { | |
637 __first = skip_comment_or_divop (__first, __last); | |
638 env.current_line += skip_comment_or_divop.lines; | |
639 } | |
640 else if (*__first == '"') | |
641 { | |
642 __first = skip_string_literal (__first, __last); | |
643 env.current_line += skip_string_literal.lines; | |
644 } | |
645 else if (*__first == '\'') | |
646 { | |
647 __first = skip_char_literal (__first, __last); | |
648 env.current_line += skip_char_literal.lines; | |
649 } | |
650 else if (*__first == '\\') | |
651 { | |
652 __first = skip_blanks (++__first, __last); | |
653 env.current_line += skip_blanks.lines; | |
654 | |
655 if (__first != __last && *__first == '\n') | |
656 { | |
657 ++__first; | |
658 ++env.current_line; | |
659 } | |
660 } | |
661 else | |
662 ++__first; | |
663 } | |
664 | |
665 return __first; | |
666 } | |
667 | |
668 inline bool pp::test_if_level() | |
669 { | |
670 bool result = !_M_skipping[iflevel++]; | |
671 _M_skipping[iflevel] = _M_skipping[iflevel - 1]; | |
672 _M_true_test[iflevel] = false; | |
673 return result; | |
674 } | |
675 | |
676 inline int pp::skipping() const | |
677 { return _M_skipping[iflevel]; } | |
678 | |
679 template <typename _InputIterator> | |
680 _InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result) | |
681 { | |
682 bool expect_paren = false; | |
683 int token; | |
684 __first = next_token (__first, __last, &token); | |
685 | |
686 switch (token) | |
687 { | |
688 case TOKEN_NUMBER: | |
689 result->set_long (token_value); | |
690 break; | |
691 | |
692 case TOKEN_UNUMBER: | |
693 result->set_ulong (token_uvalue); | |
694 break; | |
695 | |
696 case TOKEN_DEFINED: | |
697 __first = next_token (__first, __last, &token); | |
698 | |
699 if (token == '(') | |
700 { | |
701 expect_paren = true; | |
702 __first = next_token (__first, __last, &token); | |
703 } | |
704 | |
705 if (token != TOKEN_IDENTIFIER) | |
706 { | |
707 std::cerr << "** WARNING expected ``identifier'' found:" << char(token) << std::endl; | |
708 result->set_long (0); | |
709 break; | |
710 } | |
711 | |
712 result->set_long (env.resolve (token_text->c_str (), token_text->size ()) != 0); | |
713 | |
714 next_token (__first, __last, &token); // skip '(' | |
715 | |
716 if (expect_paren) | |
717 { | |
718 _InputIterator next = next_token (__first, __last, &token); | |
719 if (token != ')') | |
720 std::cerr << "** WARNING expected ``)''" << std::endl; | |
721 else | |
722 __first = next; | |
723 } | |
724 break; | |
725 | |
726 case TOKEN_IDENTIFIER: | |
727 result->set_long (0); | |
728 break; | |
729 | |
730 case '-': | |
731 __first = eval_primary (__first, __last, result); | |
732 result->set_long (- result->l); | |
733 return __first; | |
734 | |
735 case '+': | |
736 __first = eval_primary (__first, __last, result); | |
737 return __first; | |
738 | |
739 case '!': | |
740 __first = eval_primary (__first, __last, result); | |
741 result->set_long (result->is_zero ()); | |
742 return __first; | |
743 | |
744 case '(': | |
745 __first = eval_constant_expression(__first, __last, result); | |
746 next_token (__first, __last, &token); | |
747 | |
748 if (token != ')') | |
749 std::cerr << "** WARNING expected ``)'' = " << token << std::endl; | |
750 else | |
751 __first = next_token(__first, __last, &token); | |
752 break; | |
753 | |
754 default: | |
755 result->set_long (0); | |
756 } | |
757 | |
758 return __first; | |
759 } | |
760 | |
761 template <typename _InputIterator> | |
762 _InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result) | |
763 { | |
764 __first = eval_primary(__first, __last, result); | |
765 | |
766 int token; | |
767 _InputIterator next = next_token (__first, __last, &token); | |
768 | |
769 while (token == '*' || token == '/' || token == '%') | |
770 { | |
771 Value value; | |
772 __first = eval_primary(next, __last, &value); | |
773 | |
774 if (token == '*') | |
775 result->op_mult (value); | |
776 else if (token == '/') | |
777 { | |
778 if (value.is_zero ()) | |
779 { | |
780 std::cerr << "** WARNING division by zero" << std::endl; | |
781 result->set_long (0); | |
782 } | |
783 else | |
784 result->op_div (value); | |
785 } | |
786 else | |
787 { | |
788 if (value.is_zero ()) | |
789 { | |
790 std::cerr << "** WARNING division by zero" << std::endl; | |
791 result->set_long (0); | |
792 } | |
793 else | |
794 result->op_mod (value); | |
795 } | |
796 next = next_token (__first, __last, &token); | |
797 } | |
798 | |
799 return __first; | |
800 } | |
801 | |
802 template <typename _InputIterator> | |
803 _InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result) | |
804 { | |
805 __first = eval_multiplicative(__first, __last, result); | |
806 | |
807 int token; | |
808 _InputIterator next = next_token (__first, __last, &token); | |
809 | |
810 while (token == '+' || token == '-') | |
811 { | |
812 Value value; | |
813 __first = eval_multiplicative(next, __last, &value); | |
814 | |
815 if (token == '+') | |
816 result->op_add (value); | |
817 else | |
818 result->op_sub (value); | |
819 next = next_token (__first, __last, &token); | |
820 } | |
821 | |
822 return __first; | |
823 } | |
824 | |
825 template <typename _InputIterator> | |
826 _InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result) | |
827 { | |
828 __first = eval_additive(__first, __last, result); | |
829 | |
830 int token; | |
831 _InputIterator next = next_token (__first, __last, &token); | |
832 | |
833 while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) | |
834 { | |
835 Value value; | |
836 __first = eval_additive (next, __last, &value); | |
837 | |
838 if (token == TOKEN_LT_LT) | |
839 result->op_lhs (value); | |
840 else | |
841 result->op_rhs (value); | |
842 next = next_token (__first, __last, &token); | |
843 } | |
844 | |
845 return __first; | |
846 } | |
847 | |
848 template <typename _InputIterator> | |
849 _InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result) | |
850 { | |
851 __first = eval_shift(__first, __last, result); | |
852 | |
853 int token; | |
854 _InputIterator next = next_token (__first, __last, &token); | |
855 | |
856 while (token == '<' | |
857 || token == '>' | |
858 || token == TOKEN_LT_EQ | |
859 || token == TOKEN_GT_EQ) | |
860 { | |
861 Value value; | |
862 __first = eval_shift(next, __last, &value); | |
863 | |
864 switch (token) | |
865 { | |
866 default: | |
867 assert (0); | |
868 break; | |
869 | |
870 case '<': | |
871 result->op_lt (value); | |
872 break; | |
873 | |
874 case '>': | |
875 result->op_gt (value); | |
876 break; | |
877 | |
878 case TOKEN_LT_EQ: | |
879 result->op_le (value); | |
880 break; | |
881 | |
882 case TOKEN_GT_EQ: | |
883 result->op_ge (value); | |
884 break; | |
885 } | |
886 next = next_token (__first, __last, &token); | |
887 } | |
888 | |
889 return __first; | |
890 } | |
891 | |
892 template <typename _InputIterator> | |
893 _InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result) | |
894 { | |
895 __first = eval_relational(__first, __last, result); | |
896 | |
897 int token; | |
898 _InputIterator next = next_token (__first, __last, &token); | |
899 | |
900 while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) | |
901 { | |
902 Value value; | |
903 __first = eval_relational(next, __last, &value); | |
904 | |
905 if (token == TOKEN_EQ_EQ) | |
906 result->op_eq (value); | |
907 else | |
908 result->op_ne (value); | |
909 next = next_token (__first, __last, &token); | |
910 } | |
911 | |
912 return __first; | |
913 } | |
914 | |
915 template <typename _InputIterator> | |
916 _InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result) | |
917 { | |
918 __first = eval_equality(__first, __last, result); | |
919 | |
920 int token; | |
921 _InputIterator next = next_token (__first, __last, &token); | |
922 | |
923 while (token == '&') | |
924 { | |
925 Value value; | |
926 __first = eval_equality(next, __last, &value); | |
927 result->op_bit_and (value); | |
928 next = next_token (__first, __last, &token); | |
929 } | |
930 | |
931 return __first; | |
932 } | |
933 | |
934 template <typename _InputIterator> | |
935 _InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result) | |
936 { | |
937 __first = eval_and(__first, __last, result); | |
938 | |
939 int token; | |
940 _InputIterator next = next_token (__first, __last, &token); | |
941 | |
942 while (token == '^') | |
943 { | |
944 Value value; | |
945 __first = eval_and(next, __last, &value); | |
946 result->op_bit_xor (value); | |
947 next = next_token (__first, __last, &token); | |
948 } | |
949 | |
950 return __first; | |
951 } | |
952 | |
953 template <typename _InputIterator> | |
954 _InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result) | |
955 { | |
956 __first = eval_xor(__first, __last, result); | |
957 | |
958 int token; | |
959 _InputIterator next = next_token (__first, __last, &token); | |
960 | |
961 while (token == '|') | |
962 { | |
963 Value value; | |
964 __first = eval_xor(next, __last, &value); | |
965 result->op_bit_or (value); | |
966 next = next_token (__first, __last, &token); | |
967 } | |
968 | |
969 return __first; | |
970 } | |
971 | |
972 template <typename _InputIterator> | |
973 _InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result) | |
974 { | |
975 __first = eval_or(__first, __last, result); | |
976 | |
977 int token; | |
978 _InputIterator next = next_token (__first, __last, &token); | |
979 | |
980 while (token == TOKEN_AND_AND) | |
981 { | |
982 Value value; | |
983 __first = eval_or(next, __last, &value); | |
984 result->op_and (value); | |
985 next = next_token (__first, __last, &token); | |
986 } | |
987 | |
988 return __first; | |
989 } | |
990 | |
991 template <typename _InputIterator> | |
992 _InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result) | |
993 { | |
994 __first = eval_logical_and (__first, __last, result); | |
995 | |
996 int token; | |
997 _InputIterator next = next_token (__first, __last, &token); | |
998 | |
999 while (token == TOKEN_OR_OR) | |
1000 { | |
1001 Value value; | |
1002 __first = eval_logical_and(next, __last, &value); | |
1003 result->op_or (value); | |
1004 next = next_token (__first, __last, &token); | |
1005 } | |
1006 | |
1007 return __first; | |
1008 } | |
1009 | |
1010 template <typename _InputIterator> | |
1011 _InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result) | |
1012 { | |
1013 __first = eval_logical_or(__first, __last, result); | |
1014 | |
1015 int token; | |
1016 _InputIterator next = next_token (__first, __last, &token); | |
1017 | |
1018 if (token == '?') | |
1019 { | |
1020 Value left_value; | |
1021 __first = eval_constant_expression(next, __last, &left_value); | |
1022 __first = skip_blanks (__first, __last); | |
1023 | |
1024 __first = next_token(__first, __last, &token); | |
1025 if (token == ':') | |
1026 { | |
1027 Value right_value; | |
1028 __first = eval_constant_expression(__first, __last, &right_value); | |
1029 | |
1030 *result = !result->is_zero () ? left_value : right_value; | |
1031 } | |
1032 else | |
1033 { | |
1034 std::cerr << "** WARNING expected ``:'' = " << int (token) << std::endl; | |
1035 *result = left_value; | |
1036 } | |
1037 } | |
1038 | |
1039 return __first; | |
1040 } | |
1041 | |
1042 template <typename _InputIterator> | |
1043 _InputIterator pp::eval_expression (_InputIterator __first, _InputIterator __last, Value *result) | |
1044 { | |
1045 return __first = eval_constant_expression (skip_blanks (__first, __last), __last, result); | |
1046 } | |
1047 | |
1048 template <typename _InputIterator> | |
1049 _InputIterator pp::handle_if (_InputIterator __first, _InputIterator __last) | |
1050 { | |
1051 if (test_if_level()) | |
1052 { | |
1053 pp_macro_expander expand_condition (env); | |
1054 std::string condition; | |
1055 condition.reserve (255); | |
1056 expand_condition (skip_blanks (__first, __last), __last, std::back_inserter (condition)); | |
1057 | |
1058 Value result; | |
1059 result.set_long (0); | |
1060 eval_expression(condition.c_str (), condition.c_str () + condition.size (), &result); | |
1061 | |
1062 _M_true_test[iflevel] = !result.is_zero (); | |
1063 _M_skipping[iflevel] = result.is_zero (); | |
1064 } | |
1065 | |
1066 return __first; | |
1067 } | |
1068 | |
1069 template <typename _InputIterator> | |
1070 _InputIterator pp::handle_else (_InputIterator __first, _InputIterator /*__last*/) | |
1071 { | |
1072 if (iflevel == 0 && !skipping ()) | |
1073 { | |
1074 std::cerr << "** WARNING #else without #if" << std::endl; | |
1075 } | |
1076 else if (iflevel > 0 && _M_skipping[iflevel - 1]) | |
1077 { | |
1078 _M_skipping[iflevel] = true; | |
1079 } | |
1080 else | |
1081 { | |
1082 _M_skipping[iflevel] = _M_true_test[iflevel]; | |
1083 } | |
1084 | |
1085 return __first; | |
1086 } | |
1087 | |
1088 template <typename _InputIterator> | |
1089 _InputIterator pp::handle_elif (_InputIterator __first, _InputIterator __last) | |
1090 { | |
1091 assert(iflevel > 0); | |
1092 | |
1093 if (iflevel == 0 && !skipping()) | |
1094 { | |
1095 std::cerr << "** WARNING #else without #if" << std::endl; | |
1096 } | |
1097 else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) | |
1098 { | |
1099 Value result; | |
1100 __first = eval_expression(__first, __last, &result); | |
1101 _M_true_test[iflevel] = !result.is_zero (); | |
1102 _M_skipping[iflevel] = result.is_zero (); | |
1103 } | |
1104 else | |
1105 { | |
1106 _M_skipping[iflevel] = true; | |
1107 } | |
1108 | |
1109 return __first; | |
1110 } | |
1111 | |
1112 template <typename _InputIterator> | |
1113 _InputIterator pp::handle_endif (_InputIterator __first, _InputIterator /*__last*/) | |
1114 { | |
1115 if (iflevel == 0 && !skipping()) | |
1116 { | |
1117 std::cerr << "** WARNING #endif without #if" << std::endl; | |
1118 } | |
1119 else | |
1120 { | |
1121 _M_skipping[iflevel] = 0; | |
1122 _M_true_test[iflevel] = 0; | |
1123 | |
1124 --iflevel; | |
1125 } | |
1126 | |
1127 return __first; | |
1128 } | |
1129 | |
1130 template <typename _InputIterator> | |
1131 _InputIterator pp::handle_ifdef (bool check_undefined, _InputIterator __first, _InputIterator __last) | |
1132 { | |
1133 if (test_if_level()) | |
1134 { | |
1135 _InputIterator end_macro_name = skip_identifier (__first, __last); | |
1136 | |
1137 std::size_t __size; | |
1138 #if defined(__SUNPRO_CC) | |
1139 std::distance (__first, end_macro_name, __size); | |
1140 #else | |
1141 __size = std::distance (__first, end_macro_name); | |
1142 #endif | |
1143 assert (__size < 256); | |
1144 | |
1145 char __buffer [256]; | |
1146 std::copy (__first, end_macro_name, __buffer); | |
1147 | |
1148 bool value = env.resolve (__buffer, __size) != 0; | |
1149 | |
1150 __first = end_macro_name; | |
1151 | |
1152 if (check_undefined) | |
1153 value = !value; | |
1154 | |
1155 _M_true_test[iflevel] = value; | |
1156 _M_skipping[iflevel] = !value; | |
1157 } | |
1158 | |
1159 return __first; | |
1160 } | |
1161 | |
1162 template <typename _InputIterator> | |
1163 _InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last) | |
1164 { | |
1165 __first = skip_blanks (__first, __last); | |
1166 _InputIterator end_macro_name = skip_identifier (__first, __last); | |
1167 assert (end_macro_name != __first); | |
1168 | |
1169 std::size_t __size; | |
1170 #if defined(__SUNPRO_CC) | |
1171 std::distance (__first, end_macro_name, __size); | |
1172 #else | |
1173 __size = std::distance (__first, end_macro_name); | |
1174 #endif | |
1175 | |
1176 assert (__size < 256); | |
1177 | |
1178 char __buffer [256]; | |
1179 std::copy (__first, end_macro_name, __buffer); | |
1180 | |
1181 pp_fast_string const __tmp (__buffer, __size); | |
1182 env.unbind (&__tmp); | |
1183 | |
1184 __first = end_macro_name; | |
1185 | |
1186 return __first; | |
1187 } | |
1188 | |
1189 template <typename _InputIterator> | |
1190 char pp::peek_char (_InputIterator __first, _InputIterator __last) | |
1191 { | |
1192 if (__first == __last) | |
1193 return 0; | |
1194 | |
1195 return *++__first; | |
1196 } | |
1197 | |
1198 template <typename _InputIterator> | |
1199 _InputIterator pp::next_token (_InputIterator __first, _InputIterator __last, int *kind) | |
1200 { | |
1201 __first = skip_blanks (__first, __last); | |
1202 | |
1203 if (__first == __last) | |
1204 { | |
1205 *kind = 0; | |
1206 return __first; | |
1207 } | |
1208 | |
1209 char ch = *__first; | |
1210 char ch2 = peek_char (__first, __last); | |
1211 | |
1212 switch (ch) | |
1213 { | |
1214 case '/': | |
1215 if (ch2 == '/' || ch2 == '*') | |
1216 { | |
1217 __first = skip_comment_or_divop (__first, __last); | |
1218 return next_token (__first, __last, kind); | |
1219 } | |
1220 ++__first; | |
1221 *kind = '/'; | |
1222 break; | |
1223 | |
1224 case '<': | |
1225 ++__first; | |
1226 if (ch2 == '<') | |
1227 { | |
1228 ++__first; | |
1229 *kind = TOKEN_LT_LT; | |
1230 } | |
1231 else if (ch2 == '=') | |
1232 { | |
1233 ++__first; | |
1234 *kind = TOKEN_LT_EQ; | |
1235 } | |
1236 else | |
1237 *kind = '<'; | |
1238 | |
1239 return __first; | |
1240 | |
1241 case '>': | |
1242 ++__first; | |
1243 if (ch2 == '>') | |
1244 { | |
1245 ++__first; | |
1246 *kind = TOKEN_GT_GT; | |
1247 } | |
1248 else if (ch2 == '=') | |
1249 { | |
1250 ++__first; | |
1251 *kind = TOKEN_GT_EQ; | |
1252 } | |
1253 else | |
1254 *kind = '>'; | |
1255 | |
1256 return __first; | |
1257 | |
1258 case '!': | |
1259 ++__first; | |
1260 if (ch2 == '=') | |
1261 { | |
1262 ++__first; | |
1263 *kind = TOKEN_NOT_EQ; | |
1264 } | |
1265 else | |
1266 *kind = '!'; | |
1267 | |
1268 return __first; | |
1269 | |
1270 case '=': | |
1271 ++__first; | |
1272 if (ch2 == '=') | |
1273 { | |
1274 ++__first; | |
1275 *kind = TOKEN_EQ_EQ; | |
1276 } | |
1277 else | |
1278 *kind = '='; | |
1279 | |
1280 return __first; | |
1281 | |
1282 case '|': | |
1283 ++__first; | |
1284 if (ch2 == '|') | |
1285 { | |
1286 ++__first; | |
1287 *kind = TOKEN_OR_OR; | |
1288 } | |
1289 else | |
1290 *kind = '|'; | |
1291 | |
1292 return __first; | |
1293 | |
1294 case '&': | |
1295 ++__first; | |
1296 if (ch2 == '&') | |
1297 { | |
1298 ++__first; | |
1299 *kind = TOKEN_AND_AND; | |
1300 } | |
1301 else | |
1302 *kind = '&'; | |
1303 | |
1304 return __first; | |
1305 | |
1306 default: | |
1307 if (pp_isalpha (ch) || ch == '_') | |
1308 { | |
1309 _InputIterator end = skip_identifier (__first, __last); | |
1310 _M_current_text.assign (__first, end); | |
1311 | |
1312 token_text = &_M_current_text; | |
1313 __first = end; | |
1314 | |
1315 if (*token_text == "defined") | |
1316 *kind = TOKEN_DEFINED; | |
1317 else | |
1318 *kind = TOKEN_IDENTIFIER; | |
1319 } | |
1320 else if (pp_isdigit (ch)) | |
1321 { | |
1322 _InputIterator end = skip_number (__first, __last); | |
1323 std::string __str (__first, __last); | |
1324 char ch = __str [__str.size () - 1]; | |
1325 if (ch == 'u' || ch == 'U') | |
1326 { | |
1327 token_uvalue = strtoul (__str.c_str (), 0, 0); | |
1328 *kind = TOKEN_UNUMBER; | |
1329 } | |
1330 else | |
1331 { | |
1332 token_value = strtol (__str.c_str (), 0, 0); | |
1333 *kind = TOKEN_NUMBER; | |
1334 } | |
1335 __first = end; | |
1336 } | |
1337 else | |
1338 *kind = *__first++; | |
1339 } | |
1340 | |
1341 return __first; | |
1342 } | |
1343 | |
1344 } // namespace rpp | |
1345 | |
1346 #endif // PP_ENGINE_BITS_H | |
1347 | |
1348 // kate: space-indent on; indent-width 2; replace-tabs on; |