Richard Suchenwirth 2007-10-09 - Playing with tcltcc and its Critcl emulation, I had the idea of writing a very little C "compiler" which takes a (moderately) well-formed C source file, compiles (to memory) and executes it (by calling its main() function), so more along the lines of a C interpreter.
One problem I encountered is that char** seems not to be supported yet, so for first simplification I made argv a single string. Here's my script (ridiculously simple, indeed):
#!/usr/bin/env tclsh
#-- ci.tcl -- a tiny C interpreter built on tcltcc
package require critcl
set f [open [lindex $argv 0]]
set data [read $f]
close $f
critcl::ccode $data
critcl::cproc main {char* argv} int {main(1,argv);}
main [lindex $argv 1]and a tiny C program source to test it with (ci_test.c):
/* demo program for ci.tcl */
#include <stdio.h>
int main(int argc, char* argv) {
printf("hello, %s\n", argv);
return 0;
}which, when run, provides yet another solution for the classic K+R "hello, world" problem:
/Tcl/lib/tcc02> ci.tcl ci_test.c world hello, world
Brian Theado 2007-10-09 - Nice. I saw in the tcc README file you can use the tcc executable in the shebang line on unix to get C-based shell scripting (i.e. '#!/usr/bin/tcc -run'). You could do something similar with your ci.tcl (I guess you would need to parse out the shebang line like 'tcc -run' must do).
I wonder if there are any ideas to borrow from C REPL (Read-Eval-Print-Loop) at [L1 ]
RS: Well, tcc is pretty incremental, so we can just use the read-eval-print loop of an interactive tclsh for that, witness this sample session:
/Tcl/lib/tcc02> tclsh
% package req critcl
0.1.1
% critcl::cproc mul {double a double b} double {return a*b;}
% mul 6 7
42.0Or this:
% critcl::ccode {#include <string.h>}
% critcl::cproc strerror {int n} char* {return strerror(n);}
% strerror 1
Operation not permitted
% strerror 2
No such file or directory
% strerror 3
No such processRS 2007-10-10: The breaking of the main() interface above left me restless, so I hacked up this variation, which in all ugliness (global, static, strtok..) at least accepts a canonical main():
#!/usr/bin/env tclsh
#-- ci.tcl -- a tiny C interpreter built on tcltcc
package require critcl
set f [open [lindex $argv 0]]
set data [read $f][close $f]
critcl::ccode $data
critcl::ccode {
#include <string.h>
#define MAX_ARGC 64
int g_argc = 0;
static char** parse_args(char* args) {
static char* s_argv[MAX_ARGC+1];
char *cp = strtok(args," ");
while(cp) {
s_argv[g_argc] = cp;
if(++g_argc >= MAX_ARGC) break;
cp = strtok(NULL, " ");
}
s_argv[g_argc] = NULL;
return &s_argv;
}
}
critcl::cproc main {char* args} int {
char** argv = parse_args(args);
return main(g_argc, argv);
}
main $argvThe sample C program is now more canonical and robust, and supplies a default argument ("you") if there is none in argv:
/* ci_test.c -- demo program for ci.tcl */
#include <stdio.h>
int main(int argc, char* argv[]) {
char* cp = "you";
if(argc>1) cp = argv[1];
printf("hello, %s\n", cp);
return 0;
}Testing:
/Tcl/lib/tcc02> ci.tcl ci_test.c world hello, world /Tcl/lib/tcc02> ci.tcl ci_test.c hello, you
RFox 3/13/2012 - In case you are looking for a full fledged C interpreter: http://root.cern.ch/drupal/content/cint