build index.html for all winners
Updated manifest as per recent file changes. Updated winner `.winner.json` to reflect the manifest changes. Added [bin/all_run.sh](bin/all_run.sh) tool to run a command over all winning entries. These tools had slight improvements in the help usage message: * bin/gen-author.sh VERSION="1.3.1 2024-01-16" * bin/gen-inventory.sh VERSION="1.0.1 2024-01-16" * bin/pandoc_wrapper.sh VERSION="1.3.1 2024-01-16" * bin/subst.default.sh VERSION="1.1.1 2024-01-16" * bin/subst.winner-index.sh VERSION="1.1.1 2024-01-16" The `bin/readme2index.sh` tool was improved so that if the `index.html` file exists and the tool forms the exact same content, then the file `index.html` file is NOT touched. * bin/readme2index.sh VERSION="1.1 2024-01-16" We used the following command to generate `index.html` files for all winning entries: ```sh bin/all_run.sh -v 3 bin/readme2index.sh ``` NOTE: We have not (yet) built HTML files above the winner directory level (e.g., no year level nor top level HTML), nor have be built non-index HTML files for winners. NOTE: By default we are running `pandoc(1)` with: ``` --fail-if-warnings=true ``` This means that any problems with markdown to HTML generates an error. This is done to be sure that the HTML conversion is clean. We had to fix the following `README.md` files: * `2000/rince/README.md` The reference [^2] was never used. We made a guess that [^2] applies to the same spot as [^1]. Perhaps there is a better spot where [^2] applies? NOTE: For every reference, there MUST be some place where that reference is used. * 2012/vik/README.md The string "$...$" is assumed to be a TeX encoded string. NOTE: Every "$..$" needs to be backslashed as in "\$..\$". * 2018/burton1/README.md The reference [2] was duplicated. We changed the second [2] to [3]. NOTE: Every reference needs to have a unique number. * 2020/carlini/README.md The string "$...$" is assumed to be a TeX encoded string. NOTE: Every "$..$" needs to be backslashed as in "\$..\$". We also found 2 errors in the `author/author_handle.json` file set: * author/Anonymous_2001.json The `author/Anonymous_2001.json` file was missing. * author/Jari_Arkko.json The winner ID for `1989_jar.1` had a typo.
This commit is contained in:
1 parent
893cd915b6
commit
c1466f5165
350 files changed
+95242
-4217
No files matched your search
+487
-13
@@ -1,4 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<!-- START: two lines up starts content from: inc/top.default.html -->
|
||||
<!-- -->
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||||
@@ -6,27 +8,499 @@
|
||||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||||
<!-- -->
|
||||
<!-- file: 1998/fanf/index.html created by: fake.gen_index.sh version: 1.0.5 2023-10-31 -->
|
||||
<html lang="en">
|
||||
<!-- END: this line ends content from: inc/top.default.html -->
|
||||
<!-- -->
|
||||
<!-- This file was formed by the tool: bin/readme2index.sh version: 1.1 2024-01-16 -->
|
||||
<!-- -->
|
||||
<!-- START: this line starts content from: inc/head.default.html -->
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>1998 fanf</title>
|
||||
<meta name="description" content="IOCCC year: 1998 IOCCC winner: fanf winner index page">
|
||||
<meta name="keywords" content="IOCCC,1998,fanf,winner index page">
|
||||
<link rel="stylesheet" href="/temp-test-ioccc/ioccc.css">
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||||
<title>1998/fanf</title>
|
||||
<meta name="description" content="1998 IOCCC winner fanf">
|
||||
<meta name="keywords" content="IOCCC, 1998, IOCCC 1998, IOCCC winner, fanf">
|
||||
</head>
|
||||
|
||||
<!-- END: this line ends content from: inc/head.default.html -->
|
||||
<!-- START: this line starts content from: inc/body.default.html -->
|
||||
|
||||
<body>
|
||||
|
||||
<h1>1998 fanf</h1>
|
||||
<!-- END: this line ends content from: inc/body.default.html -->
|
||||
<!-- START: this line starts content from: inc/header.default.html -->
|
||||
|
||||
<p>XXX - fake content until readme2index is working - XXX</p>
|
||||
<div class="header">
|
||||
<img src="/temp-test-ioccc/png/ioccc.png" alt="IOCCC image by Matt Zucker" width=300 height=110>
|
||||
<h1>The International Obfuscated C Code Contest</h1>
|
||||
<h2>1998/fanf</h2>
|
||||
</div>
|
||||
|
||||
<hr style="width:50%;text-align:left;margin-left:0">
|
||||
<!-- END: this line ends content from: inc/header.default.html -->
|
||||
<!-- START: this line starts content from: inc/topnav.mid.html -->
|
||||
|
||||
<!-- Start Nu Html Checker -->
|
||||
<p><a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fioccc-src.github.io%2Ftemp-test-ioccc%2F1998%2Ffanf%2Findex.html">Nu Html check https://ioccc-src.github.io/temp-test-ioccc/1998/fanf/index.html</a></p>
|
||||
<!-- End Nu Html Checker -->
|
||||
<div class="topnav">
|
||||
<a class="Left" href="../dorssel/index.html">← dorssel</a>
|
||||
<a class="Left" href="../index.html">↑ 1998 ↑</a>
|
||||
<a class="Left" href="../schnitzi/index.html">schnitzi →</a>
|
||||
<a class="Right" href="#inventory">Inventory</a>
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/topnav.mid.html -->
|
||||
<!-- START: this line starts content from: inc/begin-row.default.html -->
|
||||
|
||||
<div class="row">
|
||||
|
||||
<!-- END: this line ends content from: inc/begin-row.default.html -->
|
||||
<!-- START: this line starts content from: inc/begin-leftcolumn.default.html -->
|
||||
|
||||
<div class="leftcolumn">
|
||||
|
||||
<!-- END: this line ends content from: inc/begin-leftcolumn.default.html -->
|
||||
<!-- START: this line starts content from: inc/sidenav.default.html -->
|
||||
|
||||
<div class="sidenav">
|
||||
<a href="#content">Jump to contents</a>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="sidenav">
|
||||
<a href="/temp-test-ioccc/index.html">IOCCC Home</a>
|
||||
<a href="/temp-test-ioccc/years.html">Winning Entries</a>
|
||||
<a href="/temp-test-ioccc/winners.html">People who have won</a>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="sidenav">
|
||||
<a href="/temp-test-ioccc/news.html">IOCCC News</a>
|
||||
<a href="/temp-test-ioccc/faq.html#submit">How to enter the IOCCC</a>
|
||||
<a href="/temp-test-ioccc/faq.html">FAQ</a>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="sidenav">
|
||||
<a href="/temp-test-ioccc/bugs.html">Bugs & (mis)features</a>
|
||||
<a href="/temp-test-ioccc/faq.html#fix_a_winner">Fixing IOCCC winners</a>
|
||||
<a href="/temp-test-ioccc/faq.html#fix_web_site">Fixing the web site</a>
|
||||
<a href="/temp-test-ioccc/faq.html#fix_author">Fixing winner info</a>
|
||||
<a href="/temp-test-ioccc/thanks-for-help.html">Thanks for the help</a>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="sidenav">
|
||||
<a href="/temp-test-ioccc/judges.html">The IOCCC Judges</a>
|
||||
<a href="/temp-test-ioccc/contact.html">Contacting the IOCCC</a>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="sidenav">
|
||||
<a href="#top">Jump to top</a>
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/sidenav.default.html -->
|
||||
<!-- START: this line starts content from: inc/end-leftcolumn.default.html -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/end-leftcolumn.default.html -->
|
||||
<!-- START: this line starts content from: inc/begin-rightcolumn.default.html -->
|
||||
|
||||
<div class="rightcolumn">
|
||||
|
||||
<!-- END: this line ends content from: inc/begin-rightcolumn.default.html -->
|
||||
<!-- START: this line starts content from: inc/before-content.default.html -->
|
||||
|
||||
<a name="content"></a>
|
||||
|
||||
<!-- END: this line ends content from: inc/before-content.default.html -->
|
||||
<!-- START: this line starts content generated by: bin/gen-author.sh -->
|
||||
|
||||
<p><a name="author"><strong>Author:</strong></a> <br><br>Name: <a
|
||||
href="/temp-test-ioccc/winners.html#Tony_Finch">Tony Finch</a><br>
|
||||
Location: <a href="/temp-test-ioccc/location.html#GB">GB</a></p>
|
||||
|
||||
<!-- END: next line ends content generated by: bin/gen-author.sh -->
|
||||
<h2 id="to-build">To build:</h2>
|
||||
<div class="sourceCode" id="cb1"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="fu">make</span> all</span></code></pre></div>
|
||||
<p>NOTE: this may take a while. Some systems may have problems building
|
||||
this entry because of the system resources it requires.</p>
|
||||
<h2 id="to-use">To use:</h2>
|
||||
<div class="sourceCode" id="cb2"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./fanf</span></span></code></pre></div>
|
||||
<h2 id="try">Try:</h2>
|
||||
<p>Enter an expression on standard input. To try some we have
|
||||
selected:</p>
|
||||
<div class="sourceCode" id="cb3"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./try.sh</span></span></code></pre></div>
|
||||
<h2 id="judges-remarks">Judges’ remarks:</h2>
|
||||
<h3 id="historical-aside">Historical aside:</h3>
|
||||
<p>At a time the code in <a href="fanf.c">fanf.c</a> was that of <a
|
||||
href="fanf.orig.c">fanf.orig.c</a> but to get this to compile in modern
|
||||
systems it had to be translated to what you now see. The intermediate
|
||||
steps can still be performed but they might be different from the past.
|
||||
This should be kept in mind as you read the below remarks.</p>
|
||||
<p>This program translates lambda expressions into combinator
|
||||
expressions. But you do not need to know Lambda Calculus to be impressed
|
||||
by this program!</p>
|
||||
<p>See the file <a href="fanf.lambda">fanf.lambda</a> for more examples
|
||||
of lambda calculus source.</p>
|
||||
<p>Notice how large the code grows from the <a href="fanf.c">fanf.c</a>
|
||||
into the final <code>fanftmp2.c</code> C program. Take a look at that
|
||||
final C program again, can you begin to understand what it is doing?</p>
|
||||
<p>Look at the first stage of the C pre-processing which was done
|
||||
like:</p>
|
||||
<div class="sourceCode" id="cb4"><pre class="sourceCode sh"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">cc</span> fanf.c <span class="at">-E</span> <span class="op">></span> fanftmp1.c</span></code></pre></div>
|
||||
<p>Skip to the bottom of <code>fanftmp1.c</code> (after all of the C
|
||||
pre-processor header stuff … look for a line of the form:
|
||||
<code># 38 "fanf.c"</code> near the bottom) and look at the resulting
|
||||
code. This code, when C pre-processed will expand into over 342 times
|
||||
the original code (ignoring <code>#include</code> headers) to produce
|
||||
<code>fanftmp2.c</code>. That program in turn, when compiled translates
|
||||
a single lambda expression on standard input into combinator expressions
|
||||
on standard output.</p>
|
||||
<h3 id="extra-credit-question">Extra credit question:</h3>
|
||||
<p>What do you have to do to make this program work with an old non-ANSI
|
||||
C preprocessor?</p>
|
||||
<h2 id="authors-remarks">Author’s remarks:</h2>
|
||||
<p>My program is a demonstration of some practical applications of
|
||||
theoretical computer science. The application it implements is a program
|
||||
for translating lambda expressions into combinator expressions.</p>
|
||||
<h3 id="what-the-program-does">What the program does</h3>
|
||||
<p>The syntax of lambda expressions recognised by the program is as
|
||||
follows: The basic atoms are variables which are single characters other
|
||||
than backslash or parentheses, e.g. <code>a</code> or <code>b</code> or
|
||||
<code>@</code>. Variables are combined by function application which is
|
||||
written as e.g. <code>(f a)</code> which is the function <code>f</code>
|
||||
applied to the argument <code>a</code>. Application groups to the left,
|
||||
so <code>(f a b c)</code> is equivalent to <code>(((f a) b) c)</code>.
|
||||
Functions are created from lambda terms which are written in the form
|
||||
<code>\a(expr)</code> which is the function taking argument
|
||||
<code>a</code> and having value <code>expr</code>. Lambda is spelt
|
||||
<code>\</code> because ASCII isn’t good enough. Lambda binds tightly, so
|
||||
<code>\a\bcd</code> is equivalent to <code>((\a(\b(c))) d)</code>.
|
||||
Whitespace is ignored.</p>
|
||||
<p>For example, the identity function, called <code>I</code>, is written
|
||||
<code>\x(x)</code>. A simple expression is <code>(I a)</code> which is
|
||||
equivalent to <code>(\x(x) a)</code>, which has the value
|
||||
<code>a</code>. Another function called <code>K</code> is defined as
|
||||
<code>\x\y(x)</code> and it evaluates as follows:</p>
|
||||
<pre><code> K p q
|
||||
-> \x\y(x) p q
|
||||
-> \y(p) q
|
||||
-> p</code></pre>
|
||||
<p>Another function of interest is <code>S</code>, defined as
|
||||
<code>\f\g\x((f x) (g x))</code>. My program demonstrates the fact that
|
||||
any lambda expression can be translated into an equivalent “combinator
|
||||
expression” which involves only <code>S</code>, <code>K</code>,
|
||||
<code>I</code> (the combinators), and application, with no variables or
|
||||
lambda abstractions. In fact, even <code>I</code> is unnecessary, since
|
||||
it is equivalent to <code>S K K</code>:</p>
|
||||
<pre><code> I z
|
||||
-> \a(a) z
|
||||
-> z
|
||||
|
||||
S K K z
|
||||
-> \f\g\x((f x) (g x)) K K z
|
||||
-> (K z) (K z)
|
||||
-> \x\y(x) z (K z)
|
||||
-> z</code></pre>
|
||||
<p>The algorithm for translating lambda expressions into combinator
|
||||
expressions works as follows. There are three forms of lambda expression
|
||||
to consider: variables, applications, and abstractions.</p>
|
||||
<pre><code>trans v -> v (variable)
|
||||
trans a b -> (trans a) (trans b ) (application)
|
||||
trans \ab -> abs a (trans b) (abstraction)</code></pre>
|
||||
<p>There are a further three cases to consider for the body of lambda
|
||||
expressions, where we need to do the magic that transforms away the
|
||||
variables.</p>
|
||||
<pre><code>abs a f x -> S (abs a f) (abs a x)
|
||||
abs a b -> K b (b != a)
|
||||
abs a a -> I</code></pre>
|
||||
<p>E.g. suppose we had combinator expressions for <code>+</code> and
|
||||
<code>3</code> and we wanted to see what the combinator expression for
|
||||
doubling 3 looked like:</p>
|
||||
<pre><code> trans \x(+ x x) 3
|
||||
-> (trans \x(+ x x)) (trans 3)
|
||||
-> (abs x (trans + x x)) 3
|
||||
-> (abs x + x x) 3
|
||||
-> S (abs x + x) (abs x x) 3
|
||||
-> S (S (abs x +) (abs x x)) I 3
|
||||
-> S (S (K +) I) I 3
|
||||
-> S (S (K +) I) I 3</code></pre>
|
||||
<p>We can then check that this evaluates to the expected result:</p>
|
||||
<pre><code> S (S (K +) I) I 3
|
||||
-> S (K +) I 3 (I 3)
|
||||
-> K + 3 (I 3) (I 3)
|
||||
-> + (I 3) (I 3)
|
||||
-> + 3 3</code></pre>
|
||||
<p>It is possible to perform a slightly more compact translation with a
|
||||
couple of simple optimisations. For example, note that
|
||||
<code>K (a b)</code> is the same as <code>S (K a) (K b)</code>,
|
||||
because</p>
|
||||
<pre><code> K (a b) x
|
||||
-> a b</code></pre>
|
||||
<p>and</p>
|
||||
<pre><code> S (K a) (K b) x
|
||||
-> K a x (K b x)
|
||||
-> a b</code></pre>
|
||||
<p>Also, <code>S (K a) I</code> is the same as just <code>a</code>
|
||||
because</p>
|
||||
<pre><code> S (K a) I x
|
||||
-> K a x (I x)
|
||||
-> a x</code></pre>
|
||||
<p>The program simply reads a lambda expression from the standard input,
|
||||
translates it into a combinator expression using the transformation and
|
||||
optimisations described above, and prints out the result.</p>
|
||||
<h3 id="why-this-is-a-practical-application">Why this is a practical
|
||||
application</h3>
|
||||
<p>Combinator expressions are easier to evaluate than lambda expressions
|
||||
because there are no problems with variables. For example, if I naively
|
||||
evaluated the expression <code>\x\y(x y) y</code> I might get
|
||||
<code>\y(y y)</code> which is not the same as the correct result because
|
||||
the first <code>y</code> in the body should refer to a global
|
||||
<code>y</code> rather than the local one. David Turner was the first
|
||||
person to realise that because of this fact, SK combinators provide a
|
||||
simple way to implement non-strict functional programming languages,
|
||||
either in software or directly in hardware.</p>
|
||||
<p>My program demonstrates this by being based on a combinator
|
||||
evaluation engine which is used to implement a language called
|
||||
<code>OFL</code> (pronounced like “offal” and short for “Obfuscated
|
||||
Functional Language”). I then used <code>OFL</code> to implement all the
|
||||
high-level functionality described above. This contributes a lot to the
|
||||
obfuscation because even small amounts of <code>OFL</code> are quite
|
||||
unpalatable, and large expressions are completely incomprehensible.</p>
|
||||
<p>It is fairly well known that the lambda calculus (and hence SK
|
||||
combinators) can compute anything, but mere computation is no use if you
|
||||
cannot communicate with the world. This is why <code>OFL</code> includes
|
||||
a few concessions to reality: a combinator <code>E</code> for
|
||||
representing characters and testing them for equality, two I/O
|
||||
combinators, <code>G</code> and <code>P</code>, for reading and writing
|
||||
characters respectively, and a combinator <code>J</code> for
|
||||
representing <code>false</code>. I also implemented the <code>Y</code>
|
||||
combinator directly rather than in terms of the primitive combinators,
|
||||
since it only required five characters to do so
|
||||
(viz. <code>Y W q Q g</code>). However this code is not enabled because
|
||||
the definition of <code>Y</code> in terms of other combinators is more
|
||||
cute.</p>
|
||||
<p>The <code>E</code> combinator comes in a large number of forms, one
|
||||
for each character and one for end of file. It is written
|
||||
<code>E(c)</code> for the variant of <code>E</code> corresponding to the
|
||||
character <code>c</code>. An expression of the form <code>E(c) x</code>
|
||||
is evaluated by first evaluating <code>x</code>. If <code>x</code>
|
||||
doesn’t evaluate to some form of <code>E</code>, then evaluation of the
|
||||
expression terminates. If <code>x</code> evaluates to <code>E(c)</code>,
|
||||
then the expression evaluates to <code>K</code>. If <code>x</code>
|
||||
evaluates to <code>E(d)</code> (where <code>d</code> is a different
|
||||
character to <code>c</code>), then the expression evaluates to
|
||||
<code>J</code>.</p>
|
||||
<p><code>K</code> and <code>J</code> are used to represent
|
||||
<code>true</code> and <code>false</code> respectively; they correspond
|
||||
exactly to the standard lambda calculus representations of
|
||||
<code>true</code> and <code>false</code>, viz. <code>\t\f(t)</code> and
|
||||
<code>\t\f(f)</code> respectively. In this way a conditional expression
|
||||
can just be written <code>cond then else</code>, which is even more
|
||||
terse than C <code>cond ? then : else</code>. An expression that
|
||||
compares a character with <code>a</code>, say, can be written in the
|
||||
rather obfuscated form <code>E('a') char then else</code>.</p>
|
||||
<p>The <code>P</code> combinator, like the <code>E</code> combinator,
|
||||
starts off by evaluating its first argument and checking that it is some
|
||||
form of <code>E</code>. It then writes that character on
|
||||
<code>stdout</code>, and finally it calls its second argument as a
|
||||
function with the argument <code>I</code>, i.e.</p>
|
||||
<pre><code>P x f -> f I</code></pre>
|
||||
<p>with a side-effect.</p>
|
||||
<p>The <code>G</code> combinator just reads a character from
|
||||
<code>stdin</code> then calls its argument as a function with the
|
||||
appropriate <code>E</code> combinator as an argument, i.e.</p>
|
||||
<pre><code>G f -> f E(c)</code></pre>
|
||||
<p>with a side-effect.</p>
|
||||
<p>One of the problems with non-strict languages is that it is hard to
|
||||
predict in advance in which order side-effects will occur. In my program
|
||||
I used a monadic I/O structure like that used by the programming
|
||||
language Haskell; this allows one to write programs that manipulate
|
||||
external state in a manner remarkably similar to imperative programming
|
||||
languages like C. An examination of my program should provide an
|
||||
illustration of how well this technique works in practice. (In
|
||||
particular, I used the CPS form of the I/O monad from page 6 of
|
||||
“Imperative Functional Programming”.)</p>
|
||||
<p>The <code>Y</code> combinator is used for implementing recursive
|
||||
functions. It has the evaluation rule</p>
|
||||
<pre><code>Y f -> f (Y f)</code></pre>
|
||||
<p>so that it can be used to call a function with itself as an argument.
|
||||
For example, if I had the appropriate arithmetic operators defined, I
|
||||
could write a factorial function in the lambda calculus like this:</p>
|
||||
<pre><code>Y \f\n((= n 0) 1 (* n (f (- n 1))))</code></pre>
|
||||
<p><code>OFL</code> provides a facility for naming expressions so that
|
||||
they can be used more than once without writing them in full. A
|
||||
definition must be written on one line in the form
|
||||
<code>l name b expression</code> where <code>l</code> is short for “let”
|
||||
and <code>b</code> is short for “be”. Names must be more than one
|
||||
character long. A complete <code>OFL</code> program starts off by
|
||||
defining the primitives it will use with likes of the form
|
||||
<code>p (S)</code> etc., then goes on to define the names it will use,
|
||||
and finishes off with the main expression followed by a single
|
||||
<code>e</code> short for “end”. <code>OFL</code> expressions must use
|
||||
the minimum number of brackets needed to be unambiguous, except that the
|
||||
whole expression must be surrounded by brackets.</p>
|
||||
<p><code>OFL</code> has a standard library which adds another five
|
||||
combinators to the basic eight. These combinators provide greater scope
|
||||
for optimisation when translating an expression from the lambda calculus
|
||||
to combinators, and therefore more compact programs. Their evaluation
|
||||
rules are:</p>
|
||||
<pre><code>B f g x -> f (g x)
|
||||
C f g x -> (f x) g
|
||||
BB c f g x -> c (f (g x))
|
||||
CC c f g x -> c (f x) g
|
||||
SS c f g x -> c (f x) (g x)</code></pre>
|
||||
<p>I used them to help fit my program into the required space;
|
||||
unfortunately I couldn’t fit the version that fully optimises the lambda
|
||||
expressions it reads into the required space. The complete optimisation
|
||||
rules including the ones it doesn’t use are:</p>
|
||||
<pre><code>S (K p) I -> p
|
||||
S (K p) (K r) -> K ( p r )
|
||||
S (K p) (B r s) -> BB p r s
|
||||
S (K p) r -> B p r
|
||||
S (B p q) (K r) -> CC p q r
|
||||
S p (K r) -> C p r
|
||||
S (B p q) r -> SS p q r
|
||||
S p r -> S p r</code></pre>
|
||||
<h3 id="the-implementation-of-ofl">The implementation of
|
||||
<code>OFL</code></h3>
|
||||
<p>Although <code>OFL</code> has completely different syntax and
|
||||
semantics to C, all you need to compile <code>OFL</code> programs is a C
|
||||
compiler and a header file (which in my entry to the competition has
|
||||
been included in-line). The header file implements a two-pass optimising
|
||||
compiler which produces a representation of the program that is then
|
||||
interpreted.</p>
|
||||
<p>The first pass of the compiler is implemented via the C preprocessor.
|
||||
It implements one optimisation, namely function in-lining.
|
||||
Unfortunately, this optimisation always increases object code size and
|
||||
execution time. The opposite optimisation, common sub-expression
|
||||
elimination (which would offer improvements in code size and execution
|
||||
time), has not been implemented. The output of this pass is a C program
|
||||
that may be compiled by a normal C compiler.</p>
|
||||
<p>The second pass is performed by the initialisation phase of the C
|
||||
program. It builds a data structure representing the abstract syntax
|
||||
tree of the program.</p>
|
||||
<p>The program is then executed by an interpreter. This operates by
|
||||
performing manipulations on the AST that correspond to the evaluation
|
||||
rules of the combinators that I described above.</p>
|
||||
<p>The first 54 lines of the program are mostly the interpreter; the
|
||||
next 8 lines are pass one of the compiler; the next nine declare the
|
||||
<code>OFL</code> primitives; the next five define the <code>OFL</code>
|
||||
standard library; and the rest implement the application described in
|
||||
the first part of this document. This part of the program is transformed
|
||||
into the second pass of the compiler by the first pass of the
|
||||
compiler.</p>
|
||||
<p>The first pass of the compiler relies on some magic macros that
|
||||
expand in a mutually-overlapping and almost recursive way in order to
|
||||
perpetrate a complete change of syntax. Interestingly enough, if I
|
||||
hadn’t used the same identifier for more than one thing in various
|
||||
places in the program this transformation would work with old-style cpp
|
||||
as well and ANSI cpp. It expands the program from about 2.2KB to about
|
||||
740KB. The resulting code does some tricky stuff to build a data
|
||||
structure of the same form as the code itself.</p>
|
||||
<p>The interpreter is written in fairly straightforward C, although it
|
||||
is highly compressed. The C itself is written in a fairly functional
|
||||
style, in that every function consists of a single expression. In the
|
||||
tradition of functional programming languages it assumes that memory is
|
||||
infinite and so never frees anything. It also assumes that the C
|
||||
compiler implements the tail recursion optimisation, which is probably
|
||||
not true.</p>
|
||||
<h3 id="references">References</h3>
|
||||
<p>I used these references in the course of writing this program and
|
||||
they explain some of the ideas behind it in more detail. Arthur Norman
|
||||
(one of the authors of the first paper) did a lot to enthuse me about
|
||||
this topic.</p>
|
||||
<p>Clarke, T. J. W., et al., 1980. SKIM - the S, K, I Reduction Machine.
|
||||
Proceedings of the 1980 ACM LISP Conference, pp. 128-135.</p>
|
||||
<p>Curry, H. B. and Feys, R., 1958. Combinatory Logic, Vol. 1.
|
||||
North-Holland.</p>
|
||||
<p>Gordon, M. J. C., 1988. Programming Language Theory and its
|
||||
Implementation. Prentice-Hall.</p>
|
||||
<p>Peterson, J, et al., 1997. Report on the Programming Language
|
||||
Haskell, version 1.4.</p>
|
||||
<p>Peyton Jones, S. L., 1987. The implementation of Functional
|
||||
Programming Languages, Chapters 2, 11, 12, 16. Prentice-Hall.</p>
|
||||
<p>Peyton Jones, S. L., and Wadler, P., 1992. Imperative Functional
|
||||
Programming. Proceedings of the ACM Symposium on the Principles of
|
||||
Programming Languages 1993, pp. 71-84.</p>
|
||||
<p>Turner, D. A., 1979. A new implementation technique for applicative
|
||||
languages. Software- Practice and Experience. Vol. 9, pp. 31-49.</p>
|
||||
<p>Turner, D. A., 1979. Another algorithm for bracket abstraction.
|
||||
Journal of Symbolic Logic. Vol. 44, no. 2, pp. 67-270.</p>
|
||||
<p>Wadler, P., 1990. Comprehending Monads. Proceedings of the ACM
|
||||
conference on Lisp and Functional Programming, 1990.</p>
|
||||
<p>Wadler, P., 1995. How to Declare an Imperative. Proceedings of the
|
||||
ACM International Logic Programming Symposium, 1995.</p>
|
||||
<h2 id="copyright-and-cc-by-sa-4.0-license">Copyright and CC BY-SA 4.0
|
||||
License:</h2>
|
||||
<p>This file is Copyright (c) 2023 by Landon Curt Noll. All Rights
|
||||
Reserved. You are free to share and adapt this file under the terms of
|
||||
this license:</p>
|
||||
<pre><code>Creative Commons Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)</code></pre>
|
||||
<p>For more information, see:
|
||||
https://creativecommons.org/licenses/by-sa/4.0/</p>
|
||||
<!-- START: this line starts content generated by: bin/gen-inventory.sh -->
|
||||
|
||||
<h1 id="inventory-for-1998fanf"><a name="inventory"></a>Inventory for
|
||||
1998/fanf</h1>
|
||||
<h2 id="primary-files">Primary files</h2>
|
||||
<ul>
|
||||
<li><a href="index.html">index.html</a> - winner home page</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.c">fanf.c</a>
|
||||
- winning source</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/Makefile">Makefile</a>
|
||||
- winner Makefile</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.orig.c">fanf.orig.c</a>
|
||||
- original source</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/try.sh">try.sh</a>
|
||||
- how to run</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.lambda">fanf.lambda</a>
|
||||
- lambda expressions</li>
|
||||
<li><a href="1998_fanf.tar.bz2">1998_fanf.tar.bz2</a> - download winning
|
||||
source</li>
|
||||
</ul>
|
||||
<h2 id="secondary-files">Secondary files</h2>
|
||||
<ul>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/.gitignore">.gitignore</a>
|
||||
- list of files that should not be committed under git</li>
|
||||
<li><a href=".path">.path</a> - directory path from top directory</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/.winner.json">.winner.json</a>
|
||||
- description of winner in JSON</li>
|
||||
<li><a
|
||||
href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/README.md">README.md</a>
|
||||
- markdown source for index.html</li>
|
||||
</ul>
|
||||
|
||||
<!-- END: next line ends content generated by: bin/gen-inventory.sh -->
|
||||
<!-- START: this line starts content from: inc/after-content.default.html -->
|
||||
|
||||
<!-- END: this line ends content from: inc/after-content.default.html -->
|
||||
<!-- START: this line starts content from: inc/end-rightcolumn.default.html -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/end-rightcolumn.default.html -->
|
||||
<!-- START: this line starts content from: inc/end-row.default.html -->
|
||||
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/end-row.default.html -->
|
||||
<!-- START: this line starts content from: inc/footer.default.html -->
|
||||
|
||||
<div class="footer">
|
||||
<hr>
|
||||
<h2>Coda</h2>
|
||||
<p><a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fioccc-src.github.io%2Ftemp-test-ioccc%2F1998%2Ffanf%2Findex.html">Nu HTML check this web page</a></p>
|
||||
<p><a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a></p>
|
||||
</div>
|
||||
|
||||
<!-- END: this line ends content from: inc/footer.default.html -->
|
||||
<!-- START: this line starts content from: inc/bottom.default.html -->
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<!-- END: this line ends content from: inc/bottom.default.html -->
|
||||
Reference in new issue
Block a user