3 ;;; Mes --- Maxwell Equations of Software
4 ;;; Copyright © 2008 Derek Peschel
5 ;;; Copyright © 2016 Jan Nieuwenhuizen <janneke@gnu.org>
7 ;;; paren.mes: This file is part of Mes.
9 ;;; Mes is free software; you can redistribute it and/or modify it
10 ;;; under the terms of the GNU General Public License as published by
11 ;;; the Free Software Foundation; either version 3 of the License, or (at
12 ;;; your option) any later version.
14 ;;; Mes is distributed in the hope that it will be useful, but
15 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 ;;; GNU General Public License for more details.
19 ;;; You should have received a copy of the GNU General Public License
20 ;;; along with Mes. If not, see <http://www.gnu.org/licenses/>.
24 ;;; paren.mes is a simple yet full lalr test for Mes taken from the
28 ;;; echo '___P((()))' | guile -s <(echo '(paren-depth)' | cat cc/paren.mes -)
34 (use-modules (system base lalr))
37 (mes-use-module (mes base-0))
38 (mes-use-module (mes base))
39 (mes-use-module (mes quasiquote))
40 (mes-use-module (mes let))
41 (mes-use-module (mes scm))
42 (mes-use-module (mes syntax))
43 (mes-use-module (srfi srfi-0))
44 (mes-use-module (mes record-0))
45 (mes-use-module (mes record))
46 (mes-use-module (srfi srfi-9))
47 (mes-use-module (mes lalr-0))
48 (mes-use-module (mes lalr))
51 ;;; Taken from http://gambitscheme.org/wiki/index.php/Lalr_example
52 ;;; LGPL 2.1 / Apache 2.0
54 ;;; Read C source code, breaking it into the following types of tokens:
55 ;;; the identifier ___P, other identifiers, left and right parentheses,
56 ;;; and any other non-spacing character. White space (space, tab, and
57 ;;; newline characters) is never a token and may come between any two
58 ;;; tokens, before the first, or after the last.
60 ;;; Whenever the identifier ___P is seen, read a left parenthesis
61 ;;; followed by a body (zero or more tokens) followed by a right
62 ;;; parenthesis. If the body contains parentheses they must be properly
63 ;;; paired. Other tokens in the body, including ___P, have no effect.
64 ;;; Count the deepest nesting level used in the body. Count the maximum
65 ;;; deepest level (of all the bodies seen so far).
67 ;;; At the end of the file, print the maximum deepest level, or 0 if no
68 ;;; bodies were found.
71 ;;; Global variables used by lexical analyzer and parser.
72 ;;; The lexical analyzer needs them to print the maximum level at the
78 ;;; Lexical analyzer. Passes tokens to the parser.
80 (define (paren-depth-lexer errorp)
83 ;; Utility functions, for identifying characters, skipping any
84 ;; amount of white space, or reading multicharacter tokens.
86 (letrec ((char-whitespace?
88 (or (char=? c #\space)
90 (char=? c #\newline))))
93 (let loop ((c (peek-char)))
94 (if (and (not (eof-object? c))
97 (loop (peek-char)))))))
101 (or (char-alphabetic? c)
103 (read-___P-or-other-id
105 (let ((c (peek-char)))
107 (read-___P-or-other-id (cons (read-char) l))
109 (if (equal? l '(#\P #\_ #\_ #\_))
114 ;; The lexer function.
117 (let loop ((c (read-char)))
119 ((eof-object? c) (begin (display "max depth ")
123 ((char-whitespace? c) (begin (errorp "didn't expect whitespace " c)
125 ((char-in-id? c) (read-___P-or-other-id (list c)))
126 ((char=? c #\() 'LPAREN)
127 ((char=? c #\)) 'RPAREN)
132 (define paren-depth-parser
137 (expect: 0) ;; even one conflict is an error
139 ;; List of terminal tokens.
141 (CHAR LPAREN RPAREN ID ___P)
145 (file (newfile tokens))
146 (newfile () : (begin (set! depth 0)
149 (tokens (tokens token)
152 ;; When not after a ___P, the structure of the file is unimportant.
158 ;; But after a ___P, we start counting parentheses.
159 (___P newexpr in LPAREN exprs RPAREN out)
160 (___P newexpr in LPAREN RPAREN out))
161 (newexpr () : (set! depth 0))
163 ;; Inside an expression, ___P is treated like all other identifiers.
164 ;; Only parentheses do anything very interesting. I'm assuming Lalr
165 ;; will enforce the pairing of parentheses, so my in and out actions
166 ;; don't check for too many or too few closing parens.
172 (in LPAREN exprs RPAREN out)
173 (in LPAREN RPAREN out)
176 (in () : (begin (set! depth (+ depth 1))
177 (if (> depth max-depth)
178 (set! max-depth depth))))
179 (out () : (set! depth (- depth 1)))))
186 (for-each display args)
189 (paren-depth-parser (paren-depth-lexer errorp) errorp))))