Files
Cody Boone Ferguson 41abeda97a Slight change in 'greater challenge' line
In the line in README.md and index.html files that said:

    ### NOTICE to those who wish for a greater challenge

I added a ':' at the end of the line.

There were some entries that had a link fix in the index.html file but I
only looked up through 1995/leo as those still have to have a 'look and
feel' check and it would just slow things down.
2024-07-09 11:06:20 -07:00

193 lines
5.8 KiB
Markdown

### NOTICE to those who wish for a greater challenge:
**If you want a greater challenge, don't read any further**:
just try to understand the program via the source.
If you get stuck, come back and read below for additional hints and information.
# Q(uine)R code generator
## What is difficult?
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*?
## How did I achieve that?
It is known that we can mitigate the quine restriction by `eval`.
For example, this is a quine written in Ruby:
``` <!---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!
## What sort of VM is that?
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>`.
* 21 integer registers access
* read, write, inc-and-read, dec-and-read
* Binary operations
* add, sub, mul, div, mod, xor, less than, equal, right shift
* Stack operation
* push (an immediate value)
* Heap access
* load, store
* If-Then-Else
* While-Loop
* Misc.
* putchar, exit
The instructions have variable lengths, but many of them are represented as one
printable character. (See [machine.rb](%%REPO_URL%%/2014/endoh1/machine.rb) and
[assemble.rb](%%REPO_URL%%/2014/endoh1/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.
## How did I create the main code?
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.
* [src.rb](%%REPO_URL%%/2014/endoh1/src.rb): the source code of QR code encoder written in Ruby syntax.
* [vm.c](%%REPO_URL%%/2014/endoh1/vm.c): the source code of the VM.
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
```
* [parse.rb](%%REPO_URL%%/2014/endoh1/parse.rb) converts Ruby to AST.
* [serialize.rb](%%REPO_URL%%/2014/endoh1/serialize.rb) converts AST to intermediate instruction sequence.
* [alpha.rb](%%REPO_URL%%/2014/endoh1/alpha.rb) applies "alpha-renaming" to the instruction sequence.
* [register.rb](%%REPO_URL%%/2014/endoh1/register.rb) applies "register allocation".
* [assemble.rb](%%REPO_URL%%/2014/endoh1/assemble.rb) converts the sequence to the final stack-machine instructions.
* [vm.c](%%REPO_URL%%/2014/endoh1/vm.c) is an implementation of the VM.
* [link.rb](%%REPO_URL%%/2014/endoh1/link.rb) generates `main.c` by linking the instructions and interpreter source.
* `gen-prog.rb` generates [prog.c](%%REPO_URL%%/2014/endoh1/prog.c) based on `main.c`.
You can run the process by `rake` command. `ruby-minisat` gem is needed.
``` <!---sh-->
$ gem install ruby-minisat
$ rake
```
## Tools
I checked that the following QR code readers can read the output of my program.
* Linux: [ZBar bar code reader][1].
### A note from the judges in 2023:
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.
[1]: http://zbar.sourceforge.net/
You can use [tool.rb](%%REPO_URL%%/2014/endoh1/tool.rb) to convert the output to a png file.
``` <!---sh-->
./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
```
## Limitations
* QR code error correction level is fixed to L (Low).
* It supports only byte mode (not numeric, alphanumeric, kanji mode...).
* The mask pattern is fixed to 4.
* The mask is not applied to the remained bits.
<hr style="width:10%;text-align:left;margin-left:0">
Jump to: [top](#)
<!--
Copyright © 1984-2024 by Landon Curt Noll. All Rights Reserved.
You are free to share and adapt this file under the terms of this license:
Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
For more information, see:
https://creativecommons.org/licenses/by-sa/4.0/
-->