Gengen has become GNU Gengen! Here's the new link: http://www.gnu.org/software/gengen. Gengen (GENerator GENerator) is a tool that, starting from a parameterized text, called template, generates a text generator that can substitute parameters with values.
At the moment Gengen can generate C++ or C code; however other target languages are under development (e.g., Java).
Say you are writing a C/C++ program and at some point your program has to generate the following code:
if (i < 10)
printf("the value of i is %d", i);
It is not so difficult to write this piece of C++ code:
cout << "if (i < 10)" << endl;
cout << " printf(\"the value of i is %d\", i);" << endl;
or the C code:
printf("if (i < 10)\n");
printf(" printf(\"the value of i is %%d\", i);\n");
provided that you remember to escape the
"
(and in the C code, also the
%
).
Suppose now that the previous piece of code has to be generated many times by your program, and every time instead of i
another symbol has to be generated (decided at run time). In this case, supposing that this value is contained in a variable symb
,
the code for generating this code would be a little bit more complex:
cout << "if (" << symb << "< 10)" << endl;
cout << " printf(\"the value of " << symb << " is %d\", "
<< symb << ");" << endl;
And the C version would be even more obfuscated.
Probably you didn't even realize that you forgot to leave a space before the < 10
; basically this is due to the fact that this piece of code mixes the code that has to be generated with the code that generates it, and this tends to make this part
of program less easy to maintain. Especially if some day you have to change the code that has to be generated, you'll have to act on this part of the program, and probably you'll have to
execute some tests in order to be sure that you did it right.
If the code that you have to generate is a slightly more complex, the task may easily become a pain in the neck!
Wouldn't it be nice if you could write the code to be generated in a separate file, let's call it template, say test1.cc_skel
this way
if (@i@ < 10)
printf("the value of @i@ is %d", @i@);
and have a tool that generates a generator, that you can instantiate at run-time with the value that has to be substituted to the parameter i
? If such a tool existed, and it generated a file test1_c.h with a C struct test1_gen_struct
, then you could write simply this code, in another file, say test1_gen_c.c:
#include <stdio.h>
#include "test1_c.h"
int
main()
{
struct test1_gen_struct gen_struct;
gen_struct.i = "foo";
generate_test1(stdout, &gen_struct, 0);
printf("\n");
gen_struct.i = "bar";
generate_test1(stdout, &gen_struct, 0);
printf("\n");
return 0;
}
Alternatively, if it generated a file test1.h with a C++ class test1_gen_class
, then you could write simply this code, in
another file, say test1_gen.cc:
#include <iostream>
using std::cout;
using std::endl;
#include "test1.h"
int
main()
{
test1_gen_class gen_class;
gen_class.set_i("foo");
gen_class.generate_test1(cout);
cout << endl;
gen_class.set_i("bar");
gen_class.generate_test1(cout);
cout << endl;
return 0;
}
and when you run it you would obtain the expected output:
if (foo < 10)
printf("the value of foo is %d", foo);
if (bar < 10)
printf("the value of bar is %d", bar);
Well, Gengen does right this! Now the code that has to be generated and the code that generates it are separated and they can be maintained more easily: if you want to change the code that has to be generated you act on the file test1.cc_skel; alternatively, say you need to change the value that will be substituted for i
, you just change the file test1_gen.cc or test1_gen_c.c.
I hope you try gengen, and have fun! :-)