myGroup > myProject
 

チュートリアル

はじめに

umsCodeGenerator を用いたプログラム作成の流れを説明するために、ここでは簡単なサンプルを示します。 このサンプルでは、 CSV データについて以下のステップで処理を行います。

  1. 読み込み: 外部からデータを読み込み、umsCodeGenerator で生成されたデコード関数へデータを渡します。
  2. デコード: デコード関数が mapping definition に従い、データをプログラム変数へ格納します。
  3. エンコード: エンコード関数が mapping definition に従い、プログラム変数をデータへ格納します。
  4. 書き込み: 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>
Note
XML syntax mapping definition XML 文書 です。 そこで、XMLエディタを用いると良いでしょう。 Emacs + nxml-modeが推奨されます。

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>
Warning
mapping definition において、 クラス名、変数名、関数名は自由につけることができます。 ただし、"ums"、"UMS" から始まる識別子は、umsCodeGenerator など mappingSchema の処理系で 用いるために予約されており、使用できません。

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 メソッドを作成します。

  1. 入力データをファイルから読み込み、バッファに格納する。
  2. 入力バッファの内容を表示する。
  3. デコードメソッドを呼び出す。
  4. エンコードメソッドを呼び出す。
  5. 出力バッファの内容を表示する。

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 不要 不要 print

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

Warning
この時、mapping definition の記述が正しくないと、umsCodeGenerator がエラーメッセージを出力します。 エラーメッセージに従って mapping definition を修正し、umsCodeGenerator を再度実行してください。

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>