CPS conversion produces $branch nodes, not $kif
[bpt/guile.git] / module / language / brainfuck / parse.scm
index e272b61..286d1e2 100644 (file)
@@ -1,29 +1,44 @@
 ;;; Brainfuck for GNU Guile.
 
-;; Copyright (C) 2009 Free Software Foundation, Inc.
+;; Copyright (C) 2009, 2013 Free Software Foundation, Inc.
 
-;; This program is free software; you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
-;; any later version.
+;; This library is free software; you can redistribute it and/or
+;; modify it under the terms of the GNU Lesser General Public
+;; License as published by the Free Software Foundation; either
+;; version 3 of the License, or (at your option) any later version.
 ;; 
-;; This program is distributed in the hope that it will be useful,
+;; This library is distributed in the hope that it will be useful,
 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-;; GNU General Public License for more details.
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; Lesser General Public License for more details.
 ;; 
-;; You should have received a copy of the GNU General Public License
-;; along with this program; see the file COPYING.  If not, write to
-;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; You should have received a copy of the GNU Lesser General Public
+;; License along with this library; if not, write to the Free Software
+;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+;; 02110-1301 USA
 
 ;;; Code:
 
 (define-module (language brainfuck parse)
   #:export (read-brainfuck))
 
-(define (read-brainfuck p)
-  `(<brainfuck> ,@(read-body p)))
+; Purpose of the parse module is to read in brainfuck in text form and produce
+; the corresponding tree representing the brainfuck code.
+;
+; Each object (representing basically a single instruction) is structured like:
+; (<instruction> [arguments])
+; where <instruction> is a symbolic name representing the type of instruction
+; and the optional arguments represent further data (for instance, the body of
+; a [...] loop as a number of nested instructions).
+
+
+; While reading a number of instructions in sequence, all of them are cons'ed
+; onto a list of instructions; thus this list gets out in reverse order.
+; Additionally, for "comment characters" (everything not an instruction) we
+; generate <bf-nop> NOP instructions.
+;
+; This routine reverses a list of instructions and removes all <bf-nop>'s on the
+; way to fix these two issues for a read-in list.
 
 (define (reverse-without-nops lst)
   (let iterate ((cur lst)
           (iterate tail result)
           (iterate tail (cons head result)))))))
 
-(define (read-body p)
+
+; Read in a set of instructions until a terminating ] character is found (or
+; end of file is reached).  This is used both for loop bodies and whole
+; programs, so that a program has to be either terminated by EOF or an
+; additional ], too.
+;
+; For instance, the basic program so just echo one character would be:
+; ,.]
+
+(define (read-brainfuck p)
   (let iterate ((parsed '()))
     (let ((chr (read-char p)))
-      (if (or (eof-object? chr) (eq? #\] chr))
-        (reverse-without-nops parsed)
-        (iterate (cons (process-input-char chr p) parsed))))))
+      (cond
+       ((eof-object? chr)
+        (let ((parsed (reverse-without-nops parsed)))
+          (if (null? parsed)
+              chr ;; pass on the EOF object
+              parsed)))
+       ((eqv? chr #\])
+        (reverse-without-nops parsed))
+       (else
+        (iterate (cons (process-input-char chr p) parsed)))))))
+
+
+; This routine processes a single character of input and builds the
+; corresponding instruction.  Loop bodies are read by recursively calling
+; back (read-brainfuck).
+;
+; For the poiner movement commands >< and the cell increment/decrement +-
+; commands, we only use one instruction form each and specify the direction of
+; the pointer/value increment using an argument to the instruction form.
 
 (define (process-input-char chr p)
   (case chr
@@ -51,5 +91,5 @@
     ((#\-) '(<bf-increment> -1))
     ((#\.) '(<bf-print>))
     ((#\,) '(<bf-read>))
-    ((#\[) `(<bf-loop> ,@(read-body p)))
+    ((#\[) `(<bf-loop> ,@(read-brainfuck p)))
     (else '(<bf-nop>))))