Lexer DFA で「コードが大きすぎます」というエラーが発生する
ANTLR 3 を使用して Java Server Pages を解析しようとしています。
Java には、1 つのメソッドのバイト コードに対して 64k の制限があり、ANTLR によって生成された Java ソースをコンパイルするときに、「コードが大きすぎます」というエラーが発生し続けます。
場合によっては、レクサーを妥協することで修正できました。たとえば、JSP は XML の「名前」トークンを使用しますが、これにはさまざまな文字を含めることができます。「名前」トークンでは ASCII 文字のみを受け入れることにしました。これにより、一部のテストが大幅に簡素化され、レクサーでコンパイルできるようになりました。
しかし、これ以上手を抜くことはできないところまで来ましたが、DFA はまだ複雑すぎます。
私はそれについて何をすべきですか?
複雑な DFA の原因となるよくある間違いはありますか?
おそらく予測に役立つセマンティック述語または固定先読みに依存して、DFAの生成を禁止する方法はありますか?
この字句解析器を手で書くのは簡単ですが、ANTLR をあきらめる前に、明らかなことを見落としていないことを確認したいと思います。
バックグラウンド
ANTLR 3 レクサーは、DFA を使用して、入力をトークン化する方法を決定します。生成された DFA には、 というメソッドがありspecialStateTransition()
ます。このメソッドにはswitch
、DFA の各状態のケースを含むステートメントが含まれています。各ケース内にはif
、状態からの遷移ごとに 1 つの一連のステートメントがあります。各if
ステートメントの条件は、入力文字をテストして、遷移に一致するかどうかを確認します。
これらの文字テスト条件は非常に複雑になる場合があります。通常、次の形式をとります。
int ch = … ; /* "ch" is the next character in the input stream. */
switch(s) { /* "s" is the current state. */
…
case 13 :
if ((('a' <= ch) && (ch <= 'z')) || (('A' <= ch) && (ch <= 'Z')) || … )
s = 24; /* If the character matches, move to the next state. */
else if …
lexer に小さな変更を加えたように見えるだけで、1 つの遷移に対して数十回の比較が行われ、各状態に対して複数の遷移が行われ、多数の状態が発生する可能性があります。考慮されている状態のいくつかは、私のセマンティック述語のために到達できないと思いますが、セマンティック述語は DFA によって無視されているようです。(ただし、読み間違えている可能性があります。このコードは、私が手で書くことができるものではありません!)
Jsp2x ツールで ANTLR 2 の文法を見つけましたが、その構文木に満足できず、ANTLR のスキルをリフレッシュしたいので、自分で書いてみようと思いました。私は ANTLRWorks を使用しており、DFA のグラフを生成しようとしましたが、ANTLRWorks にはそれを妨げるバグがあるようです。