2010-06-03 203 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"; 
    } 
}