C++根據.h檔案批量產生需要的函數架構

來源:互聯網
上載者:User

類似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 yourselfwe assume .cc by defualt1.touch abc.cc                        2./prodef.py abc.h abc.cc          or ./prodef.py abc.h 1.touch a.cpp2./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:])
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.