Format fix 2005/mikeash/README.md
This commit is contained in:
1 parent
5176b6429e
commit
7fcacd8b38
1 file changed
+65
-55
+65
-55
@@ -1,8 +1,9 @@
|
||||
# Best use of parenthesis
|
||||
|
||||
Michael Ash
|
||||
US
|
||||
mike@mikeash.com
|
||||
Michael Ash
|
||||
US
|
||||
mike@mikeash.com
|
||||
<https://mikeash.com>
|
||||
|
||||
## To build:
|
||||
|
||||
@@ -23,121 +24,130 @@ make
|
||||
./mikeash < mikeash.c | diff - mikeash.c
|
||||
```
|
||||
|
||||
NOTE: the author stated that they tested this under i386 machines but this works
|
||||
under 64-bit (x86_64, arm64) machines too.
|
||||
|
||||
## Judges' remarks:
|
||||
|
||||
Having problems speaking code? Do you LISP? Parenthetically
|
||||
Having problems speaking code? Do you [LISP][]? Parenthetically
|
||||
speaking, this entry takes advantage of C99 features, while
|
||||
speaking parenthetically. Best of all, it self-reproduces!
|
||||
|
||||
John McCarthy might not of imagined it quite like this! :-)
|
||||
|
||||
[LISP]: https://en.wikipedia.org/wiki/Lisp_(programming_language)
|
||||
|
||||
## Author's remarks:
|
||||
|
||||
This program is a self-reproducing program, which is on the IOCCC's list
|
||||
of discouraged program types. Worse, it's a self-reproducing program
|
||||
written in Common Lisp. What's this doing as an entry to the IOCCC?
|
||||
written in [Common Lisp](https://en.wikipedia.org/wiki/Common_Lisp). What's this
|
||||
doing as an entry to the IOCCC?
|
||||
|
||||
Start over; this program, when compiled with a C99 compiler, is an
|
||||
interpreter for an extremely limited and highly broken subset of Common
|
||||
Lisp.
|
||||
Start over: this program, when compiled with a C99 compiler, is an
|
||||
interpreter for an extremely limited and highly broken subset of [Common
|
||||
Lisp](https://en.wikipedia.org/wiki/Common_Lisp).
|
||||
|
||||
It requires C99 because of C99's ability to declare variables in the
|
||||
It requires C99 because of `C99`'s ability to declare variables in the
|
||||
initializer of a for loop. Unfortunately, C99 mode typically warns about
|
||||
implicitly declared functions, and preprocessor directives prevent the
|
||||
program from being valid Common Lisp. As a result, several warnings will
|
||||
be printed about implicit declarations of functions. There are also
|
||||
warnings about unknown escape sequences in the constant string, due to
|
||||
different string escape semantics in C and Lisp, and some implicit
|
||||
integer-to-pointer conversions due to the implicitly-declared functions.
|
||||
implicitly declared functions, and preprocessor directives prevent the program
|
||||
from being valid [Common Lisp](https://en.wikipedia.org/wiki/Common_Lisp). As a
|
||||
result, several warnings will be printed about implicit declarations of
|
||||
functions. There are also warnings about unknown escape sequences in the
|
||||
constant string, due to different string escape semantics in C and Lisp, and
|
||||
some implicit integer-to-pointer conversions due to the implicitly-declared
|
||||
functions.
|
||||
|
||||
Try:
|
||||
|
||||
```sh
|
||||
echo '(format t "~s" (+ 2 2 ))' | ./lispob
|
||||
echo '(format t "~s" (+ 2 2 ))' | ./mikeash
|
||||
```
|
||||
|
||||
You should see '4"' echoed on your command prompt. The " after the 4 and
|
||||
You should see `4"` echoed on your command prompt. The `"` after the 4 and
|
||||
the lack of a newline are due to the somewhat broken implementation of
|
||||
the format function. More sophisticated arithmetic expressions may be
|
||||
used:
|
||||
|
||||
```sh
|
||||
echo '(format t "~s" (* (+ 2 2 ) (- 5 (/ 9 3 ))))' | ./lispob
|
||||
echo '(format t "~s" (* (+ 2 2 ) (- 5 (/ 9 3 ))))' | ./mikeash
|
||||
```
|
||||
|
||||
This evaluates the expression (2+2) * (5 - 9/3) giving the correct
|
||||
This evaluates the expression `(2+2) * (5 - 9/3)` giving the correct
|
||||
result, 8. Note that due to the highly ad-hoc nature of the tokenizer,
|
||||
the spaces before the closing paretheses are mandatory.
|
||||
the spaces before the closing parentheses are mandatory.
|
||||
|
||||
The program can also be run in an interactive mode, by simply executing
|
||||
./lispob and then typing lisp expressions, but this is difficult due to the
|
||||
`./mikeash` and then typing lisp expressions, but this is difficult due to the
|
||||
lack of proper editing facilities and the total lack of error recovery in the
|
||||
interpreter. Typos will most likely crash the program.
|
||||
|
||||
Aside from being required to put spaces between tokens and closing
|
||||
parentheses, there are other limitations on the dialect of Common Lisp
|
||||
that this program understands:
|
||||
Aside from being required to put spaces between tokens and closing parentheses,
|
||||
there are other limitations on the dialect of [Common
|
||||
Lisp](https://en.wikipedia.org/wiki/Common_Lisp) that this program understands:
|
||||
|
||||
* The only built-in functions are defvar, format, substitute, char-upcase,
|
||||
+, -, *, and /.
|
||||
* The only built-in functions are `defvar`, `format`, `substitute`,
|
||||
`char-upcase`, `+`, `-`, `*`, and `/`.
|
||||
|
||||
* Only one variable is available. This variable is called 'q', although any
|
||||
symbol name starting with the letter 'q' will be mapped to this variable.
|
||||
* Only one variable is available. This variable is called `q`, although any
|
||||
symbol name starting with the letter `q` will be mapped to this variable.
|
||||
|
||||
* Only the first letter of a function name is significant. For example,
|
||||
format, f, farm, and various other words starting with 'f' will all map to the
|
||||
format function.
|
||||
`format`, `f`, `farm`, and various other words starting with `f` will all map to
|
||||
the `format` function.
|
||||
|
||||
* The defvar function completely ignores its first parameter. It will always
|
||||
store the result of evaluating its second parameter in 'q'. Unlike in Common
|
||||
Lisp, multiple invocations of defvar on the same variable will overwrite old
|
||||
values.
|
||||
* The `defvar` function completely ignores its first parameter. It will always
|
||||
store the result of evaluating its second parameter in `q`. Unlike in [Common
|
||||
Lisp](https://en.wikipedia.org/wiki/Common_Lisp), multiple invocations of
|
||||
`defvar` on the same variable will overwrite old values.
|
||||
|
||||
* Character constants are limited to #\Newline and single-character
|
||||
constants such as #\x.
|
||||
* Character constants are limited to `#\Newline` and single-character
|
||||
constants such as `#\x`.
|
||||
|
||||
* The char-upcase function will give strange results if passed something
|
||||
* The `char-upcase` function will give strange results if passed something
|
||||
other than a lowercase character.
|
||||
|
||||
* The format function takes exactly three parameters. The first parameter is
|
||||
ignored; output always goes to stdout. The second parameter must have exactly
|
||||
one ~s format specifier in it, and no other format specifiers are permitted.
|
||||
one `~s` format specifier in it, and no other format specifiers are permitted.
|
||||
|
||||
* The arithmetic functions take exactly two parameters.
|
||||
|
||||
* All tokens must be separated from a following ) by whitespace.
|
||||
* All tokens must be separated from a following `)` by whitespace.
|
||||
|
||||
* A lot of other things. Notably, the language which this program interprets
|
||||
is nowhere near Turing-complete.
|
||||
* A lot of other things. Notably, the language which this program interprets is
|
||||
nowhere near
|
||||
[Turing-complete](https://en.wikipedia.org/wiki/Turing_completeness).
|
||||
|
||||
Basically, the lisp interpreter is good for some basic math operations, and
|
||||
Basically, the [LISP][] interpreter is good for some basic math operations, and
|
||||
for running itself. To do the latter, try this:
|
||||
|
||||
```sh
|
||||
./lispob < lispob.c > lispob2.c
|
||||
diff lispob.c lispob2.c
|
||||
./mikeash < mikeash.c > mikeash2.c
|
||||
diff mikeash.c mikeash2.c
|
||||
```
|
||||
|
||||
The program can also be run from an implementation of common lisp. To do
|
||||
this, run the common lisp compiler and then type the following command:
|
||||
The program can also be run from an implementation of [common
|
||||
lisp](https://en.wikipedia.org/wiki/Common_Lisp). To do
|
||||
this, run the [common lisp compiler and then type the following command:
|
||||
|
||||
```
|
||||
(load "lispob.c")
|
||||
(load "mikeash.c")
|
||||
```
|
||||
|
||||
The source code of lispob.c will be printed.
|
||||
The source code of [mikeash.c](mikeash.c) will be printed.
|
||||
|
||||
Lispob is obfuscated in several ways. First, it's actually two programs
|
||||
`Lispob` is obfuscated in several ways. First, it's actually two programs
|
||||
in one, which actually share a small amount of code. Running a C code
|
||||
beautifier will destroy the lisp program contained within. Second and
|
||||
beautifier will destroy the [LISP][] program contained within. Second and
|
||||
more importantly, it is very badly written, which will presumably
|
||||
confuse people who are used to looking at well-implemented interpreters.
|
||||
|
||||
The program comes in at just under 2k of significant characters.
|
||||
However, this size is exaggerated, because it contains a complete copy
|
||||
of itself for the self-reproducing lisp program, making it twice the
|
||||
size. This doubling effect made it something of a challenge to fit
|
||||
inside the IOCCC's size limit.
|
||||
The program comes in at just under 2k of significant characters. However, this
|
||||
size is exaggerated, because it contains a complete copy of itself for the
|
||||
self-reproducing [LISP](https://en.wikipedia.org/wiki/Turing_completeness)
|
||||
program, making it twice the size. This doubling effect made it something of a
|
||||
challenge to fit inside the IOCCC's size limit.
|
||||
|
||||
This code should be highly portable. It was tested under Mac OS X and
|
||||
Linux on i386, but it should run elsewhere. It requires ASCII due to
|
||||
|
||||
Reference in new issue
Block a user