Mercurial > projects > qtd
view 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 source
/**************************************************************************** ** ** 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;