Fixes in 2019/lynn
Format fixes in README.md. Update .gitignore based on files being created by commands suggested in the README.md file. Any made by ghc notwithstanding as I don't have that and so can't test it.
This commit is contained in:
1 parent
7253bc16f6
commit
706d4c16a5
2 files changed
+82
-62
No files matched your search
@@ -1,3 +1,9 @@
|
|||||||
prog
|
prog
|
||||||
fib
|
fib
|
||||||
fib.c
|
fib.c
|
||||||
|
hint
|
||||||
|
hint.c
|
||||||
|
lol
|
||||||
|
lol.c
|
||||||
|
scc
|
||||||
|
scc.c
|
||||||
+76
-62
@@ -30,15 +30,15 @@ A fully functional compiler. The example prints out the 30th Fibonacci number.
|
|||||||
|
|
||||||
## Author's comments:
|
## Author's comments:
|
||||||
|
|
||||||
### Remarks
|
### Remarks:
|
||||||
|
|
||||||
A Haskell compiler. Supports a subset of Haskell more than large enough to
|
A Haskell compiler. Supports a subset of Haskell more than large enough to
|
||||||
self-host. Like GHC with custom language extensions:
|
self-host. Like GHC with custom language extensions:
|
||||||
|
|
||||||
* `WeDontServeYourType`: Compilation failing because of inscrutable type
|
* `WeDontServeYourType`: Compilation failing because of inscrutable type
|
||||||
checking rules? Confused by the ever-growing mire of extensions to the type
|
checking rules? Confused by the ever-growing mire of extensions to the type
|
||||||
system? The solution is simple: no type checking. It also means no
|
system? The solution is simple: no type checking. It also means no
|
||||||
typeclasses. Just pass dictionaries explicitly.
|
typeclasses. Just pass dictionaries explicitly.
|
||||||
|
|
||||||
* `ZeroPauseGarbageCollection`: Instead of disruptive stop-the-world garbage
|
* `ZeroPauseGarbageCollection`: Instead of disruptive stop-the-world garbage
|
||||||
collection, we only tidy up when the world stops of its own accord, that is,
|
collection, we only tidy up when the world stops of its own accord, that is,
|
||||||
@@ -49,7 +49,7 @@ self-host. Like GHC with custom language extensions:
|
|||||||
|
|
||||||
* `SyntaxForTheMasses`: See below.
|
* `SyntaxForTheMasses`: See below.
|
||||||
|
|
||||||
### Demos
|
### Building:
|
||||||
|
|
||||||
Build the compiler:
|
Build the compiler:
|
||||||
|
|
||||||
@@ -57,7 +57,9 @@ Build the compiler:
|
|||||||
cc -o prog prog.c
|
cc -o prog prog.c
|
||||||
```
|
```
|
||||||
|
|
||||||
### Fibonacci numbers
|
### Demos:
|
||||||
|
|
||||||
|
#### Fibonacci numbers:
|
||||||
|
|
||||||
Test the compiler on `fib.hs`:
|
Test the compiler on `fib.hs`:
|
||||||
|
|
||||||
@@ -67,14 +69,14 @@ Test the compiler on `fib.hs`:
|
|||||||
|
|
||||||
Compiling the output produces a binary that prints the 30th Fibonacci number.
|
Compiling the output produces a binary that prints the 30th Fibonacci number.
|
||||||
|
|
||||||
The file `ghcfib.hs` includes `fib.hs` with some glue code, and shows GHC
|
The file `ghcfib.hs` includes `fib.hs` with some glue code, and shows GHC also
|
||||||
also accepts our subset of Haskell:
|
accepts our subset of Haskell:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
ghc ghcfib.hs
|
ghc ghcfib.hs
|
||||||
```
|
```
|
||||||
|
|
||||||
### Self-hosting compiler
|
#### Self-hosting compiler:
|
||||||
|
|
||||||
To avoid spoiling this entry by revealing the original Haskell source, we
|
To avoid spoiling this entry by revealing the original Haskell source, we
|
||||||
instead provide `hint.hs`, the output of a certain stage of the compiler when
|
instead provide `hint.hs`, the output of a certain stage of the compiler when
|
||||||
@@ -83,25 +85,29 @@ yet is accepted by our compiler:
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
(./prog < hint.hs ; cat prog.c) > hint.c
|
(./prog < hint.hs ; cat prog.c) > hint.c
|
||||||
|
make hint
|
||||||
|
./hint
|
||||||
```
|
```
|
||||||
|
|
||||||
The output program behaves like the compiler itself.
|
The output program behaves like the compiler itself.
|
||||||
|
|
||||||
Unlike the original source from which it is derived, GHC fails to compile
|
Unlike the original source from which it is derived, GHC fails to compile
|
||||||
`hint.hs`. This is because values have been replaced with their Scott encodings
|
`hint.hs`. This is because values have been replaced with their Scott encodings
|
||||||
by this stage, which messes up type-checks; we'd need equirecursive types for
|
by this stage, which messes up type-checks; we'd need `equirecursive` types for
|
||||||
it to work.
|
it to work.
|
||||||
|
|
||||||
### Regexes
|
#### Regexes:
|
||||||
|
|
||||||
The file `lol.hs` contains an adaptation of [Doug McIlroy's elegant code from
|
The file `lol.hs` contains an adaptation of [Doug McIlroy's elegant code from
|
||||||
"Enumerating the strings of regular
|
"Enumerating the strings of regular
|
||||||
languages"](https://www.cs.dartmouth.edu/~doug/nfa.pdf). We exercise it by
|
languages"](https://www.cs.dartmouth.edu/~doug/nfa.pdf). We exercise it by
|
||||||
showing the first entries of the length-ordered list of all strings consisting
|
showing the first entries of the length-ordered list of all strings consisting
|
||||||
of the characters a and b that contain an even number of a's.
|
of the characters `a` and `b` that contain an even number of `a`s.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
(./prog < lol.hs ; cat prog.c) > lol.c
|
(./prog < lol.hs ; cat prog.c) > lol.c
|
||||||
|
make lol
|
||||||
|
./lol
|
||||||
```
|
```
|
||||||
|
|
||||||
A GHC wrapper is provided:
|
A GHC wrapper is provided:
|
||||||
@@ -110,7 +116,7 @@ A GHC wrapper is provided:
|
|||||||
ghc ghclol.hs
|
ghc ghclol.hs
|
||||||
```
|
```
|
||||||
|
|
||||||
### Strongly-connected components
|
### Strongly-connected components:
|
||||||
|
|
||||||
See `scc.hs` (and its GHC wrapper `ghcscc.hs`) for an elegant way to print the
|
See `scc.hs` (and its GHC wrapper `ghcscc.hs`) for an elegant way to print the
|
||||||
strongly-connected components of a graph in reverse topological order.
|
strongly-connected components of a graph in reverse topological order.
|
||||||
@@ -120,18 +126,19 @@ strongly-connected components of a graph in reverse topological order.
|
|||||||
```
|
```
|
||||||
|
|
||||||
It expects the input to be in a similar format as a previous entry
|
It expects the input to be in a similar format as a previous entry
|
||||||
(2018 vokes). Indeed, obtain the 2018 winners, and run:
|
(2018 vokes). For example:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
./scc < 2018/vokes/example-1.txt
|
make scc
|
||||||
./scc < 2018/vokes/example-2.txt
|
./scc < ../../2018/vokes/example-1.txt
|
||||||
|
./scc < ../../2018/vokes/example-2.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
The output should agree, though our program omits line numbers and does not
|
The output should agree, though our program omits line numbers and does not
|
||||||
sort entries within a line. (Also, our program only treats spaces as
|
sort entries within a line. (Also, our program only treats spaces as
|
||||||
whitespace, and supports any nonspace character in a vertex name.)
|
whitespace, and supports any non-space character in a vertex name.)
|
||||||
|
|
||||||
## Syntax ##
|
### Syntax ###
|
||||||
|
|
||||||
Some claim Haskell syntax is frightening because braces and semicolons are
|
Some claim Haskell syntax is frightening because braces and semicolons are
|
||||||
optional. Some complain about a zoo of twisty little operators, all alike. Our
|
optional. Some complain about a zoo of twisty little operators, all alike. Our
|
||||||
@@ -155,7 +162,7 @@ Within global scope or a let expression, each definition can only refer to
|
|||||||
itself or previous definitions. This implies we can only achieve mutual
|
itself or previous definitions. This implies we can only achieve mutual
|
||||||
recursion by having one function pass itself to others.
|
recursion by having one function pass itself to others.
|
||||||
|
|
||||||
## Caveats ##
|
### Caveats ###
|
||||||
|
|
||||||
The only primitive type is `Int`. In particular, they represent characters. To
|
The only primitive type is `Int`. In particular, they represent characters. To
|
||||||
interoperate with GHC, our compiler treats any undefined functions as the
|
interoperate with GHC, our compiler treats any undefined functions as the
|
||||||
@@ -169,7 +176,9 @@ function, and the result is printed to standard output.
|
|||||||
|
|
||||||
Bool must be defined as:
|
Bool must be defined as:
|
||||||
|
|
||||||
data Bool = True | False;
|
```
|
||||||
|
data Bool = True | False;
|
||||||
|
```
|
||||||
|
|
||||||
so that it matches the Scott-encoded booleans internally used by the primitive
|
so that it matches the Scott-encoded booleans internally used by the primitive
|
||||||
function `(<=)`.
|
function `(<=)`.
|
||||||
@@ -177,15 +186,19 @@ function `(<=)`.
|
|||||||
The alternatives in a case expressions must list every data constructor in
|
The alternatives in a case expressions must list every data constructor in
|
||||||
the order they are defined. For example, if we have:
|
the order they are defined. For example, if we have:
|
||||||
|
|
||||||
data Foo a b = Bar a | Baz | Qux Int [b]
|
```
|
||||||
|
data Foo a b = Bar a | Baz | Qux Int [b]
|
||||||
|
```
|
||||||
|
|
||||||
then a case expression that examines a term of this type must have the form:
|
then a case expression that examines a term of this type must have the form:
|
||||||
|
|
||||||
case x of
|
```
|
||||||
{ Bar a -> ...
|
case x of
|
||||||
; Baz -> ...
|
{ Bar a -> ...
|
||||||
; Qux n bs -> ...
|
; Baz -> ...
|
||||||
}
|
; Qux n bs -> ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
We stress braces and semicolons are required. Our fussy parser treats
|
We stress braces and semicolons are required. Our fussy parser treats
|
||||||
semicolons as separators, not terminators.
|
semicolons as separators, not terminators.
|
||||||
@@ -194,7 +207,7 @@ The effect of erroneous input is undefined. It may be best to develop with GHC,
|
|||||||
but even then, be mindful of changes needed because of issues caused by the
|
but even then, be mindful of changes needed because of issues caused by the
|
||||||
uniform operator precedence and the touchy format of case alternatives.
|
uniform operator precedence and the touchy format of case alternatives.
|
||||||
|
|
||||||
## Why? ##
|
### Why? ###
|
||||||
|
|
||||||
One-letter variable names abound in IOCCC entries, and for good reason. These
|
One-letter variable names abound in IOCCC entries, and for good reason. These
|
||||||
tiny pieces of confetti are hard to read, and leave room for more code. Then
|
tiny pieces of confetti are hard to read, and leave room for more code. Then
|
||||||
@@ -210,61 +223,62 @@ or rather, a compiler that accepts a subset of Haskell sufficiently large to
|
|||||||
self-host. You might say I wrote a tool for this contest, then ran it on itself
|
self-host. You might say I wrote a tool for this contest, then ran it on itself
|
||||||
to make an entry for it.
|
to make an entry for it.
|
||||||
|
|
||||||
### Obfuscation techniques
|
### Obfuscation techniques:
|
||||||
|
|
||||||
Even with Kiselyov's algorithm and some term rewriting, the compiler only fit
|
Even with Kiselyov's algorithm and some term rewriting, the compiler only fit
|
||||||
after compression, which naturally obfuscates the code. More tricks were needed
|
after compression, which naturally obfuscates the code. More tricks were needed
|
||||||
to fit within the size limits.
|
to fit within the size limits.
|
||||||
|
|
||||||
* One-letter variables, until enough is done to banish variables completely.
|
* One-letter variables, until enough is done to banish variables completely.
|
||||||
* Ipse dixit. Near the end, the code declares itself to be an obfuscated
|
* Ipse dixit. Near the end, the code declares itself to be an obfuscated
|
||||||
program. (There is also an exhortation intended for the judges in a similar
|
program. (There is also an exhortation intended for the judges in a similar
|
||||||
format earlier in the source.)
|
format earlier in the source.)
|
||||||
* Typical C mischief: pre- and post-increment, commutative array indexing,
|
* Typical C mischief: pre- and post-increment, commutative array indexing,
|
||||||
ternary operators, and so on.
|
ternary operators, and so on.
|
||||||
* Huffman coding.
|
* Huffman coding.
|
||||||
* Base-85 because high bits are frowned upon.
|
* Base-85 because high bits are frowned upon.
|
||||||
* Mixed radix encoding to game iocccsize. From a past winner (2018 bellard),
|
* Mixed radix encoding to game iocccsize. From a past winner
|
||||||
it seems 9 11 12 32 are the only whitespace octets that may appear verbatim in
|
([2018/bellard](/2018/bellard/prog.c)), it seems 9 11 12 32 are the only
|
||||||
string literals.
|
whitespace octets that may appear verbatim in string literals.
|
||||||
* Choosing what to encode in Huffman/base-85 and what to encode in mixed radix
|
* Choosing what to encode in Huffman/base-85 and what to encode in mixed radix
|
||||||
was a delicate balancing act. In the end, I only had a few bytes to spare,
|
was a delicate balancing act. In the end, I only had a few bytes to spare, which
|
||||||
which I spent on gratuitous confusion.
|
I spent on gratuitous confusion.
|
||||||
* The effects of some functions depend on the order their arguments are
|
* The effects of some functions depend on the order their arguments are
|
||||||
evaluated, yet the program works either way. Why?
|
evaluated, yet the program works either way. Why?
|
||||||
* Ugly macros for the runtime system's jump table for lazy reduction. A
|
* Ugly macros for the runtime system's jump table for lazy reduction. A previous
|
||||||
previous winner (2013 endoh1) has a cuter solution, which I avoid because of
|
winner ([2013/endoh1](/2013/endoh1/endoh1.c)) has a cuter solution, which I
|
||||||
originality concerns and also because my combinators are compressed.
|
avoid because of originality concerns and also because my combinators are
|
||||||
* Relies on the inability of C comments to nest.
|
compressed.
|
||||||
* Cheaper and more complicated to print comma-separated ints (and header and
|
* Relies on the inability of C comments to nest.
|
||||||
footer) in C.
|
* Cheaper and more complicated to print comma-separated ints (and header and
|
||||||
* Primitive functions use a trick described in depth by [Naylor and Runciman,
|
footer) in C.
|
||||||
|
* Primitive functions use a trick described in depth by [Naylor and Runciman,
|
||||||
"The Reduceron reconfigured and
|
"The Reduceron reconfigured and
|
||||||
re-evaluated"](https://www.cs.york.ac.uk/fp/reduceron/jfp-reduceron.pdf). We
|
re-evaluated"](https://www.cs.york.ac.uk/fp/reduceron/jfp-reduceron.pdf). We
|
||||||
represent the integer n with a term equivalent to `Y(BT)n`; it works because
|
represent the integer n with a term equivalent to `Y(BT)n`; it works because
|
||||||
`Y(BT)ne = e(Y(BT)n)`.
|
`Y(BT)ne = e(Y(BT)n)`.
|
||||||
* A sentinel in the heap often confused me, so ought to confuse others.
|
* A sentinel in the heap often confused me, so ought to confuse others.
|
||||||
|
|
||||||
Other obfuscation techniques are better appreciated after decoding the
|
Other obfuscation techniques are better appreciated after decoding the
|
||||||
compiler. See `hint.hs`.
|
compiler. See [hint.hs](hint.hs).
|
||||||
|
|
||||||
* Mercilessly point-free. Everything is a combinator.
|
* Mercilessly point-free. Everything is a combinator.
|
||||||
* Scott encoding. Everything is a combinator.
|
* Scott encoding. Everything is a combinator.
|
||||||
* Sum types are oddly ordered and may even contain unused data constructors
|
* Sum types are oddly ordered and may even contain unused data constructors to
|
||||||
to reduce code duplication. (In C terms, unions may have extra fields, and
|
reduce code duplication. (In C terms, unions may have extra fields, and they're
|
||||||
they're ordered in such a way so we can reuse code to access certain fields.)
|
ordered in such a way so we can reuse code to access certain fields.)
|
||||||
* The `undefined` function compiles to the `(.)` function.
|
* The `undefined` function compiles to the `(.)` function.
|
||||||
* Replaced the only `(&&)` with `(||)` and `not` using De Morgan's law, which
|
* Replaced the only `(&&)` with `(||)` and `not` using De Morgan's law, which
|
||||||
makes some comparisons less comprehensible.
|
makes some comparisons less comprehensible.
|
||||||
* [Kiselyov only published "λ to SKI, Semantically" last
|
* [Kiselyov only published "λ to SKI, Semantically" last
|
||||||
year](http://okmij.org/ftp/tagless-final/ski.pdf).
|
year](http://okmij.org/ftp/tagless-final/ski.pdf).
|
||||||
* Recursion via the fixpoint (Y) combinator, which is represented by the
|
* Recursion via the fixpoint (Y) combinator, which is represented by the
|
||||||
variable "" during one stage of compilation.
|
variable `""` during one stage of compilation.
|
||||||
* Involves theory that may be less familiar to C programmers: maps, folds,
|
* Involves theory that may be less familiar to C programmers: maps, folds,
|
||||||
parser combinators, lambda calculus, bracket abstraction, denotational
|
parser combinators, lambda calculus, bracket abstraction, denotational
|
||||||
semantics, etc.
|
semantics, etc.
|
||||||
|
|
||||||
### Warnings
|
### Warnings:
|
||||||
|
|
||||||
On my system, it compiles cleanly with `-Wall` with older standards, e.g.
|
On my system, it compiles cleanly with `-Wall` with older standards, e.g.
|
||||||
`-std=c89`, but less cleanly if `-pedantic` is also supplied.
|
`-std=c89`, but less cleanly if `-pedantic` is also supplied.
|
||||||
@@ -272,10 +286,10 @@ On my system, it compiles cleanly with `-Wall` with older standards, e.g.
|
|||||||
Compiling the compiler output with `-Wall` triggers a warning about a
|
Compiling the compiler output with `-Wall` triggers a warning about a
|
||||||
strange-looking comment.
|
strange-looking comment.
|
||||||
|
|
||||||
### Behind-the-scenes commentary
|
### Behind-the-scenes commentary:
|
||||||
|
|
||||||
[My website reveals how this compiler
|
[My website reveals how this compiler
|
||||||
works.](https://crypto.stanford.edu/~blynn/compiler/ioccc.html)
|
works](https://crypto.stanford.edu/~blynn/compiler/ioccc.html).
|
||||||
|
|
||||||
## Copyright and CC BY-SA 4.0 License:
|
## Copyright and CC BY-SA 4.0 License:
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user