Update 1993 winning entries' README.md files

Format and typo fixes. Starting with this year I actually did more
thorough typo fixes. It might be that I did some of this in earlier
years too but I am sure I did it for this year and beyond (at least up
through 1995 .. not sure about years beyond that that I have also
edited). Even so I'll probably want to do another pass through all files
before I can say that the typo issue is resolved. That includes possibly
other files and the worst of all files in my entries.
This commit is contained in:
Cody Boone Ferguson committed 2023-04-14 06:25:34 -07:00
1 parent cf4437c508
commit ee4ee3497d
9 files changed
+360 -298

No files matched your search

+2 -2
View File
@@ -21,7 +21,7 @@ make all
where:
`datafile` is the initial pattern (default: dgibson.data1)
`datafile` is the initial pattern (default: [dgibson.data1](dgibson.data1))
## Try:
@@ -59,7 +59,7 @@ a rectangular grid of cells can be alive or dead, and cells with more
than 3 or less than 2 (out of 8) live neighbours die, and empty cells
with exactly 3 neighbours give birth.
### Some notes:
### Some notes
- the "STAT n" information does not have to be present in the initial
configuration
+36 -30
View File
@@ -1,22 +1,28 @@
# Best Obfuscated Algorithm
E. Jay Berkenbilt
Engineering Research Associates
1595 Springhill Road
Vienna, VA 22182-2235
USA
E. Jay Berkenbilt
Engineering Research Associates
1595 Springhill Road
Vienna, VA 22182-2235
USA
## To build:
make all
```sh
make all
```
## To run:
./ejb level
```sh
./ejb level
```
where:
level a value from -128 to 127
```sh
level a value from -128 to 127
```
## Judges' remarks:
@@ -33,20 +39,22 @@ We note that this also works under macOS just fine.
## Author's remarks
WHAT THIS PROGRAM DOES
======================
### What this program does
### Output solution to Towers of Hanoi for five rings:
#### Output solution to Towers of Hanoi for five rings:
./ejb 5
```sh
./ejb 5
```
The format of the output for the Towers of Hanoi case is simply a
text description of how to solve the puzzle.
### Output solution to the Patience puzzle for six rings:
#### Output solution to the Patience puzzle for six rings:
./ejb -6
```sh
./ejb -6
```
For the patience puzzle, the output is a sequence binary codes representing
@@ -55,8 +63,7 @@ A "1" means the ring is on the U; a "0" means it is off the U. The program
prints the word "Invalid" in response to illegal command line parameters.
MOTIVATION
==========
### Motivation
Most people who have written software for other people have been
asked to count lines of code. Naturally, this brings up the
@@ -66,25 +73,24 @@ always provide a meaningful measure of code size. This is
especially true in this program where the number of semicolons
itself is ambiguous. Does it have two or three? In addition, the
only "C" keyword this program uses besides type names and
qualifiers is "return", and the only function defined in the code
is "main". The level of complexity of the program without multiple
qualifiers is `return`, and the only function defined in the code
is `main`. The level of complexity of the program without multiple
semicolons, statements, and functions is achieved by abusing C
operators, especially the comma operator. Considerable use of ||,
&&, and ? : helps too. In addition, main is called recursively.
The null pointer that terminates argv is used to pass additional
operators, especially the comma operator. Considerable use of `||`,
`&&`, and `? :` helps too. In addition, main is called recursively.
The NULL pointer that terminates argv is used to pass additional
information into main. Even though the algorithms used by this
code are simple, this program is still hard to follow even when
indented properly. (It is pretty hard to indent this code
reasonably, however.)
Although this program is has only been tested on UNIX systems but
will probably run on just about any machine with an ANSI C
compiler. It does not use the C preprocessor at all. The only
functions it uses are atoi, malloc, memset, printf, and puts. It
does, however, require that the architecture it runs on have bytes
that are at least eight bits long and pointers that are at least
four bytes long. In addition, it requires an ANSI compiler since
it uses "signed char" and ANSI-style function declarations.
Although this program has only been tested on UNIX systems it will probably run
on just about any machine with an ANSI C compiler. It does not use the C
preprocessor at all. The only functions it uses are `atoi()`, `malloc()`,
`memset()`, `printf()`, and `puts()`. It does, however, require that the
architecture it runs on have bytes that are at least eight bits long and
pointers that are at least four bytes long. In addition, it requires an ANSI
compiler since it uses "signed char" and ANSI-style function declarations.
## Copyright and CC BY-SA 4.0 License:
+13 -9
View File
@@ -1,14 +1,16 @@
# Most Obfuscated X Program
Jon Thingvold
University of Oslo
Sogn Studentby 8231
N 0858 Oslo
Norway
Jon Thingvold
University of Oslo
Sogn Studentby 8231
N 0858 Oslo
Norway
## To build:
make all
```sh
make all
```
NOTE: this entry requires `X11/Xlib.h` header file and the X11 library to
compile. macOS users running Mountain Lion and later will need to download and
@@ -33,11 +35,13 @@ prepended to them. Thank you Yusuke and Cody for your assistance!
## To run:
./jonth # must be run on an X11 server
```sh
./jonth # must be run on an X11 server
```
## Judges' remarks:
Use 'h' and 'l' to shift objects left or right. Use 'k' to
Use `h` and `l` to shift objects left or right. Use `k` to
rotate and press SPACE to drop.
This program's output may be even more obfuscated when played
@@ -52,7 +56,7 @@ This program is also an example of data abstraction. The X array is
after initialization hidden by the well defined macros `t`, `u` and `F`.
This program is highly portable as it runs on a "Notebook" size SPARC.
This program will not work on machines with `sizeof(int)!=sizeof(void *)`.
This program will not work on machines where `sizeof(int)!=sizeof(void *)`.
## Copyright and CC BY-SA 4.0 License:
+2 -2
View File
@@ -114,14 +114,14 @@ DATA=
TARGET= ${PROG}
#
ALT_OBJ=
ALT_TARGET=
ALT_TARGET= mind
#################
# build the entry
#################
#
all: data ${TARGET}
all: data ${TARGET} ${ALT_TARGET}
@${TRUE}
.PHONY: all alt data everything clean clobber install \
+52 -41
View File
@@ -1,14 +1,16 @@
# Best Game
Leonid A. Broukhis
Moscow Centre of SPARC Technology
123481 Liberty St.,
89-1-95 Moscow
Russia
Leonid A. Broukhis
Moscow Centre of SPARC Technology
123481 Liberty St.,
89-1-95 Moscow
Russia
## To build:
make all
```sh
make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this to work with
modern compilers. Thank you Cody!
@@ -18,19 +20,23 @@ modern compilers. Thank you Cody!
To have the computer guess:
./leo [colors]
```sh
./leo [colors]
```
To guess the computer's number:
./mind [colors]
```sh
./mind [colors]
```
where:
colors number of possible colors (1 to 15) (default: 6)
[colors] is the number of possible colors (1 to 15) (default: 6)
## Judges' remarks:
By default, the number of colors if 6. You may specify a
By default, the number of colors is 6. You may specify a
value of between 1 and 15 colors. See the author's notes
for instructions of how to play.
@@ -39,8 +45,9 @@ International Internet community.
## Author's remarks:
This program plays mastermind, if you call it by a name ending by
'd', otherwise it _solves_ mastermind. Call it without parameters
This program plays
[Mastermind](https://en.wikipedia.org/wiki/Mastermind_(board_game), if you call it by a name ending by
'd', otherwise it _solves_ Mastermind. Call it without parameters
to use 6 digits (colors), or indicate the number of possible digits
(you cannot change the number of positions so easily).
@@ -48,14 +55,14 @@ The number in parentheses is the number of possible combinations,
based on previous questions and answers. If you solve the puzzle,
"(1)" indicates that your previous moves are enough to give correct
answer. If the program acts as solver and terminates prematurely,
it means that you have mistaken in your answers to its guesses.
it means that you're mistaken in your answers to its question(s).
Question marks indicate the number of digits you have to enter
(either 4 when you guess or 2 when computer guesses).
Note that the program uses the same code for both player and
solver, and the only place where it makes difference is the
solver, and the only place where it makes a difference is the
interactive part. Many obfuscations have been made to achieve
this. An expression giving (bulls * 16 + cows) from two numbers
this. An expression giving `(bulls * 16 + cows)` from two numbers
is, however, quite straightforward :-) , as well as the arithmetic
of binary coded colors-base numbers is.
@@ -66,35 +73,39 @@ backspaces. Do "disable scrolling" on cmdtool or similar emulators.
#### Bugs: Please don't type ^D at the prompt!!
##### EXAMPLE: Suppose we think of 1234:
##### EXAMPLE: Suppose we think of 1234
judges-385> leo
(1296): 6433
?? 12 # one 3 is a bull, another is a cow, and 4 is a cow
(160): 5363
?? 02 # both 3's are cows
(21): 4231
?? 22 # 2 and 3 are bulls, 4 and 1 are cows
(2): 4132
?? 13 # 3 is a bull; 1, 2 and 4 are cows
(1): 1234
?? 40 # you may enter everything there
```
judges-385> ./leo
(1296): 6433
?? 12 # one 3 is a bull, another is a cow, and 4 is a cow
(160): 5363
?? 02 # both 3's are cows
(21): 4231
?? 22 # 2 and 3 are bulls, 4 and 1 are cows
(2): 4132
?? 13 # 3 is a bull; 1, 2 and 4 are cows
(1): 1234
?? 40 # you may enter everything there
```
##### EXAMPLE: Guess the computer's number:
##### EXAMPLE: Guess the computer's number
judges-387> mind
(1296): ???? 1122 # my strategy isn't the best, just as example
00
(256): ???? 3344
20
(18): ???? 5566
02
(6): ???? 3654
11
(2): ???? 3355
00
(1): ???? 6444
40 # we have guessed the number
```
judges-387> ./mind
(1296): ???? 1122 # my strategy isn't the best, just as example
00
(256): ???? 3344
20
(18): ???? 5566
02
(6): ???? 3654
11
(2): ???? 3355
00
(1): ???? 6444
40 # we have guessed the number
```
## Copyright and CC BY-SA 4.0 License:
+64 -60
View File
@@ -1,9 +1,9 @@
# Most Versatile Source
Jyrki Holopainen
Oy LM Ericsson Ab
SF-02420 Jorvas
Finland
Jyrki Holopainen
Oy LM Ericsson Ab
SF-02420 Jorvas
Finland
## To build:
@@ -17,23 +17,23 @@ option `-inum` with `find` with the delete option after finding the inode with
`ls -li` or else use a GUI to do it. Should you wish to try compiling it you
might see something like:
NOTE: This will not compile when using modern compilers because
it relies on a compiler bug which was fixed in gcc 2.3.3 (a very
long time ago now).
rm -f \"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c
cp lmfjyh.c \"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c
cc -std=gnu90 -Wall -Wextra -pedantic -include stdio.h -O3 \
\"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c -o lmfjyh
Undefined symbols for architecture arm64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [lmfjyh] Error 1
and the bogus file will be:
";main(){puts("Hello World!");}char*C=".c
```sh
$ make all
NOTE: This will not compile when using modern compilers because
it relies on a compiler bug which was fixed in gcc 2.3.3 (a very
long time ago now).
rm -f \"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c
cp lmfjyh.c \"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c
cc -std=gnu90 -Wall -Wextra -pedantic -include stdio.h -O3 \
\"\;main\(\)\{puts\(\"Hello\ World!\"\)\;\}char\*C=\".c -o lmfjyh
Undefined symbols for architecture arm64:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [lmfjyh] Error 1
```
and the bogus file will be `";main(){puts("Hello World!");}char*C=".c`.
For an explanation of why this is see the author's remarks.
@@ -41,14 +41,16 @@ For an explanation of why this is see the author's remarks.
If you have gcc < 2.3.3:
./lmfjyh
```sh
./lmfjyh
```
## Judges' remarks:
There's more than one way to get around disk quotas. :-)
## Author's remarks;
## Author's remarks:
"Practical and efficient method of compressing source code".
@@ -61,34 +63,36 @@ best with C-source code.
As an example, I have taken a simple "Hello world!" program
that should be familiar to all C-programmers.
Listing 1. A simple "Hello World" program:
#### Listing 1: A simple "Hello World" program
main()
{
puts("Hello World!");
}
```c
main()
{
puts("Hello World!");
}
```
### Packing method
Normally a file name is used only to identify the file,
but this new revolutionary method introduces a totally new concept:
THE FILE NAME IS THE PROGRAM. There is no need to waste
valuable disk space to store source code. The program is
embedded in the file name, only a minor portion of it
is inside the file.
Normally a file name is used only to identify the file, but this new
revolutionary method introduces a totally new concept: THE FILE NAME IS THE
PROGRAM. There is no need to waste valuable disk space to store source code. The
program is embedded in the file name, only a minor portion of it is inside the
file.
Listing 2. Compressed "Hello world":
#### Listing 2: Compressed "Hello world"
char*_=__FILE__;
```c
char*_=__FILE__;
```
Listing 3. Code embedded in the file name:
#### Listing 3: Code embedded in the file name
";main(){puts("Hello World!");}char*C=".c
```c
";main(){puts("Hello World!");}char*C=".c
```
The sample program in listing 1 is 36 bytes long. By using the new
@@ -97,12 +101,12 @@ bytes. In the example the compression ratio is 2:1. It is evident
that the longer the program is, the better the compression ratio
is. The maximum compression ratio in a UNIX environment is 254:16
which equals approximately to 16:1. By using the method a one
megabyte of source code can be compressed to 64 kilobytes.
megabyte of source code file can be compressed to 64 kilobytes.
One might easily think that the program could be compressed to a
single byte by writing a one character long preprocessor directive
in the source file and defining the actual source code in the
command line, eg. 'cc hello.c -DX=main(){puts...'. With this
command line, eg. `cc hello.c -DX='main(){puts ...'`. With this
method nothing is gained, since the compiling commands must be
stored in a file, and that takes even more space than writing the
code in a source file as presented in listing 1.
@@ -111,12 +115,12 @@ code in a source file as presented in listing 1.
### Packing files in a UNIX environment
In a UNIX environment it is possible to write almost any program by
including the code in file names. Since '/' is used to separate
including the code in file names. Since `/` is used to separate
path components and cannot therefore exist in a file name, all
features of C-language cannot be used.
In C, the `/` is used as a division operator and it may also be a
part of a comment start and end identifier. This is, however, not a
part of a comment start and end identifier. This, however, is not a
dangerous limitation, since practice has shown that comments are
almost totally unnecessary. A real programmer can more easily
understand pure source code, and misleading comments are
@@ -127,7 +131,7 @@ when using integers.
Large programs must be separated into small modules. This enforces
people to write better programs, since monolithic programming style
cannot be used. Program development will also be faster, no extra
code need not be recompiled after changes have been made.
code needs be recompiled after changes have been made.
### Usage with currently available tools
@@ -136,30 +140,30 @@ I have tested how well this new method works with currently
available programming tools.
Any ANSI conforming C-compiler that runs under a REAL operating
system should be able to compile the code. (there may be problems
with some older UNIX variants)
system should be able to compile the code (there might be problems
with some older UNIX variants).
### Compilers:
### Compilers
These worked:
gcc versions 2.0, 2.1, 2.3.2 (ld failed at AIX with gcc 2.1)
cc (HP-UX)
cc (VAX)
- gcc versions 2.0, 2.1, 2.3.2 (ld failed at AIX with gcc 2.1)
- cc (HP-UX)
- cc (VAX)
These failed miserably:
cc (SunOs/Solaris) - could not start cpp properly
cc/xlc (AIX) - could not open source
- cc (SunOS/Solaris) - could not start cpp properly
- cc/xlc (AIX) - could not open source
### Other tools:
### Other tools
#### Debuggers: (tested at SunOs 4.1.2)
#### Debuggers: (tested at SunOS 4.1.2)
dbx - Quit with a very 'informative' error message:
"dbx: fatal error: Is a directory"
- dbx - Quit with a very 'informative' error message:
"dbx: fatal error: Is a directory"
gdb - Printed almost the same error message ":Is a directory".
- gdb - Printed almost the same error message ": Is a directory".
It was, however, possible to step through the code but
not list it.
@@ -170,7 +174,7 @@ None of the lints tested environments were able to parse the file.
### Conclusions
The method can be used to compress any types of files, actually the
The method can be used to compress any types of files and the
compression ratios are even better when compressing other files
than C-source. For example plain text files may be compressed with
INFINITE compression ratio. It is trivial task to compress a 100
+21 -17
View File
@@ -1,22 +1,26 @@
# Best One Liner
Mark Plummer
2901 Reckord Road
Fallston, MD, 21047
USA
Mark Plummer
2901 Reckord Road
Fallston, MD, 21047
USA
## To build:
make all
```sh
make all
```
## To run:
./plummer number arg
```sh
./plummer number arg
```
where:
number is a number (try 21701)
arg is any argument
- number is a number (try 21701)
- arg is any argument
### INABIAF - it's not a bug it's a feature :-)
@@ -33,31 +37,31 @@ characters, and why?
This program prints out all numbers up to a given number of digits
on a single line. When the largest number is reached, the program
starts again with 0. It takes two arguments: the first argument
specifies the number to start counting from and uses leading 0's to
specifies the number to start counting from and uses leading `0`s to
indicate the number of digits, the second argument can be anything
but must be present.
Variable names are single characters chosen for their similarity to
other characters (O for 0, l for 1, S for 5 (in some fonts), and _
other characters (O for 0, l for 1, S for 5 in some fonts, and _
for ... well nothing really, but it is easy to miss). To prevent
the need for `strlen()`, the fact that argv is laid out sequentially
is exploited (ie. `argv[i + 1] == argv[i] + strlen(argv[i]) + 1`).
This is not portable (by the books), but it seems to work
everywhere I try (actually, for vms, that only holds for `i > 1`).
everywhere I try (actually, for VMS, that only holds for `i > 1`).
Also, I depend on the fact that a carriage return causes the line
just written to be overwritten. lint (and most compilers) complain
that there is no control path leading to a return from main(). At
just written to be overwritten. `lint` (and most compilers) complain
that there is no control path leading to a return from `main()`. At
125 characters, it still fits on a single line (for those of us who
don't mind ruining our eyes with 132 column screens).
The first statement points the base of `l` (the argument vector) to
be the first argument by incrementing it. It then assigns `O` to
point to the character before the first character of the second
argument which also happens to be the null termination of the first
argument which also happens to be the NULL termination of the first
argument. `*O` gets a `\r` assigned to it. Finally `0` is assigned to
the first character of the second argument which has the effect of
null terminating the first argument after the carriage return had
removed its null termination. I really tried to make the last part
NULL terminating the first argument after the carriage return had
removed its NULL termination. I really tried to make the last part
of that statement part of the original expression, but the best I
could do was attach it with a comma (against the advice of K&R).
The for loop runs the next for loop continuously (actually until
@@ -66,7 +70,7 @@ counting). The next for loop is the meat of the program. In the
initialization statement, the string pointed to by `l` (the first
argument containing the digits used for counting followed by a `\r`)
is printed, and `_` is started at the least significant digit in the
string. In the test portion, `_` is insured not to be past the
string. In the test portion, `_` is ensured not to be past the
beginning of the string (the most significant digit), and the digit
pointed to by `_` is incremented and checked to be sure that it _is_
greater than `9` (written here as `(S+*O+S)*S`). If the test fails,
+34 -23
View File
@@ -9,11 +9,14 @@ USA
## To build:
make all
```sh
make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) made this use `fgets()`
not `gets()` to make it safer and to prevent a warning with linking or at
runtime. Thank you Cody for your assistance!
not `gets()` to make it safer and to prevent an annoying warning with compiling
and/or linking and/or runtime, the latter of which is interspersed with the
output of the program itself. Thank you Cody for your assistance!
## To run:
@@ -23,47 +26,55 @@ where:
file a file containing some text
NOTE: this entry will segfault if the file cannot be opened.
### INABIAF - it's not a bug it's a feature! :-)
This entry will segfault if the file cannot be opened. This is not a bug.
## Try:
./schnitzi schnitzi.info
# ask some questions suggested by the author, noted below
```sh
./schnitzi schnitzi.info
# ask some questions suggested by the author, noted below
```
We also suggest you ask the program:
Who is Mark Schnitzus?
```sh
Who is Mark Schnitzus?
```
Notice how it still manages to answer the question despite there being an
intentional spelling error there.
Try feeding the program source to the program and ask both:
What is cat ?
What is cat?
```sh
What is cat ?
What is cat?
```
## Judges' remarks:
After this program prints the contents of 'file', ask it
some questions related to the text.
The author suggests the following questions when using schnitzi.info:
The author suggests the following questions when using
[schnitzi.info](schnitzi.info):
Who is Mark Schnitzius?
What exactly does this program do?
What language is it written in?
Has the Loch Ness monster really been captured?
Who was Hitler?
Were the NASA moon landings faked?
Is it true that Elvis is alive?
Do colorless green ideas sleep furiously?
- Who is Mark Schnitzius?
- What exactly does this program do?
- What language is it written in?
- Has the Loch Ness monster really been captured?
- Who was Hitler?
- Were the NASA moon landings faked?
- Is it true that Elvis is alive?
- Do colorless green ideas sleep furiously?
We suggest you try using the body (minus the header and signature line)
of a Usenet article. You might want to try something from alt.flame. :-)
NOTE: If you have a ' in the question this entry may fail.
NOTE: If you have a ' in the question this entry might fail.
NOTE: The author may also be contacted at: marks@aldrin.ksc.nasa.gov.
@@ -88,7 +99,7 @@ If you're curious as to how it works, I guess you could feed in the
source as the input file and ask "How does this work?" at the prompt,
but I'm not guaranteeing any results...
### Compilation notes:
### Compilation notes
- The use of 'strcasecmp' may be non-standard. 'strcmp' can be substituted for
it, with a slight performance penalty.
@@ -97,14 +108,14 @@ it, with a slight performance penalty.
argv[0], to hold the name of the executable. It is my understanding that this
property of argv[0] is not guaranteed on some systems.
### Obfuscation:
### Obfuscation
- It uses a hidden string to test for punctuation.
- The layout, variable names, and expression format have been chosen in such a
way as to cause visual confusion.
- It uses uses external 'system' calls to echo the text file and break up the
- It uses uses external `system()` calls to echo the text file and break up the
question into individual words with a recursive call.
- It uses a clever hack to simulate artificial intelligence.
+136 -114
View File
@@ -1,14 +1,16 @@
# Most Irregular Expression
David Van Brackle
ISX Corporation
1165 Northchase Parkway, Suite 120
Marietta, GA 30067
USA
David Van Brackle
ISX Corporation
1165 Northchase Parkway, Suite 120
Marietta, GA 30067
USA
## To build:
make all
```sh
make all
```
[Cody Boone Ferguson](/winners.html#Cody_Boone_Ferguson) fixed this to work with
clang. The problem was that the third arg to main() was not a `char **`. Instead
@@ -18,42 +20,50 @@ right parameters. Thank you Cody for your assistance!
## To run:
./vanb 'exp'
where 'exp' is an octal expression
```sh
./vanb 'exp'
```
where `exp` is an octal expression. See below for how it can also have
hexadecimal and decimal numbers.
## Try:
./vanb 1+1
```sh
./vanb '1+1'
./vanb 4+4
./vanb '4+4'
```
What happens if you use something other than valid digits?
## Judges' remarks:
The octal expression may contain:
unary operators: +, -
binary operators +, -, *, /, %
hex numbers: x or X follow by hex digits
decimal numbers: d or D follow by decimal digits
octal numbers: octal digits
grouping: ()
```
unary operators: +, -
binary operators +, -, *, /, %
hex numbers: x or X follow by hex digits
decimal numbers: d or D follow by decimal digits
octal numbers: octal digits
grouping: ()
```
No spaces are allowed in the expression. To avoid shell expansion,
one should surround the expression in single quotes.
It is a good thing that this program consists of only one
expression, otherwise it might become hard to understand. :-)
## Author's remarks
## Author's remarks:
The program does no error checking - erroneous expressions will
produce spurious results. Note that unary '-' is an operator. Thus,
decimal -46 would be entered as -d46 and not d-46.
produce spurious results. Note that unary `-` is an operator. Thus,
decimal `-46` would be entered as `-d46` and not `d-46`.
What Makes This Program Special:
### What Makes This Program Special:
0. Of course, the fact that the program takes input and produces output in
octal, rather than a more useful system like decimal, makes it "special".
@@ -68,133 +78,145 @@ printf string.
4. The variables are given names which cause visual confusion with the octal
constants.
5. The program is formatted like a roman numeral 8. The significance of 8 is
obvious. I chose roman numerals because it is a numbering system even more
5. The program is formatted like a Roman numeral 8. The significance of 8 is
obvious. I chose Roman numerals because it is a numbering system even more
arcane than octal. It's not very 'deceptive', but it's difficult to deceptively
format a program which has no explicit control structures (other than ?:'s).
format a program which has no explicit control structures (other than `?:`s).
6. Many simple tasks are done many times. I tried to do these differently each
time, to make the program harder to understand.
How It Works:
### How It Works:
It's a recursive descent parser, calling main
for all of its recursion. O2 is a state variable, telling main
It's a recursive descent parser, calling `main`
for all of its recursion. `O2` is a state variable, telling main
what grammar non-terminal to parse. `**O7` is the next character.
`O3` is an intermediate result. Whenever you see a construct like:
```
!(expression with O2)?
```
it's decrementing & testing O2 to see what state it's in. Comparisons
it's decrementing & testing `O2` to see what state it's in. Comparisons
involving `**O7` and octal constants are looking for certain characters.
Here's the grammar ('e' denotes the empty string) :
Here's the grammar `('e'` denotes the empty string) :
<E> ::= <T><E'>
<E'> ::= +<T><E'> | -<T><E'> | e
<T> ::= <F><T'>
<T'> ::= *<F><T'> | /<F><T'> | %<F><T'> | e
<F> ::= +<F> | -<F> | (<E><C> | d<D> | D<D> | x<X> | X<X> | <O>
<C> ::= )
<D> ::= [0-9]<D> | e
<X> ::= [0-9]<X> | [A-F]<X> | [a-f]<X> | e
<O> ::= [0-7]<O> | e
```
<E> ::= <T><E'>
<E'> ::= +<T><E'> | -<T><E'> | e
<T> ::= <F><T'>
<T'> ::= *<F><T'> | /<F><T'> | %<F><T'> | e
<F> ::= +<F> | -<F> | (<E><C> | d<D> | D<D> | x<X> | X<X> | <O>
<C> ::= )
<D> ::= [0-9]<D> | e
<X> ::= [0-9]<X> | [A-F]<X> | [a-f]<X> | e
<O> ::= [0-7]<O> | e
```
Here's how the grammar nonterminals map to octal state numbers:
<E> is 012
<E'> is 011
<T> is 010
<T'> is 07
<F> is 06
<C> is 013
<D> is 04
<X> is 05
<O> is 03
```
<E> is 012
<E'> is 011
<T> is 010
<T'> is 07
<F> is 06
<C> is 013
<D> is 04
<X> is 05
<O> is 03
```
Here's a version of the program before it got formatted into the VIII,
augmented with comments showing where each state begins. N1 and N2 are
augmented with comments showing where each state begins. `N1` and `N2` are
notes:
```c
#define O5 main
O5(O2,O7,O3)char**O7;
{
return
/* N1 */ !(O2+=~01+01) ?
00:
/* N2 */ !(O2-=02>01) ?
printf("\045\157\012",O5(012,O7+01,00)):
/* O */ !(O2-=02>>01) ?
(**O7<=067 && **O7>057 ? O5(03,O7,*(*O7)++-060+010*O3):O3):
/* D */ !(O2-=-O3-~O3) ?
(072>**O7 && 060<=**O7 ? O5(04,O7,012*O3-060+*(*O7)++):O3):
/* X */ !(O2-=!O3+!!O3) ?
(**O7>057 && **O7<=071 ? O5(05,O7,*(*O7)+++O3*020-060):
**O7<=0106 && 0101<=**O7 ? O5(05,O7,020*O3+*(*O7)++-067):
0140<**O7 && **O7<0147 ? O5(05,O7,-0127+*(*O7)+++020*O3):O3):
/* F */ !(O2-=02-01) ?
(**O7==050 ? 050**++*O7,O5(013,O7,O5(012,O7,00)):
**O7<056 && 054<**O7 ? 055**++*O7,-O5(06,O7,00):
054>**O7 && 052<**O7 ? 050**(*O7)++,O5(06,O7,00):
!(**O7^0170)||!(0130^**O7) ? *++*O7,O5(05,O7,00):
**O7==0144||**O7==0104 ? ++*O7,O5(04,O7,00):O5(03,O7,00)):
/* T' */ !--O2 ?
(**O7==052 ? O5(07,O7,O3*(*++*O7,O5(06,O7,00))):
!(045-**O7) ? O5(07,O7,O3%(03+(*O7)++,O5(06,O7,00))):
!(**O7^057) ? O5(07,O7,O3/(03-*++*O7,O5(06,O7,00))):O3):
/* T */ !(O2+=01-02) ?
O5(07,O7,O5(06,O7,00)):
/* E' */ !(O2+=-02/02) ?
(!(**O7-053)?O5(011,O7,O3+(++*O7,O5(010,O7,00))):
!(055^**O7) ? O5(011,O7,O3-(03+*(*O7)++,O5(010,O7,00))):O3):
/* E */ !(O2-=0563&0215) ?
O5(011,O7,O5(010,O7,00)):
/* C */ (++*O7,O3);
}
```
#define O5 main
O5(O2,O7,O3)char**O7;
{
return
/* N1 */ !(O2+=~01+01) ?
00:
/* N2 */ !(O2-=02>01) ?
printf("\045\157\012",O5(012,O7+01,00)):
/* O */ !(O2-=02>>01) ?
(**O7<=067 && **O7>057 ? O5(03,O7,*(*O7)++-060+010*O3):O3):
/* D */ !(O2-=-O3-~O3) ?
(072>**O7 && 060<=**O7 ? O5(04,O7,012*O3-060+*(*O7)++):O3):
/* X */ !(O2-=!O3+!!O3) ?
(**O7>057 && **O7<=071 ? O5(05,O7,*(*O7)+++O3*020-060):
**O7<=0106 && 0101<=**O7 ? O5(05,O7,020*O3+*(*O7)++-067):
0140<**O7 && **O7<0147 ? O5(05,O7,-0127+*(*O7)+++020*O3):O3):
/* F */ !(O2-=02-01) ?
(**O7==050 ? 050**++*O7,O5(013,O7,O5(012,O7,00)):
**O7<056 && 054<**O7 ? 055**++*O7,-O5(06,O7,00):
054>**O7 && 052<**O7 ? 050**(*O7)++,O5(06,O7,00):
!(**O7^0170)||!(0130^**O7) ? *++*O7,O5(05,O7,00):
**O7==0144||**O7==0104 ? ++*O7,O5(04,O7,00):O5(03,O7,00)):
/* T' */ !--O2 ?
(**O7==052 ? O5(07,O7,O3*(*++*O7,O5(06,O7,00))):
!(045-**O7) ? O5(07,O7,O3%(03+(*O7)++,O5(06,O7,00))):
!(**O7^057) ? O5(07,O7,O3/(03-*++*O7,O5(06,O7,00))):O3):
/* T */ !(O2+=01-02) ?
O5(07,O7,O5(06,O7,00)):
/* E' */ !(O2+=-02/02) ?
(!(**O7-053)?O5(011,O7,O3+(++*O7,O5(010,O7,00))):
!(055^**O7) ? O5(011,O7,O3-(03+*(*O7)++,O5(010,O7,00))):O3):
/* E */ !(O2-=0563&0215) ?
O5(011,O7,O5(010,O7,00)):
/* C */ (++*O7,O3);
}
Note N1: It should never enter this state, unless the user invokes the
Note `N1`: It should never enter this state, unless the user invokes the
program with no parameters, in which case it just returns 0.
Note N2: Since the program is properly invoked with 1 parameter, this is
Note `N2`: Since the program is properly invoked with 1 parameter, this is
the first state it will go into. This state just invokes
printf, and sends the parser to state 012 (which is `<E>`).
printf, and sends the parser to state `012` (which is `<E>`).
The E and T states work like this:
The `E` and `T` states work like this:
int e(){ return eprime( t() ); }
```c
int e(){ return eprime( t() ); }
```
The E' and T' states work like this:
The `E'` and `T'` states work like this:
```c
int eprime( int intermediate )
{
if( ch == '+' )
{
ch = nextchar();
return eprime( intermediate + t() );
}
else return intermediate;
}
```
int eprime( int intermediate )
{
if( ch == '+' )
{
ch = nextchar();
return eprime( intermediate + t() );
}
else return intermediate;
}
The `D`, `X` and `O` states work like this (they assume that they're initially
called with `0`):
The D, X and O states work like this (they assume that they're initially
called with 0):
```c
int octal( int intermediate )
{
if( ch>='0' && ch<='7' )
{
intermediate = intermediate * 8 + ch - '0';
ch = nextchar();
return octal( intermediate );
}
else return intermediate;
}
int octal( int intermediate )
{
if( ch>='0' && ch<='7' )
{
intermediate = intermediate * 8 + ch - '0';
ch = nextchar();
return octal( intermediate );
}
else return intermediate;
}
```
F and C work similarly.
`F` and `C` work similarly.
## Copyright and CC BY-SA 4.0 License: