Execute HQ9+/Common Lisp

From Rosetta Code
Execute HQ9+/Common Lisp is an implementation of HQ9+. Other implementations of HQ9+.
Execute HQ9+/Common Lisp is part of RCHQ9+. You may find other members of RCHQ9+ at Category:RCHQ9+.

The interpreter (in Common Lisp) accepts a string, treated as program text, or a pathname object, in which case the contents of the file are the program text.

(defun slurp (filespec)
"Return the contents of the file as a string."
(with-output-to-string (out)
(with-open-file (in filespec :direction :input)
(loop for line = (read-line in nil nil)
until (null line) do (write-line line out)))))
 
(defun hq9+ (input &optional (out *standard-output*))
"Execute the hq9+ program designated by input. If input is a
string, it is taken as the program text. If it is a pathname, then
the program text is the content of the file. The final value of the
accumulator is returned."

(loop with src = (if (stringp input) input (slurp input))
with accumulator = 0
for c across src
do (case c
(#\h (write-line "Hello, world!" out))
(#\q (write-string src out))
(#\+ (incf accumulator))
(#\9
(do ((n 99 (1- n))) ((zerop n))
(format out "~&~%~w bottle~:p of beer on the wall~%~
~w bottle~:p of beer~%~
Take one down, pass it around~%~
~:[~w bottle~:p~;No more bottles~] ~
of beer on the wall~%"

n n (zerop (1- n)) n))
(format out "~&~%No more bottles of beer on the wall~%~
No more bottles of beer on the wall~%~
Go to the store and buy some more~%~
99 bottles of beer on the wall.~%"
)))
finally (return accumulator)))