Guest User

threaded brainfuck interpreter

a guest
Feb 25th, 2013
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lisp 6.93 KB | None | 0 0
  1.  
  2. (eval-when (:load-toplevel :execute :compile-toplevel)
  3.   (defun mkstr (&rest args)
  4.     (with-output-to-string (s)
  5.       (dolist (a args) (princ a s))))
  6.  
  7.   (defun symb (&rest args)
  8.     (values (intern (apply #'mkstr args)))))
  9.  
  10.  
  11. (defun remove-whitespace (string)
  12.   (remove-if (lambda (c)
  13.                (or (char-equal #\  c)
  14.                    (char-equal #\Newline c))) string))
  15.  
  16.  
  17.  
  18. (defun translate (bf-string)
  19.   "Translates a string of brainfuck into a list of lisp expressions"
  20.   (let ((prog '())
  21.         (loop-idx 0)
  22.         (loop-stack '()))
  23.     (loop for char across (remove-whitespace bf-string) do
  24.          (let ((val (case char
  25.                       (#\> '(inc-pointer 1))
  26.                       (#\< '(dec-pointer 1))
  27.                       (#\+ '(inc-cell 1))
  28.                       (#\- '(dec-cell 1))
  29.                       (#\. '(pr-cell))
  30.                       (#\, '(rd-cell))
  31.                       ;; create a tag for goto, a start-loop
  32.                       ;; invocation, push a new loop onto stack, and
  33.                       ;; increment the loop counter
  34.                       (#\[ (progn (push (symb 'start loop-idx) prog)
  35.                                   (push loop-idx loop-stack)
  36.                                   (incf loop-idx)
  37.                                   `(start-loop ,(1- loop-idx))))
  38.                      
  39.                       ;; create a tag, a end-loop invocation,
  40.                       ;; and pop the stack
  41.                       (#\] (let ((closed-loop (pop loop-stack)))
  42.                              (push `(end-loop ,closed-loop) prog)
  43.                              (symb 'end closed-loop))))))
  44.            (if val (push val prog))))
  45.     (values loop-idx (reverse prog))))
  46.  
  47.  
  48. ;;; (translate "++<<[++->]++>>[-]")
  49.  
  50. ;;-> (TAGBODY
  51. ;;     (INC-CELL 1)
  52. ;;     (INC-CELL 1)
  53. ;;     (DEC-POINTER 1)
  54. ;;     (DEC-POINTER 1)
  55. ;;   START0               ;; loop start tag/label
  56. ;;     (START-LOOP 0)
  57. ;;     (INC-CELL 1)
  58. ;;     (INC-CELL 1)
  59. ;;     (DEC-CELL 1)
  60. ;;     (INC-POINTER 1)
  61. ;;     (END-LOOP 0)
  62. ;;   END0                 ;; loop end tag/label
  63. ;;     (INC-CELL 1)
  64. ;;     (INC-CELL 1)
  65. ;;     (INC-POINTER 1)
  66. ;;     (INC-POINTER 1)
  67. ;;   START1
  68. ;;     (START-LOOP 1)
  69. ;;     (DEC-CELL 1)
  70. ;;     (END-LOOP 1)
  71. ;;   END1)
  72.  
  73.  
  74.  
  75. (defmacro interpret (string)
  76.   "Create a brainfuck memory pointer and environment, and expand
  77.  the translated brainfuck into the let body"
  78.   `(let ((mp 0)
  79.          (mem (make-array 30000 :element-type '(integer 0 255))))
  80.      (declare (optimize (speed 3) (safety 0) (debug 0))
  81.               (type ((simple-array '(integer 0 255) (30000)) mem)
  82.                     (fixnum mp)))
  83.      (tagbody ,@(multiple-value-bind (loop-count body) (translate string)
  84.                                      (declare (ignore loop-count))
  85.                                      body))))
  86.  
  87.  
  88. ;;  (macroexpand-1 (interpret "++<<[++->]++>>[-]"))
  89.  
  90. ;; (*LET ((MP FIXNUM 0) (MEM (MAKE-ARRAY 30000 :ELEMENT-TYPE '(INTEGER 0 255))))
  91. ;;   (DECLARE (OPTIMIZE (SPEED 3) (SAFETY 0) (DEBUG 0)))
  92. ;;   (TAGBODY
  93. ;;     (INC-CELL 1)
  94. ;;     (INC-CELL 1)
  95. ;;     (DEC-POINTER 1)
  96. ;;     (DEC-POINTER 1)
  97. ;;    START0
  98. ;;     (START-LOOP 0)
  99. ;;     (INC-CELL 1)
  100. ;;     (INC-CELL 1)
  101. ;;     (DEC-CELL 1)
  102. ;;     (INC-POINTER 1)
  103. ;;     (END-LOOP 0)
  104. ;;    END0
  105. ;;     (INC-CELL 1)
  106. ;;     (INC-CELL 1)
  107. ;;     (INC-POINTER 1)
  108. ;;     (INC-POINTER 1)
  109. ;;    START1
  110. ;;     (START-LOOP 1)
  111. ;;     (DEC-CELL 1)
  112. ;;     (END-LOOP 1)
  113. ;;    END1))
  114.  
  115.  
  116. (defmacro inc-pointer (arg)
  117.   `(incf mp ,arg))
  118.  
  119. (defmacro inc-cell (arg)
  120.   `(incf (aref mem mp) ,arg))
  121.  
  122. (defmacro dec-pointer (arg)
  123.   `(decf mp ,arg))
  124.  
  125. (defmacro dec-cell (arg)
  126.   `(decf (aref mem mp) ,arg))
  127.  
  128. (defmacro clear-cell ()
  129.   `(setf (aref mem mp) 0))
  130.  
  131. (defmacro pr-cell ()
  132.   `(progn
  133.      (princ (code-char (aref mem mp)))
  134.      ;(force-output)
  135.      ))
  136.  
  137. (defmacro rd-cell ()
  138.   `(progn
  139.      (setf (aref mem mp) (char-code (read-char)))
  140.      (force-output)))
  141.  
  142.  
  143. (defmacro end-loop (loop-idx)
  144.   `(if (not (zerop (aref mem mp)))
  145.        (go ,(symb 'start loop-idx))))
  146.  
  147. (defmacro start-loop (loop-idx)
  148.   `(if (zerop (aref mem mp))
  149.        (go ,(symb 'end loop-idx))))
  150.  
  151.  
  152.  
  153.  
  154.  
  155. (defun optimizable-p (el)
  156.   (and (consp el)
  157.        (not (or (eql 'pr-cell (car el))
  158.                 (eql 'rd-cell (car el))
  159.                 (eql 'start-loop (car el))
  160.                 (eql 'end-loop (car el))
  161.                 (eql 'clear-cell (car el))))))
  162.  
  163.  
  164. (defun optimize-bf (prog)
  165.   "Accumulates repeated commands and optimizes out zero loops (e.g. [-] )"
  166.   (let ((program '()))
  167.     (loop for idx from 0 to (1- (length prog)) do
  168.          (let* ((el (elt prog idx)))
  169.            (if (and (consp el)
  170.                       (eql 'start-loop (car el))
  171.                       (< (+ 2 idx) (length prog))
  172.                       (consp (elt prog (+ 2 idx)))
  173.                       (eql 'end-loop (car (elt prog (+ 2 idx)))))
  174.                (progn (pop program)
  175.                       (setf idx (+ 3  idx))
  176.                       (push '(clear-cell) program))
  177.                (push el program))))
  178.     (setf program (nreverse program))
  179.    
  180.     (let ((opti-prog '())
  181.           (cur-type '())
  182.           (cur-num 0))
  183.       (declare (optimize speed))
  184.  
  185.       (loop for el in program do
  186.            (if (not (optimizable-p el))
  187.                (progn
  188.                  (when cur-type
  189.                    (push `(,cur-type ,cur-num) opti-prog))
  190.                  
  191.                  (setf cur-type nil
  192.                        cur-num 0)
  193.                  (push el opti-prog))
  194.  
  195.                (if (not cur-type)
  196.                    (setf cur-type (car el)
  197.                          cur-num 1)
  198.  
  199.                    (if (eq cur-type (car el))
  200.                        (incf cur-num)
  201.  
  202.                        (progn
  203.                          (push `(,cur-type ,cur-num) opti-prog)
  204.                          (setf cur-type (car el)
  205.                                cur-num 1))))))
  206.      
  207.       (nreverse opti-prog))))
  208.  
  209.  
  210. (defmacro fast-interpret (string)
  211.   `(*let ((mp fixnum 0)
  212.           (mem (make-array 30000 :element-type '(integer 0 255))))
  213.      (declare (optimize (speed 3) (safety 0) (debug 0)))
  214.      (tagbody ,@(multiple-value-bind (loop-count body) (translate string)
  215.                                      (declare (ignore loop-count))
  216.                                      (optimize-bf body)))))
  217.  
  218.  
  219. ;;  (macroexpand-1 (fast-interpret "++<<[++->]++>>[-]"))
  220.  
  221. ;; (*LET ((MP FIXNUM 0) (MEM (MAKE-ARRAY 30000 :ELEMENT-TYPE '(INTEGER 0 255))))
  222. ;;   (DECLARE (OPTIMIZE (SPEED 3) (SAFETY 0) (DEBUG 0)))
  223. ;;   (SYMBOL-MACROLET ((CELL (AREF MEM MP)))
  224. ;;     (TAGBODY
  225. ;;       (INC-CELL 2)
  226. ;;       (DEC-POINTER 2)
  227. ;;      START0
  228. ;;       (START-LOOP 0)
  229. ;;       (INC-CELL 2)
  230. ;;       (DEC-CELL 1)
  231. ;;       (INC-POINTER 1)
  232. ;;       (END-LOOP 0)
  233. ;;      END0
  234. ;;       (INC-CELL 2)
  235. ;;       (INC-POINTER 2)
  236. ;;      START1
  237. ;;       (START-LOOP 1)
  238. ;;       (DEC-CELL 1)
  239. ;;       (END-LOOP 1)
  240. ;;      END1)))
Advertisement
Add Comment
Please, Sign In to add comment