Files
ioccc/2000/dlowe
Cody Boone Ferguson 17ea7fbd9e git mv *.hint -> README.md
There is one exception:

    $ find . -name '*.hint' -execdir git mv '{}' README.md \;
    git statufatal: destination exists, source=1992/albert/albert.hint, destination=1992/albert/README.md

Looking at the two files they differ quite a bit so I've not changed it.
I'll bring this up on GitHub.
2023-02-08 05:47:28 -08:00
..
2022-09-18 23:37:49 -07:00
2023-02-08 05:47:28 -08:00

Worst Abuse of the Rules:

David Lowe
1224 11th Avenue
San Francisco, California, 94122
USA

http://pootpoot.com/~dlowe/

Judges' Comments:

To build:

   make dlowe

To run:

   echo "13 14 15 16 17 + - * / p" | ./dlowe

When this entry was submitted the rules of the IOCCC did not prohibit
the use of embedded language interpreters.  The judges considered
disqualifying this entry because of the use of perl, but on the other
hand it qualifies as the Worst Abuse of the Rules.  As a previous winner
(*) David Lowe continues to inflict the highest quality "poot" on the
Judges.

The program also contains an undocumented command for Chad and Chongo.
The judges' comments contain a clue to the hidden command :-).

(*) The IOCCC uses an anonymous judging process which keeps the identity
of the submitters hidden until all the prize winners have been selected.

Selected Author's Comments:

Usage:
 dlowe [file ...]


Synopsis:
 This is a reverse polish calculator, loosely based on the dc(1) unix
 calculator.


Syntax:
 This program understands the following dc(1) commands:
   p   prints the top stack value without altering the stack.
   P   prints the top stack value, removing it from the stack, and
       doesn't print a trailing newline.
   f   prints the contents of the stack, one number per line,
       without modifying it.
   c   clears the stack.
   d   pushes a copy of the top stack value onto the stack.
   r   reverses the order of the top two stack values.

 And the following arithmetic operators are supported:
   +   Pops 2 values and pushes their sum.
   -   Pops 2 values and pushes the result of subtracting the first
       from the second.
   *   Pops 2 values and pushes their product.
   /   Pops 2 values and pushes the result of dividing the second
       by the first.
   ^   Pops 2 values and pushes the result of raising the second
       to the power of the first.
   %   Pops 2 values and pushes the remainder of the division that
       / would do.

 The precision and range are double, like it or not, except that the
 modulus operator actually returns (p1 - (p2 * (p1 / p2))), but with
 the innermost division calculated at integer precision.  This is
 usually what you expect (e.g. echo "12 8 % p" | ./dlowe == 4)

 Commands are read from stdin or from a list of files named on
 the command line.  Unlike dc(1), multiple commands on the same line
 must be space separated.  Commands are only executed when a newline
 or EOF is encountered.


Diagnostics:
 "stack empty"    Not enough on the stack for the requested command
 "divide by zero" Attempt to divide by zero
 "unimplemented"  Invalid input
 Floating point exception (core dumped) (or something to that effect)
                  Bug in Perl_sv_upgrade causes this in some cases when
                  the results of an operation are really huge (> 10^308)
                  This bug appears to be fixed in perl5.6.0


Examples:
 $ echo "12 13 14 15 16 + + + + f" | ./dlowe
 70
 $ echo "12 13 14 15 16 17 + - * / p" | ./dlowe
 -0.0515873015873016
 $ echo "+" | ./dlowe
 stack empty
 $ echo "999999999999999 1 + p" | ./dlowe
 1e+15
 $ echo "99999999999999 1 + p" | ./dlowe
 100000000000000
 $ echo "12.5 9 % 10 * 15 + f" | ./dlowe
 50
 $ echo "7 P 6 d P P 8 p" | ./dlowe | tr 876 tpo
 poot


Code Concept:
 We all know that Perl and other VHLLs (very high level languages)
 are particularly well-suited for (among other things) string
 handling, I/O, and powerful built-in datatypes, and (relatively)
 poorly suited for number crunching and other processor-intensive
 tasks - areas where C is strongest.  This program takes this
 knowledge to its extreme conclusion, using each language for its
 strengths.  Thus, it uses Perl to read and parse input, for output,
 and for the easy-to-use list primitive, and uses C for mathematical
 operations.  Since the rules of this contest state that the program
 must be generated by an ANSI C compiler, of course, the outer Perl
 layer is wrapped with a thin layer of C.

 In case that wasn't clear, in a nutshell: this program is C, calling
 embedded Perl (contained in a C string), which in turn calls back to
 C, which performs math on Perl data types and calls Perl functions for
 error reporting.


Requirements:
 Unfortunately, Perl is an evolving beast - that includes the
 embedding API and the XS API.  The code was developed under
 Perl 5.005_03, successfully tested against Perl 5.6.0, Perl 5.005_02
 and Perl 5.004_04, and according to the version delta documentation,
 should work as-is with Perl 5.002 and later (which has been around
 since February 1996).  To clarify - it's not the Perl code itself
 that may be non-portable, it's the C code for embedding Perl and for
 calling C from Perl.

 It is also important that Perl be installed cleanly and correctly.
 You may have problems linking if, for example, you have multiple
 overlapping versions of Perl installed (which might not be a problem
 for scripts, but causes problems with embedding the interpreter).
 More commonly, you may get non-fatal warnings from the linker, caused
 by slight misconfigurations of Perl on your system.

 Some compilers also complain that "third argument of `main' is
 deprecated" or something to that effect.  But in Perl prior to
 5.6.0, the header file "proto.h" actually had a prototype for main,
 so applications which embed Perl must use the three argument form
 of main.


Aside: history...
 Larry Wall wrote the original Perl in 1986-87, the same two successive
 years he won the IOCCC.  I hope this program helps you to realize that
 this was no fluke - that Perl and Obfuscation are as inseparable as,
 say, camels and humps.


Obfuscated?
 . Reverse polish notation is pretty strange, in and of itself.

 . The layout of the program is three roughly symmetrical "stacks"
   of code.  This layout is quite sensitive in places - my C indenter
   actually breaks the code by inserting spaces in certain places.

 . Anyone who has ever programmed in Perl can attest to the fact that
   it is particularly well-suited to obfuscation; thus, the Perl is
   obfuscated.  (Here's my favorite legal Perl from this program:
   '_:$_=<>;' - but '$SS[$#SS]-=$SS[$#SS-1]' isn't bad, either).

 . I've eschewed traditional branch and loop structures such as
   'if' and 'for', in favor of their oft-neglected cousins, 'goto'
   and '?:', in both the Perl and C code.

 . I've used some highly magical Perl incantations, such as symbolic
   references, the 'goto &NAME' syntax, AUTOLOAD for exception handling,
   and abuse of the default scalar ($_).

 . I've also deliberately used Perl syntax that is very much unlike
   C syntax: the &NAME rather than NAME() function calling syntax,
   leaving off parentheses wherever possible, using print() instead
   of printf(), and using the English style logic operators 'and' and
   'or' rather than '&&' and '||', for example.

 . The fact that all the Perl code is in double-quotes doesn't lend
   any readability to the regular expressions and quoted strings
   therein.

 . The points and ways in which C and Perl connect are *really*
   obscure.  They're also incredibly poorly documented, as they're
   primarily used in machine-generated code.  However, there's a
   wealth of example code on CPAN (www.cpan.org).

 . The Perl API functions are almost all macros, so you will probably
   find that preprocessor expansion will only make things worse.  They
   also have helpful, verbose names like SvNV, SvIV, and newSVpv.  I
   couldn't have done better myself!

 . Figuring out how the mathematical C functions get called is a bit
   tricky.  Note the lack of explicit switching based on command
   input.

 . Because of the "interesting" way that commands are interpreted,
   all of the commands have synonyms.  For example, if you find it
   easier to remember, '=' is synonymous with 'd'.  This is makes it
   possible to write (even more) obfuscated reverse polish commands
   (I figure this explanation moves the synonyms from 'bug' to
   'feature'!)

 . The first IOCCC entry with an "easter egg"?...


Aside: on unobfuscated Perl
 My original intent was to write obfuscated C and crystal-clear Perl,
 to highlight my bending of the rules.  Unfortunately, Perl really
 doesn't lend itself to crystal-clear code...


Bending the rules?
 Well, the rules never state that you can't embed another programming
 language, but on the other hand, knowing Perl probably isn't high on
 the list of qualifications for judges... Oh dear, I guess your C
 beautifier won't help too much, either ;)

 If you don't change the rules, it'll be embedded Ada next year!


AutoDefend
 A. Isn't this the obfuscated C contest?  What's this Perl $#_&&$_?

 D. Hey, this program *is* 100% C, and does not exec an external Perl
 interpreter.  It simply links against the Perl language library.
 The "Perl code" is just a C string constant.

 A. Perl isn't portable enough, or ubiquitous enough.

 D. I'd argue that it is more portable than X.  According to the Perl
 folks, it runs on the following platforms: Acorn, AIX, Amiga, AS/400,
 BeOS, Concurrent, Debian, DEC OSF/1, Digital UNIX, EPOC, FreeBSD,
 Guardian, HP-UX, IRIX, LinuxPPC, LynxOS, MacOS, MachTen, Minix, MPE/iX,
 MS-DOS, MVS, NetBSD, Netware, NextStep, OpenBSD, OpenLinux, ODT, OpenVMS,
 OS/2, OS390, OSR, PowerMAX, Psion, QNX, Redhat, Reliant UNIX, RISCOS,
 SCO, SGI, SINIX, Slackware, Solaris, Sun, SuSE, Tandem, Tru64, UNIX,
 U/WIN, Unixware, VMS, Win31, Win32, Windows 3.1, and Windows 95/98/NT/2K.
 Granted, embeddable Perl isn't quite so portable, but still...

 Also, Perl 5 is bundled with the following OS distributions: AIX 4.3.3+,
 FreeBSD 3.0+, IRIX 6.4+, every Linux distribution, NetBSD, OpenBSD, and
 DEC Tru64 5.0+, again according to the Perl people.