SOLUTION: Category 4: Doppleganger programs
Clifford A. Adams (caadams@frontiernet.net)

        "Perl is executable linenoise."
            -- several anonymous sources

        Welcome to the exciting world of Perl-Portable Pascal!
By following just a few simple rules you too can deliver sources which
can be compiled by either Pascal or Perl compilers!  Here is a
sample run of the included linecnt.pas program:

C:\OB4>dcc32 linecnt.pas
Borland Delphi  Version 12.0  Copyright (c) 1983,98 Inprise Corporation
linecnt.pas(26)
27 lines, 0.49 seconds, 29936 bytes code, 2525 bytes data.

C:\OB4>linecnt<linecnt.pas
total lines: 25

C:\OB4>perl linecnt.pas<linecnt.pas
total lines: 25

C:\OB4>dir linecnt.*

 Volume in drive C has no label
 Volume Serial Number is 12AF-7D64
 Directory of C:\OB4

LINECNT  PAS           676  07-31-99  3:14p linecnt.pas
LINECNT  EXE        40,960  07-31-99  4:01p linecnt.exe
         2 file(s)         41,636 bytes
         0 dir(s)   1,102,393,344 bytes free

        Note that this simple Pascal/Perl program is a better linecounter
than Borland's Delphi compiler!  (A hand count of linecnt.pas reveals
only 25 lines, including the blank line at the end of the file.)


Here are the rules for creating portable programs:

        0.  For Delphi Pascal compatibility, lines must end with
            a CR/LF pair.  Modern Perl versions can deal with this.
        1.  Add your program after the "NO CARRIER}" line.
        2.  There must be a blank/empty line at the end of your
            program.  This must be the *only* blank line in the file.
        3.  Use uppercase letters to indicate that Perl should not
            compile certain text/symbol strings.  All non-whitespace
            next to uppercase letters will be erased, along with
            leading whitespace.
        4.  "begin" and "end" should be used in place of "{" and "}".
        5.  To indicate that a word represents a variable, insert at
            least two whitespace characters before the variable.
            This may require altered code formatting rules.
        6.  There is no rule 6.
        7.  Do *NOT* alter the code above "NO CARRIER}".  It is
            proprietary generated code, encrypted with LINENOISE 2000.

        This demonstration release also contains advanced writeln
emulation code which correctly adds the end-of-line character(s) often
forgotten in simplistic translations.  Other exciting features will
be available in future versions ("When its DONE.").


Appendix 1: Explanation of translator

        After further review, our Marketing department decided to release
linecnt.pas under an Open Source license.  In the spirit of full
disclosure, here is the section which was encrypted with LINENOISE 2000:

  # The comments at the front of the file are deliberately truncated
  # by LINENOISE 2000 as part of its "security through obscurity" feature.
$_=<<'';s$N$$;$s=$';$_=$`;s;(\S)(\S);chr((ord$1&15)+16*(ord$2&15));ge;eval}
  # The LINENOISE 2000 decoder.
  # 1. Read rest of file into $_
  # 2. Split file at separator, place code into $_, program payload to $s
  # 3. For each pair of non-whitespace chars, decode from LINENOISE(TM).
  # 4. Evaluate the decoded script.
+1;$_=$s;$\="\n";
  # The + is generated from the {" start.  To preserve Pascal compliance,
  # the entire encrypted portion must be within a {} pair.
  # Retrieve the program payload into $_.
  # Also set the $\ variable used by writeln emulation.
s/\s*\S*[A-Z]+\S*//g;
  # Delete non-whitespace that contains an uppercase letter.
  # Also delete leading whitespace.
s-:=-=-g;s'begin'{'g;s'end'}'g;
  # Simple translations.
s|\s\s([a-z])|\$$1|g;
  # Variable translation: if two spaces before text, text is $variable.
s"writeln"print"g;eval;
  # Writeln emulation, followed by evaluation of translated program.
NO CARRIER}
  # End-Of-Message indicator for LINENOISE 2000.


Appendix 2: Translation of linecnt.pas

        This is the actual translated Perl code generated from the
linecnt.pas Pascal file.

$line = 0;
while ( <> ) {
$line =$line + 1;
};
print( 'total lines: ', ($line));

