• C++根据.h文件批量生成需要的函数框架


    类似VS中添加类 A的方法 int abc();

    会在对应的实现文件.cpp中自动生成,

    int A::abc() {

    }

    初学python,尝试写了一个脚本,自动根据写好的.h文件完成这一工作,也支持模板类,不过没考虑太多模板可能会有bug。

    也可能会有很多其他的bug,不过用了下,感觉还可以,有错误再改正:)


    用法

    比如有一个abc.h,对应的实现文件abc.cc

    1.新建一个abc.cc文件

      touch abc.cc

    2.运行脚本

      ./prodef.py  abc.h abc.cc

       因为我默认是.cc文件,也可

     ./prodef.py  abc.h

      


    用google 开源的代码做了一个实验,

     我们要处理的gtest-test-part.h如下

    // Copyright 2008, Google Inc.

    // All rights reserved.


    #ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_

    #define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_


    #include <iosfwd>

    #include <gtest/internal/gtest-internal.h>

    #include <gtest/internal/gtest-string.h>


    namespace testing {


    // The possible outcomes of a test part (i.e. an assertion or an

    // explicit SUCCEED(), FAIL(), or ADD_FAILURE()).

    enum TestPartResultType {

      TPRT_SUCCESS,           // Succeeded.

      TPRT_NONFATAL_FAILURE,  // Failed but the test can continue.

      TPRT_FATAL_FAILURE      // Failed and the test should be terminated.

    };


    // A copyable object representing the result of a test part (i.e. an

    // assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()).

    //

    // Don't inherit from TestPartResult as its destructor is not virtual.

    class TestPartResult {

     public:

      // C'tor.  TestPartResult does NOT have a default constructor.

      // Always use this constructor (with parameters) to create a

      // TestPartResult object.

      TestPartResult(TestPartResultType type,

                     const char* file_name,

                     int line_number,

                     const char* message)

          : type_(type),

            file_name_(file_name),

            line_number_(line_number),

            summary_(ExtractSummary(message)),

            message_(message) {

      }


      // Gets the outcome of the test part.

      TestPartResultType type() const { return type_; }


      // Gets the name of the source file where the test part took place, or

      // NULL if it's unknown.

      const char* file_name() const { return file_name_.c_str(); }


      // Gets the line in the source file where the test part took place,

      // or -1 if it's unknown.

      int line_number() const { return line_number_; }


      // Gets the summary of the failure message.

      const char* summary() const { return summary_.c_str(); }


      // Gets the message associated with the test part.

      const char* message() const { return message_.c_str(); }


      // Returns true iff the test part passed.

      bool passed() const { return type_ == TPRT_SUCCESS; }


      // Returns true iff the test part failed.

      bool failed() const { return type_ != TPRT_SUCCESS; }


      // Returns true iff the test part non-fatally failed.

      bool nonfatally_failed() const { return type_ == TPRT_NONFATAL_FAILURE; }


      // Returns true iff the test part fatally failed.

      bool fatally_failed() const { return type_ == TPRT_FATAL_FAILURE; }

     private:

      TestPartResultType type_;


      // Gets the summary of the failure message by omitting the stack

      // trace in it.

      static internal::String ExtractSummary(const char* message);


      // The name of the source file where the test part took place, or

      // NULL if the source file is unknown.

      internal::String file_name_;

      // The line in the source file where the test part took place, or -1

      // if the line number is unknown.

      int line_number_;

      internal::String summary_;  // The test failure summary.

      internal::String message_;  // The test failure message.

    };


    // Prints a TestPartResult object.

    std::ostream& operator<<(std::ostream& os, const TestPartResult& result);


    // An array of TestPartResult objects.

    //

    // We define this class as we cannot use STL containers when compiling

    // Google Test with MSVC 7.1 and exceptions disabled.

    //

    // Don't inherit from TestPartResultArray as its destructor is not

    // virtual.

    class TestPartResultArray {

     public:

      TestPartResultArray();

      ~TestPartResultArray();


      // Appends the given TestPartResult to the array.

      void Append(const TestPartResult& result);


      // Returns the TestPartResult at the given index (0-based).

      const TestPartResult& GetTestPartResult(int index) const;


      // Returns the number of TestPartResult objects in the array.

      int size() const;

     private:

      // Internally we use a list to simulate the array.  Yes, this means

      // that random access is O(N) in time, but it's OK for its purpose.

      internal::List<TestPartResult>* const list_;


      GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray);

    };


    // This interface knows how to report a test part result.

    class TestPartResultReporterInterface {

     public:

      virtual ~TestPartResultReporterInterface() {}


      virtual void ReportTestPartResult(const TestPartResult& result) = 0;

    };


    namespace internal {


    // This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a

    // statement generates new fatal failures. To do so it registers itself as the

    // current test part result reporter. Besides checking if fatal failures were

    // reported, it only delegates the reporting to the former result reporter.

    // The original result reporter is restored in the destructor.

    // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM.

    class HasNewFatalFailureHelper : public TestPartResultReporterInterface {

     public:

      HasNewFatalFailureHelper();

      virtual ~HasNewFatalFailureHelper();

      virtual void ReportTestPartResult(const TestPartResult& result);

      bool has_new_fatal_failure() const { return has_new_fatal_failure_; }

     private:

      bool has_new_fatal_failure_;

      TestPartResultReporterInterface* original_reporter_;


      GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper);

    };


    }  // namespace internal


    }  // namespace testing


    #endif  // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_



    运行 ./prodef.py gtest-test-part.h

    生成的 gtest-test-part.cc 函数框架如下

    #include "gtest-test-part.h"


    namespace testing {


    // Gets the summary of the failure message by omitting the stack

    // trace in it.

    internal::String TestPartResult::ExtractSummary(const char* message) {


    }


    // Prints a TestPartResult object.

    std::ostream& operator<<(std::ostream& os, const TestPartResult& result) {


    }


    TestPartResultArray::TestPartResultArray() {


    }


    TestPartResultArray::~TestPartResultArray() {


    }


    // Appends the given TestPartResult to the array.

    void TestPartResultArray::Append(const TestPartResult& result) {


    }


    // Returns the TestPartResult at the given index (0-based).

    const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const {


    }


    // Returns the number of TestPartResult objects in the array.

    int TestPartResultArray::size() const {


    }


    void TestPartResultReporterInterface::ReportTestPartResult(const TestPartResult& result) {


    }


    namespace internal {


    HasNewFatalFailureHelper::HasNewFatalFailureHelper() {


    }


    HasNewFatalFailureHelper::~HasNewFatalFailureHelper() {


    }


    void HasNewFatalFailureHelper::ReportTestPartResult(const TestPartResult& result) {


    }


    }  // namespace internal


    }  // namespace testing








    下面是程序源码


    #!/usr/local/bin/python3.0


    #prodef.py

    #automate generate the .cc file according to .h file
    #generate all the functions need to be implemented 
    #defining in .h file


    #autor goldenlock@pku

    #05.13.09

    #since c++ is complex
    #there may be bugs... 
    #I assume you define class as below
    #class A {
    #};
    #I assume you define function as below
    #int abc();
    #or
    #int abc(int x,int y
    # int z);
    #Below is not allowed
    #int
    #abc (int x,int y,int z);
    #I assume you always use c++ style comment //

    def usage():
        """ 
            Run the program like this,notice need to touch a empty .cc or .cpp by yourself
    we assume .cc by defualt
    1.touch abc.cc                
            2./prodef.py abc.h abc.cc
              or ./prodef.py abc.h 

    1.touch a.cpp
    2./prodef.py a.h a.cpp

            It will read abc.h and append the fuctions 
            to be implemented to abc.cc
            """

    func_list_exist = []
    def AnalyzeOutputFile(file_handle):
        print('Analze output file right now ,the reslt of existing functions is below\n')
        file_handle.seek(0,0)
        m = file_handle.readlines()
        i = 0
        while (i < len(m)):
            line = m[i]
            find1 = re.search('[(]',line)
            find2 = re.search('[)]',line)
            if (find1 and (not find2)):
                i += 1
                line += m[i] 
                while (i < len(m) and (not re.search('[)]',line))):
                    i += 1
                    line += m[i]
            match = re.search('^.*\)',line,re.MULTILINE|re.DOTALL)
            if match:
                print(match.group())
                func_list_exist.append(match.group())
            i += 1
        print('Output file analze done!\n')
       

    def ConvertDot_h2Dot_CC(input_file,output_file):
        """
            kernal function given a .h file
            convert to a .cc one with
            all the functions properly listed
            """
        print('The file you want to deal with is '+input_file + \
            '\n It is converted to ' + output_file)
       
        pattern = re.compile(r"""(^[\s]*)             #leading withe space,we will find and delete after
                         ([a-zA-Z~_]            # void int likely the first caracter v or i...
         .* 
         [)]                   #we find )
         #(?!\s*=\s*0)          #if we find = 0  which means pur virtual we will not match after
                                #(?=\s*=\s*0) 
         (?!.*{)              # we do not want the case int abc() const { return 1;}
                                .*)
         (;.*)                 #we want to find ; and after for we will replace these later
         \n$
         """,re.VERBOSE | re.MULTILINE | re.DOTALL)
        
        pattern2 = re.compile(r'(virtual\s+|explicit\s+|friend\s+|static\s+)')   
        
        leading_space_pattern = re.compile('(^[\s]*)[a-zA-Z~]')   
        
        pattern_func_name = re.compile(r'([a-zA-Z0-9~_\-]+\s*|operator.*)[(]') 

        pattern_comment = re.compile(r'^\s*//')
        
        pattern_template = re.compile(r'(class|typename)\s+([a-zA-Z0-9_\-]+)')
        
        p1 = re.compile(r'namespace.*{')      
        p2 = re.compile(r'(class|struct)\s+([a-zA-Z0-9_\-]+).*{')
        p3 = re.compile('{')
        p4 = re.compile('}')
        
        stack = []
        stack_class = []
        stack_template = []
        f_out = open(output_file,'r+')    
        
        AnalyzeOutputFile(f_out)                        
        
        print('Below functions will be added\n')
        f_out.write('#include "' + input_file + '"\n\n')
        with open(input_file,'r') as f:
            m = f.readlines()
            i = 0
            while i < len(m):
                line = m[i]
                if line == '\n' or re.search('^\s*//',line) :
                    i += 1
                    continue
                
                f1 = p1.search(line)
                if f1:                                
                    f_out.write(line+'\n')
                    stack.append('namespace_now')
                    i += 1
                    continue
                f2 = p2.search(line)   
                if f2:                 
                    if(re.search(r'\s*template',m[i-1])):  
                        stack_template.append(m[i-1])
                    else:
                        stack_template.append('')
                    stack.append('class_now')
                    class_name = f2.group(2)   
                    stack_class.append(class_name)
                    i += 1
                    continue
                f3 = p3.search(line)
                f4 = p4.search(line)
                if f3:
                    stack.append('normal_now')
                if f4:
                    top_status = stack.pop()
                    if top_status == 'namespace_now':
                        f_out.write(line+'\n')
                    elif top_status == 'class_now':
                        stack_class.pop()
                        stack_template.pop()
                if f3 or f4:
                    i += 1
                    continue
                if len(stack) >0 and stack[-1] == 'normal_now':  
                    i += 1
                    continue
            
                find1 = re.search('[(]',line)
                find2 = re.search('[)]',line)
                if (find1 and (not find2)):
                    space = leading_space_pattern.search(line).group(1)
                    i += 1
                    line2 = m[i]
                    line2 = re.sub('^'+space,'',line2)     
                    line += line2
                    while (i < len(m) and (not re.search('[)]',line2))):
                        i += 1
                        line2 = m[i]
                        line2 = re.sub('^'+space,'',line2)
                        line += line2
                
                (line,match) = pattern.subn(r'\2 {\n\n}\n\n',line)  
                if match:
                    friend_match = re.search('friend ',line)
                    line = pattern2.sub('',line)            
                    
                
                    define_match = re.search(r'^([a-zA-Z0-9~_/-]+)\s*[(]',line)
                    if define_match:
                        if len(stack_class) == 0 or (stack_class[-1] != define_match.group(1) and ('~'+stack_class[-1]) != define_match.group(1)):
                            i += 1
                            continue
        
                    func_name = ''
                    if len(stack_class) > 0 and not friend_match :                
                        template_line = ''
                        x = ''
                        if (stack_template[-1] != ''):
                            template_line = re.sub(r'\s*template','template',stack_template[-1])
                            x = re.sub(r'template\s*\<','<',template_line)
                            x = x.rstrip()             
                            x = re.sub(r'(class|typename)\s+','',x)
                        line = pattern_func_name.sub(stack_class[-1] + x + '::' + r'\1(',line)
                        line = re.sub(r'\s*=\s*0','',line)                 
                        func_name = re.search('^.*\)',line).group()
                        line = template_line + line;                       
                    else:
                        func_name = re.search('^.*\)',line,re.MULTILINE|re.DOTALL).group()
                   
                    comment_line = ''                                   
                    for j in range(i-1,0,-1):
                        c_line = m[j]
                        if pattern_comment.search(c_line):
                            c_line = re.sub('\s*//','//',c_line)
                            comment_line = c_line + comment_line
                        else:
                            break
                    line = comment_line + line
                    if not(func_name in func_list_exist):
                        print(func_name)
                        f_out.write(line)
                i += 1
        print('Sucessfully converted,please see '+output_file)

    def main(argv):                         
        try:                                
            opts, args = getopt.getopt(argv, "h", ["help"]) 
        except getopt.GetoptError:           
            print(usage.__doc__) 
            sys.exit(2)

        if len(opts) > 0:
            for o, a in opts: 
                if o in ("-h", "--help"): 
                    print(usage.__doc__) 
                    sys.exit()
        elif len(args) > 0:
            input_file = args[0]
            if len(args) == 1:
                output_file = re.sub('.h','.cc',input_file)
            else:
                output_file = args[1]
                
            ConvertDot_h2Dot_CC(input_file,output_file)
        else:
            print(usage.__doc__)
            sys.exit()


    if __name__ == "__main__":
        main(sys.argv[1:])

  • 相关阅读:
    [刷题] 1016 部分A+B (15分)
    [刷题] 1022 D进制的A+B (20分)
    [刷题] 1021 个位数统计 (15分)
    [刷题] 1020 月饼 (25分)
    洛谷&BZOJ [POI2016]Korale
    反演魔术---二项式反演
    毒瘤养成记1: 如何卡hash
    多项式全家桶
    [CQOI]排序机械臂
    后缀自动机感性理解
  • 原文地址:https://www.cnblogs.com/rocketfan/p/1456151.html
Copyright © 2020-2023  润新知