While not strictly necessary, replacing the two ASCII tab characters in the markdown copyright comment makes it easier to detect problematic TAB indentation within markdown files. After this commit, only 90 markdown files have leading ASCII TAB characters. And again, while not strictly necessary, we can consider running expand on those 90 markdown files to see what effect that might have on the HTML files they produce. Replace leading ASCII TAB characters with multiples of 8 ASCII SPACE characters (the default action of the `expand(1)` tool) might have an negative effect on some HTML formatting where **hack-a-round** formatting was attempted to fix broken indentation caused by problematic ASCII TAB characters. Think of this as a baseline for evaluating leading TAB characters within markdown files. TODO: Consider either using `expand(1)` to replace leading ASCII TAB characters with multiples of 8 ASCII SPACE characters AND/OR modifying the appropriate `bin` tool to convert leading ASCII TAB characters into multiples of 8 ASCII SPACE characters.
806 lines
35 KiB
HTML
806 lines
35 KiB
HTML
<!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 -->
|
||
|
||
<!-- END: this line ends content from: inc/top.default.html -->
|
||
<!-- START: this line starts content from: inc/head.default.html -->
|
||
|
||
<head>
|
||
<link rel="stylesheet" href="../../ioccc.css">
|
||
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@100..900&display=swap" rel="stylesheet">
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
||
<title>1998/fanf - Most obfuscated translator</title>
|
||
<link rel="icon" type="image/x-icon" href="../../favicon.ico">
|
||
<meta name="description" content="1998 IOCCC entry fanf - Most obfuscated translator">
|
||
<meta name="keywords" content="IOCCC, 1998, IOCCC 1998, IOCCC entry, fanf, Most obfuscated translator">
|
||
</head>
|
||
|
||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||
<!-- !!! DO NOT MODIFY THIS FILE - This file is generated by a tool !!! -->
|
||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||
|
||
<!-- END: this line ends content from: inc/head.default.html -->
|
||
|
||
<!-- -->
|
||
<!-- This web page was formed via the tool: bin/readme2index.sh -->
|
||
<!-- The content of main section of this web page came from: 1998/fanf/README.md -->
|
||
<!-- -->
|
||
|
||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||
<!-- !!! Do not modify this web page, instead modify the file: 1998/fanf/README.md !!! -->
|
||
<!-- !!! Do not modify this web page, instead modify the file: 1998/fanf/README.md !!! -->
|
||
<!-- !!! Do not modify this web page, instead modify the file: 1998/fanf/README.md !!! -->
|
||
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->
|
||
|
||
<!-- Markdown content was converted into HTML via the tool: bin/md2html.sh -->
|
||
|
||
<!-- START: this line starts content from: inc/body.default.html -->
|
||
|
||
<body>
|
||
|
||
<!-- END: this line ends content from: inc/body.default.html -->
|
||
<!-- START: this line starts content from: inc/topbar.default.html -->
|
||
|
||
<div class="theader">
|
||
<nav class="topbar">
|
||
<div class="container">
|
||
<div class="logo">
|
||
<a href="../../index.html" class="logo-link">
|
||
IOCCC
|
||
</a>
|
||
</div>
|
||
|
||
<div class="topbar-items">
|
||
<div class="item">
|
||
<span class="item-header">
|
||
Entries
|
||
</span>
|
||
|
||
<div class="sub-item">
|
||
<div class="outfit-font">
|
||
<a href="../../years.html" class="sub-item-link">
|
||
Winning Entries
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../authors.html" class="sub-item-link">
|
||
Winning Authors
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../location.html" class="sub-item-link">
|
||
Location of winning authors
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../bugs.html" class="sub-item-link">
|
||
Bugs and (mis)features
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item">
|
||
<span class="item-header">
|
||
Status
|
||
</span>
|
||
|
||
<div class="sub-item">
|
||
<div class="outfit-font">
|
||
<a href="../../news.html" class="sub-item-link">
|
||
IOCCC News
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../status.html" class="sub-item-link">
|
||
Contest status
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../next/index.html" class="sub-item-link">
|
||
Rules and Guidelines
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item">
|
||
<span class="item-header">
|
||
FAQ
|
||
</span>
|
||
|
||
<div class="sub-item">
|
||
<div class="outfit-font">
|
||
<a href="../../faq.html" class="sub-item-link">
|
||
FAQ
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../faq.html#submit" class="sub-item-link">
|
||
How to enter the IOCCC
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../faq.html#fix_an_entry" class="sub-item-link">
|
||
Fixing IOCCC entries
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../faq.html#fix_web_site" class="sub-item-link">
|
||
Fixing the website
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../faq.html#fix_author" class="sub-item-link">
|
||
Updating author info
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="item">
|
||
<span class="item-header">
|
||
About
|
||
</span>
|
||
|
||
<div class="sub-item">
|
||
<div class="outfit-font">
|
||
<a href="../../index.html" class="sub-item-link">
|
||
IOCCC Home
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../judges.html" class="sub-item-link">
|
||
The IOCCC Judges
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../contact.html" class="sub-item-link">
|
||
Contacting the IOCCC
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../thanks-for-help.html" class="sub-item-link">
|
||
Thanks for the help
|
||
</a>
|
||
</div>
|
||
|
||
<div class="outfit-font">
|
||
<a href="../../markdown.html" class="sub-item-link">
|
||
IOCCC markdown guidelines
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
|
||
<div class="header-mobile-menu">
|
||
<noscript>
|
||
<a href="../../nojs-menu.html" class="topbar-js-label">
|
||
Please Enable JavaScript
|
||
</a>
|
||
</noscript>
|
||
|
||
<button id="header-open-menu-button" class="topbar-mobile-menu">
|
||
<img
|
||
src="../../png/hamburger-icon-open.png"
|
||
alt="hamburger style menu icon - open state"
|
||
width=48
|
||
height=48>
|
||
</button>
|
||
|
||
<button id="header-close-menu-button" class="hide-content">
|
||
<img
|
||
src="../../png/hamburger-icon-closed.png"
|
||
alt="hamburger style menu icon - closed state"
|
||
width=48
|
||
height=48>
|
||
</button>
|
||
|
||
<div id="mobile-menu-panel" class="hide-content">
|
||
<div class="mobile-menu-container">
|
||
|
||
<div class="mobile-menu-wrapper">
|
||
<div class="mobile-menu-item">
|
||
Entries
|
||
</div>
|
||
<div class="mobile-submenu-wrapper">
|
||
|
||
<a class="mobile-submenu-item" href="../../years.html">
|
||
Winning Entries
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../authors.html">
|
||
Authors of winning IOCCC entries
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../location.html">
|
||
Location of authors
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../bugs.html">
|
||
Bugs and (mis)features
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mobile-menu-wrapper">
|
||
|
||
<div class="mobile-menu-item">
|
||
Status
|
||
</div>
|
||
<div class="mobile-submenu-wrapper">
|
||
|
||
<a class="mobile-submenu-item" href="../../status.html">
|
||
Contest status
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../next/index.html">
|
||
Rules and Guidelines
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../news.html">
|
||
IOCCC News
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mobile-menu-wrapper">
|
||
<div class="mobile-menu-item">
|
||
FAQ
|
||
</div>
|
||
<div class="mobile-submenu-wrapper">
|
||
|
||
<a class="mobile-submenu-item" href="../../faq.html">
|
||
Frequently Asked Questions
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../faq.html#submit">
|
||
How to enter the IOCCC
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../faq.html#fix_an_entry">
|
||
Fixing IOCCC entries
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../faq.html#fix_web_site">
|
||
Fixing the website
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../faq.html#fix_author">
|
||
Fixing author info
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mobile-menu-wrapper">
|
||
<div class="mobile-menu-item">
|
||
About
|
||
</div>
|
||
<div class="mobile-submenu-wrapper">
|
||
|
||
<a class="mobile-submenu-item" href="../../index.html">
|
||
IOCCC Home
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../judges.html">
|
||
The IOCCC Judges
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../contact.html">
|
||
Contacting the IOCCC
|
||
</a>
|
||
|
||
<a class="mobile-submenu-item" href="../../thanks-for-help.html">
|
||
Thanks for the help
|
||
</a>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<script>
|
||
var headerOpenMenuButton = document.getElementById("header-open-menu-button");
|
||
var headerCloseMenuButton = document.getElementById("header-close-menu-button");
|
||
var mobileMenuPanel = document.getElementById("mobile-menu-panel");
|
||
|
||
headerOpenMenuButton.addEventListener("click", () => {
|
||
headerOpenMenuButton.classList.remove("topbar-mobile-menu");
|
||
headerOpenMenuButton.classList.add("hide-content");
|
||
|
||
headerCloseMenuButton.classList.remove("hide-content");
|
||
headerCloseMenuButton.classList.add("topbar-mobile-menu");
|
||
|
||
mobileMenuPanel.classList.remove("hide-content");
|
||
mobileMenuPanel.classList.add("topbar-mobile-panel");
|
||
});
|
||
|
||
headerCloseMenuButton.addEventListener("click", () => {
|
||
headerCloseMenuButton.classList.remove("topbar-mobile-menu");
|
||
headerCloseMenuButton.classList.add("hide-content");
|
||
|
||
mobileMenuPanel.classList.add("hide-content");
|
||
mobileMenuPanel.classList.remove("topbar-mobile-panel");
|
||
|
||
headerOpenMenuButton.classList.add("topbar-mobile-menu");
|
||
headerOpenMenuButton.classList.remove("hide-content");
|
||
});
|
||
</script>
|
||
|
||
<!-- END: this line ends content from: inc/topbar.default.html -->
|
||
<!-- START: this line starts content from: inc/header.default.html -->
|
||
|
||
<div class="header">
|
||
<a href="../../2011/zucker/index.html">
|
||
<img src="../../png/ioccc.png"
|
||
alt="IOCCC image by Matt Zucker"
|
||
width=300
|
||
height=110>
|
||
</a>
|
||
<h1>The International Obfuscated C Code Contest</h1>
|
||
<h2>1998/fanf - Most obfuscated translator</h2>
|
||
</div>
|
||
|
||
<!-- END: this line ends content from: inc/header.default.html -->
|
||
<!-- START: this line starts content from: inc/navbar.mid.html -->
|
||
|
||
<div class="navbar">
|
||
<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="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.c">C code</a>
|
||
<a class="Right" href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/Makefile">Makefile</a>
|
||
<a class="Right" href="#inventory">Inventory</a>
|
||
<a class="Right" href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fioccc-src.github.io%2Ftemp-test-ioccc%2F1998%2Ffanf%2Findex.html">✓</a>
|
||
</div>
|
||
|
||
<!-- END: this line ends content from: inc/navbar.mid.html -->
|
||
<!-- START: this line starts content from: inc/before-content.default.html -->
|
||
|
||
<div class="content" id="content">
|
||
|
||
<!-- END: this line ends content from: inc/before-content.default.html -->
|
||
<!-- START: this line starts content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
|
||
|
||
<!-- START: this line starts content generated by: bin/output-index-author.sh -->
|
||
|
||
<h2 id="author">Author:</h2>
|
||
<ul>
|
||
<li>Name: <a href="../../authors.html#Tony_Finch">Tony Finch</a><br>
|
||
Location: <a href="../../location.html#GB">GB</a> - <em>United Kingdom of Great Britain and Northern Ireland</em> (<em>United Kingdom</em>)</li>
|
||
</ul>
|
||
|
||
<!-- END: next line ends content generated by: bin/output-index-author.sh -->
|
||
|
||
<!-- END: this line ends content for HTML phase 20 by: bin/output-index-author.sh via bin/md2html.sh -->
|
||
<!-- START: this line starts content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
|
||
|
||
<!-- BEFORE: 1st line of markdown file: 1998/fanf/README.md -->
|
||
<h2 id="to-build">To build:</h2>
|
||
<pre><code> make all</code></pre>
|
||
<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>
|
||
<pre><code> ./fanf</code></pre>
|
||
<h2 id="try">Try:</h2>
|
||
<p>Enter an expression on standard input. To try some we have selected:</p>
|
||
<pre><code> ./try.sh</code></pre>
|
||
<h2 id="judges-remarks">Judges’ remarks:</h2>
|
||
<h3 id="historical-aside">Historical aside:</h3>
|
||
<p>At a time the code in <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.c">fanf.c</a> was that of <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/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="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.lambda">fanf.lambda</a> for more examples of lambda calculus
|
||
source.</p>
|
||
<p>Notice how large the code grows from the <a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/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>
|
||
<pre><code> cc fanf.c -E > fanftmp1.c</code></pre>
|
||
<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>
|
||
<!--
|
||
|
||
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/
|
||
|
||
-->
|
||
<!-- AFTER: last line of markdown file: 1998/fanf/README.md -->
|
||
|
||
<!-- END: this line ends content for HTML phase 21 by: bin/pandoc-wrapper.sh via bin/md2html.sh -->
|
||
<!-- START: this line starts content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
|
||
|
||
<!-- START: this line starts content generated by: bin/output-index-inventory.sh -->
|
||
|
||
<div id="inventory">
|
||
<h1 id="inventory-for-1998fanf">Inventory for 1998/fanf</h1>
|
||
</div>
|
||
<h2 id="primary-files">Primary files</h2>
|
||
<ul>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.c">fanf.c</a> - entry source code</li>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/Makefile">Makefile</a> - entry 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 code</li>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/try.sh">try.sh</a> - script to try entry</li>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/fanf.lambda">fanf.lambda</a> - lambda expressions</li>
|
||
</ul>
|
||
<h2 id="secondary-files">Secondary files</h2>
|
||
<ul>
|
||
<li><a href="1998_fanf.tar.bz2">1998_fanf.tar.bz2</a> - download entry tarball</li>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/README.md">README.md</a> - markdown source for this web page</li>
|
||
<li><a href="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/.entry.json">.entry.json</a> - entry summary and manifest in JSON</li>
|
||
<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="https://github.com/ioccc-src/temp-test-ioccc/blob/master/1998/fanf/.path">.path</a> - directory path from top level directory</li>
|
||
<li><a href="index.html">index.html</a> - this web page</li>
|
||
</ul>
|
||
<hr style="width:10%;text-align:left;margin-left:0">
|
||
<h4>
|
||
Jump to: <a href="#">top</a>
|
||
</h4>
|
||
|
||
<!-- END: next line ends content generated by: bin/output-index-inventory.sh -->
|
||
|
||
<!-- END: this line ends content for HTML phase 22 by: bin/output-index-inventory.sh via bin/md2html.sh -->
|
||
<!-- START: this line starts content from: inc/after-content.default.html -->
|
||
|
||
</div>
|
||
|
||
<!-- END: this line ends content from: inc/after-content.default.html -->
|
||
<!-- START: this line starts content from: inc/footer.inventory.html -->
|
||
|
||
<!--
|
||
|
||
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/
|
||
|
||
-->
|
||
|
||
<div class="footer">
|
||
|
||
<div id="copyright"><h3>Copyright © 1984-2024 by Landon Curt Noll:
|
||
<a href="https://creativecommons.org/faq/#what-does-some-rights-reserved-mean"
|
||
target="_blank"
|
||
rel="license noopener noreferrer">Some Rights Reserved</a></h3>
|
||
<p>
|
||
This work is <b>licensed by Landon Curt Noll</b> under
|
||
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/?ref=chooser-v1"
|
||
target="_blank"
|
||
rel="license noopener noreferrer"
|
||
style="display:inline-block;">CC BY-SA 4.0</a></b>.
|
||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||
src="../../png/cc.png"
|
||
alt="cc inside circle symbol">
|
||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||
src="../../png/by.png"
|
||
alt="person inside circle symbol">
|
||
<img style="height:22px!important;margin-left:3px;vertical-align:text-bottom;"
|
||
src="../../png/sa.png"
|
||
alt="arrow looping back on itself inside circle symbol"><br>
|
||
You should <b>carefully review</b> the
|
||
<b><a href="https://creativecommons.org/licenses/by-sa/4.0/legalcode.en"
|
||
target="_blank"
|
||
rel="license noopener noreferrer">CC BY-SA 4.0 LEGAL CODE</a></b>
|
||
before using the licensed material.<br>
|
||
You may wish to review the
|
||
<b><a href="../../license.html"
|
||
target="_blank"
|
||
rel="license noopener noreferrer">highlights of some of the key features and terms</a></b>
|
||
of <b>CC BY-SA 4.0</b>.<br>
|
||
</p>
|
||
</div>
|
||
|
||
<div id="coda"><h3>Coda</h3>
|
||
<p>
|
||
<a href="https://validator.w3.org/nu/?doc=https%3A%2F%2Fioccc-src.github.io%2Ftemp-test-ioccc%2F1998%2Ffanf%2Findex.html" rel="nofollow">Nu HTML check this web page</a><br>
|
||
<a href="#top">Jump to top</a> <a href="#content">Jump to Content</a> <a href="#inventory">Jump to Inventory</a><br>
|
||
</p>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- END: this line ends content from: inc/footer.inventory.html -->
|
||
<!-- START: this line starts content from: inc/bottom.default.html -->
|
||
|
||
</body>
|
||
</html>
|
||
|
||
<!-- END: this line ends content from: inc/bottom.default.html -->
|