JFlex は正規表現を記述したソースファイルから、 Java 言語の字句解析プログラム(スキャナ)を自動生成するプログラムです。 JFlex のソースファイル(通常 .jflex という拡張子をつける)は、 次のようなものです。
(構文解析系(パーサ)から利用するためのメソッド yylexを生成します。 yylexメソッドは、与えられたファイルを最初から順に読み、 呼ばれるたびに次のトークンをリターンするのが本来の使用法ですが、 この例では標準出力に結果を出力しています。)
/* import 文はここに書く */ import java.io.IOException; %% // 生成するクラスの名前 %class Lexer0 // yylex メソッドの戻り値型 %int %unicode %line %column %{ /* フィールドやメソッドはここに書く */ public static void main(String[] args) throws IOException { new Lexer0(System.in).yylex(); } %} /* この例ではここには何も書かない */ %% /* ここに動作記述を書く。*/ /* yytext()はマッチした文字列を返すメソッド */ [hH]ello { System.out.print("Bonjour"); } .|\n { System.out.print(yytext()); } /* その他の文字はそのまま出力 */
/* import 文はここに書く */ import java.io.IOException; %% // 生成するクラスの名前 %class MyLexer // yylex メソッドの戻り値型 %int %unicode %line %column %{ /* フィールドやメソッドはここに書く */ public static void main(String[] args) throws IOException { new MyLexer(System.in).yylex(); } %} /* この例ではここには何も書かない */ %% /* ここに動作記述を書く。*/ /* yytext() はマッチした文字列を返すメソッド */ [ \t]+ { System.out.print('_'); } [0-9]+(\.[0-9]+)?(E[+\-]?[0-9]+)? { System.out.print("<b>"); System.out.print(yytext()); System.out.print("</b>"); } [A-Za-z]([A-Za-z0-9])* { System.out.print("<i>"); System.out.print(yytext()); System.out.print("</i>"); } "." { System.out.print(yytext()); System.exit(1); } // その他の文字はそのまま出力 .|\n { System.out.printf(yytext()); } /* 上の動作記述では値を返していないが、動作記述の中で return 文を書くと、yylex メソッドの戻り値になる。(これが本来の使い方)*/
/* import 宣言はここに書く */ import java.io.IOException; %% // 生成するクラスの名前 %class MyLexer1 // yylex メソッドの戻り値型 %int %unicode %line %column %{ /* フィールドやメソッドはここに書く */ public static void main(String[] args) throws IOException { new MyLexer1(System.in).yylex(); } %} /* ここは正規表現の定義(良く使う正規表現に名前をつける) */ delim = [ \t] ws = {delim}+ letter = [A-Za-z] digit = [0-9] ident = {letter}({letter}|{digit})* number = {digit}+(\.{digit}+)?(E[+\-]?{digit})? %% /* ここに動作記述を書く。*/ /* yytext() はマッチした文字列を返すメソッド */ {ws} { System.out.print('_'); } {number} { System.out.print("<b>"); System.out.print(yytext()); System.out.print("</b>"); } {ident} { System.out.print("<i>"); System.out.print(yytext()); System.out.print("</i>"); } "." { System.out.print(yytext()); System.exit(1); } // その他の文字はそのまま出力 .|\n { System.out.printf(yytext()); } /* 上の動作記述では値を返していないが、動作記述の中で return 文を書くと、yylex メソッドの戻り値になる。(これが本来の使い方)*/
jacc(構文解析部生成系)で生成した構文解析部といっしょに動作させる例は、 ここにあります。
\ " . [ ] * + ? { } | ( ) - < > ^ % / $
式 | 意味 | 例 |
c | 上記の特殊文字以外の文字はその文字そのもの | a |
\c | \n, \t などは C 言語と同じ意味、 それ以外の文字 c は c そのもの | \* |
"str" | 文字列 str そのもの | "**" |
. | 改行以外の任意の文字 | a.*b |
[str] | 文字列 str 中の任意の文字 注: str は正規表現ではないので、 ], \, -, ^, "以外の文字は特別な意味を持たない。 注: flex では、" は [ 〜 ] の中に裸で書いても良いのですが、 JFlex では \" と書かなければいけないようです。 |
[abc] |
[c1-c2] | 文字 c1 から文字 c2 の範囲の任意の文字 | [a-zA-Z] |
[^str] | 文字列 str に含まれない任意の文字 注: str は正規表現ではないので、 ], \, -, ^以外の文字は特別な意味を持たない。 注: flex では、" は [ 〜 ] の中に裸で書いても良いのですが、 JFlex では \" と書かなければいけないようです。 |
[^abc] |
r* | 正規表現 r の 0 回以上の繰り返し | a* |
r+ | 正規表現 r の 1 回以上の繰り返し | a+ |
r? | 正規表現 r の 0 回か 1 回の出現 | a? |
r1r2 | 正規表現 r1 の後に 正規表現 r2 | ab |
r1|r2 | 正規表現 r1 または 正規表現 r2 | a|b |
{name} | name という名前のついた正規表現の定義の展開 | {ident} |
この他、通常の括弧、( と )、 がグループ化のために用いられます。 例えば、 (ab|cd)* は、 ab または cd の 0 回以上の繰り返しを表わします。
このようなファイル(MyLexer.jflex とする)から Java ソースファイルを生成するには
java -jar JFlex.jar MyLexer.jflex
というコマンドを実行します。
これで MyLexer.java という名前の Java ソースファイルが生成されます。
(JFlex ソース中の %class オプションで指定したクラス名の
Java ソースファイルが生成されます。)
この Java ソースファイル(MyLexer.java)を コンパイルすると、クラスファイルが生成されます。
javac MyLexer.java
次のコマンドで実行できます。
java MyLexer
Ctrl-c または Ctrl-z で終了できます。
System.exit はプログラムを終了させるためのメソッドです。 例2では 「.」を入力するとプログラムを終了するようになっています。
\. はピリオドそのものを表わします。 「.」(ピリオド)は jflex の規則中では特別な意味を持つので、 ピリオドそのものを表わすには \ でエスケープしてやります。 同様に「-」も [〜] の中では特別な意味を持つので、 エスケープが必要で、 [+\-] は 「+ または -」の意味になります。