A C Interpreter
My programming languages class this semester will begin with a few lectures on shell scripting. As an exercise for myself, I thought I’d write a little C “interpreter” so that I can “directly” run my C source code. The first thing we’ll need is a C source file. Here’s one:
#include <stdio.h>
int main(int argc, char **argv) {
int a = 7;
printf("a: %d\n", a);
return 0;
}
Now, I need to indicate what interpreter should run this C script. I’ll write an interpreter named crun
and make sure it’s in a directory on my PATH. I can associate this interpreter with my C script by prepending a shebang line as the first line of my file:
#!/usr/bin/env crun
#include <stdio.h>
int main(int argc, char **argv) {
int a = 7;
printf("a: %d\n", a);
return 0;
}
The crun
interpreter is itself just a shell script that silently compiles and runs the C code:
#!/usr/bin/env zsh
src=$1
root=${src:t:r}
exe=/tmp/$root
gcc -o $exe -x c =(sed -ne '2,$ p' $src) && ($exe; rm $exe)
The assignment to root strips the path to the source code file of any leading directory information (:t) and the file extension (:r). This will be the name of our executable, which we put in the /tmp directory. The =() is a zsh operation that abbreviates redirection to a tmp file and a reference to this tmp file. That is, it abbreviates this sequence:
sed -ne '2,$ p' $src > tmpfile
gcc -o $exe -x c tmpfile
The sed command prints out all lines of the source file but the shebang line (lines 2 through the end, or 2,$). Since the output of this is going to an anonymous tmp file, we need to force gcc to treat it as C source code (-x c). We compile. If compilation was successful, we run the executable. Afterwards, we delete the executable—whether the running was successful or not. With command1 && command2, command2 only runs if command1 returned 0. With (command1; command2), command2 always runs.
And for the final reckoning, we make our code executable and run it:
$ chmod u+x print.c
$ ./print.c
a: 7
Okay, that was silly.