トップ 差分 一覧 ソース 検索 ヘルプ RSS ログイン

サンプル:字句解析

字句解析を行うサンプル

バッファにある文字列に対して字句解析を行うElispの例を挙げます。

 字句の定義

字句 パターン
FN fn
ARROW =>
ID [a-zA-Z]+
ws [ \t\n]+
EOF $

wsは空白や改行を表すトークンです。EOFはファイルの終端、つまり最後の字句を意味しています。EOFの規則は"$"となっていて、これは普通は行末にマッチするので改行が来るたびにEOFが現れるように思えますが、改行はwsの規則で飛ばすので問題ありません。

今は対象とする言語は想定してないので字句はこの5つだけにします。

 コード

コード全体

字句解析を行う処理を追加したtest-mode.elがここにあります。

http://www.cs.ise.shibaura-it.ac.jp/files/test-mode-token.el

ファイル名を"test-mode.el"としてload-pathの通ったディレクトリに置いて.emacsの設定をすればM-x test-modeで呼び出せます。

以下では処理の各部分について説明します。

字句を読み取る関数

(defun tokenize ()
  (cond
   ((looking-at "fn")
    (goto-char (match-end 0))
    "FN")
   ((looking-at "=>")
    (goto-char (match-end 0))
    "ARROW")
   ((looking-at "[a-zA-Z]+")
    (goto-char (match-end 0))
    "ID")
   ((looking-at "[ \t\n]+")
    (goto-char (match-end 0))
    (tokenize))
   ((looking-at "$")
    "EOF")
   (t 
    (message "error-token")
    (goto-char (+ 1 (point)))
    (tokenize))))

tokenize関数はカーソル位置から始まる字句の規則がある場合、カーソル位置を字句の後ろまで移動し、字句を表す文字列を返しています。

空白(ws)は無視したいので再帰して次の字句が帰ってくるようにしています。

最後の部分はどのトークンの規則にもマッチしなかった場合で、エラーという扱いにしています。この場合、カーソル位置をひとつ右へ移動したあと再帰して次のトークンを返すようにしています。

字句を全て列挙する関数

上記tokenize関数を用いてバッファを解析し字句を列挙する関数は次のようになります。

(defun enumerateAllToken ()
  (let ((token (tokenize)))
    ;;EOFが返ってくるまで再帰する
    (if (not (equal "EOF" token)) 
	(format "%s %s" token (enumerateAllToken))
      token)))

;;キーを押したときに呼ばれる関数 
(defun test-mode-tokenize2 ()
  (interactive)
  (save-excursion 
    (goto-char (point-min));;カーソルをバッファの先頭に移動
    (message (enumerateAllToken)))) ;;解析して表示

enumerateAllToken関数はEOFが帰ってくるまでtokenize関数を呼び出し、最後に全ての字句を文字列に結合して返します。

test-mode-tokenize2関数は最初にカーソル位置をバッファ先頭に移動した後、enumerateAllToken関数の結果を表示しています。カーソル位置がtokenize関数などで変更されますが、save-excursionを使うことで処理後に元通りになります。

 改善できる点

適当な実装になっているので修正できるところは色々あります。

  • "fnx"などという文字がFNとIDというように二つになってしまう。IDになるべき。
  • 字句の属性を保持できるようにする。