diff --git a/2013/dlowe/README.md b/2013/dlowe/README.md index e644957e2..a48ac8acc 100644 --- a/2013/dlowe/README.md +++ b/2013/dlowe/README.md @@ -25,7 +25,10 @@ make ./dlowe 16 32 64 128 256 ./dlowe 16 32 64 128 256 512 +./dlowe 0 + echo "sparkline of file sizes: $(wc -c * | awk '{print $1}' | xargs ./dlowe)" # or ./slen.sh +``` ./dlowe 0 diff --git a/2013/endoh1/README.md b/2013/endoh1/README.md index d0cec0b39..7f8674ecb 100644 --- a/2013/endoh1/README.md +++ b/2013/endoh1/README.md @@ -30,19 +30,22 @@ Be patient with the last one. ## Judges' remarks: -We liked this entry because it can serve as a standalone program as well as an include file; and, as usual, -because its input data is at least as obfuscated as the program itself. +We liked this entry because it can serve as a standalone program as well as an +include file; and, as usual, because its input data is at least as obfuscated as +the program itself. -This entry can be considered an abuse of the GCC's optimizer; it takes GCC about 4x longer to compile it -with -O3 than without, compared to clang's 2x. +This entry can be considered an abuse of the GCC's optimizer; it takes GCC about +4x longer to compile it with -O3 than without, compared to clang's 2x. ## Author's remarks: ### Remarks - $ less prog.c - $ gcc -o prog prog.c - $ ./prog +```sh +less endoh1.c +gcc -o endoh1 endoh1.c +./endoh1 +``` ... Isn't there any more to it? @@ -51,30 +54,33 @@ Yes, of course. This is a tool *for C programmers* to play the [SKI combinator calculus][1], especially, [Lazy K][2]. -This program will shine when it is used as a library. -For example, `hello.lazy` is a "Hello world" program written in Lazy K. +This program will shine when it is used as a library. For example, `hello.lazy` +is a "Hello world" program written in Lazy K. - $ lazy hello.lazy - Hello, world! +```sh +$ lazy hello.lazy +Hello, world! +``` where `lazy` is [a reference implementation of Lazy K][3]. -At the same time, `hello.lazy` is *a valid C program* that uses `prog.c` as a library. +At the same time, `hello.lazy` is *a valid C program* that uses `endoh1.c` as a library. - $ gcc -o hello -xc hello.lazy - $ ./hello - Hello, world! +```sh +$ gcc -o hello -xc hello.lazy +$ ./hello +Hello, world! +``` In other words, this program is a kind of [polyglot][4]. -The usage is simple: -you just have to wrap Lazy K program with `#include "prog.c"`. -Note that `#` is a comment in Lazy K. +The usage is simple: you just have to wrap Lazy K program with `#include +"endoh1.c"`. Note that `#` is a comment in Lazy K. + [1]: http://en.wikipedia.org/wiki/SKI_combinator_calculus -[2]: redacted -[3]: redacted +[2]: https://tromp.github.io/cl/lazy-k.html +[3]: https://github.com/irori/lazyk [4]: http://en.wikipedia.org/wiki/Polyglot_%28computing%29 - ### Obfuscation ... is inherent in SKI combinator calculus :-) @@ -87,38 +93,40 @@ and to satisfy IOCCC's size rule. * Short coding These led to the good obfuscation. -See Spoiler section in detail, if you need. + +See [Spoiler section](#spoiler) in detail, if you need. ### Limitation This program supports only "Combinator-calculus style notation" of Lazy K. "Unlambda style" and "Iota and Jot" style are not supported. -Also, it requires a space between identifiers. -In short, use `(S K)` instead of `(SK)`, "\`sk", `**i*i*i*ii*i*i*ii`, -or `11111100011100`. -Huge memory may be required to compile the program -(about 300 MB on my machine). +Also, it requires a space between identifiers. In short, use `(S K)` instead of +`(SK)`, "\`sk", `**i*i*i*ii*i*i*ii`, or `11111100011100`. -In addition, there are some limitations (and workarounds) -mentioned in Spoiler section. -But I think it wouldn't matter only when you run the attached programs. +Huge memory may be required to compile the program (about 300 MB on my machine). + +In addition, there are some limitations (and workarounds) mentioned in [Spoiler +section](#spoiler). + +But I think it would only matter when you run the attached programs. ### Portability -I confirmed that the program successfully worked -with the following compilers. +I confirmed that the program successfully worked with the following compilers: - * gcc 4.6.3 [Linux, Mac OS X] - * clang 3.0 [Linux, Mac OS X] - * tcc 0.9.26 [Linux] - * N.B. tcc 0.9.25 seems to have a bug and fails to run it. +* gcc 4.6.3 [Linux, Mac OS X] +* clang 3.0 [Linux, Mac OS X] +* tcc 0.9.26 [Linux] + - N.B. tcc 0.9.25 seems to have a bug and fails to run it. Recent compilers with `-Wall -W -Wextra -pedantic` say nothing. - gcc -Wall -W -Wextra -pedantic prog.c - clang -Wall -W -Wextra -pedantic prog.c - tcc -Wall -W -Wextra -pedantic prog.c +```sh +gcc -Wall -W -Wextra -pedantic prog.c +clang -Wall -W -Wextra -pedantic prog.c +tcc -Wall -W -Wextra -pedantic prog.c +``` I think it will work on almost all platforms. I confirmed: @@ -126,83 +134,89 @@ I think it will work on almost all platforms. I confirmed: * Mac OS X * Raspberry PI -To check whether the program is specified on the command line -or included from another source file, -the program uses a predefined macro `__INCLUDE_LEVEL__`. -It is a gcc extention, and also supported by clang. -If your compiler does not support it, -you cannot use the program as a library. -But you can compile and run it as a standalone program, at least. -In fact, tcc does not support the macro, but does work. - -### Spoiler (rot13) - -Gur jubyr cebtenz vf vagrecergrq ol znpeb rkcnafvba. -Sbe rknzcyr, `F (X V)` vf genafyngrq gb n abezny P pbqr, `(f)((x)(v))`, -be fvzcyl `f(x(v))`. -Guvf rkcerffvba ergheaf na nofgenpg flagnk gerr, -naq `cebt.p` rinyhngrf vg. -Guvf cebtenz hfrf irel fvzcyr "grez erjevgvat" nccebnpu -sbe rinyhngvat FXV pbzovangbe pnyphyhf. -Gur erjevgvat ehyrf ner fubja va gur funcr bs gur pbqr. - -#### Nohfr bs shapgvba cbvagref - -Pbafvqre n frdhrapr bs shapgvba nccyvpngvbaf va P: - - f(k)(k)(k)(k)... - -Jung glcr fubhyq `f` unir? -Hasbeghangryl, P qbrf *abg* cebivqr n "erphefvir glcr", -fhpu nf `glcrqrs s (*s)();`. -Fb, V hfrq n urniyl arfgrq shapgvba cbvagre glcr: - - glcrqrs ibvq *(*(*(*...(*(s))()...)())()) - -Guvf yvzvgf ubj znal nethzragf bar shapgvba pna or pbafrphgviryl nccyvrq gb. -Ohg lbh pna vapernfr gur ahzore ol gjrnxvat gur qrsvavgvba bs znpeb `c`. +To check whether the program is specified on the command line or included from +another source file, the program uses a predefined macro `__INCLUDE_LEVEL__`. +It is a gcc extension, and also supported by clang. If your compiler does not +support it, you cannot use the program as a library. But you can compile and +run it as a standalone program, at least. In fact, tcc does not support the +macro, but does work. -#### Pbqr qhcyvpngvba ol znpebf +### Spoiler -Arkg, jr arrq gb rapbqr "pybfherf". -N pybfher vf n shapgvba gbtrgure jvgu na raivebazrag -juvpu vf n ersrerapr gb aba-ybpny inevnoyr. +The whole program is interpreted by macro expansion. +For example, `S (K I)` is translated to a normal C code, `(s)((k)(i))`, or +simply `s(k(i))`. -Va guvf pnfr, jr arrq fbzrguvat gung: +This expression returns an abstract syntax tree, and [endoh1.c](endoh1.c) +evaluates it. - * vf pnyynoyr vgfrys, - * vagreanyyl cbffrffrf n ersrerapr gb nabgure pybfher nf n aba-ybpny inevnoyr, naq - * nccyvrf gur vagreany pybfher gb na nethzrag jura vg vf pnyyrq. +This program uses a very simple "term rewriting" approach for evaluating SKI +combinator calculus. The rewriting rules are shown in the shape of the code. -Ubjrire, ab glcr va P vf pnyynoyr naq unf n ersrerapr ng gur fnzr gvzr. -(Vg vf srnfvoyr ol qlanzvp pbqr trarengvba, ohg vg vf sne sebz cbegnoyr.) +#### Abuse of function pointers -Fb, V nqqerffrq guvf vffhr ol trarengvat znal shapgvba qrsvavgvbaf -fgngvpnyyl ol (no)hfvat znpebf: +Consider a sequence of function applications in C: - ibvq *k1; ibvq s1(ibvq *l) { erghea nccyl(k1, l); } - ibvq *k2; ibvq s2(ibvq *l) { erghea nccyl(k2, l); } - ibvq *k3; ibvq s3(ibvq *l) { erghea nccyl(k3, l); } - ... - ibvq *(u[]) = { s1, s2, s3, ... } +```c +s(x)(x)(x)(x)... +``` -naq ol nyybgvat rnpu bs gurz jura n pybfher vf arrqrq. +What type should `s` have? Unfortunately, C does *not* provide a "recursive +type", such as `typedef f (*f)();`. -Guvf yrnqf gb nabgure yvzvgngvba: -gur ahzore bs cer-qrsvarq pybfherf yvzvgf -ubj znal vaqragvsvref (`F` `X` `V`) bar cebtenz pna hfr. -Ohg lbh pna vapernfr guvf ahzore -ol gjrnxvat gur qrsvavgvba bs znpeb `N` `O` `P` naq `Q`. -(Abgr gung pybfherf ner nyybggrq bayl jura cnefvat; -nsgre gur rinyhngvba fgnegf, "bhg bs pybfher" pnaabg bpphe.) +So, I used a heavily nested function pointer type: + +```c +typedef void *(*(*(*...(*(f))()...)())()) +``` + +This limits how many arguments one function can be consecutively applied to. +But you can increase the number by tweaking the definition of macro `p`. + + +#### Code duplication by macros + +Next, we need to encode "closures". A closure is a function together with an +environment which is a reference to non-local variable. + +In this case, we need something that: + +* is callable itself, +* internally possesses a reference to another closure as a non-local variable, +and +* applies the internal closure to an argument when it is called. + +However, no type in C is callable and has a reference at the same time. +(It is feasible by dynamic code generation, but it is far from portable.) + +So, I addressed this issue by generating many function definitions +statically by (ab)using macros: + +```c +void *x1; void f1(void *y) { return apply(x1, y); } +void *x2; void f2(void *y) { return apply(x2, y); } +void *x3; void f3(void *y) { return apply(x3, y); } +... +void *(h[]) = { f1, f2, f3, ... } +``` + +and by allotting each of them when a closure is needed. + +This leads to another limitation: the number of pre-defined closures limits how +many identifiers (`S` `K` `I`) one program can use. + +But you can increase this number by tweaking the definition of macro `A` `B` `C` +and `D`. (Note that closures are allotted only when parsing; after the +evaluation starts, "out of closure" cannot occur.) + +#### Short cording + +This margin is too narrow to contain a detailed explanation. Instead, I just +ask you one question. Can you tell what `v +s[]={0,0,s+6,s+2,s+4,s,s+3,s+5,s+1};` is? I found this by using SMT solver. -#### Fubeg pbeqvat -Guvf znetva vf gbb aneebj gb pbagnva n qrgnvyrq rkcynangvba. -Vafgrnq, V whfg nfx lbh bar dhrfgvba. -Pna lbh gryy jung `i f[]={0,0,f+6,f+2,f+4,f,f+3,f+5,f+1};` vf? -V sbhaq guvf ol hfvat FZG fbyire. ## Copyright and CC BY-SA 4.0 License: