MzSchemeのlex.ss

> (require (lib "lex.ss" "parser-tools"))

ライブラリのparser-toolsディレクトリの下にあるlex.ssを使います。
ファイル名=モジュール名ですな。

token

まずはdefine-tokensを覚えましょう。

> (define-tokens my-tokens (FOO BAR))
> (token-FOO 'hoge)
#<struct:token>
> (token-name (token-FOO 'hoge))
FOO
> (token-value (token-FOO 'hoge))
hoge

シンボルをトークンとして使うこともできます。
シンボルは「値」をもたないトークンを表すのに使います。

> (token-name 'BAZ)
BAZ
> (token-value 'BAZ)
#f

ただのシンボルなのですが、yaccで利用するには
define-empty-tokensでグループを定義します。

> (define-empty-tokens my-empty-toknes (BAZ QUX))
> (eq? (token-BAZ) 'BAZ)
#t

my-empty-tokens がグループの名前です。

lexer

正規表現を使ってlexerを書いてみましょう。
入力ポートを渡すとトークンを返す関数my-lexを定義します。

> (define-empty-tokens my-empty-tokens (LB RB LP RP LS RS EOF))
> (define-tokens my-tokens (VAR))
> (define my-lex
    (lexer
      ((eof) (token-EOF))
      ((char-set " \t\r\n") (my-lex input-port))
      (#\{ (token-LB))
      (#\} (token-RB))
      (#\( (token-LP))
      (#\) (token-RP))
      (#\[ (token-LS))
      (#\] (token-RS))
      ((repetition 1 +inf.0 (char-complement (char-set " \t\r\n{}()[]")))
       (token-VAR (string->symbol lexeme)))))

MzSchemeには定数eofがありますが、上のeofはそれとは別物のようです。
input-port や lexeme がいつの間にか定義されています。

正規表現の演算子として

が使えます。lex-sre.ssには便利なマクロがあります。

test

my-lexが期待どおりに動くかどうか確かめましょう。

> (let loop ()
    (let ((x (my-lex (current-input-port))))
      (write (token-name x))
      (write-char #\tab)
      (write (token-value x))
      (newline)
      (unless (eq? x 'EOF) (loop))))
inserted by FC2 system