public class TokenReader extends Object
トークン定義に従ってトークン解析を行います.
正規表現でトークンパターンを指定するトークン解析機です。コンテキスト 制御や、開始パターン、終了パターン定義指定などの機能も持ちます。 トークン定義はXMLで行います。
単体でも使用できますが、通常はSyntaxReaderの中で使われます。
SyntaxReaderで指定する<TKN_DEF>によるトークン定義と
本クラスでの定義法は同じです。。
XMLによる定義をTokenReaderに与えた上で、解析すべき入力を与え、 後はreadで回るというのが使い方の基本です。
TokenReader reader= new TokenReader();
reader.readDefinitionXML("tokenDef.xml");
reader.parse("sampleSyntax.text");
Token token=new Token();
while( reader.read(token)!=Token.EOF ){
   System.out.println("token="+token);
   //.. 
   }
逆ポーランド方式の整数計算機(名前メモリー機能付き)のサンプルを載せました。 [an error occurred while processing this directive]
// サンプルプログラム
import otsu.hiNote.*;
import otsu.symphonie.*;
import java.util.*;
import java.io.*;
class test01 {
   static Stack<Integer>          stack 
          = new Stack<Integer>();
   static HashMap<String,Integer> variables
          = new HashMap<String,Integer>();
   public static void main(String[] args_){
      try{
         TokenReader _reader= new TokenReader();
         _reader.readDefinitionXML("tokenDef.xml");
         _reader.parse("SampleIn.txt");
         Token _token=new Token();
         boolean assign_flag=false;
         while( _reader.read(_token)!=Token.EOF ){
            if( _token.name.equals("NUMBER") ){
               stack.push(Integer.parseInt(_token.text));
               }
            else if( _token.name.equals("ASSIGN") ){
               assign_flag= true;
               continue;
               }
            else if( _token.name.equals("NAME") ){
               if( assign_flag ){
                  assign_flag=false;
                  Integer _ans;
                  if( stack.isEmpty() ) {
                     System.out.println("error: value lacked");
                     continue;
                     }
                  _ans= stack.pop();
                  stack.clear();
                  variables.put(_token.text,_ans);
                  System.out.println("Assign "+_ans+" to "+_token.text);
                  continue;
                  }
               else{
                  Integer _i= variables.get(_token.text);
                  if( _i==null ){
                     System.out.println("error: "+_token.text+" not defined");
                     _i = 0;
                     }
                  stack.push(_i);
                  }
               }
            else if( _token.name.equals("OPERATION") ){
               if( stack.size()<2 ){
                  System.out.println("error: value lacked");
                  continue;
                  }
               Integer _i2= stack.pop();
               Integer _i1= stack.pop();
               if( _token.text.equals("+") ){
                  stack.push(_i1+_i2);
                  }
               else if( _token.text.equals("-") ){
                  stack.push(_i1-_i2);
                  }
               else if( _token.text.equals("*") ){
                  stack.push(_i1*_i2);
                  }
               else if( _token.text.equals("/") ){
                  stack.push(_i1/_i2);
                  }
               }
            System.out.println(_token.text+" : "+stack);
            }
         }
      catch(Exception e){
         e.printStackTrace(hiU.err);
         }
      }
   }
// サンプルトークン定義
<?xml version="1.0" encoding="UTF-8"?>
<definition>
   <TKN_DEF pattern="[ \t\n]*"/>
   <TKN_DEF pattern="//.*$"/>
   <TKN_DEF name="OPERATION" pattern="[\-+/*]" />
   <TKN_DEF name="ASSIGN"    pattern="="/>
   <TKN_DEF name="CLEAR"     pattern=";"/>
   <TKN_DEF name="NUMBER"    pattern="[0-9][9-9]*"/>
   <TKN_DEF name="NAME"      pattern="[a-zA-Z_][0-9a-zA-Z_]*" />
</definition>
// TokenReader 逆ポーランド計算機プログラム入力サンプル
1 2 3 * + = aa
4 aa * 5 3 - / = bb
aa bb - = cc
// 実行結果
1 : [1]
2 : [1, 2]
3 : [1, 2, 3]
*: [1, 6]
+ : [7]
Assign 7 to aa
4 : [4]
aa : [4, 7]
*: [28]
5 : [28, 5]
3 : [28, 5, 3]
- : [28, 2]
/ : [14]
Assign 14 to bb
aa : [7]
bb : [7, 14]
- : [-7]
Assign -7 to cc
トークン定義はXMLで与えます。
<!--トークン全体パターンを与える指定 --> <TKN_DEF name = "トークン名" 省略可※ pattern= "正規表現によるトークンパターン" 省略可※ on = "依存コンテキスト" 省略可 to = "新たなコンテキスト" 省略可 /> <!-- ※:name,patternのどちらかを省略することはできますが 両方省略することはできません --> <!-- トークンの開始パターンと終了パターンを指定する書き方 --> <TKN_DEF name = "トークン名" 省略可 start = "正規表現によるトークンの開始パターン" end = "正規表現によるトークンの終了パターン on = "依存コンテキスト" 省略可 to = "新たなコンテキスト" 省略可 > <TKN_ALT pttern= "正規表現による代替対象" alt = "代替文字列" /> 省略可複数可 </TKN_DEFv
これらの定義を複数並べます。基本的には先に書かれたパターンにマッチ すると後ろのパターンは検証されません。
空白や単純コメント
トークン名は省略可能で、省略した場合は、読み取った上で廃棄されます。
通常空白やコメントはトークン名を書かずに廃棄します。
<!-- 空白とC形式の行コメント --> <TKN_DEF pattern=" \t\n\r"/> <TKN_DEF pattern="//.*$"/>
単純キーワード
単純キーワードはnameとpatternに同じ値を書くか、nameだけを記述 することにより定義できます。
<!-- 単純キーワード定義 --> <TKN_DEF name="struct" pattern="struct"/> <TKN_DEF name="enum"/>
パターンワード
プログラム上での名前や数値などはname=でその型名を与え、pattern= で正規表現パターンを示します。
<!-- C風nameと整数値 --> <TKN_DEF name="NAME" pattern="[a-zA-Z_][0-9a-zA-Z_]*"/> <TKN_DEF name="INT_NUM" pattern="[0-9]+"/>
コンテキスト制御(例えばCのブロックコメントなどを実現)
特定コンテキスト(文脈)の場合のみ有効なパターンを定義できます。
パターンマッチ後移行するコンテキストを指定することもできます。
コンテキストは文字列による名前で示されます。デフォルトは"0"です。
特定のコンテキストの場合のみ有効な定義はon=で指定します。
移行するコンテキストはto=で指定します。
<!-- Cのブロックコメント --> <TKN_DEF pattern="/\*" to="com"/> "/*"でコンテキストをcomに切り替える <TKN_DEF pattern="\*/" on="com" to="0" /> "*/"でコンテキストをデフォルトに切り替える <TKN_DEF pattern="." on="com" /> コンテキストがcomの場合1文字を読み飛ばす 注意:このコードはjavadocの制限により半角の*の代わりに全角の*を使っています
開始終了パターン指定、文字置き換えのあるトークン(Cの文字列など)
開始パターンと終了パターンを指定してトークンを得ることができます。 開始パターン、終了パターン自体はトークンから外されます。
開始から終了の間に出てくるパターンの置き換え機能を持ちます。
次の定義は引用符から引用符までを1トークンとする定義です。
ただし、その中に現れるエスケープシーケンスとして\"を"に置き換え
\\を\に置き換えます。\は正規表現自体のエスケープ文字ですので
\を\\と書く必要があります。
<TKN_DEF name="string" start='"' end='"'> 引用符から引用符まで <TKN_ALT pattern="\\\\" alt="\"/> \\は\に置き換える <TKN_ALT pattern='\\"' alt='"'/> \"は"に置き換える </TKN_DEF>
| コンストラクタと説明 | 
|---|
| TokenReader() | 
| 修飾子とタイプ | メソッドと説明 | 
|---|---|
| String | getContext()文脈を得る. | 
| void | parse(BufferedReader br_)解析するソースを設定する. | 
| void | parse(String fileName_)解析するファイルを設定する. | 
| void | parse(String fileName_,
     String charSet_)解析するファイルを設定する. | 
| int | read(Token tkn_)トークンを取得する. | 
| void | readDefinitionXML(InputStream is_)XMLによるトークン定義を読み込む | 
| void | readDefinitionXML(String fileName_)XMLによるトークン定義を読み込む | 
| void | setContext(String context_)文脈を変える | 
| void | setSourceName(String sourceName_)ソース名を設定する. | 
public int read(Token tkn_) throws Exception
tkn_ - トークン情報をセットするToken構造体Exception - 失敗public String getContext()
public void setContext(String context_)
context_ - 文脈名public void parse(BufferedReader br_) throws Exception
 この関数は直ちにリターンします。
 この後read(Token)を呼び出してください。
br_ - ソースException - 失敗public void setSourceName(String sourceName_) throws Exception
parse(BufferedReader)の場合ソースファイル名が
ないが、この関数で仮の名前を与えることができる。
parse(String)の場合、この関数を呼ぶ必要はない
sourceName_ - ソース名Exception - 失敗public void parse(String fileName_) throws Exception
 この関数の中でオープンされます。
 この関数は直ちにリターンします。
 この後read(Token)を呼び出してください。
fileName_ - ファイル名Exception - 失敗public void parse(String fileName_, String charSet_) throws Exception
 この関数の中でオープンされます。
 この関数は直ちにリターンします。
 この後read(Token)を呼び出してください。
fileName_ - ファイル名charSet_ - 文字セットException - 失敗public void readDefinitionXML(String fileName_) throws Exception
fileName_ - トークン定義ファイル名Exception - 失敗public void readDefinitionXML(InputStream is_) throws Exception
is_ - トークン定義を読み込むストリームException - 失敗