Be liberal in what you accept, and conservative in what you send.
--Postel's Prescription. (I think that this popular quote is relevant to this post, but I can't decide how.)
I wrote a code generator to take a C enum type and make a string parsing function for it. While writing this parser, I ran into parsing difficulties.
Code has to be generated from some other information. To get that information, I had to read it from another file. So I had to parse it myself before I could write my parser.
On my first try, I started by reading the header file containing the enum type. I immediately ran into apparently necessary feature creep. What if the user put other code before the enum in the file? What if the user defined values for the cases? These cases would require me to expend a lot more work to implement, but a user would be shocked to find that his code suddenly didn't work because he did these perfectly normal things. I implemented more features than I needed for my use case, but still felt that my approach was far too naive and constrained. Eventually I gave up.
The next time, I made a text file listing the cases I wanted. Then I iterated over that and generated both the enum and the parser function. Easy as pi.
For the understanding of non-programmers, which looks easier to deal with?
gardening-tools.h:
#ifndef GARDENINGTOOLS_H
#define GARDENINGTOOLS_H
typedef enum GardeningTools {
Trowel,
Hose,
Dynamite
}
#endif // GARDENINGTOOLS_H
Or gardening-tools.enum:
Trowel
Hose
Dynamite
But they contain the same information! I can generate the second from the first!
If I have to read data, why would I encode it in a format that has more features than I need to use right now?
Hooray for flat, simple data layouts! My three lines of data doesn't need the power of C. Here is the entire spec for my layout: Put a line break after each case name. I get the enum type name from the input file name.
I can add more features if I wish. Since my format is simple, modifying it is easy. Values for the enum cases? Put a space between the case name and value. File name different from the enum name? One extra parameter. Documentation comments? Now lines starting with "//" pass through to the output unmodified. But I probably won't need any of that, so why bother now?
Code generation: Accomplished
Number of library references added: 0