Smart people write C. Pragmatic people write Go. Only a fool would write C code that outputs Go code that outputs the original C code.
So I made one. Below is the code:
#include <stdio.h>
int main(){
char*c="#include <stdio.h>%cint main(){%cchar*c=%c%s%c,o[1000],g[1000];%csprintf(g,%cpackage main;import%ccfmt%cc;func main(){fmt.Print(%cc%ccs%cc)}%c,34,34,96,37,96);%csprintf(o,c,10,10,34,c,34,10,34,37,37,37,37,37,34,10,10,10,10,10);%cfprintf(stdout,g,o);%creturn 0;%c}%c",o[1000],g[1000];
sprintf(g,"package main;import%cfmt%c;func main(){fmt.Print(%c%cs%c)}",34,34,96,37,96);
sprintf(o,c,10,10,34,c,34,10,34,37,37,37,37,37,34,10,10,10,10,10);
fprintf(stdout,g,o);
return 0;
}
If you run it, you should get the result below:
$ cc ouroboros.c -o ouroboros
$ ./ouroboros > ouroboros.go
$ go run ouroboros.go > ouroboros2.c
$ diff ouroboros.c ouroboros2.c && cowsay "wtf?"
______
< wtf? >
------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
How
One of the simplest quines in C looks like this:
#include <stdio.h>
int main(){
char*c="#include <stdio.h>%cint main(){%cchar*c=%c%s%c;%cprintf(c,10,10,34,c,34,10,10,10,10);%creturn 0;%c}%c";
printf(c,10,10,34,c,34,10,10,10,10);
return 0;
}
I’m not going to dive into the details - there’s a detailed explanation on the tricks and examples for writing quines available in Rosetta Code’s wiki page.
Since I wasn’t going to waste my time hand-crafting the string that should contain the original source code, I wrote Python code which generates the C code above:
quine = r'''#include <stdio.h>
int main(){
char*c="?";
printf(c,!);
return 0;
}
'''
quinestr = r''
args = []
for i, ch in enumerate(quine):
if ch in '\n"':
quinestr += '%c'
args.append(ord(ch))
elif ch == '?':
quinestr += '%s'
args.append('c')
else:
quinestr += ch
args = ','.join(map(str, args))
print(
quine\
.replace('?',
quinestr\
.replace('?', '%s')\
.replace('!', args))\
.replace('!', args),
end='')
To go further than just a simple quine, I had to make the quine self-aware, storing the output string in a variable. To do so I updated the template C code to the one below:
#include <stdio.h>
int main(){
char*c="?",o[1000];
sprintf(o,c,!);
fputs(o, stdout);
return 0;
}
The variable o
now holds the value of the source code.
Next, I came up with Go code snippet that should output it:
package main;import"fmt";func main(){fmt.Print(`<your_quine_here>`)})
I used back-quoted string since they can contain any characters,
even newlines, which will be present in the o
.
And the final tricky part - I needed to add the Go code as a C string:
#include <stdio.h>
int main(){
char*c="?",o[1000],g[1000];
sprintf(g,"package main;import%cfmt%c;func main(){fmt.Print(%c%cs%c)}",34,34,96,37,96);
sprintf(o,c,!);
fprintf(stdout,g,o);
return 0;
}
The variable g
now contains the template Go code.
The trick here is making sure that the variable for Go code
contains %s
and `
, but implicitly.
The former needs to be used in the next sprintf
call to do the substitution,
and the latter can’t be explicit because back-quoted strings in Go cannot contain
back-quote characters.
The final Python code which outputs the C code which outputs the Go code which outputs the C… you got it, is available here.
Why
Why not?