What are some techniques for code generation?

前端 未结 8 1112
抹茶落季
抹茶落季 2021-01-06 13:05

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 stan

相关标签:
8条回答
  • 2021-01-06 13:15

    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.

    1. 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.

    2. 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.

    3. 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.

    0 讨论(0)
  • 2021-01-06 13:22

    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.

    0 讨论(0)
  • 2021-01-06 13:32

    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.

    0 讨论(0)
  • 2021-01-06 13:34

    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.

    0 讨论(0)
  • 2021-01-06 13:35

    as Ned suggested, Cog is an excellent tool for writing boilerplate code. For instance, i've had to write a AOP-style event system support for certain classes that it would work like this:

    • you declare a method for a class
    • for each method, an event needs to be triggered upon invocation, passing the arguments of the method as event parameters

    So i did a special python declarator function that i would invoke on a cog region which would generate the boilerplate declarations and definitions for each method and event. At the end of the cog region the user places a block of code for a function that hides the implementation and is invoked by the AOP wrapper, something roughly like this:

    class MyFoo
    {
    
    public:
    /*[[[cog
    import myAOPDeclarators
    AOP = myAOPDeclarators.AOP
    
    AOP.declareAOPInterceptorMethod( 'invokeSomeStuff' , '(int param1, std::string param2)' )
    ]]]*/
    //AOP wrapper
    void invokeSomeStuff_ImplementationAOP(int param1, std::string param2);
    void invokeSomeStuff(int param1, std::string param2) {
     sendAOPPreEvent( param1 , param2 , "invokeSomeStuff" );
     invokeSomeStuff_ImplementationAOP( param1 , param2);
    }
    void invokeSomeStuff_ImplementationAOP(int param1, std::string param2)
    //[[[end]]]
    {
    // ...invokeSomeStuff implementation, not automatically generated
    }
    

    The best guideline i can give you for code generation is; make your generated code as readable as your hand written one. It makes the usage of code-generation transparent (even more transparent than template code, buy YMMV), Of course, as Greg suggested, indent can be applied afterwards, so there is really no point in wasting time in mixing indentation tinkering with code generation if a tool can post-process the source files anyways

    0 讨论(0)
  • 2021-01-06 13:35

    I was also looking for something like this and found this question. I wasn't very satisfied with cog, so I ended up writing my own which is similar but adds some (imo) much needed features.

    https://github.com/icholy/swapm

    0 讨论(0)
提交回复
热议问题