チュートリアル
はじめに
umsCodeGenerator を用いたプログラム作成の流れを説明するために、ここでは簡単なサンプルを示します。 このサンプルでは、 CSV データについて以下のステップで処理を行います。
- 読み込み: 外部からデータを読み込み、umsCodeGenerator で生成されたデコード関数へデータを渡します。
- デコード: デコード関数が mapping definition に従い、データをプログラム変数へ格納します。
- エンコード: エンコード関数が mapping definition に従い、プログラム変数をデータへ格納します。
- 書き込み: umsCodeGenerator で生成されたエンコード関数からデータを受け取り、外部へデータを書き出します。
2番目と3番目のステップが umsCodeGenerator によって生成されたソースコードが処理する部分です。 その他の部分は普通にプログラムを作成します。
チュートリアルを開始するまでに、umsCodeGenerator のインストールを完了しておいてください。
なお、以降で作成するサンプルは umsCodeGenerator/yyyymmddvv/sample/tutorial に含まれています。 このディレクトリには、Java 版の XML syntax、Language syntax、C 版の XML syntax、Language syntax のサンプルが含まれています。
1. 入力データの作成
入力データと出力データの書式はどちらも同じで、"," を区切り文字とした CSV 形式とします。 以下のデータを "sample.csv" という名前でファイルに保存してください。
A,100,1.1
B,200,2.2
C,300,3.3
今回、 mappingSchema で 定義するデータの単位は、各行単位にします(ファイル全体を定義することもできます)。 行の切り出しは外付けで処理し(ステップ 1、4)、 各行の処理を mappingSchema で定義する(ステップ 2、3)ことにします。
2. mapping definition の作成
任意のエディタで mapping definition を作成します。 mapping definition は、XML syntax、Language syntax、C 版、Java 版ともに以下の記述が必要になります。 2.1 以降では、この記述に追記していく形で、Java 版の XML syntax の mapping definition を作成していきます。
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://ums.isas.jaxa.jp/0.4/dat" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> : </start> </grammar>
2.1 クラス名を決める
デコード・エンコード関数を持つクラス名を決めます。今回は、"Sample" というクラス名を用います。 (この定義は、C 言語版では不要です。) ソースコードでは以下のように表せます。
class Sample { : }
これを、 mapping definition の XML 形式に書き直すと以下になります。
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://ums.isas.jaxa.jp/0.4/dat" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <java:class name="Sample" xmlns:java="http://ums.isas.jaxa.jp/0.4/java"> : </java:class> </start> </grammar>
2.2 エンコード関数、デコード関数の名前を決める
デコード処理、エンコード処理を行う関数の名前を決めます。 今回は、デコード処理を行う関数を"decode"、エンコード処理を行う関数を"encode"という名前にします。
次に、エンコード関数、デコード関数のインターフェースを決めます。 これらの関数のインターフェース(引数の型、引数の名前)は、umsCodeGenerator で以下のように固定です ( mappingSchema の決まりではありません)。
言語 | 関数種別 | インターフェース |
---|---|---|
C言語 | デコード関数 |
/** * デコード処理を行う。 * * @param ums__buffer 入力データ格納バッファ * @param ums__bitlen 入力データ長(bit) * ※入力データそのもののデータであり、入力格納バッファのサイズではない。 * @param ums__ex 例外情報 * @return デコードデータサイズ(bit) */ ums__bitlen_t decode( ums__bitdata_t *ums__buffer, ums__bitlen_t ums__bitlen, ums__exception_t *ums__ex ) |
エンコード関数 |
/** * エンコード処理を行う。 * * @param ums__buffer 出力データ格納バッファ * @param ums__bitlen 出力データ格納バッファの長さ(bit) * @param ums__ex 例外情報 * @return エンコードデータサイズ(bit) */ ums__bitlen_t encode( ums__bitdata_t *ums__buffer, ums__bitlen_t ums__bitlen, ums__exception_t *ums__ex ) |
|
Java | デコード関数 |
/** * デコード処理を行う。 * * @param ums__buffer 入力データ格納バッファ * @param ums__bitlen 入力データ長(bit) * ※入力データそのもののデータであり、入力格納バッファのサイズではない。 * @return デコードデータサイズ(bit) * @exception UMSException デコード処理エラー */ int decode( byte[] ums__buffer, int ums__bitlen ) throws UMSException |
エンコード関数 |
/** * エンコード処理を行う。 * * @param ums__buffer 出力データ格納バッファ * @param ums__bitlen 出力データ格納バッファの長さ(bit) * @return エンコードデータサイズ(bit) * @exception UMSException エンコード処理エラー */ int encode( byte[] ums__buffer, int ums__bitlen ) throws UMSException |
ソースコードでは以下のように表すことができます。
class Sample { : int decode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : } int encode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : } }
これを、 mapping definition の XML 形式に書き直すと以下になります。
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://ums.isas.jaxa.jp/0.4" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <java:class name="Sample" xmlns:java="http://ums.isas.jaxa.jp/0.4/java"> : <defineFunctions> <java:function name="decode"> <java:arg type="byte[]" name="ums__buffer" direction="in"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> : </java:function> <java:function name="encode"> <java:arg type="byte[]" name="ums__buffer" direction="out"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> : </java:function> </defineFunctions> </java:class> </start> </grammar>
2.3 データ構造の定義
以下のデータについて、データ構造を mappingSchema の文法に沿った XML 形式で定義します。
A,100,1.1
以下の定義は、セパレータ "," で区切られたリスト形式で、 順に"トークン型"、"整数型"、"浮動小数点型"のデータ構造であることを示しています。
<byte> <list separator=","> <data type="token"/> <data type="int"/> <data type="double"/> </list> </byte>
2.4 プログラミング言語の処理の定義
次に、プログラミング言語の処理を決めます。 ここでは、処理対象のデータ全てを変数に保持する処理を採用します。 そこで、これを保持するための変数を用意することにします。 ソースコードでは以下のように表せます。
class Sample { String sData; int iData; double dData; int decode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : } int encode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : } }
これを、 mappingSchema の XML 形式に書き直すと以下になります。
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://ums.isas.jaxa.jp/0.4" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <java:class name="Sample" xmlns:java="http://ums.isas.jaxa.jp/0.4/java"> <defineVariables> <java:var class="String" name="sData"/> <java:var type="int" name="iData"/> <java:var type="double" name="dData"/> </defineVariables> <defineFunctions> <java:function name="decode"> <java:arg type="byte[]" name="ums__buffer" direction="in"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> : </java:function> <java:function name="encode"> <java:arg type="byte[]" name="ums__buffer" direction="out"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> : </java:function> </defineFunctions> </java:class> </start> </grammar>
2.5 データ構造と言語での処理の対応の定義
次に、データ構造と、プログラミング言語の処理の対応を定義します。 ここでは、データを順に変数と対応させます。 ソースコードでは以下のように表せます。
class Sample { String sData; int iData; double dData; int decode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : sData = ... ; // 1項目目のデコード : iData = ... ; // 2項目目のデコード : dData = ... ; // 3項目目のデコード : } int encode( byte[] ums__buffer, int ums__bitlen ) throws UMSException { : ... = sData ; // 1項目目のエンコード : ... = iData ; // 2項目目のエンコード : ... = dData ; // 3項目目のエンコード : } }
これを、 mapping definition の XML 形式に書き直すと以下になります。
<?xml version="1.0" encoding="UTF-8"?> <grammar xmlns="http://ums.isas.jaxa.jp/0.4" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"> <start> <java:class name="Sample" xmlns:java="http://ums.isas.jaxa.jp/0.4/java"> <defineVariables> <java:var class="String" name="sData"/> <java:var type="int" name="iData"/> <java:var type="double" name="dData"/> </defineVariables> <defineFunctions> <java:function name="decode"> <java:arg type="byte[]" name="ums__buffer" direction="in"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> <defineMapping direction="decode"> <dat:byte encode="txt" xmlns:dat="http://ums.isas.jaxa.jp/0.4/dat"> <dat:list separator=","> <java:value-of select="sData"> <data type="token"/> </java:value-of> <java:value-of select="iData"> <data type="int"/> </java:value-of> <java:value-of select="dData"> <data type="double"/> </java:value-of> </dat:list> </dat:byte> </defineMapping> </java:function> <java:function name="encode"> <java:arg type="byte[]" name="ums__buffer" direction="out"/> <java:arg type="int" name="ums__bitlen" direction="in"/> <java:return type="int"/> <java:exception type="UMSException"/> <defineMapping direction="encode"> <dat:byte encode="txt" xmlns:dat="http://ums.isas.jaxa.jp/0.4/dat"> <dat:list separator=","> <java:value-of select="sData"> <data type="token"/> </java:value-of> <java:value-of select="iData"> <data type="int"/> </java:value-of> <java:value-of select="dData"> <data type="double"/> </java:value-of> </dat:list> </dat:byte> </defineMapping> </java:function> </defineFunctions> </java:class> </start> </grammar>
以上で mapping definition の作成は終了です。 この mapping definition を、Sample.ums という名前でファイルに保存してください。
3. その他のソースコードの作成
デコード関数、エンコード関数以外のソースコードを通常の方法で作成します。 ここでは、以下の処理を行う main メソッドを作成します。
- 入力データをファイルから読み込み、バッファに格納する。
- 入力バッファの内容を表示する。
- デコードメソッドを呼び出す。
- エンコードメソッドを呼び出す。
- 出力バッファの内容を表示する。
3.1 デコード関数・エンコード関数使用時に必要な処理
デコード関数、エンコード関数を使用するにあたって、次の処理を行う必要があります。
- ライブラリクラスの include(C 言語) / import(java)
- 初期化関数の呼び出し
- 終了関数の呼び出し
各プログラミング言語において、ライブラリ、初期化関数、終了関数は、それぞれ以下のようになります。
言語 | ライブラリ | 初期化関数 | 終了関数 |
---|---|---|---|
C言語 | ums.h | tableTools_init() | tableTools_end() |
Java | jp.jaxa.isas.ums.runtime.* | UMSLibrary.tableTools_init() | UMSLibrary.tableTools_end() |
main 関数は以下のようになります。
import java.io.*; import jp.jaxa.isas.ums.runtime.*; class Main { private static final int BUFFER_SIZE = 4096; public static void main( String[] args ) { String inString = null; byte[] inBuffer = null; int inBitlen = 0; int decodeBitlen = 0; byte[] outBuffer = new byte[BUFFER_SIZE]; int outBitlen = 0; int encodeBitlen = 0; BufferedReader br = null; UMSLibrary.tableTools_init(); try { Sample sample = new Sample(); br = new BufferedReader( new FileReader( args[0] ) ); while ( ( inString = br.readLine() ) != null ) { inBitlen = inString.length() * 8; inBuffer = inString.getBytes( "US-ASCII" ); System.out.println( "input(" + inBitlen/8 + "*8+" + inBitlen%8 + "):<" + inString + ">" ); /* call decode method */ decodeBitlen = sample.decode( inBuffer, inBitlen ); outBitlen = BUFFER_SIZE * 8; /* call encode method */ encodeBitlen = sample.encode( outBuffer, outBitlen ); String outString = new String( outBuffer, 0, encodeBitlen/8, "US-ASCII"); System.out.println( "output(" + encodeBitlen/8 + "*8+" + encodeBitlen%8 + "):<" + outString.trim() + ">" ); } } catch ( IOException ex ) { ex.printStackTrace( System.err ); } catch ( Throwable th ) { th.printStackTrace( System.err ); } finally { try { if ( br != null ) { br.close(); } } catch ( Exception ex ) {} } UMSLibrary.tableTools_end(); } }
3.2 例外機構の使い方
エンコード関数・デコード関数は、データが定義にマッチしなかった場合などに例外を発生します。 例外機構を使用するにあたって、次の処理を行う必要があります。
- ライブラリクラスの include(C 言語) / import(java)
- 例外情報保持変数の宣言(C言語のみ)
- 例外情報初期化関数の呼び出し(C言語のみ)
- 例外情報の出力
各プログラミング言語において、ライブラリ、初期化関数、終了関数は、それぞれ以下のようになります。
言語 | ライブラリ | 例外情報保持変数型 | 例外情報初期化関数 | 例外情報出力関数 |
---|---|---|---|---|
C言語 | umsException.h | ums__exception_t | ums__exception_init | ums__exception_print |
Java | jp.jaxa.isas.ums.runtime.UMSException | 不要 | 不要 |
main 関数は以下のようになります。
import java.io.*; import jp.jaxa.isas.ums.runtime.*; class Main { private static final int BUFFER_SIZE = 4096; public static void main( String[] args ) { String inString = null; byte[] inBuffer = null; int inBitlen = 0; int decodeBitlen = 0; byte[] outBuffer = new byte[BUFFER_SIZE]; int outBitlen = 0; int encodeBitlen = 0; BufferedReader br = null; UMSLibrary.tableTools_init(); try { Sample sample = new Sample(); br = new BufferedReader( new FileReader( args[0] ) ); while ( ( inString = br.readLine() ) != null ) { inBitlen = inString.length() * 8; inBuffer = inString.getBytes( "US-ASCII" ); System.out.println( "input(" + inBitlen/8 + "*8+" + inBitlen%8 + "):<" + inString + ">" ); /* call decode method */ decodeBitlen = sample.decode( inBuffer, inBitlen ); outBitlen = BUFFER_SIZE * 8; /* call encode method */ encodeBitlen = sample.encode( outBuffer, outBitlen ); String outString = new String( outBuffer, 0, encodeBitlen/8, "US-ASCII"); System.out.println( "output(" + encodeBitlen/8 + "*8+" + encodeBitlen%8 + "):<" + outString.trim() + ">" ); } } catch ( UMSException ex ) { ex.print( outBuffer, outBitlen ); ex.printStackTrace( System.err ); } catch ( IOException ex ) { ex.printStackTrace( System.err ); } catch ( Throwable th ) { th.printStackTrace( System.err ); } finally { try { if ( br != null ) { br.close(); } } catch ( Exception ex ) {} } UMSLibrary.tableTools_end(); } }
上記の main メソッドを、"Main.java" という名前で保存してください。
4. umsCodeGenerator の実行
mapping definition から ソースコードを生成するため、以下のコマンドで umsCodeGenerator を実行してください。 カレントディレクトリに、"Sample.java" というファイルが生成されます。
$ txt2java -x Sample.ums
5. コンパイル・実行
これ以降は普通のプログラム開発と同じです。 これまで作成、生成したファイル(sample.csv、Main.java、Sample.java)をカレントディレクトリに格納し、 以下のコマンドを実行してください。
-
C言語
$ gcc -std=c99 -ggdb -o main -Wall -I${TABLETOOLS_HOME}/build/include -I. *.c -L${TABLETOOLS_HOME}/build/lib/ -lums -lumstt
$ ./main < sample.csv -
Java
$ javac -classpath .:$TABLETOOLS_HOME/build/classes Main.java Sample.java
$ java -cp .:$TABLETOOLS_HOME/build/classes Main sample.csv
正しく処理ができていれば、以下が表示されます。
input(9*8+0):<A,100,1.1>
output(9*8+0):<A,100,1.1>
input(9*8+0):<B,200,2.2>
output(9*8+0):<B,200,2.2>
input(9*8+0):<C,300,3.3>
output(9*8+0):<C,300,3.3>