Trying to make out C is a real pain in the back; but we already know how to parse C; call the C compiler! Here we collect the eval code into a dynamic library and load it.
You may have problems when your dynamic code cannot find other functions or variables in your own code; A simple solution for this is to compile your entire program, except for main () as a library and linking the dynamic code library to it. You can avoid the -fpic penalty by setting the library download address only a few kilograms above your main download address. On Linux, unresolved characters in a library can be resolved by an executable file if not separated, and glibc depends on this function; however, compiler optimization sometimes interferes, so a general library method may be required.
Sample code below for Linux. This can be adopted on other Unix, including Mac OSX, with little work. Trying Windows is possible, but harder because you do not have the C compiler guarantee unless you are ready to send it; and on Windows there is an obscene rule about several C sessions, so you must build with the one you are sending, and therefore must also build with the same compiler you are sending. In addition, here you must use a common library technique or characters in your main program simply will not be allowed in the library (the PE file format cannot express the need).
This code example does not allow eval () to save state; if you need it, you must make it either variables in the main program, or (preferred) passing in the state structure at the address.
If you are trying to do this in an embedded environment, do not do this. This is a bad idea in the embedded world.
In response to the comment rici; I have never seen a case where the argument types and the returned block type of eval () were not statically determined from the surrounding code; besides, what could you call it? The code sample below can reduce the extraction of the shared part, so the part of each type is just a couple of lines; exercise remains for the reader.
Unless you have a specific reason for dynamic C; try the built-in LUA instead with a well-defined interface.
#include <dlfcn.h> #include <stdio.h> typedef void (*fevalvd)(int arg); /* We need one of these per function signature */ /* Disclaimer: does not support currying; attempting to return functions -> undefined behavior */ /* The function to be called must be named fctn or this does not work. */ void evalvd(const char *function, int arg) { char buf1[50]; char buf2[50]; char buf3[100]; void *ctr; fevalvd fc; snprintf(buf1, 50, "/tmp/dl%dc", getpid()); snprintf(buf2, 50, "/tmp/libdl%d.so", getpid()); FILE *f = fopen(buf1, "w"); if (!f) { fprintf (stderr, "can't open temp file\n"); } fprintf(f, "%s", function); fclose(f); snprintf(buf3, 100, "gcc -shared -fpic -o %s %s", buf2, buf1); if (system(buf3)) { unlink(buf1); return ; /* oops */ } ctr = dlopen(buf2, RTLD_NOW | RTLD_LOCAL); if (!ctr) { fprintf(stderr, "can't open\n"); unlink(buf1); unlink(buf2); return ; } fc = (fevalvd)dlsym(ctr, "fctn"); if (fc) { fc(arg); } else { fprintf(stderr, "Can't find fctn in dynamic code\n"); } dlclose(ctr); unlink(buf2); unlink(buf1); } int main(int argc, char **argv) { evalvd("#include <stdio.h>\nvoid fctn(int a) { printf(\"%d\\n\", a); }\n", 10); }