[net.lang] Cute little liar program

mpdevine@watdaisy.UUCP (Michel P. Devine) (06/13/86)

  During my CS340 lectures (a second course in Data Structures), I alluded to 
some of the unusual features of some programming languages, in particular Pascal
and Fortran.  On the spur of the moment (as an (spectacularly unsuccessful) 
attempt at stimulating class participation), I suggested an exercise: write a 
program which prints the identity of the compiler used to compile it.  In the 
following script session, both liar.f and liar.p are links to the data file liar
(which is the program in question). 

Script started on Mon Jun  9 11:52:23 1986
%
% ls -l liar*
-rw-r--r--  1 mpdevine           440 Jun  9 11:50 liar
lrwxr-xr-x  1 mpdevine             4 Jun  9 11:45 liar.f@ -> liar
lrwxr-xr-x  1 mpdevine             4 Jun  9 11:45 liar.p@ -> liar
%
% pc liar.p
% a.out
  Compiled by a Pascal  compiler
%
% f77 liar.f
liar.f:
   MAIN liar:
% a.out
  Compiled by a FORTRAN compiler
%

If you like challenges, you can mark this article for later reference,
otherwise skip quickly to the supplied solution (hold on to your hat!).

% cat liar
      program liar                                                          (*
c *)               (output);					            (*
c *)  begin
                                                                   writeln  (*
     1  ( *,* )    'Compiled by a FORTRAN compiler'
c *)            ('  Compiled by a Pascal  compiler');
      end                                                               .   (*
c				       			    column 72  ^    *) 
% 
script done on Mon Jun  9 11:53:42 1986


Nice, no?  The main tricks to notice are:

	a) FORTRAN ignores all characters beyond the 72nd column (these were 
	   originally used for sequence numbers).  
	
	b) '(*' and '*)' are Pascal's comment delimiters.  In FORTRAN, the 
	   character 'c' in the first column comments out the whole line,
	   while a '1' in column 6 indicates a continuation of the previous
	   statement.

	c) 'write' is a valid FORTRAN statement, while 'writeln' is correct 
	   Pascal.

	d) Pascal requires a period after the 'end' keyword (which is found
	   at column 73!!!)

Also, notice the blanks around the logical unit and format specification:
there are necessary to avoid nested comments (for Pascal, of course).  For 
some  FORTRAN compilers, *any* character in column 1 as the effect of 
commenting out the line and therefore a simpler (ah!) solution would be:

      program liar
(output);  begin	
                                                                   writeln (*  
     1  ( *,* )    'Compiled by a FORTRAN compiler'                        *)
('  Compiled by a Pascal  compiler');
      end                                                               .  


A further challenge: write a similar program for C and Pascal.

ps.

Before any comments are made about the good government money I wasted doing
this silliness, I should point out that only 10 minutes were required to
write and debug the program.
-- 
--------------------------------------------------------------------------------
mpdevine%watdaisy@waterloo.csnet            (519) 884-7123 Michel P. Devine
mpdevine%watdaisy%waterloo.csnet@csnet-relay.arpa          CS Dept., U. Waterloo
{allegra,decvax,inhp4,utzoo}!watmath!watdaisy!mpdevine     Waterloo, Ont. N2L3G1

long@ittvax.ATC.ITT.UUCP (H. Morrow Long [CRT]) (06/16/86)

> 
> mpdevine%watdaisy%waterloo.csnet@csnet-relay.arpa          CS Dept., U. Waterloo
> A further challenge: write a similar program for C and Pascal.
> 

I did something similar in my International Obfuscated C Code Contest entry for
1986.  It can be compiled by both the pascal and C compiler on our 4.2bsd Vax.

				H. Morrow Long

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

(*FOO);

/**********************************************************
 *                                                        *
 * 1986 Obfuscated C program entry - H. Morrow Long       *
 *                                                        *
 * This program can be compiled by both the 4.2 BSD C and *
 * pascal (pc) compilers.  'pc' will complain a bit but   *
 * will generate an executable.                           *
 *                                                        *
 * To run:                                                *
 *      Copy this file to both foo.c and foo.p            *
 *      cc -o c_foo foo.c                                 *
 *      pc -o p_foo foo.p                                 *
 *                                                        *
 **********************************************************/

#define	program		void
#define Main(a,b)	main()
#define	procedure	void
#define begin		{
#define end		}
#define	writeln		puts

#define foobar		(FOO\
*)

program Main(input,output)

begin

	writeln("Hello World");
end


-- 

			H. Morrow Long
			Member Research Staff - Knowledge Based Systems
			ITT-ATC Advanced Technology Group
			1 Research Drive Shelton, CT  06484
			Phone #: (203)-929-7341 x. 634

path = {allegra bunker dcdvaxb dcdwest ucbvax!decvax milford mit-eddie
	psuvax1 qumix sii supai tmmnet yale}!ittatc!long

wesommer@mit-trillian.MIT.EDU (William Sommerfeld) (06/18/86)

This one works a little better; it doesn't complain when compiled by the
Pascal compiler (at least under 4.3BSD)

Tricks:
	- { } is a comment in Pascal, statement delimeters in C.
	- /*) and (*/ to toggle between 'C' and Pascal.  
	- The only reason to have the #define openbrace in there is so
that the Pascal compiler doesn't give you a warning about having an
open brace character in the middle of a comment.

Anyone want to work on some more obscure ones???

				Bill Sommerfeld
			ARPA:   wesommer@athena.mit.edu
			UUCP:	mit-eddie!wesommer (forwards)

(*foo); 
#define openbrace {
/*)
program main(output);
begin
	writeln('I was compiled by a Pascal compiler.');
end.
{*/
main()
openbrace
	puts("I was compiled by a C compiler");
}

levy@ttrdc.UUCP (Daniel R. Levy) (06/21/86)

In article <722@mit-trillian.MIT.EDU>, wesommer@mit-trillian.MIT.EDU (William Sommerfeld) writes:
>This one works a little better; it doesn't complain when compiled by the
>Pascal compiler (at least under 4.3BSD)
>Tricks:
>	- { } is a comment in Pascal, statement delimeters in C.
>	- /*) and (*/ to toggle between 'C' and Pascal.
>	- The only reason to have the #define openbrace in there is so
>that the Pascal compiler doesn't give you a warning about having an
>open brace character in the middle of a comment.
>Anyone want to work on some more obscure ones???
>				Bill Sommerfeld
>			ARPA:   wesommer@athena.mit.edu
>			UUCP:	mit-eddie!wesommer (forwards)
>(*foo);
>#define openbrace {
>/*)
>program main(output);
>begin
>	writeln('I was compiled by a Pascal compiler.');
>end.
>{*/
>main()
>openbrace
>	puts("I was compiled by a C compiler");
>}

Good show.  Can anyone write one of these which combines Pascal, C, AND
Fortran-77?  I tried to do this but kept running into a situation where I
needed a #define, which must be on the first character of a line (Fortran
doesn't like that one bit since its comments are determined by the first
character of each line).

Oh yes, Fortran-77 considers '*', 'c', and 'C' all to be valid comment
characters (begin a comment line by being in column 1), if that's any help
(also a completely "blank" [columns 1-72] line is considered to be a comment).

It's trivial to do a C/Fortran combination, however:

                                                                       main(){printf("I was compiled by a C compiler\n"); /*  [starts in column 73]
C                                                                      ^
C                                                                      |
C                                                              Column 73
C                                                                      |
C                                                                      v
      write(*,*)'I was compiled by a Fortran compiler'                 */
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
						vax135}!ttrdc!levy

dik@zuring.uucp (Dik T. Winter) (06/21/86)

In article <7772@watdaisy.UUCP> mpdevine@watdaisy.UUCP writes:
>
>  During my CS340 lectures (a second course in Data Structures), I alluded to 
>some of the unusual features of some programming languages, in particular Pascal
>and Fortran.  On the spur of the moment (as an (spectacularly unsuccessful) 
>attempt at stimulating class participation), I suggested an exercise: write a 
>program which prints the identity of the compiler used to compile it.  In the 
>following script session, both liar.f and liar.p are links to the data file liar
>(which is the program in question). 
>
Reminds me.  Eons ago I wrote a program for the CDC Cyber which would be
compiled by 4 compilers (Fortran, Pascal, Algol 60 and Algol 68).
The most remarkable of the program was not that it passed 4 compilers,
but it reproduced itself (regardless of the compiler, however,  the
Algol 60 compiler choked because of some compiler restrictions).

This brings on another question.  Is it possible to create non-trivial
input to {t,d}itroff that reproduces itself?  (By non-trivial I mean
it should contain at least one line starting with period or apostrophe,
because, as a silly co-worker pointed out to me, the empty file
reproduces itself.  Also .sy should not be permitted.)
-- 
dik t. winter, cwi, amsterdam, nederland
UUCP: {seismo,decvax,philabs,okstate,garfield}!mcvax!dik
  or: dik@mcvax.uucp
ARPA: dik%mcvax.uucp@seismo.css.gov

jeff@pixar (Jeffrey Mock) (06/23/86)

Someone else try the harder case of using this clever `programming
methodology' to write a program that produces the text of the program
as output.  This program will print itself regardless of being
compiled with a C or Pascal compiler.  I just spent a few minutes
trying to do it and the solution isn't as simple as I first thought.

jeff mock 
{ucbvax, sun}!pixar!jeff

lwall@sdcrdcf.UUCP (Larry Wall) (06/27/86)

In article <301@zuring.UUCP> dik@zuring.UUCP (Dik T. Winter) writes:
> This brings on another question.  Is it possible to create non-trivial
> input to {t,d}itroff that reproduces itself?  (By non-trivial I mean
> it should contain at least one line starting with period or apostrophe,
> because, as a silly co-worker pointed out to me, the empty file
> reproduces itself.  Also .sy should not be permitted.)

Well...

I took this as a challenge, and wrote something that may do what you want.
I don't have {t,d}itroff real handy, but I did come up with a self-reproducing
nroff script, so you might try it out with {t,d}itroff and see if it works.
Not only was it NOT trivial, it was durn near impossible!  I had to get rather
devious.  If there's an Obfuscated Nroff Code Contest in the near future,
consider this my entry for it.

Since there may be some people who wouldn't try doing this until they find
out that it IS possible, I'll just say to them that it is.  Have fun.  So that
I don't spoil their fun, the one I wrote follows both in uuencoded and rot13
format for those who aren't interested in trying to solve the problem
themselves.  I had another version that used '.eo' to reduce the number of
escape characters, but it came out to the same number of bytes, and more lines,
so I won't post it.  If anyone can shorten this one, they're welcome to try.
To run this,

	uudecode this_article
	nroff self.n >self.out
	cmp self.n self.out

(By the way, I leave you with the challenge to make a C/nroff program that
compiles without error and prints out "hello world\n" either way.  Yes, it
can be done.  If anything it's easier than the self-reproducer, but that's
not saying much.  Definitely an AHA! type problem.)

Larry Wall
sdcrdcf!lwall

THE UUENCODED VERSION:

begin 664 self.n
M+F5C.`HN96U:6@HN;G)Y>3$P,#`M,3(*+FYR>GHQ,#`M,0HN;F8*+F1E6%@*
M+G1R.#AN*'EY"C@X(3@X(3@X)#$*+G1R.#AN*'IZ"BYA;5I:+BX*.#@A.#@A
M+EA8.#@D,0HN;G)N;#`M,0HN+BX*+BX*+EA8+F5C.0HN6%@N96U:6@HN6%@N
M;G)Y>3$P,#`M,3(*+EA8+FYR>GHQ,#`M,0HN6%@N;F8*+EA8+F1E6%@*+EA8
M+G1R.3EN*'EY"BY86#DY(3DY(3DY)#$*+EA8+G1R.3EN*'IZ"BY86"YA;5I:
M+BX*+EA8.3DA.3DA+EA8.3DD,0HN6%@N;G)N;#`M,0HN6%@N+BX*+EA8+BX*
`
end

(***SPOILER WARNING***)
Reading the ROT13 version may give you clues you don't want, despite the
encryption.

THE ROT13 VERSION:

Abgr gung gur frpbaq unys vf vqragvpny gb gur svefg unys, jvgu gur
rvtugf genafyngrq gb avarf naq n .KK cercraqrq.

.rp8
.rzMM
.aell1000-12
.aemm100-1
.as
.qrKK
.ge88a(ll
88!88!88$1
.ge88a(mm
.nzMM..
88!88!.KK88$1
.aeay0-1
...
..
.KK.rp9
.KK.rzMM
.KK.aell1000-12
.KK.aemm100-1
.KK.as
.KK.qrKK
.KK.ge99a(ll
.KK99!99!99$1
.KK.ge99a(mm
.KK.nzMM..
.KK99!99!.KK99$1
.KK.aeay0-1
.KK...
.KK..