2010-06-03 66 views
8

任何人都可以向我指出一些关于如何使用Python(或Perl或任何其他Linux友好脚本语言)编写脚本的文档,这些文档可以从命令行生成XML或py文件的C++代码。我希望能够写出一些xml文件,然后运行一个shell命令来读取这些文件并生成带有完全内联函数的.h文件,例如流媒体运营商,构造商等使用Python进行C++代码生成

+1

退房http://www.altova.com/xmlspy /xml-code-generation.html – schoetbi 2012-02-24 12:23:46

回答

0

我实际上做了一些工作与旧的“4GL”开发环境做了类似的事情,老4GL范例中的很多模型使用C和C++作为他们输出它们的语言生成的代码英寸

即使这样说,4GL几乎已经辞去了历史的尘土堆。问题是,当你机器生成C代码时,你会失去首先使用C所带来的性能提升,代码难以维护。不妨先用Python编写程序。

+0

我不是在寻找一个程序转换器。我正在寻找关于如何编写自己的Python/Perl/etc脚本的文档,该脚本可以简单地生成具有诸如基于短数据类型规范的流操作符等基本功能的C++数据类型。该规范只会列出每个成员的类名,其成员,基类和一些简单的文档。输出将是具有完全内联类定义的头文件。我认为Python或Perl应该能够轻松地做到这一点。 – user357525 2010-06-03 14:28:58

1

你可以看看Shedskin,一个从Python代码生成C++代码的项目。

根据你的理由,这可能有点毫无意义,正如Satanicpuppy指出的那样。

+0

如果可能的话,我更感兴趣的是编写几个简单的shell脚本来做基本的解析和代码生成。如果不是的话,我会自己手写基本课程。 – user357525 2010-06-03 14:39:22

+0

我不知道比Shedskin更简单 - 你可能想要推出自己的,尽管一些人提到了XML解析器。我想像得到一些相当简单的工作是相当简单的。 – 2010-06-03 14:55:24

1

看一看Cheetah。这是一个用Python编写的模板引擎。

+0

我已经看过猎豹几次了。尽管它说它用于C++生成,但没有这方面的例子,也没有关于它如何用于C++的文档。 我想写我自己的基本数据类型的简单生成器。如果这太复杂了,那么我就不会打扰任何代码工具。 – user357525 2010-06-03 14:37:47

2

恐怕您找不到已经构建的解决方案,它会将您特定的xml或python文件转换为您需要的输出“开箱即用”。

你将不得不自己实现解析,数据处理和输出。尽管如此,并不全是你自己;这里有一些关于解析和输出的指针。

Python附带有2个不同的XML解析器(SAX and DOM -scroll down查看一些示例)。您将必须使用其中之一才能读取源文件。

为了更容易地生成输出,您可以使用模板库(如StringTemplate),或者只是手动生成代码(如果它很小)。

+0

除了StringTemplate之外,还有很多其他模板解决方案最初是针对模板化网页(例如Jinja2),可以相对轻松地重新使用。 – jleahy 2013-01-11 14:02:59

+0

https://github.com/kblomqvist/yasha - Jinja2重新为此:) – kblomqvist 2017-07-03 18:36:50

1

几年前,我曾参与一个项目,以简化大规模仿真系统的进程间共享内存管理。我们使用了一种相关的方法,其中共享内存中的数据布局是在XML文件中定义的,并使用python编写的代码生成器,读取XML并吐出一组定义结构和相关函数/运算符/等的头文件以匹配XML描述。当时,我看了几个模板引擎,但令我惊讶的是,发现只需“手动”就可以更简单,更直接。

在阅读XML时,只需填充一组与您的代码相匹配的数据结构即可。头文件对象包含类和类包含变量(可能是其他类类型)。为每个对象提供一个遍历其内容的方法printSelf(),并为其包含的每个对象调用printSelf()

起初看起来有点令人生畏,但一旦你开始使用,它非常简单。哦,还有一个提示可以帮助生成代码,将一个缩进参数添加到printSelf()并在每个级别增加它。它使得生成的代码更容易阅读。

+1

好吧,我会试试看,看看StringTemplate了。 – user357525 2010-06-03 15:21:04

+0

事实上,使用字符串模板化您所生成的内容是非常重要的。我用简单的%操作符完成了我的大部分代码,它的运行效果很好,但是新的(是的,代码是旧的;-) StringTemplates应该更容易。 – Rakis 2010-06-03 17:20:27

9

如果你只想用标准的Python东西来做到这一点,你可以尝试制作使用Python 3风格字符串格式的模板文件。例如,类模板可能是这个样子:

{className}::{className}() 
{{ 
}} 

{className}::~{className}() 
{{ 
}} 

{className}::{className}(const {className}& other) 
{{ 
}} 

{className}& {className}::operator=(const {className}& other) 
{{ 
    return *this; 
}} 

然后Python代码是超级简单:

d = {} 
d['className'] = 'MyCPlusPlusClassName' 
with open(yourTemplateFile, 'r') as ftemp: 
    templateString = ftemp.read() 
with open(generatedFile, 'w') as f: 
    f.write(templateString.format(**d)) 

当然你也可以使用相同的添加大量的一起“的className”等领域招。如果你不需要像条件代码生成这样的东西,你可以用这么简单的东西获得很多里程。

1

我可以推荐Jinja2(http://jinja.pocoo.org/docs/dev/)。尽管Jinja的主要目标语言是HTML,但它对于C++来说工作得很好。这不仅是我的意见,请参阅https://www.chromium.org/developers/jinja :)。有一个独立的版本(https://github.com/filwaitman/jinja2-standalone-compiler)可能有用,因为Jinja2本身只是一个API。我正在使用我的项目的独立版本https://github.com/TomSmartBishop/avl以及定制的环境设置,以便Jinja2开启和关闭标签符合更多C++风格。

0

希望这将是为别人有用的(你可以使用Win32的剪贴板数据读取)

import sys, string 
import win32clipboard 
import re 


data = ''' 
    enum FeedTypeT 
    { 
     AA, 
     BB, 
     DDD, 
     F 
    }; 
''' 

def get_from_clippord(): 
    # get clipboard data 
    win32clipboard.OpenClipboard() 
    data = win32clipboard.GetClipboardData() 
    win32clipboard.CloseClipboard() 
    return data 

def enum_type(inenum): 
    inenum = inenum.replace('\r\n', '\n') 
    inenum = re.sub(r'\s', r'', inenum) 
    inenum = re.sub(r'^(.*)\{.*$', r'\1', inenum) 
    return inenum 

def cleanup_enum(inenum): 
    inenum = inenum.replace('\r\n', '\n') 
    # inenum = inenum.replace('enum', '') 
    inenum = re.sub(r'\s', r'', inenum) 
    # inenum = re.sub(r'^.*\{(.+)[|,]\}.*$', r'\1', inenum) 
    inenum = re.sub(r'^.*\{(.+)\}.*$', r'\1', inenum) 
    inenum = inenum.split(',') 
    return inenum 

def get_element(inlist): 
    for element in inlist: 
     [one, two] = element.split('=') 
     print('{0:20} ==> {1:>20}'.format(one, two))   # right align 
#  one = element.split('=') 
#  print('{0:20} ==> {1:10}'.format(one[0], one[1])) 

def print_switch(typename): 
    retstr = 'const std::string toString(' + typename + ' type)' 
    retstr += '\n{\n switch(type)\n {' 
    return retstr 

def print_case_line(instr, w): 
    retstr = '  case ' + '{:{fw}}'.format(instr + ':', fw = w) + ' return "' + instr + '";' 
    return retstr 

def print_switch_end(w): 
    retstr = '  default: ' + ' '*(w-4) + ' return "undef";\n }\n}\n' 
    return retstr 

def main(): 
    #data = get_from_clippord() 

    ll = cleanup_enum(data) 
    print (ll) 
    print ("="*80 + "\n\n") 
    print (print_switch(enum_type(data))) 

    w = 25 
    # pick right with for formating, based on the lenght of elements of enum 
    for line in ll: 
     if w < len(line): 
      w = len(line) + 2 

    for line in ll: 
     print (print_case_line(line, w)) 

    print (print_switch_end(w)) 


if __name__ == '__main__': 
    main() 

输出:

['AA', 'BB', 'DDD', 'F'] 
================================================================================ 


const std::string toString(enumFeedTypeT type) 
{ 
    switch(type) 
    { 
     case AA:      return "AA"; 
     case BB:      return "BB"; 
     case DDD:      return "DDD"; 
     case F:      return "F"; 
     default:      return "undef"; 
    } 
}