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;