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;