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.
193 lines
5.8 KiB
Markdown
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/
|
|
|
|
-->
|