commit 3201e41ee1948be15dcf947a85cc468b8c271ced Spenser Truex <struex0@gmail.com> 2016-02-15 20:24:22 -0800 Provided debugging facilities
README.md | 54 ++++++++++++++++++++++++++++++------------------------ interpreter.lisp | 20 +++++++++++--------- packages.lisp | 25 +++++++++++++++++++++---- 3 files changed, 62 insertions(+), 37 deletions(-)
diff --git a/README.md b/README.md index e3c5246..e46d83e 100644 --- a/README.md +++ b/README.md @@ -50,40 +50,46 @@ If everything runs smoothly you will be ready to brainfuck. If not then please * !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ" ``` -#Debugging +#Debugging Brainfuck -Debugging brainfuck code can be done using all the normal Common Lisp functions: `step`, `trace`, `time`, etc., but require the user to understand how the internal code works. For this reason there is no tutorial on how to properly debug your brainfuck code, just a couple examples. The user is encouraged to read the Common Lisp source code to get all the features of the Lisp debugging environment in their brainfuck. +Debugging brainfuck code can be done using all the normal Common Lisp functions: `step`, `trace`, `time`, etc. The following functions and variables are exported and may be useful for debugging brainfuck code: +``` +brain:fuck ;Used to execute a brainfuck string directly +brain:*tape-size-default* ;Number of cells in the tape Default: 30,000 +brain:decf-byte ;The - operator function +brain:incf-byte ;The + operator function +brain:read-this-byte ;The , operator function +brain:print-this-byte ;The . operator function +brain:right-shift ;The > operator function +brain:left-shift ;The < operator function +brain:one-off-fuck ;Function called to loop over each character in the code +brain:*separators* ;Characters that terminate #F brainfuck code Default: (#\Space, #\Newline) +brain:byte-value ;Returns the value of the curren byte at the *pointer* position +brain:*tape* ;Returns the entire tape +brain:*pointer* ;The current position in the byte tape. Useful with byte-value Default: Exactly in the middle of the tape. (15,000) +``` +Note that the variables `*tape*` and `*pointer*` are reset upon executing new brainfuck code. Once the execution is finished their state is frozen in time and ready to be debugged. -To debug your brainfuck code you should start with: +#Examples for Debugging: +Suppose you want to make the tape only 10 bytes long (instead of the default 30000) This way you can easily view the tape contents after execution: ``` -> (in-package :brain) +> (setf brain:*tape-size-default* 10) ;Sets the tape to only elements 0 to 9 +> #f->+ +> brain:*tape* ;Holds the byte tape vector +#(0 0 0 0 0 255 1 0 0 0) +> brain:*pointer* +6 ``` -to get access to the internal functions. - -Suppose you want to make the tape only 10 bytes long (instead of the default 30000): -``` -> (in-package :brain) -> (setf *tape-size-default* 10) ;Sets the tape to only elements 0 to 9 -> (reset-globals) ;Resets the tape, pointer, and a few other things -> *tape* ;Holds the byte tape vector -#(0 0 0 0 0 0 0 0 0 0) -> *pointer* ;This shows that the pointer gets moved to the middle regardless of the size -5 +Suppose you want to find information about how often and with what values + and - were used: ``` -Suppose you want to find information about the + and - operations: -``` -> (trace incf-byte decf-byte) -> (fuck "+-") -;;;; The following text is implementation dependent, and looks like this only on SBCL +> (trace brain:incf-byte brain:decf-byte) +> (brain:fuck "+-") +;;;; The following text is implementation dependent, and looks exactly like this only on SBCL 0: (INCF-BYTE) 0: INCF-BYTE returned 1 0: (DECF-BYTE) 0: DECF-BYTE returned 0 "" ``` -#TODO: -- Test on other implementations and operating systems (CCL, ECL, ABCL, CLISP, AllegroCL, LispWorks), to verify that it works. -- Make debugging more user friendly. Better documentation and some external functions to be called with `brain:function` or `brain:*variable*` - This software is licensed under the MIT free software license. ==== \ No newline at end of file diff --git a/interpreter.lisp b/interpreter.lisp index cda089a..d33923b 100644 --- a/interpreter.lisp +++ b/interpreter.lisp @@ -22,12 +22,19 @@ (defvar *output* "" "Defaults to an empty string because it is setf'd by other functions") +(defparameter *initial-element* 0 + "initial value for inside the byte array") + +(defparameter *separators* '(#\Newline #\Space) + "#F notation separators. +These can be changed to allow whitespace comments") (defun make-tape-array () "Creates a new tape array" (make-array *tape-size-default* :element-type '(unsigned-byte 8) - :initial-element 0)) + :initial-element *initial-element*)) + (defvar *tape* (make-tape-array) "The tape array used to store each byte") @@ -65,9 +72,8 @@ (defun shorthand-fuck-aux (stream list) (let ((char (read-char stream nil nil))) ;; TODO: Replace the #\Space, #\Newline, #\Tab with proper separations - (if (or (char-equal char #\Space) - (char-equal char #\Newline) - (char-equal char #\Tab) + (if (or (some #'(lambda (x) (char-equal x char)) + *separators*) (null char)) (char-list->string (nreverse list)) (shorthand-fuck-aux stream (push char list))))) @@ -179,7 +185,7 @@ (defun skip-loop (position) (skip-loop-aux position 0)) -(defun interpret (brainfuck-string) +(defun fuck (brainfuck-string) "Interpret the brainfuck" (reset-globals) (setf *brainfuck* brainfuck-string) @@ -193,7 +199,3 @@ (1- (skip-loop position)))))) *output*) -(defun fuck (brainfuck-string) - "An alias for the interpret function" - (interpret brainfuck-string)) - diff --git a/packages.lisp b/packages.lisp index 91b907f..62f268e 100644 --- a/packages.lisp +++ b/packages.lisp @@ -8,7 +8,24 @@ (in-package :cl-user) (defpackage :brain (:use :cl) - (:export :interpret - :fuck)) - - + (:export :fuck ;Used to execute a brainfuck string directly + :*tape-size-default* ;Number of cells in the tape + :decf-byte ;The - operator + :incf-byte ;The + operator + :read-this-byte ;The , operator + :print-this-byte ;The . operator + :right-shift ;The > operator + :left-shift ;The < operator + + ;;Function called to loop over each character in the code + :one-off-fuck + + :*separators* ;Characters that terminate #F brainfuck code + + ;; Returns the value of the current byte, most probably the one + ;; that the code finished executing over + :byte-value + + :*tape* ;contains the entire byte tape. Useful to view contents. + :*pointer* ;The current position in the byte tape. Useful with byte-value + ))