Updates to 2001/herrmann1
Format fix README.md. There are some missing files - added to bugs.md. Unfortunately they're not in the archive. I'm aware of an issue in the entry to do with more recent compilers. I will be investigating it in the coming days very likely but it might be said that this entry does not work at least in part or maybe in whole. I wrote in the bugs.md that it's in part but now I think on it I think it doesn't work at all and I'll be looking at it soon. Updated .gitignore. Added file that the author referred to and actually gave the contents of. Unfortunately the missing files were not given.
This commit is contained in:
1 parent
0d0c2c4250
commit
49d4f7e69b
5 files changed
+106
-55
No files matched your search
@@ -1 +1,4 @@
|
||||
herrmann1
|
||||
error
|
||||
herrmann1-1.c
|
||||
herrmann1-3.c
|
||||
+74
-53
@@ -1,9 +1,6 @@
|
||||
# Best abuse of the C preprocessor
|
||||
|
||||
Immanuel Herrmann
|
||||
University of Freiburg, Germany
|
||||
Rehlingstr. 17
|
||||
79100 Freiburg
|
||||
Germany
|
||||
<https://web.archive.org/web/20071018081145/http://pcpool.mathematik.uni-freiburg.de/~immi/>
|
||||
|
||||
@@ -16,9 +13,16 @@ make
|
||||
## To run:
|
||||
|
||||
```sh
|
||||
./herrmann1.sh 'prg=file'
|
||||
./herrmann1.sh 'prg=file'
|
||||
```
|
||||
|
||||
NOTE: this entry seems to rely on older versions of gcc for the compilation
|
||||
stage and as such if you wish to see that part like it was designed you will
|
||||
need an older compiler perhaps gcc 2.95.
|
||||
|
||||
NOTE: some files are missing and are not found in the archive either. See
|
||||
[bugs.md](/bugs.md) for more details.
|
||||
|
||||
## Try:
|
||||
|
||||
```sh
|
||||
@@ -64,7 +68,7 @@ be reported nicely. (That's something which is not often seen in
|
||||
IOCCC programs.)
|
||||
|
||||
- Ultra-fast: The resulting C program will print the output in
|
||||
time O(n), where n is the length of the output. This means for
|
||||
time `O(n)`, where `n` is the length of the output. This means for
|
||||
example that you can solve NP hard problems in polynomial time!
|
||||
;-)
|
||||
|
||||
@@ -76,7 +80,7 @@ terminal!
|
||||
|
||||
#### For the impatient
|
||||
|
||||
The info files "herrmann1.turing" and "herrmann1.gcd" are sample
|
||||
The info files `herrmann1.turing` and [herrmann1.gcd](herrmann1.gcd) are sample
|
||||
programs for the Turing machine. For example, type
|
||||
|
||||
```sh
|
||||
@@ -86,6 +90,7 @@ programs for the Turing machine. For example, type
|
||||
and watch the animated Turing machine multiply 8 by two (in
|
||||
unary representation). Here's a screen shot during compilation:
|
||||
|
||||
```
|
||||
/*
|
||||
*
|
||||
* State: st2.
|
||||
@@ -96,58 +101,66 @@ unary representation). Here's a screen shot during compilation:
|
||||
*
|
||||
*
|
||||
*/
|
||||
```
|
||||
|
||||
(As on real videos, you'll see a bit of "white noise" at the
|
||||
beginning and at the end.;-) After compilation has terminated,
|
||||
type ./prog to see the final result. The output will be
|
||||
type `./herrmann1` to see the final result. The output will be
|
||||
|
||||
Final tape:
|
||||
|
||||
```
|
||||
*
|
||||
..OOIIIIIIIIIIIIIIIIOOOO..
|
||||
*
|
||||
```
|
||||
|
||||
(Note that the last frame of the animation is _not_ the final
|
||||
result.)
|
||||
|
||||
|
||||
In the previous example, the Turing machine started on the default
|
||||
tape of the program "times2.turing". To provide your own tape, type
|
||||
tape of the program `times2.turing`. To provide your own tape, type
|
||||
(for example)
|
||||
|
||||
./build prg=times2.turing tape="O O O I I I O O O"
|
||||
```sh
|
||||
./herrmann1 prg=times2.turing tape="O O O I I I O O O"
|
||||
|
||||
(The O's and I's are letters, not digits.) You might prefer to
|
||||
```
|
||||
|
||||
(The `O`s and `I`s are letters, not digits.) You might prefer to
|
||||
provide only a finite portion of the tape, like I did above. In
|
||||
this case, the remainder of the tape is filled with O's. ;-)
|
||||
this case, the remainder of the tape is filled with `O`s. ;-)
|
||||
|
||||
If you just type:
|
||||
|
||||
```
|
||||
./build
|
||||
./herrmann1
|
||||
```
|
||||
|
||||
and run the program, you'll get a usage message (and the return
|
||||
code will be 2).
|
||||
|
||||
Note: To get a really nice animation, you'll need a terminal which
|
||||
is able to scroll fast enough. (xterm is not very good. The
|
||||
kde terminal "konsole" or the text console under linux are much
|
||||
better. Simply try some out.)
|
||||
is able to scroll fast enough. `xterm` is not very good. The
|
||||
KDE terminal `konsole` or the text console under linux are much
|
||||
better. Simply try some out.
|
||||
|
||||
### Writing your own programs
|
||||
|
||||
Now, let's assume you want to write a program which adds 1 to a
|
||||
number in unary representation. (That is, a row of I's is
|
||||
expected, and one more I is appended to the row.) Let's call it
|
||||
"plus1.turing". Here's what it could look like:
|
||||
`plus1.turing`. Here's what it could look like:
|
||||
|
||||
```c
|
||||
/* Search beginning of number. */
|
||||
#define start_O O, right, start
|
||||
/* Number found. Move one step to the left. */
|
||||
#define start_I I, left, st2
|
||||
/* Write a I and stop */
|
||||
#define st2_O I, left, stop
|
||||
```
|
||||
|
||||
Some explanations:
|
||||
- The tape alphabet is always O and I.
|
||||
@@ -172,7 +185,9 @@ O's). For many programs, this doesn't make much sense (as is
|
||||
the case for "plus1.turing"). So you might want to provide a
|
||||
default tape by adding a line like
|
||||
|
||||
```c
|
||||
#define tape O O O O O I I I I
|
||||
```
|
||||
|
||||
to your program.
|
||||
|
||||
@@ -182,11 +197,15 @@ When writing long programs, the most common errors are to forget
|
||||
to define a state or to misspell one. Let's assume you forgot the
|
||||
line
|
||||
|
||||
```c
|
||||
#define start_I I, left, st2
|
||||
```
|
||||
|
||||
Remove it and type
|
||||
|
||||
```sh
|
||||
./herrmann1 'prg=plus1.turing'
|
||||
```
|
||||
|
||||
The output will be
|
||||
|
||||
@@ -194,17 +213,19 @@ Undefined state start.
|
||||
|
||||
Tape:
|
||||
|
||||
```
|
||||
*
|
||||
..OOOOOOOOIIIIOO..
|
||||
*
|
||||
```
|
||||
|
||||
and the return code will be 1. As you can see, the Turing machine
|
||||
moved over the O's, but when it arrived at the I (still in state
|
||||
moved over the O's, but when it arrived at the `I` (still in state
|
||||
start), the error occurred.
|
||||
|
||||
Note that other kinds of errors can cause compilation to fail.
|
||||
If this happens, the build script will write the error message of
|
||||
gcc into a file called "error" and then exit.
|
||||
gcc into a file called `error` and then exit.
|
||||
|
||||
### What the build script does
|
||||
|
||||
@@ -221,28 +242,28 @@ picture won't look right. And second, after some time, the file
|
||||
will grow too big for your hard disk. (The amount of white space
|
||||
grows exponentially.) So after each preprocessing, the first thing
|
||||
the build script does is remove all the unnecessary white space
|
||||
using sed.
|
||||
using `sed`.
|
||||
|
||||
(gcc would even insert #line directives if I didn't suppress
|
||||
them with the -P option.)
|
||||
(gcc would even insert `#line` directives if I didn't suppress
|
||||
them with the `-P` option.)
|
||||
|
||||
### Some more details
|
||||
|
||||
- The arguments passed to the build script are passed on to gcc
|
||||
with a "-D" before. I had a slight technical problem doing this
|
||||
with a `-D` before. I had a slight technical problem doing this
|
||||
(especially with the spaces that can appear within the tape
|
||||
argument). That made the build script a bit longer.
|
||||
|
||||
- It would be enough to pass the defines in the first
|
||||
preprocessing. The program then "remembers" them. However, it
|
||||
doesn't matter if they are passed in all preprocessings. (This
|
||||
doesn't matter if they are passed in all pre-processes. (This
|
||||
doesn't sound very impressive, but it has required some extra
|
||||
lines of code.)
|
||||
|
||||
- During the preprocessing, intermediate files "herrmann1-1.c" and
|
||||
"herrmann1-2.c" are generated.
|
||||
- During the preprocessing, intermediate files `herrmann1-1.c` and
|
||||
`herrmann1-2.c` are generated.
|
||||
|
||||
- Also, a file "error" is generated. This file is removed after
|
||||
- Also, a file `error` is generated. This file is removed after
|
||||
the compilation, except if gcc produced an error; then it contains
|
||||
the error message. (I can't let gcc output all its messages
|
||||
directly, because the warnings would clobber the animation. I
|
||||
@@ -254,7 +275,7 @@ of an error, but I didn't want to make it yet longer.)
|
||||
- The program is compressed. In the first three preprocessing
|
||||
passes, it uncompresses itself and initializes the
|
||||
"variables". So if you want to understand how it works, the best
|
||||
thing is to preprocess it three times and then look at it
|
||||
thing is to pre-process it three times and then look at it
|
||||
again. (However, I wouldn't have wasted three passes if they
|
||||
weren't needed anyway to initialize the tape in certain
|
||||
cases. Find out why.)
|
||||
@@ -268,16 +289,16 @@ easy.
|
||||
|
||||
- The next problem to solve was how to pass results of a
|
||||
calculation of one preprocessing to the next one. This is done
|
||||
by outputting #defines with the result. But there's a problem
|
||||
with this: it is impossible to output a "#define result xxx",
|
||||
where xxx depends on the previous value of result. Try it if you
|
||||
by outputting `#define`s with the result. But there's a problem
|
||||
with this: it is impossible to output a `#define result xxx`,
|
||||
where `xxx` depends on the previous value of result. Try it if you
|
||||
don't believe it. And find out what I did instead.
|
||||
|
||||
- What's a useful way to store information, especially the content
|
||||
of the tape? Of course, a "#define tape OOIOOIOIIIIO" contains
|
||||
of the tape? Of course, a `#define tape OOIOOIOIIIIO` contains
|
||||
the information, but then, how do you access the information?
|
||||
(For example, you won't be able to write preprocessor code which
|
||||
replaces the first O by I.) My answer looks very much like the
|
||||
replaces the first `O` by `I`.) My answer looks very much like the
|
||||
way a stack would have been implemented in lambda calculus. (The
|
||||
tape is implemented as two stacks, to be exact.) And still,
|
||||
there were some technical problems to solve. Look at the program
|
||||
@@ -287,17 +308,17 @@ for more details.
|
||||
to access the information in the user-provided program, the way
|
||||
a non-defined state is detected, the way the picture is
|
||||
produced, etc. If you want a real challenge, try to understand
|
||||
what the line "w j k(P ## x)" does.
|
||||
what the line `w j k(P ## x)` does.
|
||||
|
||||
- Due to the fact that our alphabet has only 53 ;-) letters, I had
|
||||
to use many variables more than once.
|
||||
|
||||
- I couldn't refrain from doing a little bit of nasty stuff like
|
||||
|
||||
#define a 0&0
|
||||
#if !a
|
||||
#define a 0&0
|
||||
#if !a
|
||||
|
||||
Of course, it is a bit more subtle, and even useful.
|
||||
Of course, it is a bit more subtle, and even useful.
|
||||
|
||||
- The layout of the source code..., well, let's call it the
|
||||
"modern art of programming" - a mixture of program-like
|
||||
@@ -310,11 +331,11 @@ indenting and modern art. There are even some comments...
|
||||
of gcc produced "internal compiler errors" (obviously not my
|
||||
fault).
|
||||
|
||||
- The only warnings I get tell me that I'm undefining __FILE__ and
|
||||
- The only warnings I get tell me that I'm undefining `__FILE__` and
|
||||
that preprocessing directives are not recognized within macro
|
||||
args. My answer to this is "yes, I know this and it's all
|
||||
right". With "-Wall", I also get some warnings about "/*"
|
||||
inside comments (Well, _I_ like some well-placed "/*/*/".) as
|
||||
right". With `-Wall`, I also get some warnings about `/*`
|
||||
inside comments (Well, _I_ like some well-placed `/*/*/`.) as
|
||||
well as some suggestions where to place some more parentheses
|
||||
(as if I didn't know the operator precedence).
|
||||
|
||||
@@ -331,31 +352,31 @@ script, so that one does not have to choose "preprocess" from
|
||||
the menu over and over again. I leave this as an exercise to the
|
||||
experienced Mac programmer.)
|
||||
|
||||
- In the build script, I passed the -P option to gcc to suppress
|
||||
the insertion of #line directives. If your compiler doesn't
|
||||
support this option (and does insert #line directives), you
|
||||
should change the call to sed to remove them, too: Add
|
||||
- In the build script, I passed the `-P` option to gcc to suppress
|
||||
the insertion of `#line` directives. If your compiler doesn't
|
||||
support this option (and does insert `#line` directives), you
|
||||
should change the call to `sed` to remove them, too: Add
|
||||
|
||||
-e "/^#line/ d"
|
||||
-e "/^#line/ d"
|
||||
|
||||
to the sed parameters. Or, if your #line directives look like
|
||||
to the sed parameters. Or, if your `#line` directives look like
|
||||
|
||||
# 15 "filename"
|
||||
# 15 "filename"
|
||||
|
||||
add
|
||||
add
|
||||
|
||||
-e "/^# [0-9]/ d"
|
||||
-e "/^# [0-9]/ d"
|
||||
|
||||
instead.
|
||||
instead.
|
||||
|
||||
- First, I had "-ansi -pedantic" turned on, but on some systems,
|
||||
the stdio.h is not compatible to that, so I turned it back off.
|
||||
- First, I had `-ansi -pedantic` turned on, but on some systems,
|
||||
the `stdio.h` is not compatible to that, so I turned it back off.
|
||||
|
||||
- The build script probably needs a bash to run in. So perhaps you
|
||||
have to add "#!/bin/bash" or something like this at the
|
||||
have to add `#!/bin/bash` or something like this at the
|
||||
beginning.
|
||||
|
||||
- On SunOS, I had to remove the "-q" option from diff in the build
|
||||
- On SunOS, I had to remove the `-q` option from diff in the build
|
||||
script.
|
||||
|
||||
## Copyright and CC BY-SA 4.0 License:
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
name=herrmann1
|
||||
|
||||
# Make sure things are clean to start with...
|
||||
rm -f ${name} ${name}-1.c ${name}-2.c ${name}-3.c
|
||||
#rm -f ${name} ${name}-1.c ${name}-2.c ${name}-3.c
|
||||
set -x
|
||||
|
||||
defs=""
|
||||
for p in ${1+"$@"}; do
|
||||
@@ -26,4 +27,4 @@ eval ${CC:-cc} ${name}-1.c -o ${name} 2> error && rm error
|
||||
eval ./${name}
|
||||
|
||||
# Clean up intermediates...
|
||||
rm -f ${name}-1.c ${name}-2.c ${name}-3.c
|
||||
#rm -f ${name}-1.c ${name}-2.c ${name}-3.c
|
||||
@@ -0,0 +1,7 @@
|
||||
/* Search beginning of number. */
|
||||
#define start_O O, right, start
|
||||
/* Number found. Move one step to the left. */
|
||||
#define start_I I, left, st2
|
||||
/* Write a I and stop */
|
||||
#define st2_O I, left, stop
|
||||
|
||||
@@ -1078,6 +1078,25 @@ This program will very likely crash or do something different without an arg.
|
||||
|
||||
This program deliberately crashes if it loses (which is what it aims to do).
|
||||
|
||||
## [2001/herrmann1](2001/herrmann1/herrmann1.c) ([README.md](2001/herrmann1/README.md)
|
||||
## STATUS: missing files - please provide them
|
||||
|
||||
The author referred to the file `herrmann1.turing` but it does not exist not even
|
||||
in the archive. Do you have a copy? Please provide it!
|
||||
|
||||
## STATUS: missing files - please provide them
|
||||
|
||||
The author also referred to the file `times2.turing` but this is also missing in
|
||||
the archive. Do you have a copy? Please provide it!
|
||||
|
||||
|
||||
## STATUS: known bug - please help us fix
|
||||
|
||||
There is also a bug in part. During compilation you're supposed to see some
|
||||
animation but this does not seem to work with modern gcc versions. It appears
|
||||
that version 2.95 works but maybe others do as well. Do you have a fix? We would
|
||||
appreciate your help!
|
||||
|
||||
# 2002
|
||||
|
||||
There was no IOCCC in 2002.
|
||||
|
||||
Reference in new issue
Block a user