Mercurial > projects > qtd
diff generator/parser/rpp/pp-macro-expander.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-macro-expander.h Mon May 11 16:01:50 2009 +0000 @@ -0,0 +1,410 @@ +/**************************************************************************** +** +** 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_MACRO_EXPANDER_H +#define PP_MACRO_EXPANDER_H + +namespace rpp { + +struct pp_frame +{ + pp_macro *expanding_macro; + std::vector<std::string> *actuals; + + pp_frame (pp_macro *__expanding_macro, std::vector<std::string> *__actuals): + expanding_macro (__expanding_macro), actuals (__actuals) {} +}; + +class pp_macro_expander +{ + pp_environment &env; + pp_frame *frame; + + pp_skip_number skip_number; + pp_skip_identifier skip_identifier; + pp_skip_string_literal skip_string_literal; + pp_skip_char_literal skip_char_literal; + pp_skip_argument skip_argument; + pp_skip_comment_or_divop skip_comment_or_divop; + pp_skip_blanks skip_blanks; + pp_skip_whitespaces skip_whitespaces; + + std::string const *resolve_formal (pp_fast_string const *__name) + { + assert (__name != 0); + + if (! frame) + return 0; + + assert (frame->expanding_macro != 0); + + std::vector<pp_fast_string const *> const formals = frame->expanding_macro->formals; + for (std::size_t index = 0; index < formals.size(); ++index) + { + pp_fast_string const *formal = formals[index]; + + if (*formal != *__name) + continue; + + else if (frame->actuals && index < frame->actuals->size()) + return &(*frame->actuals)[index]; + + else + assert (0); // internal error? + } + + return 0; + } + +public: // attributes + int lines; + int generated_lines; + +public: + pp_macro_expander (pp_environment &__env, pp_frame *__frame = 0): + env (__env), frame (__frame), lines (0), generated_lines (0) {} + + template <typename _InputIterator, typename _OutputIterator> + _InputIterator operator () (_InputIterator __first, _InputIterator __last, _OutputIterator __result) + { + generated_lines = 0; + __first = skip_blanks (__first, __last); + lines = skip_blanks.lines; + + while (__first != __last) + { + if (*__first == '\n') + { + *__result++ = *__first; + ++lines; + + __first = skip_blanks (++__first, __last); + lines += skip_blanks.lines; + + if (__first != __last && *__first == '#') + break; + } + else if (*__first == '#') + { + __first = skip_blanks (++__first, __last); + lines += skip_blanks.lines; + + _InputIterator end_id = skip_identifier (__first, __last); + + // ### rewrite: not safe + char name_buffer[512], *cp = name_buffer; + std::copy (__first, end_id, cp); + std::size_t name_size = end_id - __first; + name_buffer[name_size] = '\0'; + + pp_fast_string fast_name (name_buffer, name_size); + + if (std::string const *actual = resolve_formal (&fast_name)) + { + *__result++ = '\"'; + + for (std::string::const_iterator it = skip_whitespaces (actual->begin (), actual->end ()); + it != actual->end (); ++it) + { + if (*it == '"') + { + *__result++ = '\\'; + *__result++ = *it; + } + + else if (*it == '\n') + { + *__result++ = '"'; + *__result++ = '\n'; + *__result++ = '"'; + } + + else + *__result++ = *it; + } + + *__result++ = '\"'; + __first = end_id; + } + else + *__result++ = '#'; // ### warning message? + } + else if (*__first == '\"') + { + _InputIterator next_pos = skip_string_literal (__first, __last); + lines += skip_string_literal.lines; + std::copy (__first, next_pos, __result); + __first = next_pos; + } + else if (*__first == '\'') + { + _InputIterator next_pos = skip_char_literal (__first, __last); + lines += skip_char_literal.lines; + std::copy (__first, next_pos, __result); + __first = next_pos; + } + else if (_PP_internal::comment_p (__first, __last)) + { + __first = skip_comment_or_divop (__first, __last); + int n = skip_comment_or_divop.lines; + lines += n; + + while (n-- > 0) + *__result++ = '\n'; + } + else if (pp_isspace (*__first)) + { + for (; __first != __last; ++__first) + { + if (*__first == '\n' || !pp_isspace (*__first)) + break; + } + + *__result = ' '; + } + else if (pp_isdigit (*__first)) + { + _InputIterator next_pos = skip_number (__first, __last); + lines += skip_number.lines; + std::copy (__first, next_pos, __result); + __first = next_pos; + } + else if (pp_isalpha (*__first) || *__first == '_') + { + _InputIterator name_begin = __first; + _InputIterator name_end = skip_identifier (__first, __last); + __first = name_end; // advance + + // search for the paste token + _InputIterator next = skip_blanks (__first, __last); + if (next != __last && *next == '#') + { + ++next; + if (next != __last && *next == '#') + __first = skip_blanks(++next, __last); + } + + // ### rewrite: not safe + + std::ptrdiff_t name_size; +#if defined(__SUNPRO_CC) + std::distance (name_begin, name_end, name_size); +#else + name_size = std::distance (name_begin, name_end); +#endif + assert (name_size >= 0 && name_size < 512); + + char name_buffer[512], *cp = name_buffer; + std::size_t __size = name_end - name_begin; + std::copy (name_begin, name_end, cp); + name_buffer[__size] = '\0'; + + pp_fast_string fast_name (name_buffer, name_size); + + if (std::string const *actual = resolve_formal (&fast_name)) + { + std::copy (actual->begin (), actual->end (), __result); + continue; + } + + static bool hide_next = false; // ### remove me + + pp_macro *macro = env.resolve (name_buffer, name_size); + if (! macro || macro->hidden || hide_next) + { + hide_next = ! strcmp (name_buffer, "defined"); + + if (__size == 8 && name_buffer [0] == '_' && name_buffer [1] == '_') + { + if (! strcmp (name_buffer, "__LINE__")) + { + char buf [16]; + char *end = buf + pp_snprintf (buf, 16, "%d", env.current_line + lines); + + std::copy (&buf [0], end, __result); + continue; + } + + else if (! strcmp (name_buffer, "__FILE__")) + { + __result++ = '"'; + std::copy (env.current_file.begin (), env.current_file.end (), __result); // ### quote + __result++ = '"'; + continue; + } + } + + std::copy (name_begin, name_end, __result); + continue; + } + + if (! macro->function_like) + { + pp_macro *m = 0; + + if (macro->definition) + { + macro->hidden = true; + + std::string __tmp; + __tmp.reserve (256); + + pp_macro_expander expand_macro (env); + expand_macro (macro->definition->begin (), macro->definition->end (), std::back_inserter (__tmp)); + generated_lines += expand_macro.lines; + + if (! __tmp.empty ()) + { + std::string::iterator __begin_id = skip_whitespaces (__tmp.begin (), __tmp.end ()); + std::string::iterator __end_id = skip_identifier (__begin_id, __tmp.end ()); + + if (__end_id == __tmp.end ()) + { + std::string __id; + __id.assign (__begin_id, __end_id); + + std::size_t x; +#if defined(__SUNPRO_CC) + std::distance (__begin_id, __end_id, x); +#else + x = std::distance (__begin_id, __end_id); +#endif + m = env.resolve (__id.c_str (), x); + } + + if (! m) + std::copy (__tmp.begin (), __tmp.end (), __result); + } + + macro->hidden = false; + } + + if (! m) + continue; + + macro = m; + } + + // function like macro + _InputIterator arg_it = skip_whitespaces (__first, __last); + + if (arg_it == __last || *arg_it != '(') + { + std::copy (name_begin, name_end, __result); + lines += skip_whitespaces.lines; + __first = arg_it; + continue; + } + + std::vector<std::string> actuals; + actuals.reserve (5); + ++arg_it; // skip '(' + + pp_macro_expander expand_actual (env, frame); + + _InputIterator arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); + if (arg_it != arg_end) + { + std::string actual (arg_it, arg_end); + actuals.resize (actuals.size() + 1); + actuals.back ().reserve (255); + expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back())); + arg_it = arg_end; + } + + while (arg_it != __last && *arg_end == ',') + { + ++arg_it; // skip ',' + + arg_end = skip_argument_variadics (actuals, macro, arg_it, __last); + std::string actual (arg_it, arg_end); + actuals.resize (actuals.size() + 1); + actuals.back ().reserve (255); + expand_actual (actual.begin (), actual.end(), std::back_inserter (actuals.back())); + arg_it = arg_end; + } + + assert (arg_it != __last && *arg_it == ')'); + + ++arg_it; // skip ')' + __first = arg_it; + +#if 0 // ### enable me + assert ((macro->variadics && macro->formals.size () >= actuals.size ()) + || macro->formals.size() == actuals.size()); +#endif + + pp_frame frame (macro, &actuals); + pp_macro_expander expand_macro (env, &frame); + macro->hidden = true; + expand_macro (macro->definition->begin (), macro->definition->end (), __result); + macro->hidden = false; + generated_lines += expand_macro.lines; + } + else + *__result++ = *__first++; + } + + return __first; + } + + template <typename _InputIterator> + _InputIterator skip_argument_variadics (std::vector<std::string> const &__actuals, pp_macro *__macro, + _InputIterator __first, _InputIterator __last) + { + _InputIterator arg_end = skip_argument (__first, __last); + + while (__macro->variadics && __first != arg_end && arg_end != __last && *arg_end == ',' + && (__actuals.size () + 1) == __macro->formals.size ()) + { + arg_end = skip_argument (++arg_end, __last); + } + + return arg_end; + } +}; + +} // namespace rpp + +#endif // PP_MACRO_EXPANDER_H + +// kate: space-indent on; indent-width 2; replace-tabs on;