Mercurial > projects > qtd
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/generator/parser/rpp/pp-engine-bits.h Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,1348 @@ +/**************************************************************************** +** +** Copyright (C) 1992-2008 Nokia. All rights reserved. +** Copyright 2005 Roberto Raggi <roberto@kdevelop.org> +** +** This file is part of Qt Jambi. +** +** * Commercial Usage +* Licensees holding valid Qt Commercial licenses may use this file in +* accordance with the Qt Commercial License Agreement provided with the +* Software or, alternatively, in accordance with the terms contained in +* a written agreement between you and Nokia. +* +* +* GNU General Public License Usage +* Alternatively, this file may be used under the terms of the GNU +* General Public License versions 2.0 or 3.0 as published by the Free +* Software Foundation and appearing in the file LICENSE.GPL included in +* the packaging of this file. Please review the following information +* to ensure GNU General Public Licensing requirements will be met: +* http://www.fsf.org/licensing/licenses/info/GPLv2.html and +* http://www.gnu.org/copyleft/gpl.html. In addition, as a special +* exception, Nokia gives you certain additional rights. These rights +* are described in the Nokia Qt GPL Exception version 1.2, included in +* the file GPL_EXCEPTION.txt in this package. +* +* Qt for Windows(R) Licensees +* As a special exception, Nokia, as the sole copyright holder for Qt +* Designer, grants users of the Qt/Eclipse Integration plug-in the +* right for the Qt/Eclipse Integration to link to functionality +* provided by Qt Designer and its related libraries. +* +* +* If you are unsure which license is appropriate for your use, please +* contact the sales department at qt-sales@nokia.com. + +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef PP_ENGINE_BITS_H +#define PP_ENGINE_BITS_H + +namespace rpp { + +inline std::string pp::fix_file_path(std::string const &filename) const +{ +#if defined (PP_OS_WIN) + std::string s = filename; + for (std::string::iterator it = s.begin(); it != s.end(); ++it) + { + if (*it == '/') + *it = '\\'; + } + return s; +#else + return filename; +#endif +} + +inline bool pp::is_absolute(std::string const &filename) const +{ +#if defined(PP_OS_WIN) + return filename.length() >= 3 + && filename.at(1) == ':' + && (filename.at(2) == '\\' || filename.at(2) == '/'); +#else + return filename.length() >= 1 + && filename.at(0) == '/'; +#endif +} + +template <typename _OutputIterator> +void pp::file (std::string const &filename, _OutputIterator __result) +{ + FILE *fp = fopen (filename.c_str(), "rb"); + if (fp != 0) + { + std::string was = env.current_file; + env.current_file = filename; + file (fp, __result); + env.current_file = was; + } + //else + //std::cerr << "** WARNING file ``" << filename << " not found!" << std::endl; +} + +template <typename _OutputIterator> +void pp::file (FILE *fp, _OutputIterator __result) +{ + assert (fp != 0); + +#if defined (HAVE_MMAP) + struct stat st; + fstat(FILENO (fp), &st); + std::size_t size = st.st_size; + char *buffer = 0; + buffer = (char *) ::mmap(0, size, PROT_READ, MAP_SHARED, FILENO (fp), 0); + fclose (fp); + if (!buffer || buffer == (char*) -1) + return; + this->operator () (buffer, buffer + size, __result); + ::munmap(buffer, size); +#else + std::string buffer; + while (!feof(fp)) { + char tmp[1024]; + int read = (int) fread (tmp, sizeof(char), 1023, fp); + tmp[read] = '\0'; + buffer += tmp; + } + fclose (fp); + this->operator () (buffer.c_str(), buffer.c_str() + buffer.size(), __result); +#endif +} + +template <typename _InputIterator> +bool pp::find_header_protection (_InputIterator __first, _InputIterator __last, std::string *__prot) +{ + int was = env.current_line; + + while (__first != __last) + { + if (pp_isspace (*__first)) + { + if (*__first == '\n') + ++env.current_line; + + ++__first; + } + else if (_PP_internal::comment_p (__first, __last)) + { + __first = skip_comment_or_divop (__first, __last); + env.current_line += skip_comment_or_divop.lines; + } + else if (*__first == '#') + { + __first = skip_blanks (++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == 'i') + { + _InputIterator __begin = __first; + __first = skip_identifier (__begin, __last); + env.current_line += skip_identifier.lines; + + std::string __directive (__begin, __first); + + if (__directive == "ifndef") + { + __first = skip_blanks (__first, __last); + env.current_line += skip_blanks.lines; + + __begin = __first; + __first = skip_identifier (__first, __last); + env.current_line += skip_identifier.lines; + + if (__begin != __first && __first != __last) + { + __prot->assign (__begin, __first); + return true; + } + } + } + break; + } + else + break; + } + + env.current_line = was; + return false; +} + +inline pp::PP_DIRECTIVE_TYPE pp::find_directive (char const *__directive, std::size_t __size) const +{ + switch (__size) + { + case 2: + if (__directive[0] == 'i' + && __directive[1] == 'f') + return PP_IF; + break; + + case 4: + if (__directive[0] == 'e' && !strcmp (__directive, "elif")) + return PP_ELIF; + else if (__directive[0] == 'e' && !strcmp (__directive, "else")) + return PP_ELSE; + break; + + case 5: + if (__directive[0] == 'i' && !strcmp (__directive, "ifdef")) + return PP_IFDEF; + else if (__directive[0] == 'u' && !strcmp (__directive, "undef")) + return PP_UNDEF; + else if (__directive[0] == 'e') { + if (!strcmp (__directive, "endif")) + return PP_ENDIF; + else if (!strcmp (__directive, "error")) + return PP_ERROR; + } + break; + + case 6: + if (__directive[0] == 'i' && !strcmp (__directive, "ifndef")) + return PP_IFNDEF; + else if (__directive[0] == 'd' && !strcmp (__directive, "define")) + return PP_DEFINE; + else if (__directive[0] == 'p' && !strcmp (__directive, "pragma")) + return PP_PRAGMA; + break; + + case 7: + if (__directive[0] == 'i' && !strcmp (__directive, "include")) + return PP_INCLUDE; + break; + + case 12: + if (__directive[0] == 'i' && !strcmp (__directive, "include_next")) + return PP_INCLUDE_NEXT; + break; + + default: + break; + } + std::cerr << "** WARNING unknown directive '#" << __directive << "' at " << env.current_file << ":" << env.current_line << std::endl; + return PP_UNKNOWN_DIRECTIVE; +} + +inline bool pp::file_isdir (std::string const &__filename) const +{ + struct stat __st; +#if defined(PP_OS_WIN) + if (stat(__filename.c_str (), &__st) == 0) + return (__st.st_mode & _S_IFDIR) == _S_IFDIR; + else + return false; +#else + if (lstat (__filename.c_str (), &__st) == 0) + return (__st.st_mode & S_IFDIR) == S_IFDIR; + else + return false; +#endif +} + +inline bool pp::file_exists (std::string const &__filename) const +{ + struct stat __st; +#if defined(PP_OS_WIN) + return stat(__filename.c_str (), &__st) == 0; +#else + return lstat (__filename.c_str (), &__st) == 0; +#endif +} + +inline FILE *pp::find_include_file(std::string const &__input_filename, std::string *__filepath, + INCLUDE_POLICY __include_policy, bool __skip_current_path) const +{ + assert (__filepath != 0); + assert (! __input_filename.empty()); + + __filepath->assign (__input_filename); + + if (is_absolute (*__filepath)) + return fopen (__filepath->c_str(), "r"); + + if (! env.current_file.empty ()) + _PP_internal::extract_file_path (env.current_file, __filepath); + + if (__include_policy == INCLUDE_LOCAL && ! __skip_current_path) + { + std::string __tmp (*__filepath); + __tmp += __input_filename; + + if (file_exists (__tmp) && !file_isdir(__tmp)) + { + __filepath->append (__input_filename); + return fopen (__filepath->c_str (), "r"); + } + } + + std::vector<std::string>::const_iterator it = include_paths.begin (); + + if (__skip_current_path) + { + it = std::find (include_paths.begin (), include_paths.end (), *__filepath); + + if (it != include_paths.end ()) + ++it; + + else + it = include_paths.begin (); + } + + for (; it != include_paths.end (); ++it) + { + if (__skip_current_path && it == include_paths.begin()) + continue; + + __filepath->assign (*it); + __filepath->append (__input_filename); + + if (file_exists (*__filepath) && !file_isdir(*__filepath)) + return fopen (__filepath->c_str(), "r"); + } + + return 0; +} + +template <typename _InputIterator, typename _OutputIterator> +_InputIterator pp::handle_directive(char const *__directive, std::size_t __size, + _InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ + __first = skip_blanks (__first, __last); + + PP_DIRECTIVE_TYPE d = find_directive (__directive, __size); + switch (d) + { + case PP_DEFINE: + if (! skipping ()) + return handle_define (__first, __last); + break; + + case PP_INCLUDE: + case PP_INCLUDE_NEXT: + if (! skipping ()) + return handle_include (d == PP_INCLUDE_NEXT, __first, __last, __result); + break; + + case PP_UNDEF: + if (! skipping ()) + return handle_undef(__first, __last); + break; + + case PP_ELIF: + return handle_elif (__first, __last); + + case PP_ELSE: + return handle_else (__first, __last); + + case PP_ENDIF: + return handle_endif (__first, __last); + + case PP_IF: + return handle_if (__first, __last); + + case PP_IFDEF: + return handle_ifdef (false, __first, __last); + + case PP_IFNDEF: + return handle_ifdef (true, __first, __last); + + default: + break; + } + + return __first; +} + +template <typename _InputIterator, typename _OutputIterator> +_InputIterator pp::handle_include (bool __skip_current_path, _InputIterator __first, _InputIterator __last, + _OutputIterator __result) +{ + if (pp_isalpha (*__first) || *__first == '_') + { + pp_macro_expander expand_include (env); + std::string name; + name.reserve (255); + expand_include (__first, __last, std::back_inserter (name)); + std::string::iterator it = skip_blanks (name.begin (), name.end ()); + assert (it != name.end () && (*it == '<' || *it == '"')); + handle_include (__skip_current_path, it, name.end (), __result); + return __first; + } + + assert (*__first == '<' || *__first == '"'); + int quote = (*__first == '"') ? '"' : '>'; + ++__first; + + _InputIterator end_name = __first; + for (; end_name != __last; ++end_name) + { + assert (*end_name != '\n'); + + if (*end_name == quote) + break; + } + + std::string filename (__first, end_name); + +#ifdef PP_OS_WIN + std::replace(filename.begin(), filename.end(), '/', '\\'); +#endif + + std::string filepath; + FILE *fp = find_include_file (filename, &filepath, quote == '>' ? INCLUDE_GLOBAL : INCLUDE_LOCAL, __skip_current_path); + +#if defined (PP_HOOK_ON_FILE_INCLUDED) + PP_HOOK_ON_FILE_INCLUDED (env.current_file, fp ? filepath : filename, fp); +#endif + + if (fp != 0) + { + std::string old_file = env.current_file; + env.current_file = filepath; + int __saved_lines = env.current_line; + + env.current_line = 1; + //output_line (env.current_file, 1, __result); + + file (fp, __result); + + // restore the file name and the line position + env.current_file = old_file; + env.current_line = __saved_lines; + + // sync the buffer + _PP_internal::output_line (env.current_file, env.current_line, __result); + } +#ifndef RPP_JAMBI +// else +// std::cerr << "*** WARNING " << filename << ": No such file or directory" << std::endl; +#endif + + return __first; +} + +template <typename _InputIterator, typename _OutputIterator> +void pp::operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) +{ +#ifndef PP_NO_SMART_HEADER_PROTECTION + std::string __prot; + __prot.reserve (255); + pp_fast_string __tmp (__prot.c_str (), __prot.size ()); + + if (find_header_protection (__first, __last, &__prot) + && env.resolve (&__tmp) != 0) + { + // std::cerr << "** DEBUG found header protection:" << __prot << std::endl; + return; + } +#endif + + env.current_line = 1; + char __buffer[512]; + + while (true) + { + __first = skip_blanks (__first, __last); + env.current_line += skip_blanks.lines; + + if (__first == __last) + break; + else if (*__first == '#') + { + assert (*__first == '#'); + __first = skip_blanks (++__first, __last); + env.current_line += skip_blanks.lines; + + _InputIterator end_id = skip_identifier (__first, __last); + env.current_line += skip_identifier.lines; + std::size_t __size = end_id - __first; + + assert (__size < 512); + char *__cp = __buffer; + std::copy (__first, end_id, __cp); + __cp[__size] = '\0'; + + end_id = skip_blanks (end_id, __last); + __first = skip (end_id, __last); + + int was = env.current_line; + (void) handle_directive (__buffer, __size, end_id, __first, __result); + + if (env.current_line != was) + { + env.current_line = was; + _PP_internal::output_line (env.current_file, env.current_line, __result); + } + } + else if (*__first == '\n') + { + // ### compress the line + *__result++ = *__first++; + ++env.current_line; + } + else if (skipping ()) + __first = skip (__first, __last); + else + { + _PP_internal::output_line (env.current_file, env.current_line, __result); + __first = expand (__first, __last, __result); + env.current_line += expand.lines; + + if (expand.generated_lines) + _PP_internal::output_line (env.current_file, env.current_line, __result); + } + } +} + +inline pp::pp (pp_environment &__env): + env (__env), expand (env) +{ + iflevel = 0; + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; +} + +inline std::back_insert_iterator<std::vector<std::string> > pp::include_paths_inserter () +{ return std::back_inserter (include_paths); } + +inline std::vector<std::string>::iterator pp::include_paths_begin () +{ return include_paths.begin (); } + +inline std::vector<std::string>::iterator pp::include_paths_end () +{ return include_paths.end (); } + +inline std::vector<std::string>::const_iterator pp::include_paths_begin () const +{ return include_paths.begin (); } + +inline std::vector<std::string>::const_iterator pp::include_paths_end () const +{ return include_paths.end (); } + +inline void pp::push_include_path (std::string const &__path) +{ + if (__path.empty () || __path [__path.size () - 1] != PATH_SEPARATOR) + { + std::string __tmp (__path); + __tmp += PATH_SEPARATOR; + include_paths.push_back (__tmp); + } + + else + include_paths.push_back (__path); +} + +template <typename _InputIterator> +_InputIterator pp::handle_define (_InputIterator __first, _InputIterator __last) +{ + pp_macro macro; +#if defined (PP_WITH_MACRO_POSITION) + macro.file = pp_symbol::get (env.current_file); +#endif + std::string definition; + + __first = skip_blanks (__first, __last); + _InputIterator end_macro_name = skip_identifier (__first, __last); + pp_fast_string const *macro_name = pp_symbol::get (__first, end_macro_name); + __first = end_macro_name; + + if (__first != __last && *__first == '(') + { + macro.function_like = true; + macro.formals.reserve (5); + + __first = skip_blanks (++__first, __last); // skip '(' + _InputIterator arg_end = skip_identifier (__first, __last); + if (__first != arg_end) + macro.formals.push_back (pp_symbol::get (__first, arg_end)); + + __first = skip_blanks (arg_end, __last); + + if (*__first == '.') + { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + + while (__first != __last && *__first == ',') + { + __first = skip_blanks (++__first, __last); + + arg_end = skip_identifier (__first, __last); + if (__first != arg_end) + macro.formals.push_back (pp_symbol::get (__first, arg_end)); + + __first = skip_blanks (arg_end, __last); + + if (*__first == '.') + { + macro.variadics = true; + while (*__first == '.') + ++__first; + } + } + + assert (*__first == ')'); + ++__first; + } + + __first = skip_blanks (__first, __last); + + while (__first != __last && *__first != '\n') + { + if (*__first == '/') { + __first = skip_comment_or_divop(__first, __last); + env.current_line += skip_comment_or_divop.lines; + } + + if (*__first == '\\') + { + _InputIterator __begin = __first; + __begin = skip_blanks (++__begin, __last); + + if (__begin != __last && *__begin == '\n') + { + ++macro.lines; + __first = skip_blanks (++__begin, __last); + definition += ' '; + continue; + } + } + + definition += *__first++; + } + + macro.definition = pp_symbol::get (definition); + env.bind (macro_name, macro); + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::skip (_InputIterator __first, _InputIterator __last) +{ + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + + while (__first != __last && *__first != '\n') + { + if (*__first == '/') + { + __first = skip_comment_or_divop (__first, __last); + env.current_line += skip_comment_or_divop.lines; + } + else if (*__first == '"') + { + __first = skip_string_literal (__first, __last); + env.current_line += skip_string_literal.lines; + } + else if (*__first == '\'') + { + __first = skip_char_literal (__first, __last); + env.current_line += skip_char_literal.lines; + } + else if (*__first == '\\') + { + __first = skip_blanks (++__first, __last); + env.current_line += skip_blanks.lines; + + if (__first != __last && *__first == '\n') + { + ++__first; + ++env.current_line; + } + } + else + ++__first; + } + + return __first; +} + +inline bool pp::test_if_level() +{ + bool result = !_M_skipping[iflevel++]; + _M_skipping[iflevel] = _M_skipping[iflevel - 1]; + _M_true_test[iflevel] = false; + return result; +} + +inline int pp::skipping() const +{ return _M_skipping[iflevel]; } + +template <typename _InputIterator> +_InputIterator pp::eval_primary(_InputIterator __first, _InputIterator __last, Value *result) +{ + bool expect_paren = false; + int token; + __first = next_token (__first, __last, &token); + + switch (token) + { + case TOKEN_NUMBER: + result->set_long (token_value); + break; + + case TOKEN_UNUMBER: + result->set_ulong (token_uvalue); + break; + + case TOKEN_DEFINED: + __first = next_token (__first, __last, &token); + + if (token == '(') + { + expect_paren = true; + __first = next_token (__first, __last, &token); + } + + if (token != TOKEN_IDENTIFIER) + { + std::cerr << "** WARNING expected ``identifier'' found:" << char(token) << std::endl; + result->set_long (0); + break; + } + + result->set_long (env.resolve (token_text->c_str (), token_text->size ()) != 0); + + next_token (__first, __last, &token); // skip '(' + + if (expect_paren) + { + _InputIterator next = next_token (__first, __last, &token); + if (token != ')') + std::cerr << "** WARNING expected ``)''" << std::endl; + else + __first = next; + } + break; + + case TOKEN_IDENTIFIER: + result->set_long (0); + break; + + case '-': + __first = eval_primary (__first, __last, result); + result->set_long (- result->l); + return __first; + + case '+': + __first = eval_primary (__first, __last, result); + return __first; + + case '!': + __first = eval_primary (__first, __last, result); + result->set_long (result->is_zero ()); + return __first; + + case '(': + __first = eval_constant_expression(__first, __last, result); + next_token (__first, __last, &token); + + if (token != ')') + std::cerr << "** WARNING expected ``)'' = " << token << std::endl; + else + __first = next_token(__first, __last, &token); + break; + + default: + result->set_long (0); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_multiplicative(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_primary(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '*' || token == '/' || token == '%') + { + Value value; + __first = eval_primary(next, __last, &value); + + if (token == '*') + result->op_mult (value); + else if (token == '/') + { + if (value.is_zero ()) + { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long (0); + } + else + result->op_div (value); + } + else + { + if (value.is_zero ()) + { + std::cerr << "** WARNING division by zero" << std::endl; + result->set_long (0); + } + else + result->op_mod (value); + } + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_additive(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_multiplicative(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '+' || token == '-') + { + Value value; + __first = eval_multiplicative(next, __last, &value); + + if (token == '+') + result->op_add (value); + else + result->op_sub (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_shift(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_additive(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == TOKEN_LT_LT || token == TOKEN_GT_GT) + { + Value value; + __first = eval_additive (next, __last, &value); + + if (token == TOKEN_LT_LT) + result->op_lhs (value); + else + result->op_rhs (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_relational(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_shift(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '<' + || token == '>' + || token == TOKEN_LT_EQ + || token == TOKEN_GT_EQ) + { + Value value; + __first = eval_shift(next, __last, &value); + + switch (token) + { + default: + assert (0); + break; + + case '<': + result->op_lt (value); + break; + + case '>': + result->op_gt (value); + break; + + case TOKEN_LT_EQ: + result->op_le (value); + break; + + case TOKEN_GT_EQ: + result->op_ge (value); + break; + } + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_equality(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_relational(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == TOKEN_EQ_EQ || token == TOKEN_NOT_EQ) + { + Value value; + __first = eval_relational(next, __last, &value); + + if (token == TOKEN_EQ_EQ) + result->op_eq (value); + else + result->op_ne (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_equality(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '&') + { + Value value; + __first = eval_equality(next, __last, &value); + result->op_bit_and (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_xor(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_and(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '^') + { + Value value; + __first = eval_and(next, __last, &value); + result->op_bit_xor (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_xor(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == '|') + { + Value value; + __first = eval_xor(next, __last, &value); + result->op_bit_or (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_logical_and(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_or(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == TOKEN_AND_AND) + { + Value value; + __first = eval_or(next, __last, &value); + result->op_and (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_logical_or(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_and (__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + while (token == TOKEN_OR_OR) + { + Value value; + __first = eval_logical_and(next, __last, &value); + result->op_or (value); + next = next_token (__first, __last, &token); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_constant_expression(_InputIterator __first, _InputIterator __last, Value *result) +{ + __first = eval_logical_or(__first, __last, result); + + int token; + _InputIterator next = next_token (__first, __last, &token); + + if (token == '?') + { + Value left_value; + __first = eval_constant_expression(next, __last, &left_value); + __first = skip_blanks (__first, __last); + + __first = next_token(__first, __last, &token); + if (token == ':') + { + Value right_value; + __first = eval_constant_expression(__first, __last, &right_value); + + *result = !result->is_zero () ? left_value : right_value; + } + else + { + std::cerr << "** WARNING expected ``:'' = " << int (token) << std::endl; + *result = left_value; + } + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::eval_expression (_InputIterator __first, _InputIterator __last, Value *result) +{ + return __first = eval_constant_expression (skip_blanks (__first, __last), __last, result); +} + +template <typename _InputIterator> +_InputIterator pp::handle_if (_InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) + { + pp_macro_expander expand_condition (env); + std::string condition; + condition.reserve (255); + expand_condition (skip_blanks (__first, __last), __last, std::back_inserter (condition)); + + Value result; + result.set_long (0); + eval_expression(condition.c_str (), condition.c_str () + condition.size (), &result); + + _M_true_test[iflevel] = !result.is_zero (); + _M_skipping[iflevel] = result.is_zero (); + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_else (_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping ()) + { + std::cerr << "** WARNING #else without #if" << std::endl; + } + else if (iflevel > 0 && _M_skipping[iflevel - 1]) + { + _M_skipping[iflevel] = true; + } + else + { + _M_skipping[iflevel] = _M_true_test[iflevel]; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_elif (_InputIterator __first, _InputIterator __last) +{ + assert(iflevel > 0); + + if (iflevel == 0 && !skipping()) + { + std::cerr << "** WARNING #else without #if" << std::endl; + } + else if (!_M_true_test[iflevel] && !_M_skipping[iflevel - 1]) + { + Value result; + __first = eval_expression(__first, __last, &result); + _M_true_test[iflevel] = !result.is_zero (); + _M_skipping[iflevel] = result.is_zero (); + } + else + { + _M_skipping[iflevel] = true; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_endif (_InputIterator __first, _InputIterator /*__last*/) +{ + if (iflevel == 0 && !skipping()) + { + std::cerr << "** WARNING #endif without #if" << std::endl; + } + else + { + _M_skipping[iflevel] = 0; + _M_true_test[iflevel] = 0; + + --iflevel; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_ifdef (bool check_undefined, _InputIterator __first, _InputIterator __last) +{ + if (test_if_level()) + { + _InputIterator end_macro_name = skip_identifier (__first, __last); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance (__first, end_macro_name, __size); +#else + __size = std::distance (__first, end_macro_name); +#endif + assert (__size < 256); + + char __buffer [256]; + std::copy (__first, end_macro_name, __buffer); + + bool value = env.resolve (__buffer, __size) != 0; + + __first = end_macro_name; + + if (check_undefined) + value = !value; + + _M_true_test[iflevel] = value; + _M_skipping[iflevel] = !value; + } + + return __first; +} + +template <typename _InputIterator> +_InputIterator pp::handle_undef(_InputIterator __first, _InputIterator __last) +{ + __first = skip_blanks (__first, __last); + _InputIterator end_macro_name = skip_identifier (__first, __last); + assert (end_macro_name != __first); + + std::size_t __size; +#if defined(__SUNPRO_CC) + std::distance (__first, end_macro_name, __size); +#else + __size = std::distance (__first, end_macro_name); +#endif + + assert (__size < 256); + + char __buffer [256]; + std::copy (__first, end_macro_name, __buffer); + + pp_fast_string const __tmp (__buffer, __size); + env.unbind (&__tmp); + + __first = end_macro_name; + + return __first; +} + +template <typename _InputIterator> +char pp::peek_char (_InputIterator __first, _InputIterator __last) +{ + if (__first == __last) + return 0; + + return *++__first; +} + +template <typename _InputIterator> +_InputIterator pp::next_token (_InputIterator __first, _InputIterator __last, int *kind) +{ + __first = skip_blanks (__first, __last); + + if (__first == __last) + { + *kind = 0; + return __first; + } + + char ch = *__first; + char ch2 = peek_char (__first, __last); + + switch (ch) + { + case '/': + if (ch2 == '/' || ch2 == '*') + { + __first = skip_comment_or_divop (__first, __last); + return next_token (__first, __last, kind); + } + ++__first; + *kind = '/'; + break; + + case '<': + ++__first; + if (ch2 == '<') + { + ++__first; + *kind = TOKEN_LT_LT; + } + else if (ch2 == '=') + { + ++__first; + *kind = TOKEN_LT_EQ; + } + else + *kind = '<'; + + return __first; + + case '>': + ++__first; + if (ch2 == '>') + { + ++__first; + *kind = TOKEN_GT_GT; + } + else if (ch2 == '=') + { + ++__first; + *kind = TOKEN_GT_EQ; + } + else + *kind = '>'; + + return __first; + + case '!': + ++__first; + if (ch2 == '=') + { + ++__first; + *kind = TOKEN_NOT_EQ; + } + else + *kind = '!'; + + return __first; + + case '=': + ++__first; + if (ch2 == '=') + { + ++__first; + *kind = TOKEN_EQ_EQ; + } + else + *kind = '='; + + return __first; + + case '|': + ++__first; + if (ch2 == '|') + { + ++__first; + *kind = TOKEN_OR_OR; + } + else + *kind = '|'; + + return __first; + + case '&': + ++__first; + if (ch2 == '&') + { + ++__first; + *kind = TOKEN_AND_AND; + } + else + *kind = '&'; + + return __first; + + default: + if (pp_isalpha (ch) || ch == '_') + { + _InputIterator end = skip_identifier (__first, __last); + _M_current_text.assign (__first, end); + + token_text = &_M_current_text; + __first = end; + + if (*token_text == "defined") + *kind = TOKEN_DEFINED; + else + *kind = TOKEN_IDENTIFIER; + } + else if (pp_isdigit (ch)) + { + _InputIterator end = skip_number (__first, __last); + std::string __str (__first, __last); + char ch = __str [__str.size () - 1]; + if (ch == 'u' || ch == 'U') + { + token_uvalue = strtoul (__str.c_str (), 0, 0); + *kind = TOKEN_UNUMBER; + } + else + { + token_value = strtol (__str.c_str (), 0, 0); + *kind = TOKEN_NUMBER; + } + __first = end; + } + else + *kind = *__first++; + } + + return __first; +} + +} // namespace rpp + +#endif // PP_ENGINE_BITS_H + +// kate: space-indent on; indent-width 2; replace-tabs on;