On the bAdkOde project page, I mentioned that I didn't know whether bAdkOde is Turing Complete (although I suspected it). I also mentioned that if I was able to write a quine in bAdkOde, then it would probably mean that it is Turing Complete. I was able to write one after going through this excellent quine tutorial by Dave Cope.
A quine is basically a program that prints a copy of its source code. Writing a quine seems trivial, but can be, and is in most cases, fiendishly difficult. The quine tutorial that I mentioned earlier describes a rather simple method to create a quine. In any quine, you need to store a representation of part of the source code. This representation is referred to as the core or body. In the method described in the tutorial, and the method that I used, the core is represented as ASCII codes. In some approaches, the core is represented as a string or character array (which, when it comes down to it, is probably represented in memory as an array of ASCII codes). In the approach that I used, there are two parts to the core. The first part prints out the code for the data structure that will contain a representation of the core, and the second part prints out the actual core. For example, let's say I wanted to make a Perl quine. I start off with the core:
print " \@body = (\n"; map { printf "0x%x, ", $_ } @body; print " );\n"; map { printf "%c", $_ } @body;
Here, you can see that I've decided to use an array called @body to store the ASCII values (in hexadecimal). The first three lines print out the definition for the array that will hold the ASCII values. The last line reads the array, translates the code into actual characters, and prints them out. Now all we have to do is get the hexadecimal codes and create the array. To do that, we use a utility called xxd:
vivin@dauntless ~/Projects/code/perl/quine $ xxd -i quinegen.pl >qhex.pl
The output is an array definition in C:
unsigned char quinegen_pl[] = { 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x5c, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x30, 0x78, 0x25, 0x78, 0x2c, 0x20, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x29, 0x3b, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x25, 0x63, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a }; unsigned int quinegen_pl_len = 108;
We need to change this to valid Perl, and that's quite simple:
@body = ( 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x5c, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x30, 0x78, 0x25, 0x78, 0x2c, 0x20, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x29, 0x3b, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x25, 0x63, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a );
We take this and paste it on top of our core:
@body = ( 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x5c, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x30, 0x78, 0x25, 0x78, 0x2c, 0x20, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x29, 0x3b, 0x5c, 0x6e, 0x22, 0x3b, 0x0a, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x25, 0x63, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0x0a ); print " \@body = (\n"; map { printf "0x%x, ", $_ } @body; print " );\n"; map { printf "%c", $_ } @body;
Now the interesting thing here is that this piece of code is not the actual quine. Rather, it generates the quine. But the generated code isn't that different from the generator:
@body = ( 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x5c, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x3d, 0x20, 0x28, 0x5c, 0x6e, 0x22, 0x3b, 0xa, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x30, 0x78, 0x25, 0x78, 0x2c, 0x20, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0xa, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x20, 0x22, 0x20, 0x29, 0x3b, 0x5c, 0x6e, 0x22, 0x3b, 0xa, 0x20, 0x6d, 0x61, 0x70, 0x20, 0x7b, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x66, 0x20, 0x22, 0x25, 0x63, 0x22, 0x2c, 0x20, 0x24, 0x5f, 0x20, 0x7d, 0x20, 0x40, 0x62, 0x6f, 0x64, 0x79, 0x3b, 0xa, ); print " \@body = (\n"; map { printf "0x%x, ", $_ } @body; print " );\n"; map { printf "%c", $_ } @body;
The only difference is the extra comma in the array definition, and the fact that all the ASCII codes are on one line. If you run this perl script, you will get an exact copy of its source code. Now how do we write a quine in bAdkOde? We use a similar approach. First we write the core:
>0a "62"48"97"10 {![a "62'[a"91"97"43"49"97 +1a } "10 >0a {![a "[a +1a }
To implement a quine in bAdkOde, I decided to store the representation of the core (in decimal ASCII values) in memory starting at location zero. The first line initializes the a register to zero. The second line prints out the string >0a with a newline. This line is analogous to the print " \@body = (\n"; line in the perl quine. Within our first loop, we're printing out the actual code that will store the representation of the core in memory. So the first line within the loop prints >ASCII[a+1a where ASCII is the ASCII value of a character from the core. The line is analogous to the printf "0x%x, ", $_ line in the perl quine. There is another print statement right outside the first loop, which simply prints a newline. This line is analogous to the print " );\n"; line in the perl quine. The second loop performs the actual translation of the ASCII code into the core. Now, just like the perl quine, we use xxd:
vivin@dauntless ~/Projects/code/perl/bAdkOde $ xxd -i quine.bad >qhex.txt
After doing this, we get C code that looks like this:
unsigned char quine_bad[] = { 0x3e, 0x30, 0x61, 0x0a, 0x22, 0x36, 0x32, 0x22, 0x34, 0x38, 0x22, 0x39, 0x37, 0x22, 0x31, 0x30, 0x0a, 0x7b, 0x21, 0x5b, 0x61, 0x0a, 0x20, 0x22, 0x36, 0x32, 0x27, 0x5b, 0x61, 0x22, 0x39, 0x31, 0x22, 0x39, 0x37, 0x22, 0x34, 0x33, 0x22, 0x34, 0x39, 0x22, 0x39, 0x37, 0x0a, 0x20, 0x2b, 0x31, 0x61, 0x0a, 0x7d, 0x0a, 0x22, 0x31, 0x30, 0x0a, 0x3e, 0x30, 0x61, 0x0a, 0x7b, 0x21, 0x5b, 0x61, 0x0a, 0x20, 0x22, 0x5b, 0x61, 0x0a, 0x20, 0x2b, 0x31, 0x61, 0x0a, 0x7d, 0x0a }; unsigned int quine_bad_len = 77;
Translating this into bAdkOde is not as straightforward, but it's not that difficult either. I removed the first line, and the last two lines from qhex.txt and then used a oneliner:
vivin@dauntless ~/Projects/code/perl/bAdkOde $ cat qhex.txt | perl -e 'chomp($a=); map { print ">" . hex($_) . "[a+1a"; } \ split(",", $a);' > qdec.txt
You end up with this snippet of bAdkOde:
>62[a+1a>48[a+1a>97[a+1a>10[a+1a>34[a+1a>54[a+1a>50[a+1a>34[a+1a>52[a+1a>56[a+1a>34[a+1a>57[a+1a>55[a+1a>34[a+1a>49[a+1a>48[a+1a>10[a+1a>123[a+1a>33[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>34[a+1a>54[a+1a>50[a+ 1a>39[a+1a>91[a+1a>97[a+1a>34[a+1a>57[a+1a>49[a+1a>34[a+1a>57[a+1a>55[a+1a>34[a+1a>52[a+1a>51[a+1a>34[a+1a>52[a+1a>57[a+1a>34[a+1a>57[a+1a>55[a+1a>10[a+1a>32[a+1a>43[a+1a>49[a+1a>97[a+1a>10[a+1a>125[a+1a>10[ a+1a>34[a+1a>49[a+1a>48[a+1a>10[a+1a>62[a+1a>48[a+1a>97[a+1a>10[a+1a>123[a+1a>33[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>34[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>43[a+1a>49[a+1a>97[a+1a>10[a+1a>125[a+1a>10[a+1a
Now all you need to do is copy this snippet into quine.bad (with one minor change) to get a bAdkOde quine:
>0a >62[a+1a>48[a+1a>97[a+1a>10[a+1a>34[a+1a>54[a+1a>50[a+1a>34[a+1a>52[a+1a>56[a+1a>34[a+1a>57[a+1a>55[a+1a>34[a+1a>49[a+1a>48[a+1a>10[a+1a>123[a+1a>33[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>34[a+1a>54[a+1a>50[a+ 1a>39[a+1a>91[a+1a>97[a+1a>34[a+1a>57[a+1a>49[a+1a>34[a+1a>57[a+1a>55[a+1a>34[a+1a>52[a+1a>51[a+1a>34[a+1a>52[a+1a>57[a+1a>34[a+1a>57[a+1a>55[a+1a>10[a+1a>32[a+1a>43[a+1a>49[a+1a>97[a+1a>10[a+1a>125[a+1a>10[ a+1a>34[a+1a>49[a+1a>48[a+1a>10[a+1a>62[a+1a>48[a+1a>97[a+1a>10[a+1a>123[a+1a>33[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>34[a+1a>91[a+1a>97[a+1a>10[a+1a>32[a+1a>43[a+1a>49[a+1a>97[a+1a>10[a+1a>125[a+1a>10[a+1a >0a "62"48"97"10 {![a "62'[a"91"97"43"49"97 +1a } "10 >0a {![a "[a +1a }
The small change I had to make, was to add >0a at the beginning. If you run this bAdkOde program, it will print its source code as output. So there you have it. A bAdkOde quine, which proves that bAdkOde is Turing Complete. I have to thank Dave Cope for his quine tutorial, without which it would have been extremely difficult for me to write a bAdkOde quine!
Update (12/26/2009)
Dave mentioned that writing a quine only suggests that a language is Turing Complete, but not that it is. He suggested that I write an interpreter for Brainfuck which would then prove that bAdkOde is Turing Complete. That was actually my next project!
Update (12/26/2009)
I've been able to provide a direct translation of Brainfuck into bAdkOde, which proves the Turing Completeness of bAdkOde.
1 thought on “A bAdkOde quine (which suggests that bAdkOde is Turing Complete)”