fix Makefile and README.md for 2000/dlowe

This commit is contained in:
Landon Curt Noll committed 2023-03-14 01:28:57 -07:00
1 parent e997fd64bd
commit 1846adc6e4
2 files changed
+558 -420

No files matched your search

+302 -186
View File
@@ -1,215 +1,331 @@
#!/bin/make
# 2000 makefile
#!/usr/bin/env make
#
# Copyright (C) Simon Cooper, Landon Curt Noll, Peter Seebach
# and Leonid A. Broukhis, 2000.
# All Rights Reserved. Permission for personal, educational or non-profit
# use is granted provided this this copyright and notice are included in its
# entirety and remains unaltered. All other uses must receive prior permission
# from the contest judges.
# IOCCC 2000 winning entry - dlowe
SHELL= /bin/sh
CAT= cat
RM= rm
SED= sed
TRUE= true
#CINCLUDE= -I ${HOMEBREW_PREFIX}/include/SDL2
# optimization
################################################################################
#
# Most compiles will safely use -O2. Some can use only -O.
# A few compilers have broken optimizers and thus you may
# not want anything.
# Regarding individual entries:
#
# IOCCC winning entry code may not work on your system. Even with standards,
# conditions and build environments change, especially when it comes to more
# extreme code such you might find in an IOCCC winner. Moreover, what was
# allowed and liked in one IOCCC contest may no longer be liked/allowed in
# later IOCCC years.
#
# Corrections on winning author and fixing typos in remarks are VERY WELCOME.
#
# GitHub pull requests are welcome:
#
# If you have a patch that might make running an entry work in modern Unix-like
# environments, please create a GitHub pull request for the IOCCC judges to
# consider.
#
# Suggestions and corrections regarding Makefiles, winning author information,
# fixing typos in remarks, and code patches are welcome via opening a GitHub
# issue or better yet, by creating a GitHub pull request for the IOCCC judges
# to consider. To form a GitHub issue or GitHub pull, please visit:
#
# https://github.com/ioccc-src/winner
#
################################################################################
# This work by Landon Curt Noll and Leonid A. Broukhis is licensed under:
#
# Creative Commons Attribution-ShareAlike 3.0 Unported License.
#
# See: http://creativecommons.org/licenses/by-sa/3.0/
#############################
# shell used by this Makefile
#############################
#
SHELL= bash
#######################
# common tool locations
#######################
#
include ../../var.mk
# Set X11_LIBDIR to the directory where the X11 library resides
#
#X11_LIBDIR= /usr/X11R6/lib
#X11_LIBDIR= /usr/X11/lib
X11_LIBDIR= /opt/X11/lib
# Set X11_INCLUDEDIR to the directory where the X11 include files reside
#
#X11_INCDIR= /usr/X11R6/include
#X11_INCDIR= /usr/X11/include
X11_INCDIR= /opt/X11/include
# Common C compiler warnings to silence
#
#CSILENCE=
CSILENCE= -Wno-gnu-statement-expression -Wno-unused-parameter
# Common C compiler warning flags
#
#CWARN= ${CSILENCE}
#CWARN= -Wall ${CSILENCE}
#CWARN= -Wall -Wextra ${CSILENCE}
CWARN= -Wall -Wextra -pedantic ${CSILENCE}
# Compiler standard
#
#CSTD=
#CSTD= -ansi
CSTD= -std=gnu99
# Compiler bit architecture
#
# Some entries require 32-bitness:
# ARCH= -m32
#
# Some entries require 64-bitness:
# ARCH= -m64
#
# By default we assume nothing:
#
ARCH=
# Defines that are needed to compile
#
CDEFINE=
#CDEFINE= -Dna=0
# Include files that are needed to compile
#
CINCLUDE=
#CINCLUDE= -include stdlib.h
#CINCLUDE= -include stdio.h
#CINCLUDE= -include stdlib.h -include stdio.h
#CINCLUDE= -I ${X11_INCDIR}
#CINCLUDE= `${SDL2_CONFIG} --cflags`
# Optimization
#
# Most compiles will safely use -O2. Some can use only -O1 or -O.
# A few compilers have broken optimizers or this entry make break
# under those buggy optimizers and thus you may not want anything.
# Reasonable compilers will allow for -O3.
#
#OPT=
#OPT= -O
OPT= -O2
#OPT= -O1
#OPT= -O2
OPT= -O3
# flags for ANSI compiles
# Default flags for ANSI C compilation
#
# NOTE: Some ANSI compilers make use of -Xa to turn on ANSI mode,
# others such as gcc may want -ansi, others (Compaq Tru64 Unix)
# want -std1, and others may want nothing at all.
# Adjust the CFLAGS line as needed.
#
# NOTE: Some compilers cannot optimize, or optimize some entries
# incorrectly. You might want to turn on -O to see if your
# compiler can handle them.
#
#
#CFLAGS= -Xa ${OPT}
#CFLAGS= -std1 $(OPT)
CFLAGS= -ansi ${OPT}
CFLAGS= ${CSTD} ${CWARN} ${ARCH} ${CDEFINE} ${CINCLUDE} ${OPT}
NO_ANSI_CFLAGS=
#NO_ANSI_CFLAGS=
# Libraries needed to build
#
LIBS=
#LIBS= -lm
#LIBS= -L ${X11_LIBDIR} -lX11
#LIBS= `${SDL2_CONFIG} --libs`
# NOTE: On some systems, the library path does not include the location
# of the X11 libraries. You might need to use a -L/path/to/X11/lib/dir
# in order to compile with these libs.
#
X11CCFLAGS= -I/usr/X11R6/include -I/usr/X11R6/include/X11 -I/usr/include/X11
#X11CCFLAGS=
X11LDFLAGS= -L/usr/X11R6/lib
#X11LDFLAGS=
# Perl
#
PERL= perl
#PERL= perl5
# ANSI compiler
#
# Set CC to the name of your ANSI compiler.
#
# Some entries seem to need gcc. If you have gcc, set
# both CC and MAY_NEED_GCC to gcc.
#
# If you do not have gcc, set CC to the name of your ANSI compiler, and
# set MAY_NEED_GCC to either ${CC} (and hope for the best) or to just :
# to disable such programs.
# C compiler to use
#
CC= cc
MAY_NEED_GCC= gcc
#CC=clang
#CC=gcc
# winners that compile under ANSI C
# Compiler add-ons or replacements for clang only
#
WINNERS= anderson schneiderwent primenum bellard bmeyer briddlebane dhyang \
dmy2jd jarijyrki dlowe natori rince robison thadgavin tomx
ALT_NAMES= schneiderwent.orig briddlebane.orig thadgavin.orig
DATA_FILES= schneiderwent_files bmeyer_files jarijyrki_files
all: ${WINNERS}
# Best use of flags
ifeq ($(CC),clang)
#
anderson: anderson.c
${CC} ${CFLAGS} $? -o $@
# Most Timely Output
CSILENCE+= -Wno-cast-align -Wno-cast-qual -Wno-comma -Wno-float-equal \
-Wno-implicit-int-conversion -Wno-missing-prototypes -Wno-padded \
-Wno-poison-system-directories -Wno-shadow -Wno-shorten-64-to-32 \
-Wno-sign-conversion -Wno-strict-prototypes -Wno-switch-enum \
-Wno-undef -Wno-used-but-marked-unused
#
schneiderwent: schneiderwent.c
${CC} ${CFLAGS} $? -o $@
schneiderwent_files: schneiderwent.data
schneiderwent.orig: schneiderwent.orig.c
${CC} ${CFLAGS} $? -o $@
# Best Abuse of CPP
CWARN+= -Weverything
#
primenum: primenum.c
${CC} ${CFLAGS} $? -o $@
endif
# Most Specific Output
# Specific add-ons or replacements for gcc only
#
bellard: bellard.c
${CC} ${CFLAGS} $? -o $@
ifeq ($(CC),gcc)
#
#CSILENCE+=
#
#CWARN+=
#
endif
# Best Utility
#
# machines operating in 64 bit mode:
#
bmeyer: bmeyer.c
${CC} -DY= -O6 $? -o $@ -lm
#
# linux/x86, glibc 2.0, libc4/5:
#
# bmeyer: bmeyer.c
# ${CC} -DY="__setfpucw(0x127f)" -O6 $? -o $@ -lm
#
# linux/x86, glibc 2.1:
#
# bmeyer: bmeyer.c
# ${MAY_NEED_GCC} -DY='int x=0x127f; __asm__ ("fldcw %0" : : "m" (*&x))' \
# -O6 $? -o $@ -lm
bmeyer_files: lavabus.pgm lenna.glic michael.pgm
# Best Abuse of User
##############################
# Special flags for this entry
##############################
#
briddlebane: briddlebane.c
${CC} ${CFLAGS} $? -o $@ -lm
briddlebane.orig: briddlebane.orig.c
${CC} ${CFLAGS} $? -o $@ -lm
# Best Layout
ENTRY= dlowe
PROG= ${ENTRY}
#
dhyang: dhyang.c
${CC} ${CFLAGS} $? -o $@
dmy2jd: dmy2jd.c
${CC} ${CFLAGS} $? -o $@
# Best of Show
OBJ= ${PROG}.o
DATA=
TARGET= ${PROG}
#
jarijyrki: jarijyrki.c
${CC} ${X11CCFLAGS} ${CFLAGS} -DNeedFunctionPrototypes \
-DU=40 -DT=98 '-Dz=(T+1)*U*U' -DQ=80 -DS=20 -DN=10 -DB=5 -DG=23 \
-Dp=7 '-DM=((p+1)*Q)+S' '-DH=(G*S)+S+S' -DC=XK_Up -DL=XK_Down \
-DO=XK_Left -DV=XK_Right -DR=XK_Escape -D_=XK_BackSpace \
$? -o $@ ${X11LDFLAGS} -lX11
ALT_OBJ=
ALT_TARGET=
jarijyrki_files: sheet1.info
# Worst Abuse of the Rules
#################
# build the entry
#################
#
# NOTE: You will need to adjust this path to the place where Perl has been
# installed on your system. Running "perl -V" may help you locate
# this place.
#
# The following bit of perl may help determining the values you need:
#
# perl -MConfig -e 'print "$Config{archlibexp}/CORE\n"'
#
#
dlowe: dlowe.c
${CC} ${NO_ANSI_CFLAGS} -DPERL_POLLUTE \
`${PERL} -MExtUtils::Embed -e ccopts` $? -o $@ \
`${PERL} -MExtUtils::Embed -e ldopts`
# Best Small Program
#
natori: natori.c
${CC} ${CFLAGS} $? -o $@ -lm
# Astronomically Obfuscated
#
rince: rince.c
${CC} ${X11CCFLAGS} ${CFLAGS} -DM_PI=3.14159265358979323846 \
$? -o $@ -lm ${X11LDFLAGS} -lX11
# Best game
#
robison: robison.c
${CC} ${CFLAGS} $? -o $@
# Most Portable Output
#
thadgavin: thadgavin.c
${CC} ${CFLAGS} $? -o $@ -lcurses -lm
thadgavin.orig: thadgavin.orig.c
${CC} ${CFLAGS} $? -o $@ -lncurses -lm
# Most Complete Program
#
tomx: tomx.c
${CC} ${CFLAGS} $? -o $@
everything: ${WINNERS} ${ALT_NAMES} ${DATA_FILES}
clean:
${RM} -f *.o a.out core ${WINNERS}
clobber: clean
${RM} -f ${WINNERS}
${RM} -f ${ALT_NAMES}
nuke: clobber
all: data ${TARGET}
@${TRUE}
install: all
${CAT} ${WINNERS} ${ALT_NAMES} > /dev/null
.PHONY: all alt data everything clean clobber install \
love haste waste maker easter_egg sandwich \
supernova deep_magic magic charon pluto
${PROG}: ${PROG}.c
${CC} ${CDEFINE} ${CSILENCE} -DPERL_POLLUTE \
`${PERL} -MExtUtils::Embed -e ccopts` $? -o $@ \
`${PERL} -MExtUtils::Embed -e ldopts`
# alternative executable
#
alt: data ${ALT_TARGET}
@${TRUE}
# data files
#
data: ${DATA}
@${TRUE}
# both all and alt
#
everything: all alt
###############
# utility rules
###############
#
clean:
${RM} -f ${OBJ} ${ALT_OBJ}
@-if [ -f indent.c ]; then \
echo ${RM} -f indent.c; \
${RM} -f indent.c; \
fi
clobber: clean
${RM} -f ${TARGET} ${ALT_TARGET}
@-if [ -e sandwich ]; then \
${RM} -f sandwich; \
echo 'ate sandwich'; \
fi
install:
@echo "Dr. Spock says that is not logical!"
@${TRUE}
# you may be able to misunderstand the source by reading indent.c
#
indent.c: ${PROG}.c
@if which "${GINDENT}" >/dev/null 2>&1; then \
echo ${RM} -f $@; \
${RM} -f $@; \
echo "${GINDENT} < $< > $@"; \
${GINDENT} < $< > $@; \
elif which "${INDENT}" >/dev/null 2>&1; then \
echo ${RM} -f $@; \
${RM} -f $@; \
echo "${INDENT} < $< > $@"; \
${INDENT} < $< > $@; \
else \
echo "no intent tool found, ident $< yourself, sorry"; \
echo "exit 1"; \
exit 1; \
fi
##################
# 133t hacker rulz
##################
#
love:
@echo 'not war?'
@${TRUE}
haste:
$(MAKE) waste
@${TRUE}
waste:
@echo 'haste'
@${TRUE}
maker:
@echo 'Participate in a maker faire'
@${TRUE}
easter_egg:
@echo "you expected to often misunderstand this $${RANDOM} magic"
@echo "chongo '<was here>' /\\oo/\\"
@echo "Eggy"
sandwich: easter_egg
@if [ `id -u` -eq 0 ]; then \
echo 'Okay.'; \
echo "$${RANDOM}`date +%s`$${RANDOM}" > $@; \
else \
echo 'What? Make it yourself.'; \
exit 1; \
fi
# Understand the history of the Homebrew Computer Club
# as well as the West Coast Computer Faire and
# you might be confused different. :-)
#
supernova: sandwich
@-if [ -r .code_anal ]; then \
${RM} -f .code_anal_v6; \
else \
echo "planet deniers, like some members of the IAU, are so cute when they try to defend their logic"; \
fi
@echo "A $@ helps ${MAKE} the elements that help form planets"
@${TRUE}
deep_magic: supernova
@-if [ -r .code_anal ]; then \
ccode_analysis --deep_magic 7889066cdbdf09b0408021754586e895be641cc9be29e7eafd3ca65359541f17 \
--FNV1a_hash_512_bit -v2 "${PROG}" "${PROG}.c"; \
else \
echo "Wrong! Do it again!"; \
sleep 2; \
echo "Wrong! Do it again!"; \
sleep 2; \
echo "Wrong! Do it again!"; \
fi
@${TRUE}
magic: deep_magic
@-if [ -r .code_anal ]; then \
ccode_analysis --level 20003 --mode 5717175 --FNV1a_hash_512_bit -v2 "${PROG}" "${PROG}.c"; \
else \
echo "If you don't eat yer meat, you can't have any pudding!"; \
echo "How can you have any pudding if you don't eat yer meat?!"; \
fi
@${TRUE}
# The IOCCC resident astronomer states
#
charon: magic
@echo "$@ is a dwarf planet"
@echo "dwarf is a type of planet"
@echo "therefore IAU, $@ is a planet"
pluto: charon
${MAKE} charon
@echo "$@ is a dwarf planet"
@echo "dwarf is a type of planet"
@echo "therefore, $@ is a planet"
@echo "having lots of planets is good feature because supernovae can help ${MAKE} a lot of them"
+256 -234
View File
@@ -1,247 +1,269 @@
Worst Abuse of the Rules:
# Worst Abuse of the Rules:
David Lowe
1224 11th Avenue
San Francisco, California, 94122
USA
David Lowe
1224 11th Avenue
San Francisco, California, 94122
USA
http://pootpoot.com/~dlowe/
http://pootpoot.com/~dlowe/
## To build:
```sh
make
```
The following bit of perl may help determining the values you need:
```sh
perl -MConfig -e 'print "$Config{archlibexp}/CORE\n"'
```
### To run:
```sh
./dlowe [file ...]
```
### Try:
```sh
echo "13 14 15 16 17 + - * / p" | ./dlowe
```
## Judges' comments:
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.
## 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:
```sh
$ 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"?...
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.
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...
Selected Author's Comments:
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 ;)
Usage:
dlowe [file ...]
If you don't change the rules, it'll be embedded Ada next year!
### AutoDefend
Synopsis:
This is a reverse polish calculator, loosely based on the dc(1) unix
calculator.
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.
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.
A. Perl isn't portable enough, or ubiquitous enough.
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.
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...
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.
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.