[comp.std.c] Portable Self-Replicating C Contest

karl@haddock.ima.isc.com (Karl Heuer) (03/24/89)

In article <2976@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>To me, the really interesting problem is, Write a _portable_
>program which writes its source code exactly.

Well, it happens that I was going to post this anyway...

*** Portable Self-Replicating C Contest ***

Rules:
0.  The output of the program must be its own source code.
1.  It may not be safely assumed that the source code resides in an openable
    file at runtime.
2.  The program must be written in Strictly Conforming ANSI C.
3.  The program must return a proper exit status, indicating whether or not
    its output-calls succeeded.
4.  The source must use only the ISO 646 character set, using trigraphs as
    needed.
5.  No source line may exceed 72 characters.
6.  There will be two winners: the first correct program to arrive at my site,
    and the shortest (measured in source characters, including newlines).  The
    contest ends on 23-Apr-1989.  No prizes will be awarded.

The rationale for rules 4 and 5 is that I want to distribute the result on
punch-cards.  :-)

I will be the sole judge, and my interpretation of the rules is final.  (You
might not like trigraphs, but it makes the puzzle more challenging.)  Appeals
will be allowed on the question of whether a construct is legal Strictly
Conforming ANSI C; the pANS should be the final authority here.

Be warned that rule 2 will be observed to the letter.  For example, if you
invoke the variadic function printf(), there must be a prototype in scope
(either explicitly declared in the code, or via including <stdio.h>).

Followups to comp.std.c only.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
(Why 72?  The last eight columns are reserved for possible addition of a card
sequence number at some future date.)

uucibg@sw1e.UUCP (3929]) (03/24/89)

In article <12144@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>Well, it happens that I was going to post this anyway...
>
>*** Portable Self-Replicating C Contest ***
>
>Rules:
>0.  The output of the program must be its own source code.

          [ More of the rules of the contest ]

>Followups to comp.std.c only.
>
>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
>(Why 72?  The last eight columns are reserved for possible addition of a card
>sequence number at some future date.)

This is a good opportunity for me to ask a question that's been bugging me for
quite a while:

It seems that it would be impossible to create a program which generates it's
source as output because you have a self-referential system and will end up
with an infinite recursion.  I guess this presumes that you can't go out to
the operating system to do things, since then it's not a strictly self-refer-
ential system.  I note that this contest doesn't prevent you from going to the
operating system, it simply prevents you from opening the source file and
printing it out (that rule was in part of the text I deleted...sorry). But:

Isn't it impossible for a C program to replicate itself if it doesn't access
the operating system (other than printing to stdout)?  The question of whether
it can be done while *using* the OS should come out of this contest so I'll
wait patiently...

By the way, please forgive me if this all seems trivially true/false...but
please enlighten me.


Brian R. Gilstrap                          Southwestern Bell Telephone
One Bell Center Rm 17-G-4                  ...!ames!killer!texbell!sw1e!uucibg
St. Louis, MO 63101                        ...!bellcore!texbell!sw1e!uucibg
(314) 235-3929
#include <std_disclaimers.h>

geoff@tom.harvard.edu (Geoff Clemm) (03/26/89)

Here is an old self-replicating program I did a while back ... no attempt
was made to make the program short.  It may not be ansi but it should be
trivial to make it so.

------------  cut here -----------------
char *text =
"\n\
#include <stdio.h>\n\
main()\n\
{\n\
   (void)printf(\"char *text =\\n\\\"\");\n\
   out(text);\n\
   (void)printf(\"\\\";\\n%s\\n\", text); exit(0);};\n\
\n\
out(s)\n\
   char *s;\n\
{\n\
   while (*s != 0) {\n\
      if (*s == '\\n') (void)printf(\"\\\\n\\\\\");\n\
      if (*s == '\\\\' || *s == '\"') (void)putchar('\\\\');\n\
      (void)putchar(*s); s += 1; };};\n\
";

#include <stdio.h>
main()
{
   (void)printf("char *text =\n\"");
   out(text);
   (void)printf("\";\n%s\n", text); exit(0);};

out(s)
   char *s;
{
   while (*s != 0) {
      if (*s == '\n') (void)printf("\\n\\");
      if (*s == '\\' || *s == '"') (void)putchar('\\');
      (void)putchar(*s); s += 1; };};

------------  cut here -----------------

Geoff Clemm
geoff@harvard.harvard.edu

jdchrist@watcgl.waterloo.edu (Dan Christensen) (03/27/89)

In article <12144@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>*** Portable Self-Replicating C Contest ***
>
>Rules:
>4.  The source must use only the ISO 646 character set, using trigraphs as
>    needed.
>
>(You might not like trigraphs, but it makes the puzzle more challenging.)
>
>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

Sorry if this is trivial, but what is the ISO 646 character set and what
are trigraphs?

----
Dan Christensen, Computer Graphics Lab,	         jdchrist@watcgl.uwaterloo.ca
University of Waterloo, Waterloo, Ont.	         jdchrist@watcgl.waterloo.edu

gwyn@smoke.BRL.MIL (Doug Gwyn ) (03/27/89)

In article <1417@sw1e.UUCP> uucibg@sw1e.UUCP (Brian Gilstrap [5-3929]) writes:
>It seems that it would be impossible to create a program which generates it's
>source as output because you have a self-referential system and will end up
>with an infinite recursion.

Nope.  If you try to make that line of reasoning precise you'll find
gaps in the logic.  In fact self-replicating systems can be quite small.
Self-reference need not imply infinite recursion, and self-replication
need not imply self-reference.

utoddl@ecsvax.UUCP (Todd M. Lewis) (03/27/89)

In article <9929@smoke.BRL.MIL>, gwyn@smoke.BRL.MIL (Doug Gwyn ) writes:
> In article <1417@sw1e.UUCP> uucibg@sw1e.UUCP (Brian Gilstrap [5-3929]) writes:
> >It seems that it would be impossible to create a program which generates it's
> >source as output because you have a self-referential system and will end up
> >with an infinite recursion.
> 
> Nope.  If you try to make that line of reasoning precise you'll find
> gaps in the logic.  In fact self-replicating systems can be quite small.
> Self-reference need not imply infinite recursion, and self-replication
> need not imply self-reference.

That's a bit theoretical.  If it doesn't convince you, try
thinking about it this way.  Most programs that will be submitted
will use some form of put or printf call, yet the source to
printf will not be printed.  The point is that it could be.
Think of the token "printf" as expanding to the entire source
to printf.  The program would still work, but the string produced
by the program would have to be longer.  That may make it more
tricky, but not any harder, er, theoretically.  Note also that this
printf need not use the OS, but could go right to the hardware
so that it could work without any OS at all.  (How it would have
gotten into the machine is another question.)
   Now that the magic is done, consider this: this program will
only work on specific hardware.  You have to consider this because
each op-code is in fact "expanded" to the hardware design that
supports it, just as printf is expanded on a higher level.  Programs
can only reproduce themselves in a suitable environment.  (That goes
for lizards, fish, people, and other self-replicating systems.)
   So work back from this perspective to our self-replicating
program and you will see that the OS and library routines and
the hardware all work together to create an environment in which
our programs can "live" (dont take this too far..) and in which
some programs can reproduce.
   You are right in thinking that programs can't really reproduce
without some greater reference capabilities.  Self-replicating
systems rely heavily on building on the structure of their
environments, whether that means computer op-codes and address
spaces or atoms and the Universe.  The "meaning" of our programms'
op-codes derives from the hardware.

   Now, about that entropy thingy ... :)

  _____        
    |      Todd M. Lewis            Disclaimer: If you want my employer's
    ||\/|  utoddl@ecsvax.uncecs.edu             ideas, you'll have to
    ||  ||                                      _buy_ them. 
     |  ||     
         |___   (Never write a program bigger than your screen.)

hearn@claris.com (Bob Hearn) (03/28/89)

From article <1417@sw1e.UUCP>, by uucibg@sw1e.UUCP (3929]):
> In article <12144@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
>>Well, it happens that I was going to post this anyway...
>>
>>*** Portable Self-Replicating C Contest ***
>>
>>Rules:
>>0.  The output of the program must be its own source code.
> 
>           [ More of the rules of the contest ]
> 
>>Followups to comp.std.c only.
>>
>>Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
>>(Why 72?  The last eight columns are reserved for possible addition of a card
>>sequence number at some future date.)
> 
> This is a good opportunity for me to ask a question that's been bugging me for
> quite a while:
> 
> It seems that it would be impossible to create a program which generates it's
> source as output because you have a self-referential system and will end up
> with an infinite recursion.  I guess this presumes that you can't go out to
> the operating system to do things, since then it's not a strictly self-refer-
> ential system.  I note that this contest doesn't prevent you from going to the
> operating system, it simply prevents you from opening the source file and
> printing it out (that rule was in part of the text I deleted...sorry). But:
> 
> Isn't it impossible for a C program to replicate itself if it doesn't access
> the operating system (other than printing to stdout)?  The question of whether
> it can be done while *using* the OS should come out of this contest so I'll
> wait patiently...
> 
> By the way, please forgive me if this all seems trivially true/false...but
> please enlighten me.
> 
> 
> Brian R. Gilstrap                          Southwestern Bell Telephone
> One Bell Center Rm 17-G-4                  ...!ames!killer!texbell!sw1e!uucibg
> St. Louis, MO 63101                        ...!bellcore!texbell!sw1e!uucibg
> (314) 235-3929
> #include <std_disclaimers.h>

hearn@claris.com (Bob Hearn) (03/28/89)

Oops... sorry.  Stupid mailer sent the wrong file.  One more time...

> Isn't it impossible for a C program to replicate itself if it doesn't access
> the operating system (other than printing to stdout)?  The question of whether
> it can be done while *using* the OS should come out of this contest so I'll
> wait patiently...
> 
> By the way, please forgive me if this all seems trivially true/false...but
> please enlighten me.

No, it's not impossible... the basic idea is to write a program that means
the equivalent of:

Write the following quotation, then write it again, quoted: "Write the 
following quotation, then write it again, quoted:"

Bob Hearn
hearn@claris.com

dhesi@bsu-cs.UUCP (Rahul Dhesi) (03/28/89)

In article <9201@claris.com> hearn@claris.com (Bob Hearn) writes:
   Write the following quotation, then write it again, quoted: "Write
   the following quotation, then write it again, quoted:"

Tell me to tell you to do what I just did.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi
                    ARPA:  dhesi@bsu-cs.bsu.edu

huxtable@kuhub.cc.ukans.edu (Kathryn Huxtable) (04/01/89)

char a[] = "char a[] = %c%s%c; main() { printf( a, 34, a, 34 ); }"; main() {
printf( a, 34, a, 34 ); }

Of course, all this has to be on one long line.

Kathryn Huxtable
huxtable@kuhub.cc.ukans.edu

karl@haddock.ima.isc.com (Karl Heuer) (04/08/89)

I've received several contest entries by mail.  Our gateway has been flakey,
so if you haven't gotten a response, try again.  I reply to each entry.

My reply has almost become a form letter, since I keep seeing the same
mistakes.  So I guess it's time for a followup.  Here are the rules from my
original article:

>0.  The output of the program must be its own source code.
>1.  It may not be safely assumed that the source code resides in an openable
>    file at runtime.
>2.  The program must be written in Strictly Conforming ANSI C.
>3.  The program must return a proper exit status, indicating whether or not
>    its output-calls succeeded.
>4.  The source must use only the ISO 646 character set, using trigraphs as
>    needed.
>5.  No source line may exceed 72 characters.
>6.  There will be two winners: the first correct program to arrive at my site,
>    and the shortest (measured in source characters, including newlines).  The
>    contest ends on 23-Apr-1989.  No prizes will be awarded.

Note rule 3.  Output calls can fail (e.g. disk full); the program must detect
this condition and return the value EXIT_FAILURE to the execution environment.
This constant is defined in <stdlib.h>, which must therefore be included.

Note rule 4 especially.  The nine characters   # ^ ~ { | } [ \ ]  are not
allowed to appear in the source; you must use the trigraph equivalents   ??=
??' ??- ??< ??! ??> ??( ??/ ??)   instead.  Only one entrant has observed this
rule so far!

I should also point out that assumptions such as '"'==34 are an artifact of
the ASCII character set, which a strictly conforming program may not rely on.

I use the enclosed shell script as a preliminary test.  If you don't have
<stdlib.h>, or if your compiler doesn't understand trigraphs, you might find
it useful.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
________
#!/bin/sh
# Accepts a program by file name, or on standard input.
PATH=/bin:/usr/bin:/usr/ucb; export PATH
E=2; T=/tmp/$$self.d; trap 'rm -rf $T; trap 0; exit $E' 0 1 2 3 15
mkdir $T; cat $1 >$T/self.src; cd $T
if [ `tr -cd '#^~[\\]{|}' <self.src | wc -c` != 0 ]; then
    echo 'bad character set'; E=1
fi
awk '{if (length>72) {print "too wide"; exit 1}}' <self.src || E=1
if grep printf <self.src >/dev/null; then
    if egrep '\.\.\.|stdio' <self.src >/dev/null; then :; else
	echo 'printf not declared'; E=1
    fi
fi
sed -e "s/??=/#/g" -e "s/??'/^/g" -e "s/??!/|/g" -e "s/??-/~/g" \
	 -e "s/??</{/g" -e "s/??>/}/g" -e "s/??(/[/g" -e "s/??)/]/g" \
	 -e 's;??/;\\;g' <self.src >self.c
cat <<\! >stdlib.h
#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1
!
${CC-/bin/cc} -I. self.c -o self && ./self | cmp - self.src || E=1
if [ "$E" = "2" ]; then echo 'looks good'; E=0; fi

huxtable@kuhub.cc.ukans.edu (Kathryn Huxtable) (04/08/89)

Jerry Schwarz <jss@ulysses.att.com> writes (through E-Mail):
> In article <4244@kuhub.cc.ukans.edu> you write:
> >char a[] = "char a[] = %c%s%c; main() { printf( a, 34, a, 34 ); }"; main() {
> >printf( a, 34, a, 34 ); }

> Not portable.  The code for " does not have to be 34.

I answered with a variant of the following:

Aw....You're right, of course.  No one has pointed out that it doesn't
print a trailing newline, either.  Actually, Stan Switzer at
sjs@bellcore.whatever_it_is has made a study of what he calls "Quine"
programs.

He calls them Quine programs after Willard van Orman Quine, who said:
"Yields falsehood when preceded by itself in quotations," yields
falsehood when preceded by itself in quotations.

Stan had a program when he was a student here at KU (1981) which was
extremely clean.  It wasn't particularly terse, though.  I say clean,
because the method generalized to a program of arbitrary complexity.

-Kathryn Huxtable
huxtable@kuhub.cc.ukans.edu

Reconstructing from memory:

-------------------------  Cut here  -------------------------
/*
 *  Quine -- Self replicating program.
 *
 *  Just compile, link and go.
 *
 *  Written by Kathryn Huxtable, after a memory of a similar
 *  program written by Stan Switzer.
 */

#include <stdio.h>

char *first[] = {
        "/*",
        " *  Quine -- Self replicating program.",
        " *",
        " *  Just compile, link and go.",
        " *",
        " *  Written by Kathryn Huxtable, after a memory of a similar",
        " *  program written by Stan Switzer.",
        " */",
        "",
        "#include <stdio.h>",
        NULL
};

char *last[] = {
        "/*",
        " *  Print a vector of lines one line at a time.",
        " */",
        "",
        "print_norm( char *lines[] )",
        "{",
        "        int     i;",
        "",
        "        for( i = 0; lines[i] != NULL; i++ )",
        "                printf( \"%s\\n\", lines[i] );",
        "",
        "}       /*  print_norm  */",
        "",
        "",
        "/*",
        " *  Print a quoted string, enclosing it in quotes",
        " *  and escaping quote and backslash.",
        " */",
        "",
        "puts_quoted( char *str )",
        "{",
        "        int     i;",
        "",
        "        putchar( '\"' );",
        "",
        "        for( i = 0; str[i] != '\\0'; ++i ) {",
        "                if( str[i] == '\"' || str[i] == '\\\\' )",
        "                        putchar( '\\\\' );",
        "                putchar( str[i] );",
        "        }",
        "",
        "        putchar( '\"' );",
        "",
        "}       /*  puts_quoted  */",
        "",
        "",
        "/*",
        " *  Print a vector of lines, in the format",
        " *  in which it was declared.",
        " */",
        "",
        "print_quoted( char *name, char *lines[] )",
        "{",
        "        int     i;",
        "",
        "        printf( \"char *%s[] = {\\n\", name );",
        "",
        "        for( i = 0; lines[i] != NULL; i++ ) {",
        "                printf( \"        \" );",
        "                puts_quoted( lines[i] );",
        "                printf( \",\\n\" );",
        "        }",
        "",
        "        printf( \"        NULL\\n\" );",
        "        printf( \"};\\n\" );",
        "        printf( \"\\n\" );",
        "",
        "}       /*  print_quoted  */",
        "",
        "",
        "/*",
        " *  Print a copy of my source, reconstructed",
        " *  from the vectors first and last.",
        " */",
        "",
        "main()",
        "{",
        "        print_norm( first );",
        "        printf( \"\\n\" );",
        "        print_quoted( \"first\", first );",
        "        print_quoted( \"last\", last );",
        "        printf( \"\\n\" );",
        "        print_norm( last );",
        "",
        "}       /*  main  */",
        NULL
};


/*
 *  Print a vector of lines one line at a time.
 */

print_norm( char *lines[] )
{
        int     i;

        for( i = 0; lines[i] != NULL; i++ )
                printf( "%s\n", lines[i] );

}       /*  print_norm  */


/*
 *  Print a quoted string, enclosing it in quotes
 *  and escaping quote and backslash.
 */

puts_quoted( char *str )
{
        int     i;

        putchar( '"' );

        for( i = 0; str[i] != '\0'; ++i ) {
                if( str[i] == '"' || str[i] == '\\' )
                        putchar( '\\' );
                putchar( str[i] );
        }

        putchar( '"' );

}       /*  puts_quoted  */


/*
 *  Print a vector of lines, in the format
 *  in which it was declared.
 */

print_quoted( char *name, char *lines[] )
{
        int     i;

        printf( "char *%s[] = {\n", name );

        for( i = 0; lines[i] != NULL; i++ ) {
                printf( "        " );
                puts_quoted( lines[i] );
                printf( ",\n" );
        }

        printf( "        NULL\n" );
        printf( "};\n" );
        printf( "\n" );

}       /*  print_quoted  */


/*
 *  Print a copy of my source, reconstructed
 *  from the vectors first and last.
 */

main()
{
        print_norm( first );
        printf( "\n" );
        print_quoted( "first", first );
        print_quoted( "last", last );
        printf( "\n" );
        print_norm( last );

}       /*  main  */

dhesi@bsu-cs.bsu.edu (Rahul Dhesi) (04/09/89)

In article <12593@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
writes:
>The nine characters   # ^ ~ { | } [ \ ]  are not
>allowed to appear in the source; you must use the trigraph equivalents   ??=
>??' ??- ??< ??! ??> ??( ??/ ??)   instead.

(I'm ??xorry, my ??x key i??x broken, ??xo I'm ??xub??xtituting the
trigraph ??x in it??x place.)

I'm curiou??x to know:  What i??x the purpo??xe of the rule above?  All
it will do i??x make ??xubmitted program??x harder to read, and nearly
impo??x??xible to make ??xen??xe of in a ca??xual ??xcan.
-- 
Rahul Dhesi <dhesi@bsu-cs.bsu.edu>
UUCP:    ...!{iuvax,pur-ee}!bsu-cs!dhesi

friedl@vsi.COM (Stephen J. Friedl) (04/10/89)

In article <6647@bsu-cs.bsu.edu>, dhesi@bsu-cs.bsu.edu (Rahul Dhesi) writes:
> 
> (I'm ??xorry, my ??x key i??x broken, ??xo I'm ??xub??xtituting the
> trigraph ??x in it??x place.)
> 
> I'm curiou??x to know:  What i??x the purpo??xe of the rule above?  All
> it will do i??x make ??xubmitted program??x harder to read, and nearly
> impo??x??xible to make ??xen??xe of in a ca??xual ??xcan.

I really like Rahul's point here and wish to talk to him about
it, but mail to "dhe??xi@b??xu-c??x.b??xu.edu" keeps bouncing.
Any ideas?

     Steve :-)

-- 
Stephen J. Friedl / V-Systems, Inc. / Santa Ana, CA / +1 714 545 6442 
3B2-kind-of-guy   / friedl@vsi.com  / {attmail, uunet, etc}!vsi!friedl

"I do everything in software, even DMA" - Gary W. Keefe (garyk@telxon)

karl@haddock.ima.isc.com (Karl Heuer) (04/11/89)

In article <6647@bsu-cs.bsu.edu> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
>In article <12593@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
>writes [that contest entries must use trigraphs]
>
>I'm curious to know:  What is the purpose of the rule above?  All
>it will do is make submitted programs harder to read, and nearly
>impossible to make sense of in a casual scan.

It makes the problem more challenging.  Note that a program which satisfies
all of the rules except this one is not self-reproducing after a naive
conversion to trigraphs, because `printf("??=")' will output `#', not `??='.
(One correct fix is to use `printf("?\?=")', but since `\' is itself a
trigraphable character, this must be written `printf("???/?=")'!)

Yes, it's hard to read, but one pass through a detrigraphing sed script will
fix that, as I did with your text before quoting it above.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

diamond@diamond.csl.sony.junet (Norman Diamond) (04/13/89)

In article <12629@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
[about the rule that contest entries must use trigraphs]
> It makes the problem more challenging.  Note that a program which satisfies
> all of the rules except this one is not self-reproducing after a naive
> conversion to trigraphs, because `printf("??=")' will output `#', not `??='.

Yes indeed, such conversions take place even in strings.  I wonder how
such programs execute in environments that don't have a '#' character.

Norman Diamond, Sony Computer Science Lab (diamond%csl.sony.jp@relay.cs.net)
  The above opinions are my own.   |  Why are programmers criticized for
  If they're also your opinions,   |  re-inventing the wheel, when car
  you're infringing my copyright.  |  manufacturers are praised for it?

dhe??xi@b??xu-c??x.b??xu.edu (Rahul Dhe??xi) (04/14/89)

In article <12629@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
writes:
>(One correct fix is to use `printf("?\?=")', but since `\' is itself a
>trigraphable character, this must be written `printf("???/?=")'!)
                                                       ^^^^^^
This seems awfully difficult for a lexical analyzer to handle, and
perhaps illustrates my point again.  (Isn't ? itself a trigraph
character, at least when ambiguity requires it?)

As a sporting gesture, would you be willing to repost the contest
rules, this time using trigraphs only in place of the offending
symbols?  If that doesn't make my point, nothing will.

Rahul Dhe??xi <dhe??xi@b??xu-c??x.b??xu.edu>
UUCP:    ...!{iuvax,pur-ee}!b??xu-c??x!dhe??xi

david@dhw68k.cts.com (David H. Wolfskill) (04/16/89)

In article <6756@bsu-cs.bsu.edu> dhesi@bsu-cs.bsu.edu (Rahul Dhesi) writes:
>In article <12629@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer)
>writes:
>>(One correct fix is to use `printf("?\?=")', but since `\' is itself a
>>trigraphable character, this must be written `printf("???/?=")'!)
>                                                       ^^^^^^
>This seems awfully difficult for a lexical analyzer to handle, and
>perhaps illustrates my point again.  (Isn't ? itself a trigraph
>character, at least when ambiguity requires it?)

No, '?' is *not* representable by a trigraph sequence.  Section 2.2.1.1
("Trigraph Sequences") reads (in the May 13, 1988 draft):

-=-=-=-=-=-=-=-=-=-=-=

All occurrences in a source file of the following sequences of three
characters (called *trigraph sequences*[5]) are replaced with the
corresponding single character.

	??=	#
	??(	[
	??/	\
	??)	]
	??'	^
	??<	{
	??!	|
	??>	}
	??-	~

No other trigraph sequences exist. Each ? that does not begin one of the
trigraphs listed above is not changed.

Example

	The following source line

		printf("Eh???/n");
	
becomes (after replacement of the trigraph sequence ??/)

		printf("Eh?\n");

-----
5. The trigraph sequences enable the input of characters that are not
   defined in the ISO 646-1983 Invariant Code Set, which is a subset of
   the seven-bit ASCII code set.

-=-=-=-=-=-=-=-=-=-=-=

>As a sporting gesture, would you be willing to repost the contest
>rules, this time using trigraphs only in place of the offending
>symbols?  If that doesn't make my point, nothing will.

I think Karl's rules were clear enough.  As to the trigraphs, I don't
know of anyone who claims that they are aesthetically pleasing; some
mechanism, however, needs to exist for representing characters that do
not exist in an environment's character set (unless, of course, X3J11
had been willing to banish folks in such circumstances to a C-less
existence).  To quote Douglas Adams (note "Adams," not "Gwyn") "You
were quite entitled to make any suggestions or protests at the
appropriate time, you know."

david
-- 
David H. Wolfskill
uucp: ...{spsd,zardoz,felix}!dhw68k!david	InterNet: david@dhw68k.cts.com

karl@haddock.ima.isc.com (Karl Heuer) (04/28/89)

# Compilation Copyright (c) 1989 by Karl Heuer.  I don't care what you do with
# this article, but the right to resubmit these programs to the IOCCC remains
# with the original authors.

#!/bin/sh
: run this file through sh to unbundle
:    README scjones diomidis
cat <<\--------cut-------- >README
Well, the contest is over, and here are the results.  For those of you who
missed the beginning of this, the challenge was to write a self-reproducing
program which is strictly pANS-conforming (to the letter!), had a proper exit
status, was no more than 72 characters wide, and used only the characters in
ISO 646 (using trigraphs as needed).  (I should also have had a rule against
using any obsolescent feature, but I didn't think of that in time.)  To the
best of my knowledge, the two enclosed programs were the only entries that
satisfied all of the rules.  If someone still manages to spot a flaw in either
of these, I'll be impressed.

The Early Bird Winner was Larry Jones <scjones@sdrc.UU.NET>.  His entry
demonstrated that I should have said "columns" instead of "characters" in the
width requirement (he used tabs), but that's not important.  (If I'd insisted
on rephrasing the rule, a simple `tr \\11 \\40' would have fixed his entry.)
Note that he didn't resort to printf trickery to construct trigraphs for
output; he just used the straightforward notation like `???/?/'.  I like that.

The winner for shortest program was Diomidis Spinellis <ecrcvax!diomidis>, at
499 characters.  Interestingly enough, there was still some slack here; it
would still be strictly conforming to drop the `int' declaration from main()
and to use 0 rather than EXIT_SUCCESS, for example.  This entry deserves a
special award for the clever use of the `#' operator to do most of the work;
that possibility hadn't occurred to me.  (It should also be pointed out that
this program cannot be directly tested with gcc 1.32, because of a bug in the
gnu preprocessor that was discovered when he submitted an earlier attempt.)

A few other entries were only slightly flawed, and probably could have been
fixed if the deadline hadn't expired first.  I apologize for the sometimes
long turnaround time on reporting such flaws; besides my having other business
to take care of, we had severe problems with our mail gateway.  (I considered
extending the duration of the contest as a sporting gesture, but I'm getting
rather tired of this.  If you want to improve on these, you can do it without
my help.)

When I first thought about this puzzle, I was thinking in terms of the simple
program (shown here folded)
	char*f="char*f=%c%s%c;main(){printf(f,34,f,34,10);}%c";\
	main(){printf(f,34,f,34,10);}
and wondered how much effort it would be to make it portable.  After fixing
the hardcoded ASCII values, entrigraphing, adding required headers, and
checking the exit status, the program had grown to:
	??=include<stdlib.h>
	??=include<stdio.h>
	char*f="?%c=include<stdlib.h>%c?%c=include<stdio.h>%cchar*f=%c%s%c,\
	t='?',n='?%c/n',q='%c';main()?%c<exit(printf(f,t,n,t,n,q,f,q,t,q,t,\
	t,n)<0?EXIT_FAILURE:0);?%c>%c",t='?',n='??/n',q='"';main()??<exit(p\
	rintf(f,t,n,t,n,q,f,q,t,q,t,t,n)<0?EXIT_FAILURE:0);??>
and I still needed a way to break up that 255-character third line.  At this
point I gave up on the single-printf approach, though I'd be interested to
hear if anybody can salvage it.
--------cut--------
cat <<\--------cut-------- >scjones
static const char *foo??(??) = ??<
"??=include <stdio.h>??/n",
"??=include <stdlib.h>??/n",
"??/n",
"void out(q, f)??/n",
"	const char *q;??/n",
"	int f;??/n",
"	??<??/n",
"	for (;; q++) ??<??/n",
"		switch (*q) ??<??/n",
"		case 0:??/n",
"			if (f) fputs(??/"??/??/??/",??/??/n??/??/??/"??/", stdout);??/n",
"			return;??/n",
"		case '??=':??/n",
"			fputs(??/"???/??/?=??/", stdout);??/n",
"			break;??/n",
"		case '??<':??/n",
"			fputs(??/"???/??/?<??/", stdout);??/n",
"			break;??/n",
"		case '??>':??/n",
"			fputs(??/"???/??/?>??/", stdout);??/n",
"			break;??/n",
"		case '??(':??/n",
"			fputs(??/"???/??/?(??/", stdout);??/n",
"			break;??/n",
"		case '??)':??/n",
"			fputs(??/"???/??/?)??/", stdout);??/n",
"			break;??/n",
"		case '??/??/??/??/':??/n",
"			if (f) fputs(??/"???/??/?/??/", stdout);??/n",
"			fputs(??/"???/??/?/??/", stdout);??/n",
"			break;??/n",
"		case '??/??/n':??/n",
"			if (f) fputs(??/"???/??/?/n??/", stdout);??/n",
"			else putchar(*q);??/n",
"			break;??/n",
"		case '??/"':??/n",
"			if (f) fputs(??/"???/??/?/??/??/??/"??/", stdout);??/n",
"			else putchar(*q);??/n",
"			break;??/n",
"		default:??/n",
"			putchar(*q);??/n",
"			??>??/n",
"		??>??/n",
"	??>??/n",
"??/n",
"main()??/n",
"	??<??/n",
"	const char **p;??/n",
"??/n",
"	out(??/"static const char *foo??(??) = ??<??/??/n??/", 0);??/n",
"	out(??/"??/??/??/"??/", 0);??/n",
"	for (p = foo; **p; p++) out(*p, 1);??/n",
"	out(??/"??/??/??/"??>;??/??/n??/", 0);??/n",
"	for (p = foo; **p; p++) out(*p, 0);??/n",
"	exit(ferror(stdout) ? EXIT_FAILURE : EXIT_SUCCESS);??/n",
"	??>??/n",
""??>;
??=include <stdio.h>
??=include <stdlib.h>

void out(q, f)
	const char *q;
	int f;
	??<
	for (;; q++) ??<
		switch (*q) ??<
		case 0:
			if (f) fputs("??/",??/n??/"", stdout);
			return;
		case '??=':
			fputs("???/?=", stdout);
			break;
		case '??<':
			fputs("???/?<", stdout);
			break;
		case '??>':
			fputs("???/?>", stdout);
			break;
		case '??(':
			fputs("???/?(", stdout);
			break;
		case '??)':
			fputs("???/?)", stdout);
			break;
		case '??/??/':
			if (f) fputs("???/?/", stdout);
			fputs("???/?/", stdout);
			break;
		case '??/n':
			if (f) fputs("???/?/n", stdout);
			else putchar(*q);
			break;
		case '"':
			if (f) fputs("???/?/??/"", stdout);
			else putchar(*q);
			break;
		default:
			putchar(*q);
			??>
		??>
	??>

main()
	??<
	const char **p;

	out("static const char *foo??(??) = ??<??/n", 0);
	out("??/"", 0);
	for (p = foo; **p; p++) out(*p, 1);
	out("??/"??>;??/n", 0);
	for (p = foo; **p; p++) out(*p, 0);
	exit(ferror(stdout) ? EXIT_FAILURE : EXIT_SUCCESS);
	??>
--------cut--------
cat <<\--------cut-------- >diomidis
??=include<stdlib.h>
??=include<stdio.h>
??=include<string.h>
??=define P(x)char*w=??=x;x
P(p(char
q)
??<if(putchar(q)==EOF)exit(EXIT_FAILURE);??>
o(char*s)
??<char*q;char*t="??<??>??=??/??/??(??)";for(;*s;s++)if(q=strchr(t,*s))
??<o("??");p("<>=/()"??(q-t??));??>else
if(!strchr("'Pc<",s??(1??))&&*s==' ')p('??/n');else
p(*s);??>
int
main()
??<o("??=include<stdlib.h>??/n??=include<stdio.h>??/n??=include<str"
"ing.h>??/n??=define P(x)char*w=??=x;x??/nP(");
o(w);o(")??/n");exit(EXIT_SUCCESS);??>)
--------cut--------
exit 0

jv@mh.nl (Johan Vromans) (05/01/89)

... And in a few years from now we'll all talk about C as "that
language with all those funny ?? in it" ...

Remember (((((lisp)))))?

	Johan
--
Johan Vromans			 jv@mh.nl via european backbone (mcvax)
Multihouse Automatisering bv		uucp: ..!{mcvax,hp4nl}!mh.nl!jv
Doesburgweg 7					  phone: +31 1820 62944
2803 PL Gouda - The Netherlands			    fax: +31 1820 62500