定義内のシンボルの数を数える。

シンボルの数を数えるといっても、実際は葉の数をかぞえているだけ。
なんか、冗長な処理がある。途中で方針変えたからなぁ。。。
作っていて思ったが、作り方がおかしい。なんかトップダウンで作っているし。こういうものって、ボトムアップで作るんだよなぁ。

(define *total-symbols* (make-hash-table))

(define (add-total-symbols! total)
  (let1 t (if (hash-table-exists? *total-symbols* total)
	      (+ 1 (hash-table-get *total-symbols* total))
	      1)
    (hash-table-put! *total-symbols* total (+ t 1))))
(define (show-result)
  (let1 keys (sort (hash-table-keys *total-symbols*) <)
    (for-each (lambda (key)
		(let1 value (hash-table-get *total-symbols* key)
		  (display #`"total symbol ,key : ,value")
		  (newline)))
	      keys)))


(define (count-definition-symbols s-exp)
  (if (pair? s-exp)
      (case (car s-exp)
	((define define-class define-condition-type define-constant 
	   define-generic define-in-module define-macro define-method
	   define-module define-reader-ctor define-record-type
	   define-syntax define-values)
	 (let ((name (car s-exp))
	       (total (count-symbols (cdr s-exp))))
	   (add-total-symbols! (car total))
	   total))
	(else
	 (count-symbols s-exp)))
      (count-symbols s-exp)))

(define (count-symbols s-exp)
  ;; list of list
  (define (filter-inners inners)
    (let loop ((inners inners)
	       (symbols 0)
	       (others '()))
      (cond ((null? inners) (values symbols others))
	    (else 
	     (if (number? (caar inners))
		 (loop (cdr inners)
		       (+ (caar inners) symbols)
		       others)
		 (loop (cdr inners)
		       symbols
		       (cons (car inners) others)))))))
  (let loop ((s-exp s-exp)
	     (symbols 0)
	     (inners '()))
    (cond ((null? s-exp)
	   (receive (syms defs)
	       (filter-inners inners)
	     (cons (+ symbols syms) defs))
	     )
	  ((not (pair? s-exp)) (loop '() (+ 1 symbols) inners))
	  ((pair? (car s-exp))
	   (loop (cdr s-exp)
		 symbols
		 (cons (count-definition-symbols (car s-exp))
		       inners)))
	  (else
	   (loop (cdr s-exp) (+ 1 symbols) inners)))))

(define (main args) ;entry point
  (let ((files (cdr args)))
    (for-each
     (cut call-with-input-file <>
	  (lambda (in)
	    (let loop ((s-exp (read in)))
	      (cond ((eof-object? s-exp) )
		    (else (count-definition-symbols s-exp)
			  (loop (read in)))))))
     files))
  (show-result))

totalとか、リストだったり数値だったり。絶対通らない条件とかありそう。