1. (defconstant TAPE_LEN 30000)
    
  2. 
    
  3. ; return hash tables to find matching braces
    
  4. (defun build_jumps (program)
    
  5.   ; first element of stack is top of stack
    
  6.   (let ((stack nil)
    
  7. 	(forward (make-hash-table))
    
  8. 	(backward (make-hash-table)))
    
  9.     (loop for i below (length program) 
    
  10. 	  for c = (char program i)
    
  11. 	  do (cond 
    
  12. 	       ((eq c #\[) (setf stack (cons i stack)))
    
  13. 	       ((eq c #\])
    
  14. 	         (let ((open (car stack))
    
  15. 	  	       (close i))
    
  16. 	  	 (progn
    
  17. 	  	   (setf stack (cdr stack))
    
  18. 	  	   (setf (gethash open forward) close)
    
  19. 	  	   (setf (gethash close backward) open)))))
    
  20. 	  finally 
    
  21. 	  	(return (if 
    
  22. 		  (eq nil stack)
    
  23. 		  (cons forward backward)
    
  24. 		  (error "jump stack not empty"))))))
    
  25. (defun jump (table i)
    
  26.   (if (gethash i table)
    
  27.     (gethash i table)
    
  28.     (error "missing jump.")))
    
  29. 
    
  30. (defun tape-inc (tape i)
    
  31.   (if (< i 0)
    
  32.     (error "negative index: " i)
    
  33.     (setf (aref tape i) (rem (+ (aref tape i) 1) 256))))
    
  34. (defun tape-dec (tape i)
    
  35.   (if (< i 0)
    
  36.     (error "negative index: " i)
    
  37.     (setf (aref tape i) (rem (- (aref tape i) 1) 256))))
    
  38. 
    
  39. (defun bf (program)
    
  40.   (let* ((jumps (build_jumps program))
    
  41. 	 (tape (make-array (list TAPE_LEN) :initial-element 0))
    
  42. 	 (pc 0)
    
  43. 	 (ptr 0)
    
  44. 	 (forward (car jumps))
    
  45. 	 (backward (cdr jumps)))
    
  46.     (loop while (< pc (length program))
    
  47.        do 
    
  48.         (let ((c (char program pc)))
    
  49.        	  (cond 
    
  50. 	       ((eq c #\+) (tape-inc tape ptr))
    
  51.      	       ((eq c #\-) (tape-dec tape ptr))
    
  52.      	       ((eq c #\>) (setf ptr (+ ptr 1) ))
    
  53.      	       ((eq c #\<) (setf ptr (- ptr 1) ))
    
  54.      	       ((eq c #\.) (princ (code-char (aref tape ptr))))
    
  55.      	       ((eq c #\[) (if (= 0 (aref tape ptr))
    
  56.      	  		     (setf pc (jump forward pc))))
    
  57.      	       ((eq c #\]) (if (/= 0 (aref tape ptr))
    
  58.      	  		     (setf pc (jump backward pc))))
    
  59.      	       (t (error "unknown instruction" c))))
    
  60.           (setf pc (+ 1 pc))
    
  61.      	  finally (return "done"))))
    
  62. 
    
  63. (defun is-comment? (line)
    
  64.   (and (> (length line) 0)
    
  65.        (eq #\; (char line 0))))
    
  66. 
    
  67. ; Read in a program, dropping lines that start with a ;
    
  68. (defun read-program (input acc)
    
  69.   (let ((line (read-line input nil)))
    
  70.     (if (eq nil line)
    
  71.       acc
    
  72.       (read-program input 
    
  73. 		    (concatenate 'string acc
    
  74. 				 (if (is-comment? line)
    
  75. 				   ""
    
  76. 				   line))))))
    
  77. 
    
  78. (defun run_program (filename)
    
  79.   (let* (
    
  80. 	 (file (open filename))
    
  81. 	 (program (read-program file (make-string 0))))
    
  82.     (bf program)))
    
  83. (defun main ()
    
  84. 	(run_program (nth 1 sb-ext:*posix-argv*)))