Advertisement
Guest User

Untitled

a guest
Jan 16th, 2018
86
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.41 KB | None | 0 0
  1. ;; Even though it is all undefined, it seems the data array are only bytes.
  2. (define-modify-macro incf-mod-256 (&optional (delta 1))
  3. (lambda (val &optional (delta 1))
  4. (mod (+ val delta) 256)))
  5.  
  6. (define-modify-macro decf-mod-256 (&optional (delta 1))
  7. (lambda (val &optional (delta 1))
  8. (mod (- val delta) 256)))
  9.  
  10.  
  11. (defun %brainfuck->cl (data-array-size bf-code)
  12. (let ((while-stack ())
  13. (instr-stream ()))
  14.  
  15. (loop :for command :across bf-code :do
  16. (case command
  17. (#\> (push `(incf data-index) instr-stream))
  18. (#\< (push `(decf data-index) instr-stream))
  19. (#\+ (push `(incf-mod-256 (aref data-array data-index)) instr-stream))
  20. (#\- (push `(decf-mod-256 (aref data-array data-index)) instr-stream))
  21. (#\. (push `(princ (code-char (aref data-array data-index)))
  22. instr-stream))
  23. (#\, (push `(setf (aref data-array data-index)
  24. (mod (char-code (read-char)) 256))
  25. instr-stream))
  26. (#\[ (let* ((while-begin-label (gensym "BEGIN-WHILE-"))
  27. (while-end-label (gensym "END-WHILE-"))
  28. (conditional
  29. `(when (zerop (aref data-array data-index))
  30. (go ,while-end-label))))
  31. (push while-begin-label instr-stream)
  32. (push conditional instr-stream)
  33. (push (list while-begin-label while-end-label) while-stack)))
  34. (#\] (destructuring-bind (while-begin while-end) (pop while-stack)
  35. (push `(go ,while-begin) instr-stream)
  36. (push while-end instr-stream)))
  37. (otherwise
  38. nil)))
  39.  
  40. (setf instr-stream (reverse instr-stream))
  41.  
  42. `(lambda ()
  43. (let ((data-array (make-array ,data-array-size
  44. :element-type '(unsigned-byte 8)
  45. :initial-element 0))
  46. (data-index 0))
  47. (tagbody
  48. ,@instr-stream)))))
  49.  
  50. ;; compiling BF to CL. at the repl, (funcall (brainfuck->cl 1024 "<bf-code>"))
  51. ;; to run your code in lisp.
  52. (defmacro brainfuck->cl (data-array-size bf-code)
  53. (%brainfuck->cl data-array-size bf-code))
  54.  
  55.  
  56. ;; But, suppose we want to just _interpret_ some BF code.
  57. (defun brainfuck-interpreter (data-array-size bf-code)
  58. (let ((while-symtab (make-hash-table))
  59. (while-match-list ()))
  60. (flet ((analyze-while-loops (bf-code)
  61. ;; First, we walk the entire program and build the address table
  62. ;; for the while loops.
  63. (loop :for ip :below (length bf-code)
  64. :for command = (aref bf-code ip) :do
  65. (case command
  66. (#\[
  67. (let ((entry (list :begin ip :end nil)))
  68. (setf (gethash ip while-symtab) entry)
  69. (push entry while-match-list)))
  70. (#\]
  71. ;; entry is sharing reference with hash table!
  72. (let ((entry (pop while-match-list)))
  73. ;; and also insert the end of the while loop so
  74. ;; we can find the beginning.
  75. (setf (gethash ip while-symtab) entry)
  76. (setf (getf entry :end) (1+ ip))))))))
  77.  
  78. (analyze-while-loops bf-code)
  79.  
  80. ;; Then we simply evaluate everything. carefully looking up the
  81. ;; while address we built before for looping.
  82. (let ((data-array (make-array data-array-size
  83. :element-type '(unsigned-byte 8)
  84. :initial-element 0))
  85. (data-index 0))
  86.  
  87. (loop
  88. :with ip = 0
  89. :until (>= ip (length bf-code))
  90. :for command = (aref bf-code ip)
  91. :do
  92. (case command
  93. (#\>
  94. (incf data-index)
  95. (incf ip))
  96. (#\<
  97. (decf data-index)
  98. (incf ip))
  99. (#\+
  100. (incf-mod-256 (aref data-array data-index))
  101. (incf ip))
  102. (#\-
  103. (decf-mod-256 (aref data-array data-index))
  104. (incf ip))
  105. (#\.
  106. (princ (code-char (aref data-array data-index)))
  107. (incf ip))
  108. (#\,
  109. (setf (aref data-array data-index)
  110. (mod (char-code (read-char)) 256))
  111. (incf ip))
  112. (#\[
  113. (let ((while-entry (gethash ip while-symtab)))
  114. (if (zerop (aref data-array data-index))
  115. (setf ip (getf while-entry :end))
  116. (incf ip))))
  117.  
  118. (#\]
  119. (let ((while-entry (gethash ip while-symtab)))
  120. (setf ip (getf while-entry :begin))))
  121.  
  122. (otherwise nil)))))))
  123.  
  124.  
  125. (defparameter *hello-world*
  126. "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.")
  127.  
  128. ;; run the macro. I didn't care enough to get the variable eval right.
  129. (defun doit-0 ()
  130. (brainfuck->cl 1024 "++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++."))
  131.  
  132. ;; run the interpreter on hello world instead.
  133. (defun doit-1 (&optional (bf-code *hello-world*))
  134. (brainfuck-interpreter 1024 bf-code))
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement