The smallest C compiler of this kind I know of is tcc, Fabrice Bellard's Tiny C Compiler. For the easiest use it has to be compiled to a Windows dll, which needs some tweaking, described by Adel Amro. You can also download the version I used from here. Just unzip it to a directory of your choice. I used c:\tcclib. It has two subdirectories, the original "include" and "lib" of tcc, with the compiled libtcc.dll and libtcc.def added. All together about 800KB. (If you install tcc, you only need to copy these two files to its "lib" subdirectory, all others are already there.)
We interface AHK to this dll, with appropriate dllcall's. There are not too many of them:
"LoadLibrary" to keep the dll in memory while needed
"tcc_new" to create a C compiler context (allocate memory, establish internal data structures)
"tcc_add_sysinclude_path" to tell it where its include (header) files are
"tcc_add_library_path" to tell it where the library is
"tcc_compile_string" to compile a program stored as a string
"tcc_run" to run it
"tcc_delete" to remove the compiler context
"FreeLibrary" to unload the dll from memory.
We have to tell the C program, where in memory to write its result. For that we allocate a large enough AHK variable, and write its <address> directly to the C source code as
char* _result = <address>;
The C program has to write its result as a string to the place _result points to, which is our AHK variable, directly available after the program terminates.
The usage is simple:
1. Assign the C source code to an AHK variable, as string. Make sure that all % are escaped with `, there is no ; or ) in the first position in a continuation line.
2. You can have references to AHK variables between % signs (%i%)
3. Include a declaration in main(): "char* _result;". The target of this pointer has to be updated with the result we want to see from the C program.
4. Run the C program with the Run function below. Its parameters are: the path to the directory containing libtcc.dll, the AHK string containing the C program and optionally an upper bound on the length of the returned AHK string:
#NoEnv MsgBox % Run("c:\tcclib",p:="main(){char*_result;strcpy(_result,""Hello World"");}") i = 101 C_prog = ; floating point support ( #include <math.h> double f(double x) { return sqrt(x); } main() { char* _result; // needed to export the result int i = %i%; // AHK varible reference %i% sprintf(_result,"f(`%u) --> `%0.17g",i,f(i)); } // Escape `% ) MsgBox % Run("c:\tcclib",C_Prog) h = 0x12345678 PROG = ; assembler support ( typedef unsigned long UInt32; UInt32 BSWAP(UInt32 x) { // Byte reversal __asm__("bswap `%0" : "=r" (x) : "0" (x)); return x; } main() { char* _result; sprintf(_result,"ByteSwap of `%x = `%x",%h%,BSWAP(%h%)); } ) MsgBox % Run("c:\tcclib",PROG) Run(libpath, ByRef prog, ResultLen=999) { If (0 = hModule := DllCall("LoadLibrary",Str,libpath . "\lib\libtcc.dll")) { MsgBox Cannot load libray %libpath%\lib\libtcc.dll Return } Context := DllCall("libtcc\tcc_new", "cdecl UInt") DllCall("libtcc\tcc_add_sysinclude_path", UInt,Context, Str,libpath . "\include", "cdecl UInt") DllCall("libtcc\tcc_add_library_path", UInt,Context, Str,libpath . "\lib", "cdecl UInt") VarSetCapacity(x,ResultLen) prog := RegExReplace(prog,"(char\s*\*\s*_result)([^;]*)", "$1 = " . &x, Count) If (Count = 0) MsgBox Found NO char* _result...; Else { If (DllCall("libtcc\tcc_compile_string", UInt,Context, Str,prog, "cdecl UInt") || ErrorLevel) MsgBox Compile error Else DllCall("libtcc\tcc_run", UInt,Context, "cdecl UInt") } DllCall("libtcc\tcc_delete", UInt,Context, "cdecl") DllCall("FreeLibrary", UInt, hModule) VarSetCapacity(x,-1) ; set correct length Return x }The tcclib.zip file contains a TEST.ahk file in the topmost level (similar to the script above). Unzip it anywhere, with maintaining the relative paths of files. Double clicking on TEST.ahk (or running it otherwise) should pop up a Hello World message box, and one with
f(101) --> 10.04987562112089
testing sprintf and the floating point library. When everything works, you can delete this TEST.ahk, or keep it for a quick reference.
Edit 20070429: Added #NoEnv, to avoid possible conflicts with environment variables.
Edit 20070429: Added TEST.ahk to tcclib.zip.
Edit 20070429: Fixed bug: added VarSetCapacity(x,-1) before Return. #NoEnv is not normally needed any more, but safer to keep it.