Lexerとかの挙動
僭越ながら ASTは、タダじゃ作ってくれない。 - 設計と実装の狭間で。 を添削。
トーカナイズ
まず、↓の評価について。
charactors : (CHAR)+;
...
CHAR : ('0'..'9'|'a'..'z'|'A'..'Z') ;
これをやると、"hoge"っていう文字列に対して、"h", "o", "g", "e" って言うトークンを作った後に charactersという構文ルールで纏め上げてしまう。
ということで、
charactors : IDENT; ... IDENT : CHAR+; fragment CHAR : ('0'..'9'|'a'..'z'|'A'..'Z') ;
こんなかんじ。こうすると、IDENTというlexerルールで"hoge"というトークンを作る。
fragmentはlexerルールの前につけると、トークンを作らずにマクロっぽい動きをするという指示子。
正規表現の罠
これだけで終わりにしてしまうと、なぜかIFとかが出現しなくなってしまう。
これは、Lexer特有の優先度付けのせいで、
- 最長一致 (文字数の多いトークンを優先)
- 早い者勝ち (文字数が同じならば、先に宣言したものを優先)
というなぞの2個目のルールがあるため。
なので、IDENTが
BEGIN : WS* 'BEGIN' WS*;
IF : WS* 'IF' WS*;
ELSE : WS* 'ELSE' WS*;
END : WS* 'END' WS*;
の、BEGINやらIFやらを食ってしまう。
これは単純に、IDENTをこれらより後ろで宣言すればいい。
つまり、
BEGIN : WS* 'BEGIN' WS*; IF : WS* 'IF' WS*; ELSE : WS* 'ELSE' WS*; END : WS* 'END' WS*; IDENT : CHAR+;
なかんじ。
WSをparserルール上に出現させない方法などは次回。