| #!/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() |