JFlex は正規表現を記述したソースファイルから、 Java 言語の字句解析プログラム(スキャナ)を自動生成するプログラムです。 JFlex のソースファイル(通常 .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 | 上記の特殊文字以外の文字は c という文字そのもの | a | 
| \c |  \n, \t などは C 言語と同じ意味、
それ以外の文字は c そのもの 上記の特殊文字そのものをあらわすためには、この形を使う必要がある。  | 
\* \"  | 
| "str" | 文字列 str そのもの 注: "〜"の中では " と \ は特別な意味を持つのでエスケープ (\" と \\)する必要がある。 注: \n, \t など C 言語で使われるエスケープシーケンスは C 言語と同じ意味になる。 注: その他の文字は特別な意味を持たない。  | 
"**" "\"\"\"" "\\\""  | 
| . | 改行以外の任意の文字 | a.*b | 
| [str] |  文字列 str 中の任意の文字 注: [〜] の中では ], \, -, ^, "は特別な意味を持つので エスケープ(\], \\, \-, \^, \")する必要がある。 注: ], \, -, ^, " 以外の文字は特別な意味を持たない。 注: flex では、" は [ 〜 ] の中に裸で書いても良いのですが、 JFlex では \" と書かなければいけないようです。  | 
[abc] | 
| [c1-c2] |  文字 c1 から文字 c2
の範囲の任意の文字 注: [〜] の中では ], \, -, ^, " は特別な意味を持つので エスケープ(\], \\, \-, \^, \")する必要がある。 注: ], \, -, ^, " 以外の文字は特別な意味を持たない。 注: flex では、" は [ 〜 ] の中に裸で書いても良いのですが、 JFlex では \" と書かなければいけないようです。  | 
[0-9] [a-zA-Z] [a-zA-Z_\-$]  | 
| [^str] |  文字列 str に含まれない任意の文字 注: [〜] の中では ], \, -, ^, " は特別な意味を持つので エスケープ(\], \\, \-, \^, \")する必要がある。 注: ], \, -, ^, " 以外の文字は特別な意味を持たない。 注: flex では、" は [ 〜 ] の中に裸で書いても良いのですが、 JFlex では \" と書かなければいけないようです。  | [^abc] [^*+/\-]  | 
| r* | 正規表現 r が表す文字列の 0 回以上の繰り返し | a* | 
| r+ | 正規表現 r が表す文字列の 1 回以上の繰り返し。 rr* のこと | a+ | 
| r? | 正規表現 r が表す文字列の 0 回か 1 回の出現。 (r|ε) に相当する | 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 の規則中では特別な意味を持つので、 ピリオドそのものを表わすには \ でエスケープしてやります。 同様に「-」も [〜] の中では特別な意味を持つので、 エスケープが必要で、 [+\-] は 「+ または -」の意味になります。