Lua字句解析 llex.\* を読んだ
luaに演算子を追加したけど単に感想を書いただけだと何の意味もなくなってしまうので、 テーマ毎に整理しておく。 最初は字句解析器関係(llex.h, llex.c)について。
公開API
字句解析器はユーザーの文字列から字句列に変換する部分。 ヘッダファイル で公開されている関数は以下。
- 基本的に構文解析器が呼ぶ
- 字句解析処理の進行は構造体LexStateの変化に一致する
- 実際の先読み字句取得などはLexStateのメンバで判断する
読んだところ以下の様な機能を提供している。
関数 | 処理 |
---|---|
void luaX_init (lua_State *L) |
Lua仮想機械に予約語を登録 |
void luaX_setinput(lua_State *L, LexState *ls, ZIO *z, TString *source) |
字句解析器に解析対象設定 |
TString *luaX_newstring (LexState *ls, const char *str, size_t l) |
解析結果文字列を文字列定数として格納, 格納先は構文解析器 |
void luaX_next (LexState *ls) |
字句解析を進める(現在の字句) |
void luaX_lookahead (LexState *ls) |
先読み字句の解析を行ないlsに設定する |
void luaX_lexerror (LexState *ls, const char *msg, int token) |
字句解析エラーをLua状態機械に伝える |
void luaX_syntaxerror(LexState *ls, const char *s) |
構文解析エラーをLua状態機械に渡す(luaX_lexerrorをそのまま使ってる) |
const char *luaX_token2str (LexState *ls, int token) |
字句に対応するLua文字列を取得 |
luaX_init詳細
Lua_State
を予約語を受け付けられる状態にする。
- 予約語をLua文字列として生成する(
luaX_tokens, RESERVED
) luaX_fix
を用いてガベージコレクションの対象から外すTString.txv.reserved
にトークンの番号+1 を代入する(lu_byte
にキャストしてた)
3つ目の具体的な目的がよくわかっていない。
luaX_setinput詳細
Lexerを初期化している
- 仮想マシンを保持
- 先読み字句を無しにする(まだ先読みしていない状態)
TK_EOS
- メンバ(source)にソースコード格納
- デバッグ用?に現在の行数と最終行数を1に初期化
- ZIO(?)を格納
llex詳細
文字列から字句を判別して返却する
check_next
現在の文字が与えた文字集合に属するか判別し含まれる場合、確認する文字を1つ進める。 その際、次の字句の為にbufferに文字を追加する。
save
字句に対応する文字列を特定する為に字句解析最中に文字をバッファに保存する。
read_numeral, read_string, read_long_string
それぞれ対応する字句か判別すると思う。
その他
他にある関数は以下で詳細は追っていない。
- txtToken
- luaX_token2str
- luaX_newstring
- skip_sep
- buffreplace
- trydecpoint
字句の登録
字句の登録は配列luaX_tokens
で行なった。
対応する様にenum RESERVED
に字句種別を登録する必要がある。
llex
が字句識別の本体なので他の真似をして追加した。
これらの事を行なったコミットが以下。
ref. https://github.com/masu-mi/lua-with-yorihijouni/commit/3b601929ee2d6fd5ba87e31ad7f8795abe4a7047
書いたときは普通にTK_WHILE
より後ろにTK_LS
などを追加したが以下の記述があったので予約語として扱われる為には
TK_WHILE
より前に置くか、下の記述のTK_WHILE
を自分で追加した予約語に置き換える必要がある。
|
|
これを怠ると何が不都合なのかはまだわかっていない。
- ガベージコレクションの対象になる? そもそも文字列が生成されないので問題になるかわからない
- 字句から予約語の文字列として引き当てに失敗するのかも知れない 前に書いた時は引き当てられていたけどそれは対応する意味情報として引き当てていただけ?
感想
字句解析は単純な処理だけあり読み易い。 ただLua仮想機械でエラーが把握するためにLua文字列の生成や メモリ・バッファの管理などが入り組んでしまう所もある。
字句解析処理はllexで決まっていて既にcodeになっているのに対応する予約語は 後からLua仮想機械に文字列として登録する仕掛けになっているの何でだろうって思った。
次は何処を読もうか迷っている。
順当には構文解析なのだけどLuaはLL(1)
手書きなので想像はつく。
やはりlcode, lvm, ldo
あたりに手をつけた方が得る物が大きいだろうか。