I'm generating C++ code, and it seems like it's going to get very messy, even my simple generating classes already have tons of special cases. Here is the code as it stands now: http://github.com/alex/alex-s-language/tree/local%2Fcpp-generation/alexs_lang/cpp .
I wrote Cog partly to generate C++ code from an XML data schema. It lets you use Python code embedded in C++ source files to generate C++ source.
One technique I've used for code generation is to not worry at all about formatting in the code generator. Then, as a next step after generating the code, run it through indent
to format it reasonably so you can read (and more importantly, debug) it.
See Tooling to Build Test Cases.
It's not clear what your problem is.
If you question is "how do I handle all the special cases in my generating classes?" then here's some advice. If your question is something else, then update your question.
Use a template generator. Mako, for example, will make your life simpler.
Write an example of your result. Replace parts with
${thing}
placeholders. Since you started with something that worked, turning it into a template is easy.When generating code in another language, you need to have all of the class definitions in other other language designed for flexible assembly. You want to generate as little fresh, new code as possible. You want to tweak and customize a bit, but you don't want to generate a lot of stuff from scratch.
Special cases are best handled with ordinary polymorphism. Separate subclasses of a common superclass can implement the various exceptions and special cases. Really complex situations are handled well by the Strategy design pattern.
In essence, you have Python classes that represent the real-world objects. Those classes have attributes that can be fit into a C++ template to generate the C++ version of those objects.
I have a code generation system and one of the best choices I have taken with it is to put much of the resultant program in non generated code, e.g. a library/runtime. Using templates works well also. Complex template systems may be hard to work with by hand, but your not working with them by hand so leverage that.
It would actually be just recursing straight down, except I need to pull all function declarations out and put them elsewhere, and the fact that for all function calls I need to build a vector of all of the arguments, and then pass that to the function, since C++ doesn't have a syntax for vectors.
I agree with S.Lott, that you should write out an example of what you want to generate.
Solving a problem with code generation should be less complicated than without.
This is because your total program has to deal with a lot of input information, and if a subset of that information changes very seldom, like once a week, the code generator only has to condition on that subset. The generated code conditions on the remaining input that changes more frequently. It's a divide-and-conquer strategy. Another name for it is "partial evaluation".
Generated code should also run a lot faster because it's less general.
In your specific case, there's no harm in doing the code generation in 2 (or more) passes. Like on pass 1 you generate declarations. On pass 2 you generate process code. Alternatively you could generate two output streams, and concatenate them at the end.
Hope that helps. Sorry if I'm just saying what's obvious.