整数ジェネレータ
さて、前回の字句解析#1では、与えられたファイルを字句解析して、トークンを切り出した。ここでいうトークンとは、文字列とファイルを読み出した順番の対である。今回は、後者の"ファイルを読み出した順序"を掘り下げてみよう。
前回、このファイルを読み出した順番を求めるために関数getOrderを次のように定義した。これには少々問題がある。具体的には、与えられたファイルの構造に対する暗黙的な前提がある点である。すなわち、与えられたファイルを固定長251バイトづつ読んでいることが前提になっている。
(defun getOrder (f) (save-excursion (set-buffer f) (1+ (/ (point) 251))))
ここで言う、"ファイルを読み出した順番"は、一般的な字句解析では解析対象ファイルの行数にあたる。字句解析は通例、一文字づつ読んで、トークンを切り出し改行が現れたら、"改行"というトークンとともに解析対象ファイルの行数を+1していく。したがって、必ずしもファイルを読んだ回数とは普通は一致しないものなのである。
では、このように書けないともし仮定した場合、呼び出す毎に+1づつ増えていくような関数はどうやったら実現できるのであろうか?
lispではこれをジェネレータと言い、Emacs Lispでは次のようになる。Emacs Lispはクロージャがないので少し難しい。簡単に実現するにはclパッケージのlexical-letを使用する。
(require 'cl) (defun make-naturalnum (n) (lexical-let ((x n)) (lambda () (setq x (1+ x))))) (setq lineno (make-naturalnum 0)) (funcall lineno) 1 (funcall lineno) 2
funcall がうっとおしい時は次のように書けばよい
(defun make-naturalnum (sym n) (fset sym (lexical-let ((x n)) (lambda () (setq x (1+ x)))))) (make-naturalnum 'lineno 0) (lineno) 1 (lineno) 2