--- /dev/null
+;;; Read C source code, breaking it into the following types of tokens:
+;;; the identifier ___P, other identifiers, left and right parentheses,
+;;; and any other non-spacing character. White space (space, tab, and
+;;; newline characters) is never a token and may come between any two
+;;; tokens, before the first, or after the last.
+
+;;; Whenever the identifier ___P is seen, read a left parenthesis
+;;; followed by a body (zero or more tokens) followed by a right
+;;; parenthesis. If the body contains parentheses they must be properly
+;;; paired. Other tokens in the body, including ___P, have no effect.
+;;; Count the deepest nesting level used in the body. Count the maximum
+;;; deepest level (of all the bodies seen so far).
+
+;;; At the end of the file, print the maximum deepest level, or 0 if no
+;;; bodies were found.
+
+
+;;; Global variables used by lexical analyzer and parser.
+;;; The lexical analyzer needs them to print the maximum level at the
+;;; end of the file.
+
+(define depth 0)
+(define max-depth 0)
+
+;;; Lexical analyzer. Passes tokens to the parser.
+
+(define (paren-depth-lexer errorp)
+ (lambda ()
+
+ ;; Utility functions, for identifying characters, skipping any
+ ;; amount of white space, or reading multicharacter tokens.
+
+ (letrec ((char-whitespace?
+ (lambda (c)
+ (or (char=? c #\space)
+ (char=? c #\tab)
+ (char=? c #\newline))))
+ (skip-whitespace
+ (lambda ()
+ (let loop ((c (peek-char)))
+ (if (and (not (eof-object? c))
+ (char-whitespace? c))
+ (begin (read-char)
+ (loop (peek-char)))))))
+
+ (char-in-id?
+ (lambda (c)
+ (or (char-alphabetic? c)
+ (char=? c #\_))))
+ (read-___P-or-other-id
+ (lambda (l)
+ (let ((c (peek-char)))
+ (if (char-in-id? c)
+ (read-___P-or-other-id (cons (read-char) l))
+ ;; else
+ (if (equal? l '(#\P #\_ #\_ #\_))
+ '___P
+ ;; else
+ 'ID))))))
+
+ ;; The lexer function.
+
+ (skip-whitespace)
+ (let loop ((c (read-char)))
+ (cond
+ ((eof-object? c) (begin (display "max depth ")
+ (display max-depth)
+ (newline)
+ '*eoi*))
+ ((char-whitespace? c) (begin (errorp "didn't expect whitespace " c)
+ (loop (read-char))))
+ ((char-in-id? c) (read-___P-or-other-id (list c)))
+ ((char=? c #\() 'LPAREN)
+ ((char=? c #\)) 'RPAREN)
+ (else 'CHAR))))))
+
+;;; Parser.
+
+(define paren-depth-parser
+ (lalr-parser
+
+ ;; Options.
+
+ ;; (expect: 0) ;; even one conflict is an error
+
+ ;; List of terminal tokens.
+
+ (CHAR LPAREN RPAREN ID ___P)
+
+ ;; Grammar rules.
+
+ (file (newfile tokens))
+ (newfile () : (begin (set! depth 0)
+ (set! max-depth 0)))
+
+ (tokens (tokens token)
+ (token))
+
+ ;; When not after a ___P, the structure of the file is unimportant.
+ (token (CHAR)
+ (LPAREN)
+ (RPAREN)
+ (ID)
+
+ ;; But after a ___P, we start counting parentheses.
+ (___P newexpr in LPAREN exprs RPAREN out)
+ (___P newexpr in LPAREN RPAREN out))
+ (newexpr () : (set! depth 0))
+
+ ;; Inside an expression, ___P is treated like all other identifiers.
+ ;; Only parentheses do anything very interesting. I'm assuming Lalr
+ ;; will enforce the pairing of parentheses, so my in and out actions
+ ;; don't check for too many or too few closing parens.
+
+ (exprs (exprs expr)
+ (expr))
+
+ (expr (CHAR)
+ (in LPAREN exprs RPAREN out)
+ (in LPAREN RPAREN out)
+ (ID)
+ (___P))
+ (in () : (begin (set! depth (+ depth 1))
+ (if (> depth max-depth)
+ (set! max-depth depth))))
+ (out () : (set! depth (- depth 1)))))
+
+;;; Main program.
+
+(define paren-depth
+ (let ((errorp
+ (lambda args
+ (for-each display args)
+ (newline))))
+ (lambda ()
+ (paren-depth-parser (paren-depth-lexer errorp) errorp))))
+
+(paren-depth)
(pass-if "assq-ref 2" (seq? (assq-ref '((b . 1) (c . 2)) 'a) #f))
(pass-if "assq-set!" (sequal? (assq-set! '((b . 1)) 'a 0) '((a . 0) (b . 1))))
(pass-if "assq-set! 2" (sequal? (assq-set! '((a . 0)) 'a 1) '((a . 1))))
+(pass-if "assoc" (sequal? (assoc '(a . 0) '((a . 0) (b . 1) ((a . 0) aa))) '((a . 0) aa)))
;; works, but debugging is foo
;; (cond ((defined? 'loop2)
#t))
(pass-if "last-pair " (sequal? (last-pair '(1 2 3 4)) '(4)))
-(pass-if "last-pair 2" (eq? (last-pair '()) '()))
+(pass-if "last-pair 2" (seq? (last-pair '()) '()))
;; (pass-if "circular-list? "
;; (seq?
;; (let ((x (list 1 2 3 4)))
;; (circular-list? x))
;; #t))
+(pass-if "reverse" (sequal? (reverse '(1 2 3)) '(3 2 1)))
+
(pass-if "cond-expand" (sequal? (cond-expand (foobar #f) (mes (display ": pass: *YAY*") 'mes) (guile (display ": pass: *GUILE*") 'mes)) 'mes))
(begin (define *top-begin-a* '*top-begin-a*))