> (require (lib "lex.ss" "parser-tools"))
ライブラリのparser-toolsディレクトリの下にあるlex.ssを使います。
ファイル名=モジュール名ですな。
まずは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を書いてみましょう。
入力ポートを渡すとトークンを返す関数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には便利なマクロがあります。
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))))