|  | #!/usr/bin/python | 
|  | """ | 
|  | Filters out some of the #defines used throughout the GCC sources: | 
|  | - GTY(()) marks declarations for gengtype.c | 
|  | - PARAMS(()) is used for K&R compatibility. See ansidecl.h. | 
|  |  | 
|  | When passed one or more filenames, acts on those files and prints the | 
|  | results to stdout. | 
|  |  | 
|  | When run without a filename, runs a unit-testing suite. | 
|  | """ | 
|  | import re | 
|  | import sys | 
|  | import unittest | 
|  |  | 
|  | # Optional whitespace | 
|  | OPT_WS = '\s*' | 
|  |  | 
|  | def filter_src(text): | 
|  | """ | 
|  | str -> str.  We operate on the whole of the source file at once | 
|  | (rather than individual lines) so that we can have multiline | 
|  | regexes. | 
|  | """ | 
|  |  | 
|  | # Convert C comments from GNU coding convention of: | 
|  | #    /* FIRST_LINE | 
|  | #       NEXT_LINE | 
|  | #       FINAL_LINE.  */ | 
|  | # to: | 
|  | #    /** @verbatim FIRST_LINE | 
|  | #       NEXT_LINE | 
|  | #       FINAL_LINE.  @endverbatim */ | 
|  | # so that doxygen will parse them. | 
|  | # | 
|  | # Only comments that begin on the left-most column are converted. | 
|  | # | 
|  | text = re.sub(r'^/\*\* ', | 
|  | r'/** @verbatim ', | 
|  | text, | 
|  | flags=re.MULTILINE) | 
|  | text = re.sub(r'^/\* ', | 
|  | r'/** @verbatim ', | 
|  | text, | 
|  | flags=re.MULTILINE) | 
|  | text = re.sub(r'\*/', | 
|  | r' @endverbatim */', | 
|  | text) | 
|  |  | 
|  | # Remove GTY markings (potentially multiline ones): | 
|  | text = re.sub('GTY' + OPT_WS + r'\(\(.*?\)\)\s+', | 
|  | '', | 
|  | text, | 
|  | flags=(re.MULTILINE|re.DOTALL)) | 
|  |  | 
|  | # Strip out 'ATTRIBUTE_UNUSED' | 
|  | text = re.sub('\sATTRIBUTE_UNUSED', | 
|  | '', | 
|  | text) | 
|  |  | 
|  | # PARAMS(()) is used for K&R compatibility. See ansidecl.h. | 
|  | text = re.sub('PARAMS' + OPT_WS + r'\(\((.*?)\)\)', | 
|  | r'(\1)', | 
|  | text) | 
|  |  | 
|  | # Replace 'ENUM_BITFIELD(enum_name)' with 'enum enum_name'. | 
|  | text = re.sub('ENUM_BITFIELD\s*\(([^\)]*)\)', | 
|  | r'enum \1', | 
|  | text) | 
|  |  | 
|  | return text | 
|  |  | 
|  | class FilteringTests(unittest.TestCase): | 
|  | ''' | 
|  | Unit tests for filter_src. | 
|  | ''' | 
|  | def assert_filters_to(self, src_input, expected_result): | 
|  | # assertMultiLineEqual was added to unittest in 2.7/3.1 | 
|  | if hasattr(self, 'assertMultiLineEqual'): | 
|  | assertion = self.assertMultiLineEqual | 
|  | else: | 
|  | assertion = self.assertEqual | 
|  | assertion(expected_result, filter_src(src_input)) | 
|  |  | 
|  | def test_comment_example(self): | 
|  | self.assert_filters_to( | 
|  | ('/* FIRST_LINE\n' | 
|  | '   NEXT_LINE\n' | 
|  | '   FINAL_LINE.  */\n'), | 
|  | ('/** @verbatim FIRST_LINE\n' | 
|  | '   NEXT_LINE\n' | 
|  | '   FINAL_LINE.   @endverbatim */\n')) | 
|  |  | 
|  | def test_comment_example_gengtype(self): | 
|  | self.assert_filters_to( | 
|  | ('/** Allocate and initialize an input buffer state.\n' | 
|  | ' * @param file A readable stream.\n' | 
|  | ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n' | 
|  | ' * \n' | 
|  | ' * @return the allocated buffer state.\n' | 
|  | ' */'), | 
|  | ('/** @verbatim Allocate and initialize an input buffer state.\n' | 
|  | ' * @param file A readable stream.\n' | 
|  | ' * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.\n' | 
|  | ' * \n' | 
|  | ' * @return the allocated buffer state.\n' | 
|  | '  @endverbatim */')) | 
|  |  | 
|  | def test_oneliner_comment(self): | 
|  | self.assert_filters_to( | 
|  | '/* Returns the string representing CLASS.  */\n', | 
|  | ('/** @verbatim Returns the string representing CLASS.   @endverbatim */\n')) | 
|  |  | 
|  | def test_multiline_comment(self): | 
|  | self.assert_filters_to( | 
|  | ('/* The thread-local storage model associated with a given VAR_DECL\n' | 
|  | "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n" | 
|  | "   to it, so it's here.  */\n"), | 
|  | ('/** @verbatim The thread-local storage model associated with a given VAR_DECL\n' | 
|  | "   or SYMBOL_REF.  This isn't used much, but both trees and RTL refer\n" | 
|  | "   to it, so it's here.   @endverbatim */\n")) | 
|  |  | 
|  | def test_GTY(self): | 
|  | self.assert_filters_to( | 
|  | ('typedef struct GTY(()) alias_pair {\n' | 
|  | '  tree decl;\n' | 
|  | '  tree target;\n' | 
|  | '} alias_pair;\n'), | 
|  | ('typedef struct alias_pair {\n' | 
|  | '  tree decl;\n' | 
|  | '  tree target;\n' | 
|  | '} alias_pair;\n')) | 
|  |  | 
|  | def test_multiline_GTY(self): | 
|  | # Ensure that a multiline GTY is filtered out. | 
|  | self.assert_filters_to( | 
|  | ('class GTY((desc ("%h.type"), tag ("SYMTAB_SYMBOL"),\n' | 
|  | '\t   chain_next ("%h.next"), chain_prev ("%h.previous")))\n' | 
|  | '  symtab_node_base\n' | 
|  | '{\n'), | 
|  | ('class symtab_node_base\n' | 
|  | '{\n')) | 
|  |  | 
|  | def test_ATTRIBUTE_UNUSED(self): | 
|  | # Ensure that ATTRIBUTE_UNUSED is filtered out. | 
|  | self.assert_filters_to( | 
|  | ('static void\n' | 
|  | 'record_set (rtx dest, const_rtx set, void *data ATTRIBUTE_UNUSED)\n' | 
|  | '{\n'), | 
|  | ('static void\n' | 
|  | 'record_set (rtx dest, const_rtx set, void *data)\n' | 
|  | '{\n')) | 
|  |  | 
|  | def test_PARAMS(self): | 
|  | self.assert_filters_to( | 
|  | 'char *strcpy PARAMS ((char *dest, char *source));\n', | 
|  | 'char *strcpy (char *dest, char *source);\n') | 
|  |  | 
|  | def test_ENUM_BITFIELD(self): | 
|  | self.assert_filters_to( | 
|  | '  ENUM_BITFIELD (sym_intent) intent:2;\n', | 
|  | '  enum sym_intent intent:2;\n') | 
|  |  | 
|  | def act_on_files(argv): | 
|  | for filename in argv[1:]: | 
|  | with open(filename) as f: | 
|  | text = f.read() | 
|  | print(filter_src(text)) | 
|  |  | 
|  | if __name__ == '__main__': | 
|  | if len(sys.argv) > 1: | 
|  | act_on_files(sys.argv) | 
|  | else: | 
|  | unittest.main() |