2010-06-03 23 views
8

¿Alguien me puede indicar documentación sobre cómo escribir scripts en Python (o Perl o cualquier otro lenguaje de scripts compatible con Linux) que genere código C++ desde archivos XML o py desde la línea de comandos. Me gustaría poder escribir algunos archivos xml y luego ejecutar un comando de shell que lea estos archivos y genere archivos .h con funciones totalmente en línea, p. Ej. operadores de streaming, constructores, etc.Generación de código C++ con Python

+1

Salida http://www.altova.com/xmlspy /xml-code-generation.html – schoetbi

Respuesta

0

De hecho, trabajo un poco con un entorno de desarrollo heredado "4GL" que hace algo similar, y muchos modelos del antiguo paradigma 4GL usan C y C++ como el lenguaje que emiten. código generado en.

Habiendo dicho eso, 4GL está bastante resignado al montón de polvo de la historia. El problema es que, cuando se genera máquina el código C, se pierden las ganancias de rendimiento que se derivarían del uso de C en primer lugar, y el código es extremadamente difícil de mantener. Bien podría escribir el programa en Python en primer lugar.

+0

No estoy buscando un convertidor de programa. Estoy buscando un documento sobre cómo escribir mi propia secuencia de comandos Python/Perl/etc que simplemente genere tipos de datos C++ con características básicas, como operadores de transmisión en tiempo real basados ​​en una especificación corta de tipo de datos. La especificación solo enumeraría el nombre de clase, sus miembros, una clase base y alguna documentación simple para cada miembro. El resultado sería un archivo de encabezado con una definición de clase completamente en línea. Creo que Python o Perl deberían poder hacer esto fácilmente. – user357525

1

Puede echar un vistazo a Shedskin, un proyecto que genera código C++ a partir del código Python.

Según cuáles sean sus motivos, puede ser un poco inútil como señaló Satanicpuppy.

+0

Estoy más interesado en simplemente escribir algunos scripts de shell simples para hacer un análisis básico y código gen, si es posible. Si no, solo escribiré las clases básicas yo mismo. – user357525

+0

No conozco nada más simple que Shedskin. Probablemente prefieras obtener el tuyo, aunque algunas personas han mencionado los analizadores XML. Me imagino que sería bastante trivial conseguir algo bastante simple de trabajo. –

1

Eche un vistazo a Cheetah. Es un motor de plantillas escrito en Python.

+0

He mirado a Cheetah hace un tiempo. Aunque dice que se usa para la generación de C++, no hay ejemplos de esto y no hay documentación de cómo se usa para C++. Me gustaría escribir mi propio generador simple para tipos de datos básicos. Si esto resulta ser demasiado complicado, entonces no me molestaré con ninguna herramienta de código genérico. – user357525

2

Me temo que no encontrará una solución ya incorporada que tome sus archivos xml o python en particular y los transforme en su salida requerida "fuera de la caja".

Deberá implementar el análisis, el tratamiento de datos y la salida usted mismo. No todo por ti solo, sin embargo; Aquí hay algunos consejos sobre el análisis y la salida.

Python viene con 2 analizadores XML diferentes (SAX and DOM -desplácese hacia abajo para ver algunos ejemplos). Deberá usar uno de ellos para leer los archivos fuente.

Para generar la salida más fácilmente, probablemente pueda utilizar una biblioteca de plantillas, como StringTemplate, o simplemente generar el código manualmente, si es pequeño.

+0

Además de StringTemplate, existen muchas otras soluciones de plantillas originalmente destinadas a la creación de plantillas de páginas web (por ejemplo, Jinja2) que se pueden volver a utilizar con relativa facilidad. – jleahy

+0

https://github.com/kblomqvist/yasha - Jinja2 re-propuesto para esto :) – kblomqvist

1

Hace unos años trabajé en un proyecto para simplificar el manejo de memoria compartida entre procesos para sistemas de simulación a gran escala. Utilizamos un enfoque relacionado donde el diseño de los datos en la memoria compartida se definió en archivos XML y un generador de códigos, escrito en python, leemos el XML y escupemos un conjunto de archivos de cabecera definiendo estructuras y funciones/operadores/etc asociados para que coincidan Descripción XML En ese momento, miré varios motores de plantillas y, para mi sorpresa, descubrí que era más fácil y sencillo simplemente hacerlo "a mano".

Mientras lee el XML, solo llene un conjunto de estructuras de datos que coincidan con su código. Los objetos del archivo de encabezado contienen clases y las clases contienen variables (que pueden ser de otros tipos de clases). Dé a cada objeto un método printSelf() que itere sobre su contenido y llame al printSelf() para cada objeto que contenga.

Parece un poco desalentador al principio, pero una vez que empiezas, es bastante directo. Ah, y un consejo que ayuda con el código generado, agregue un argumento de sangría al printSelf() y auméntelo en cada nivel. Hace que el código generado sea mucho más fácil de leer que.

+1

Bien, voy a probar esto y también a StringTemplate. – user357525

+0

De hecho, usar cadenas para modelar bits de lo que generas es esencial. Hice la mayor parte de mi código con el operador% simple y funcionó bien, pero el nuevo (sí, el código es viejo ;-) StringTemplates debería hacerlo aún más fácil. – Rakis

9

Si desea hacer esto simplemente con las cosas estándar de Python, puede intentar crear archivos de plantilla que utilicen el formato de cadena de estilo Python 3.Por ejemplo, una plantilla de clase podría ser algo como esto:

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

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

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

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

A continuación, el código Python es super simple:

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

por supuesto se puede añadir un montón de otros campos junto a 'className' utilizando el mismo truco. Si no necesita cosas como la generación de código condicional, puede sacarle mucho provecho a algo tan simple.

1

Por mi propia experiencia puedo recomendar Jinja2 (http://jinja.pocoo.org/docs/dev/). Aunque el principal idioma de destino de Jinja es HTML, funciona bastante bien para C++. Y esa no es solo mi opinión, vea https://www.chromium.org/developers/jinja :). Existe una versión independiente (https://github.com/filwaitman/jinja2-standalone-compiler) que puede ser útil, ya que Jinja2 en sí es solo una API. Estoy usando la versión independiente para mi proyecto aquí https://github.com/TomSmartBishop/avl con ajustes de entorno personalizados para que las etiquetas de apertura y cierre de Jinja2 coincidan con más estilo C++.

0

Esperamos que sea útil para alguien (puede usar Win32 portapapeles para leer los datos)

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() 

Salida:

['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"; 
    } 
}