Commit | Line | Data |
---|---|---|
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))) | |
8753fd53 AW |
69 | (cond |
70 | ((eof-object? chr) | |
71 | (let ((parsed (reverse-without-nops parsed))) | |
72 | (if (null? parsed) | |
73 | chr ;; pass on the EOF object | |
74 | parsed))) | |
75 | ((eqv? chr #\]) | |
76 | (reverse-without-nops parsed)) | |
77 | (else | |
78 | (iterate (cons (process-input-char chr p) parsed))))))) | |
6370a6ad | 79 | |
e63d888e DK |
80 | |
81 | ; This routine processes a single character of input and builds the | |
82 | ; corresponding instruction. Loop bodies are read by recursively calling | |
5c27902e | 83 | ; back (read-brainfuck). |
e63d888e DK |
84 | ; |
85 | ; For the poiner movement commands >< and the cell increment/decrement +- | |
86 | ; commands, we only use one instruction form each and specify the direction of | |
87 | ; the pointer/value increment using an argument to the instruction form. | |
88 | ||
6370a6ad DK |
89 | (define (process-input-char chr p) |
90 | (case chr | |
91 | ((#\>) '(<bf-move> 1)) | |
92 | ((#\<) '(<bf-move> -1)) | |
93 | ((#\+) '(<bf-increment> 1)) | |
94 | ((#\-) '(<bf-increment> -1)) | |
95 | ((#\.) '(<bf-print>)) | |
96 | ((#\,) '(<bf-read>)) | |
5c27902e | 97 | ((#\[) `(<bf-loop> ,@(read-brainfuck p))) |
6370a6ad | 98 | (else '(<bf-nop>)))) |