Following an [interesting discussion on Reddit](http://programming.reddit.com/info/62v70/comments) about [first class functions](http://en.wikipedia.org/wiki/First-class_function) in C, I was inspired to see what I could do with this new-found knowledge. The result is what I affectionately call “GCCalc”, for reasons that will become clear below.

GCCalc is a simple command line calculator, much like the common [bc](http://en.wikipedia.org/wiki/Bc_programming_language) calculator on many Unix systems. It’s implementation, however, is *very* different than most calculators. While bc is said to have “C-like syntax”, GCCalc’s syntax *is* C. Whatever you enter on the command line automatically gets compiled, loaded, and executed, and the result is returned (as a double) and printed to the screen.

You can either enter expressions like:

round(46.95886*sqrt(1+2/9.99*sin((21%5)*pow(2,8))))

or you can enter whole C statements (as long as they’re on one line, for now) like:

int i; for (i=0;i<10;i++) { printf("hello world!

"); } printf("goodbye

"); Unfortunately variables are scoped to the function that wraps them, so they don't persist across multiple entries. However, you can access the last result using the "last" variable (a double). [Here's the source file](http://tlrobinson.net/projects/gccalc/gccalc.c), and here's a syntax highlighted version: It's been tested on Mac OS X (Leopard) and Linux (Ubuntu Gutsy), with GCC 4. Compile with "gcc -o gccalc gccalc.c" on OS X, or "gcc -o gccalc gccalc.c -ldl" on Linux.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <dlfcn.h>

#include <unistd.h>



#ifdef __ELF__

#define GCC_FLAGS "-fPIC -shared"

#define EXTENSION "so"

#else

#define GCC_FLAGS "-dynamiclib"

#define EXTENSION "dylib"

#endif



#define HEADERS "#include <stdio.h>

#include<math.h>"



typedef double (func_return_double)( double ); (func_return_double)(); unsigned count = 0;

char *cwd;

char tmp_path[1024] = {‘\0’}; void *lib = NULL; int main(int argc, char **argv)

{

double result = 0.0;

char input_buffer[1024], code_buffer[2048], function_name[32], command_buffer[1024];



// get out current directory, which we’ll use for tmp files (dlopen seems to need absolute paths)

cwd = getcwd(NULL, 0);



while (1)

{

// for unique function and file names (needed for dlopen/dlsym to work correctly)

count++;



// read in the next line

printf(">> ");

fgets(input_buffer, sizeof(input_buffer), stdin);



// format the function name

sprintf(function_name, "f%d", count);



// format the code string: if it doesn’t contain a semicolon, assume it is just an expression

if (strchr(input_buffer, ‘;’))

sprintf(code_buffer, "%s

double %s(double last) { %s

return 0; }", HEADERS, function_name, input_buffer);

else

sprintf(code_buffer, "%s

double %s(double last) { return (%s); }", HEADERS, function_name, input_buffer);



// format the filename string, delete the file if it exists

sprintf(tmp_path, "%s/libtmp%d.%s", cwd, count, EXTENSION);

unlink(tmp_path);



// format the gcc command string

sprintf(command_buffer, "gcc -Wall %s -x c – -o %s", GCC_FLAGS, tmp_path);



// execute gcc command, write out the code

FILE *fp = popen(command_buffer, "w");

fwrite(code_buffer, 1, strlen(code_buffer), fp);

fprintf(fp, "

");



// pclose waits for gcc to terminate (fclose/close do NOT thus compilation will sometimes not finish prior to the dlopen)

pclose(fp); void *ptr = NULL;



// open the just-compiled dynamic library

if ((lib = dlopen(tmp_path, RTLD_NOW|RTLD_LOCAL)) == NULL) {

puts(dlerror());

}

// get the function pointer

else if ((ptr = dlsym(lib, function_name)) == NULL) {

puts(dlerror());

}



// execute it

if (ptr != NULL)

{

func_return_double *func = (func_return_double*)ptr;

result = (*func)(result);

// print the result

printf("=> %.*lf

", (result/((int)result)>1.0)?5:0, result);

} // clean up: close the library, delete the temp file

dlclose(lib);

unlink(tmp_path);

} return 0;

}

Thanks to jbert on Reddit for the initial code and inspiration.

If only I had known about this back when The Daily WTF has having their [OMG WTF](http://omg.thedailywtf.com/) crazy calculator programming contest…