C-INTERCAL, 177 bytes
This is my first, and hopefully last, INTERCAL program. INTERCAL is a truly remarkable language. Those who haven't heard of it should immediately investigate (here is the manual I used).
PLEASEDO,1<-#2PLEASEDOWRITEIN,1PLEASEDO.1<-',1SUB#1'~#4DO(2)NEXTDO,1SUB#1<-#76(1)DO,1SUB#2<-#40(2)DO(3)NEXTDO,1<-#1DO,1SUB#1<-#116DOCOMEFROM(1)DOREADOUT,1(3)DOFORGET.1DORESUME#1
The program reads from standard input and writes to standard output. After printing the appropriate string, the program crashes with one of two humorous error messages depending on the input.
Try It Online
Ungolfed
PLEASE DO ,1 <- #2
PLEASE DO WRITE IN ,1
PLEASE DO .1 <- ',1 SUB #1' ~ #4
DO (2) NEXT
DO ,1 SUB #1 <- #76
(1) DO ,1 SUB #2 <- #40
(2) DO (3) NEXT
DO ,1 <- #1
DO ,1 SUB #1 <- #116
DO COME FROM (1)
DO READ OUT ,1
(3) DO FORGET .1
DO RESUME #1
Well, that didn't help much...
In the first three lines, we read 2 (#2
in INTERCAL) characters from the input into array ,1
and store in variable .1
whether the first character read has bit 2 set (mask of 4); in ASCII h
is 0b1101000
and t
is 0b1110100
, so this variable now indicates whether the input is tails
. This uses the "select" operator ~
, which in this case performs both masking and shifting to select bit 2 as 0 or 1.
The rest of the program is an if/else conditional and a print statement. Unfortunately, control flow is very limited in INTERCAL. The only mechanism is a call stack that's pushed to when the program executes DO (x) NEXT
. DO RESUME #1
then operates like a return statement (but with no return value), popping the stack and jumping to the next statement after the most recent DO (x) NEXT
. But the value passed to DO RESUME
can be any number. DO RESUME #3
pops the call stack three times and jumps to the third-from-last DO NEXT
.
A similar construct is DO FORGET
, which only pops the stack the specified number of times but does not jump. DO RESUME
always jumps, so passing it 0 is a run-time error. But the instruction DO FORGET #0
is valid, and doesn't do anything.
And so with the statements DO (2) NEXT
and DO (3) NEXT
I push two locations onto the call stack. At (3)
I then discard .1
frames, which has the effect of "forgetting" the call at (2)
if and only if the input was tails
. As a result, we end up just after either DO (2) NEXT
or DO (3) NEXT
after the return on the last line, depending on the input.
Each branch then loads the appropriate character data into ,1
(see here for why the values don't make any sense), and COME FROM (1)
, an inverted goto
, joins the two branches at the output statement DO READ OUT
. Control then continues, but luckily in either case the program crashes before printing anything else.