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 (正規表現ではありません!) 中の任意の文字 | [abc] |
| [c1-c2] | 文字 c1から文字c2 の範囲の任意の文字 | [a-zA-Z] |
| [^str] | 文字列 str に含まれない任意の文字 | [^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
Ctrl-cまたは Ctrl-zで終了できます。
System.exitはプログラムを終了させるためのメソッドです。 例2では 「.」を入力するとプログラムを終了するようになっています。
\.はピリオドそのものを表わします。 「.」(ピリオド)は flexの規則中では特別な意味を持つので、 ピリオドそのものを表わすには\でエスケープしてやります。 同様に「-」も[〜]の中では特別な意味を持つので、 エスケープが必要で、 [+\-]は 「+または -」の意味になります。