As you may know, QR code (specification: ISO/IEC 18004) is quite complex. It requires a bit stream, Reed-Solomon codes, BCH codes, data relocation, big (and irregular!) numerical tables, human-oriented pattern arrangement (difficult to implement by a small program), etc.
On the other hand, a quine has a big restriction: it needs to have two copies of the program!
Do you think that it is possible to write QR code encoder in C within 1kB?
It is known that we can mitigate the quine restriction by eval
.
For example, this is a quine written in Ruby:
eval s="print 'eval s='; p s"
Note that print
appears just once in the program.
To emulate this approach in C, I adopted the following structure.
char s[]="<main code>int main() { <VM code> }";
int main() { <VM code>; }
<VM code>
: An own VM implementation (written in C) that executes the main
code.<main code>
: An object code of quine and QR code encoder (written in the
assembly language of the VM).<main code>
(about 1100 bytes) appears once and <VM code>
(about 450 bytes)
appears twice. So the whole code is about 1100 + 450 * 2 = 2000 bytes. Hooray!
The VM is a kind of stack machine which makes the object code compact. The
instruction set is carefully selected to minimize the sizes of both <main code>
and <VM code>
.
The instructions have variable lengths, but many of them are represented as one
printable character. (See machine.rb and
assemble.rb in detail.) The mapping between instructions and
characters is also carefully designed to minimize <VM code>
, which makes the
resulted program non-human-readable.
It is too tedious to write the machine language directly. So I wrote the source code in Ruby syntax and created a Ruby-to-VM compiler that involves alpha renaming and automatic register allocation only for this purpose.
The compiler tool chain is the following.
src.rb interp.c
| |
| [parse.rb] |
V |
ast.txt |
| |
| [serialize.rb] |
V |
seq.txt |
| |
| [alpha.rb] |
V |
alpha.txt |
| |
| [register.rb] |
V |
reg.txt |
| |
| [assemble.rb] |
V |
raw.txt |
| |
+---------+---------+
|
| [link.rb]
V
main.c
|
| [gen-prog.c]
V
prog.c
main.c
by linking the instructions and interpreter source.main.c
.You can run the process by rake
command. ruby-minisat
gem is needed.
$ gem install ruby-minisat
$ rake
I checked that the following QR code readers can read the output of my program.
The author also tested an Android app called Barcode Scanner which used to be
found at
https://play.google.com/store/apps/details?id=com.google.zxing.client.android
but it appears to no longer exist.
You can use tool.rb to convert the output to a png file.
./main Hello | ruby tool.rb > hello.png
$ zbarimg -q hello.png
QR-Code:Hello
$ ruby tool.rb prog.c
$ ruby tool.rb prog.c | ruby tool.rb