Merge branch 'master' into boehm-demers-weiser-gc
[bpt/guile.git] / module / language / brainfuck / parse.scm
CommitLineData
6370a6ad
DK
1;;; Brainfuck for GNU Guile.
2
3;; Copyright (C) 2009 Free Software Foundation, Inc.
4
5c27902e
AW
5;; This library is free software; you can redistribute it and/or
6;; modify it under the terms of the GNU Lesser General Public
7;; License as published by the Free Software Foundation; either
8;; version 3 of the License, or (at your option) any later version.
6370a6ad 9;;
5c27902e 10;; This library is distributed in the hope that it will be useful,
6370a6ad 11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
5c27902e
AW
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13;; Lesser General Public License for more details.
6370a6ad 14;;
5c27902e
AW
15;; You should have received a copy of the GNU Lesser General Public
16;; License along with this library; if not, write to the Free Software
17;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18;; 02110-1301 USA
6370a6ad
DK
19
20;;; Code:
21
22(define-module (language brainfuck parse)
23 #:export (read-brainfuck))
24
e63d888e
DK
25; Purpose of the parse module is to read in brainfuck in text form and produce
26; the corresponding tree representing the brainfuck code.
27;
28; Each object (representing basically a single instruction) is structured like:
29; (<instruction> [arguments])
30; where <instruction> is a symbolic name representing the type of instruction
31; and the optional arguments represent further data (for instance, the body of
32; a [...] loop as a number of nested instructions).
33;
34; A full brainfuck program is represented by the (<brainfuck> instructions)
35; object.
36
37
e63d888e
DK
38; While reading a number of instructions in sequence, all of them are cons'ed
39; onto a list of instructions; thus this list gets out in reverse order.
40; Additionally, for "comment characters" (everything not an instruction) we
41; generate <bf-nop> NOP instructions.
42;
43; This routine reverses a list of instructions and removes all <bf-nop>'s on the
44; way to fix these two issues for a read-in list.
45
6370a6ad
DK
46(define (reverse-without-nops lst)
47 (let iterate ((cur lst)
48 (result '()))
49 (if (null? cur)
50 result
51 (let ((head (car cur))
52 (tail (cdr cur)))
53 (if (eq? (car head) '<bf-nop>)
54 (iterate tail result)
55 (iterate tail (cons head result)))))))
56
e63d888e
DK
57
58; Read in a set of instructions until a terminating ] character is found (or
59; end of file is reached). This is used both for loop bodies and whole
60; programs, so that a program has to be either terminated by EOF or an
61; additional ], too.
62;
63; For instance, the basic program so just echo one character would be:
64; ,.]
65
5c27902e 66(define (read-brainfuck p)
6370a6ad
DK
67 (let iterate ((parsed '()))
68 (let ((chr (read-char p)))
69 (if (or (eof-object? chr) (eq? #\] chr))
70 (reverse-without-nops parsed)
71 (iterate (cons (process-input-char chr p) parsed))))))
72
e63d888e
DK
73
74; This routine processes a single character of input and builds the
75; corresponding instruction. Loop bodies are read by recursively calling
5c27902e 76; back (read-brainfuck).
e63d888e
DK
77;
78; For the poiner movement commands >< and the cell increment/decrement +-
79; commands, we only use one instruction form each and specify the direction of
80; the pointer/value increment using an argument to the instruction form.
81
6370a6ad
DK
82(define (process-input-char chr p)
83 (case chr
84 ((#\>) '(<bf-move> 1))
85 ((#\<) '(<bf-move> -1))
86 ((#\+) '(<bf-increment> 1))
87 ((#\-) '(<bf-increment> -1))
88 ((#\.) '(<bf-print>))
89 ((#\,) '(<bf-read>))
5c27902e 90 ((#\[) `(<bf-loop> ,@(read-brainfuck p)))
6370a6ad 91 (else '(<bf-nop>))))