Creating a HQ9+ interpreter
APL (Dyalog) (326 - 8 = 318)
Paste it in an editor window and call H
. Input is taken from the keyboard.
H
⎕←'Source code contains invalid characters'/⍨~∧/'HhQq9+'∊⍨V←⍞
B←' of beer'
W←' on the wall'
L←⎕TC[2]
Z←{k←' bottle','s'/⍨⍵≠1⋄⍵<0:'99',k⋄⍵=0:'No',k⋄k,⍨⍕⍵}
{⍵∊'Hh':⎕←'Hello, world!'
⍵∊'Qq':⎕←V
⍵∊'9':{⎕←G,K,(G←Z⍵),B,L,(⊃'Go to the store and buy some more' 'Take one down and pass it around'[1+×⍵]),L,(Z⍵-1),K←B,W,L}¨1-⍨⌽⍳100}¨V
C, 599 587 487 481 467 characters
I'm sure this can be beaten. I'm using C after all. There's a reason you don't see a lot of winning golf entries written in C. This is now 467 characters thanks to criminal abuse of #define
.
Specify the HQ9+ source file as a command line argument.
EDIT: Now accepts the source from stdin, not a file. Start the program, start typing the code, CTRL‑C when done to run it.
It compiles at least in MinGW/GCC with: gcc -o hq9+.exe hq9+.c
Should work in MSVC, but I didn't feel like creating a whole solution just for this. :)
#define B "bottles of beer"
#define C case
#define P printf
#define R break
a,i,j,s;
main(){
char p[9999],c;
for(;;) {
switch(c=getch()){
C 'H':C 'Q':C '9':C '+': C 3: R;
default:P("Source code contains invalid characters\n");
}
if (c==3) R;
p[s++]=c;
}
for(i=0;i<s;i++){
c = p[i];
switch(c){
C 'H':
P("Hello world!");
R;
C 'Q':
for(j=0;j<s;j++)putchar(p[j]);
R;
C '9':
j=99;
while(j){
P("%d "B" on the wall,\n%d "B".\nTake one down, pass it around,\n%d "B".\n",j,j,j-1);
j--;
}
R;
C '+':
a++;
}
}
}
Or:
#define B "bottles of beer"
#define C case
#define P printf
#define R break
a,i,j,s;main(){char p[9999],c;for(;;){switch(c=getch()){C 'H':C 'Q':C '9':C '+': C 3: R;default:P("Source code contains invalid characters\n");}if (c==3) R;p[s++]=c;}for(i=0;i<s;i++){c = p[i];switch(c){C 'H':P("Hello world!");R;C 'Q':for(j=0;j<s;j++)putchar(p[j]);R;C '9':j=99;while(j){P("%d "B" on the wall,\n%d "B".\nTake one down, pass it around,\n%d "B".\n",j,j,j-1);j--;}R;C '+':a++;}}}
Mathematica, 349 346 341 chars
h = If[StringMatchQ[#, ("H" | "Q" | "9" | "+") ...],
b = If[# > 0, ToString@#, "No"] <> " bottle" <>
If[# == 1, "", "s"] <> " of beer" &;
w = b@# <> " on the wall" &;
Print /@
StringCases[#, {"H" -> "Hello, world!", "Q" -> #,
"9" -> "" <>
Table[w@n <> ",\n" <> b@n <>
".\ntake one down, pass it around,\n" <> w[n - 1] <>
If[n == 1, ".", ".\n\n"], {n, 99, 1, -1}]}];,
"Source code contains invalid characters"] &