<DIV>
<DIV>PythoidC ( <A href="http://pythoidc.googlecode.com">http://pythoidc.googlecode.com</A> ) is a C code generator (not C++)</DIV>
<DIV> </DIV>
<DIV>----- Original Message ----- 
<DIV>From: "Dan Goodman" <<A href="mailto:dg.gmane@thesamovar.net">dg.gmane@thesamovar.net</A>></DIV>
<DIV>To: <<A href="mailto:python-list@python.org">python-list@python.org</A>></DIV>
<DIV>Sent: Wednesday, March 17, 2010 9:00 AM</DIV>
<DIV>Subject: C++ code generation</DIV></DIV>
<DIV><BR></DIV>> Hi all,<BR>> <BR>> I'm doing some C++ code generation using Python, and would be interested <BR>> in any comments on the approach I'm taking.<BR>> <BR>> Basically, the problem involves doing some nested loops and executing <BR>> relatively simple arithmetic code snippets, like:<BR>> <BR>> for i in xrange(len(X)):<BR>>   X[i] += 5<BR>> <BR>> Actually they're considerably more complicated than this, but this gives <BR>> the basic idea. One way to get C++ code from this would be to use <BR>> Cython, but there are two problems with doing that. The first problem is <BR>> that the arithmetic code snippets are user-specified. What I want to do <BR>> is generate code, and then compile and run it using Scipy's weave <BR>> package. The second problem is that I have various different data <BR>> structures and the C++ code generated needs to be different for the <BR>> different structures (e.g. sparse or dense matrices).<BR>> <BR>> So far what I've been doing is writing Python code that writes the C++ <BR>> code, but in a very non-transparent way. I like the idea of specifying <BR>> the C++ code using Python syntax, like in Cython. So the idea I came up <BR>> with was basically to abuse generators and iterators so that when you <BR>> write something like:<BR>> <BR>> for x in X:<BR>>    ...<BR>> <BR>> it actually outputs some C++ code that looks like:<BR>> <BR>> for(int i=0; i<X_len; i++){<BR>> double &x = X[i];<BR>> ...<BR>> }<BR>> <BR>> The ... in the Python code is only executed once because when X is <BR>> iterated over it only returns one value.<BR>> <BR>> Here's the example I've written so far (complete code given below):<BR>> <BR>> # initialisation code<BR>> code = OutputCode()<BR>> evaluate = Evaluator(code)<BR>> X = Array(code, 'values')<BR>> # specification of the C++ loop<BR>> for x in X:<BR>>     evaluate('x += 5; x *= 2')<BR>> # and show the output<BR>> print code.code<BR>> <BR>> It generates the following C++ code:<BR>> <BR>> for(int values_index=0; values_index<values_len; values_index++){<BR>> double &values = values_array[values_index];<BR>> values += 5;<BR>> values *= 2;<BR>> }<BR>> <BR>> OK, so that's an overview of the idea that I have of how to do it. Any <BR>> comments or suggestions on either the approach or the implementation?<BR>> <BR>> Below is the complete code I've written for the example above (linewraps <BR>> aren't perfect but there's only a couple of lines to correct).<BR>> <BR>> Thanks for any feedback,<BR>> <BR>> Dan<BR>> <BR>> import re, inspect<BR>> <BR>> # We just use this class to identify certain variables<BR>> class Symbol(str): pass<BR>> <BR>> # This class is basically just a mutable string<BR>> class OutputCode(object):<BR>>     def __init__(self):<BR>>         self.code = ''<BR>>     def __iadd__(self, code):<BR>>         self.code = self.code+code<BR>>         return self<BR>> <BR>> # Iterating over instances of this class generates code<BR>> # for iterating over a C++ array, it yields a single<BR>> # Symbol object, the variable name of the value in the<BR>> # array<BR>> class Array(object):<BR>>     def __init__(self, code, name, dtype='double'):<BR>>         self.name = name<BR>>         self.dtype = dtype<BR>>         self.code = code<BR>>     def __iter__(self):<BR>>         def f():<BR>>             self.code += 'for(int {name}_index=0; <BR>> {name}_index<{name}_len; {name}_index++){{\n'.format(name=self.name)<BR>>             self.code += '{dtype} &{name} = <BR>> {name}_array[{name}_index];\n'.format(dtype=self.dtype, name=self.name)<BR>>             yield Symbol(self.name)<BR>>             self.code += '}\n'<BR>>         return f()<BR>> <BR>> # Instances of this class generate C++ code from Python syntax<BR>> # code snippets, replacing variable names that are a Symbol in the<BR>> # namespace with the value of that Symbol.<BR>> class Evaluator(object):<BR>>     def __init__(self, code):<BR>>         self.code = code<BR>>     def __call__(self, code):<BR>>         # The set of variables in the code snippet<BR>>         vars = re.findall(r'\b(\w+)\b', code)<BR>>         # Extract any names from the namespace of the calling frame<BR>>         frame = inspect.stack()[1][0]<BR>>         globals, locals = frame.f_globals, frame.f_locals<BR>>         values = {}<BR>>         for var in vars:<BR>>             if var in locals:<BR>>                 values[var] = locals[var]<BR>>             elif var in globals:<BR>>                 values[var] = globals[var]<BR>>         # Replace any variables whose values are Symbols with their values<BR>>         for var, value in values.iteritems():<BR>>             if isinstance(value, Symbol):<BR>>                 code = re.sub(r'\b{var}\b'.format(var=var), str(value), <BR>> code)<BR>>         # Turn Python snippets into C++ (just a simplified version for now)<BR>>         code = code.replace(';', '\n')<BR>>         lines = [line.strip() for line in code.split('\n')]<BR>>         code = ''.join(line+';\n' for line in lines)<BR>>         self.code += code<BR>> <BR>> if __name__=='__main__':<BR>>     code = OutputCode()<BR>>     evaluate = Evaluator(code)<BR>>     X = Array(code, 'values')<BR>>     for x in X:<BR>>         evaluate('x += 5; x *= 2')<BR>>     print code.code<BR>> </DIV><br><br><span title="neteasefooter"/></span>