Vino言語 (4/4) - やまざき@BinaryTechnology
「デスマーチと戦う武蔵流プログラマ やまざき のページ」

TopPage
(サイトマップ)


Book
(書籍)


「火事場プロジェクトの法則」
サポートページ


「LHAとZIP」
サポートページ



Document
(文章)

デスマーチの記録に見る
運命の分かれ道
NEW!

武蔵流プログラマからの提言

武蔵流プログラマが斬る Eclipse

コードデザイン最前線
1
2 3 4 5 6 7 8 9
10 11 12 13 ML

C++で読む
デザインパターン


ポインタ不要論

データ圧縮の基礎

プログラマへの
アドバイス


データ指向の話1 2

インターフェースの話


Diary & Books
(日記と本屋)

やまざきの
はてなダイアリ
(日記)
[] [PC] [資産運用]
[デスマ] [映画] [2足ロボ]

やまざきの本屋


SoftWorks
(ソフトウェア)


(1) DeepFreezer
(ディープ・フリーザー)
高速アーカイバ

(English Page)

(2) Closedown-Planet
(クローズダウン・プラネット)
アクションパズルゲーム


(3) PieceMaker
(ピース・メーカー)
ファイル分割/結合


(4) WakuPita
(枠ピタ)
ウィンドウ移動便利ツール

(English Page)

(5) ググ郎
(Bookmarklet)
選択文字列をGoogleで検索

NEW!


Developing
(開発中)


(1) DeepFreezer2
yz2dlg.dll alpha6


C Magazine特集yz2


Hobby & Favorite
(道楽/お気に入り)


2LegRobo
MindStorms



p.s.
(雑談)


Profile

i_want^^;


やまざきが書いた本


[システム開発]
火事場プロジェクトの法則
どうすればデスマーチをなくせるか?
2006/09/13 発売


LHAとZIP
圧縮アルゴリズム×プログラミング入門

奥村さんと共著です。
2003/12/01 発売


やまざきが寄稿した本


SEの読書術
「本質を読む」力を磨く10の哲学 2006/02発売。



開発の現場 Vol.002
「反デスマーチ大研究」という記事。2005/09/13発売。



Software People Vol.3
「武蔵流プログラマからの提言」という記事。2003/10/31発売。



Eclipse パーフェクトマニュアル vol.1
「武蔵流プログラマが斬る Eclipse」という記事。2003/06/05発売。




Vino言語(1/4) (2/4) (3/4) (4/4)


Vino 言語仕様の予定 ver. 0.02 2002/11/20

…と、ここまで書いて力尽きた…。ごめんなさい。以下、工事中です。^^;
break, continue の話と、ライブラリの話と、例外の話がちょっぴりです。
------------------------------------------------------------

◆ vector[] の each と break の組み合わせ。

label A                       -- ラベル名称 A
{
    tbl : 'a''b''c', ;
    tbl.each(
        func {
            -- sys.put( in[0].type_name() ) ; -- string が表示される

            in[0] == 'b' ? break A ; -- ここから
            sys.put( "{in[0]}\n" ) ;
        }
    ) ;
} ;                           -- ここへ飛ぶ(Aを抜ける)
-- a のみが表示される



'a''b''c', ).each(
    func {
        -- sys.put( in[0].type_name() ) ; -- string が表示される

        in[0] == 'b' ? break each ;  -- ここから
        sys.put( "{in[0]}\n" ) ;
    }
) ;                                  -- ここへ飛ぶ(each の外へ飛ぶ)
-- a のみが表示される


◆ continue文 

C/C++言語のcontinueと同じ動きをする。
label のスコープを繰り返すか、最も内側のループを繰り返す。

comment_rex : Rex( '^#' ) ;
sys.each( -- 標準入力
    func {
        -- sys.put( in[0].type_name() ) ; -- string が表示される

        comment_rex.match( in[0] ) ? continue each ; -- コメント # は除外
        sys.put( in[0] ) ;
    }
) ;

◆ vector[] の each と continue の組み合わせ。

label A                       -- ラベル名称 A -- ここへ飛ぶ
{
    tbl : 'a''b''c', ;
    tbl.each(
        func {
            -- sys.put( in[0].type_name() ) ; -- string が表示される

            in[0] == 'b' ? continue A ; -- ここから
            sys.put( "{in[0]}\n" ) ;
        }
    ) ;
} ;                           
-- a a a a a ... が表示される(無限ループだねー)


tbl : 'a''b''c', ;
tbl.each(                     -- ここへ飛ぶ(次の each へ)
    func {
        -- sys.put( in[0].type_name() ) ; -- string が表示される

        in[0] == 'b' ? continue each ; -- ここから
        sys.put( "{in[0]}\n" ) ;
    }
) ;
-- a c が表示される



●4章 ライブラリ 

class File, class FileBinary, class FileStatus

ファイル入出力(_FileIn, _FileOut, _FileAdd)

interface _StreamIn
{
out func each
    {
        in:funcin:string, },
    }
}

interface _StreamIn
{
out func put
    {
        in:string,
    }
}

interface _FileIn
{
out func read_open
    {
        in:funcin:_StreamIn, },
    }
}

interface _FileOut
{
out func write_open
    {
        in:funcin:_StreamOut, },
    } ;
} ;


interface _FileAdd
{
out func add_open
    {
        in:funcin:_StreamOut, },
    } ;
} ;

class File
{
    in_filename : string in[0] ;

    use _FileOut ;
    use _FileIn ;
    use _FileAdd ;
} ;

class FileBinary
{
    in_filename : string in[0] ;

    use _FileOut ;
    use _FileIn ;
    use _FileAdd ;
} ;


◆ _StreamIn の each と break の組み合わせ。
break は C/C++言語の break とほぼ同じ動きをする。
label のスコープを抜けるか、最も内側のスコープを抜ける。

File( 'file.txt' ).read_open(
func {
    -- sys.put( in[0].type_name() ) ; -- interface:_StreamIn が表示される
    fp : in[0] ;
    fp.each(
        func {
            -- sys.put( in[0].type_name() ) ; -- string が表示される

            in[0] == "END\n" ? break each ; -- ここから
            sys.put( "{in[0]}\n" ) ;
        }
    ) ;                         -- ここへ飛ぶ
} ) ;


◆ ファイル読み込み 

fp : File( 'file.txt' ) ;
-- sys.put( fp.type_name() ) ; -- class:File{in:string,} が表示される

fp.read_open(
    func {
        -- sys.put( in[0].type_name() ) ; -- interface:_StreamIn{} が表示される

        in[0].each(
            func {
                -- sys.put( in[0].type_name() ) ; -- string が表示される

                line : in[0] ;
                sys.put( line ) ; -- 一行ずつ表示
            }
        ) ;
    }
) ;

上のコードを簡単に書くと

File( 'datafile.txt' ).read_open
{
    -- sys.put( in[0].type_name() ) ; -- _StreamIn が表示される

    in[0].each
    {
        -- sys.put( in[0].type_name() ) ; -- string が表示される

        sys.put( in[0] ) ;
    } ;
} ;


もっと簡単に書くと

File( 'datafile.txt' ).read_open().each{ sys.put( in ) ; } ;

では、なにも省略せずにすべて書いてみると…

fp : File( 'file.txt' ) ;

func read_open_callback
{
    input : _StreamIn in[0] ;

    func input_each_callback
    {
        one_line : string in[0] ;

        sys.put( one_line ) ; -- 一行ずつ表示
    } ;
    input.each( input_each_callback ) ;
} ;

fp.read_open( read_open_callback ) ;


次のようにファイルの各行を配列に一括して読み込むこともできます。

tbl $ list[string] ;
File( 'datafile.txt' ).read_open().each{ tbl <<= in[0] ; } ;
sys.put( tbl.str() ;



また、次のようにすると、コマンドラインで指定したファイルをひとつづつオープンし、
それを順次読み込むことができます。

sys.arg.each(
    func {
        -- sys.put( in[0].type_name() ; -- string が表示される

        File( in[0] ).read_open().each(
            func { sys.put( in[0] ) ; }
        ) ;
    }
) ;

これは、だいたい、次のような処理と同等になります。

sys.arg.size.each(
    func {
        -- sys.put( in[0].type_name() ; -- int が表示される

        File( sys.arg[in[0]] ).read_open().each(
            func { sys.put( in[0] ) ; }
        ) ;
    }
) ;

◆ ファイル書き込み 

ファイルに何かを書き込むには次のようにします。

File( 'datafile.txt' ).write_open(
    func {
        -- sys.put( in[0].type_name() ; -- _StreamOut が表示される

        in[0] <<= "こんにちは\n" ;
    }
) ;

では、なにも省略せずに書いてみます。

fw : File( 'datafile.txt' ) ;

func write_ok_callback
{
    strm : _StreamOut in[0] ;

    strm.push( "こんにちは\n" ) ;
} ;

fp.write_open( write_ok_callback ) ;

ファイルに追加書き込みするには次のようにします。

File( 'datafile.txt' ).add_open
{
    -- sys.put( in[0].type_name() ; -- _StreamOut が表示される

    in[0] <<= "こんにちは\n" ;
}


◆ 標準入出力 

File() を用いて作成する他に、次の3つのハンドルがあらかじめオープンされています。

sys          -- 標準入力 interface:_StreamIn ;
sys          -- 標準出力 interface:_StreamOut ;
sys.stderr   -- 標準エラー出力 interface:_StreamOut ;

sys : class System
{
    use _StreamIn ;
    use _StreamOut ;
    out stderr : _StreamOut ;
}

標準入力から各行を読み込むには次のようにします。

sys.each{ sys <<= in[0] ; } ;


◆ バイナリ読み込み 

例えば次のようなコードを用いる事により、ファイルをバイナリデータとして読み込む事ができます。

buff $ vectorbyte ] ; -- byte や bit もいるのかな?

FileBinary( 'binary.dat' ).read_open(
    func {
        fp : _StreamIn in[0] ;
        in.each(
            func {
                buff <<= in[0] ;
            }
        ) ;
    }
) ;

buff.each
{
    sys.put( "{02x:in[0]}" ) ;
} ;



●以下、おまけ(Pipe, Call, Rex)


◆ 外部コマンド実行 

出力結果を外部コマンドに渡すこともできます。
次の例ではsys.put文の出力をnkfコマンドでJISコードに変換して出力しています。

Pipe( '/usr/local/bin/nkf -j' ).write_open
{
    -- sys.put( in[0].type_name() ; -- _StreamOut が表示される

    in[0] <<= "こんにちは\n" ;
} ;

また、外部コマンドの出力結果を読み取ることもできます。
次の例では、file.txt の中身を nkf コマンドでEUCに変換したデータを読み込みます。

Pipe( '/usr/local/bin/nkf -e file.txt' ).read_open().each(
    func {
        -- sys.put( in[0].type_name() ; -- string が表示される

        sys.put( in[0] ) ;
    }
) ;

単に外部コマンドを実行するだけであれば、次のようにします。

rtn_code : Call( '/usr/local/bin/nkf -e file.txt' ) ;


◆ 環境変数(sys.env) 

sys.envという特別な連想配列変数を用いて環境変数の値を読み取ったり設定したりすることができます。

sys.env.type_name()  -- 型は map[string..string]

sys.put( sys.env['PATH'] ;   -- 環境変数PATHの値を表示する。
sys.env['TZ'] = "JST-9" ;    -- 環境変数TZに値を設定する。


◆ コマンド引数(sys.arg) 

コマンドラインからの引数を得るために、次の変数が使用できます。

sys.arg[0]         -- 引数の配列(0番目はプログラム名称)
sys.arg.size       -- 引数の個数
sys.arg[1]         -- 最初の引数
sys.arg.type_name()  -- 型は vector[string]


◆ シグナル(sys.sig) 

シグナルはプログラムに送信される非同期のメッセージです。
例えば、強請終了を明示された時はSIGTERMシグナルが、
プロセス間の通信が切断された時はSIGPIPEメッセージが、
設定しておいた時刻になったらSIGALRMシグナルが、
プログラムに対して送信されます。

sys.sig['TERM'] = func { sys.put( 'sigterm!!' ); } ;
sys.sig.type_name()  -- 型は map[string..func]

と宣言することにより、そのプログラムに SIGTERMシグナルが送信された時に、

sys.put( 'sigterm!!' ) ;

が実行されるようになります。




◆ 正規表現 Regular Expression (Rex)

-- 正規表現文字列 'ABCDEFG' が文字列'EFG'を含んでいたら
r : Rex( 'EFG' ) ;
r.match(
    'ABCDEFG',
    func {
        -- sys.put( in.type_name() ; -- vector[string] が表示される

        sys.put( "含んでいる.{in[0]}\n" ) ; -- ABCDEFG を表示
    }
) ;

-- 文字列 'ABCDEFG' が文字列'EFG'を含んでいたら
Rex( 'EFG' ).match( 'ABCDEFG', { sys.put( "含んでいる.{in[0]}\n" ) ; } ) ;

上記の rex は「変数 xx の中に、EFGという文字列が含まれていたら」という意味になる。
正規表現の EFG の箇所には次のような表記を用いることができる。

  A           Aという文字
  ABC         ABCという文字列
  A+          1個以上連続したA(A, AA, AAA, ...)
  A*          0個以上連続したA(  , A, AA, AAA, ...)
  .           1つの任意文字(A, B, C, ...) (\nを除く)
  ?           0または1つの任意文字(  , A, B, C, ...)
  ^ABC        ABCで始まっていたら
  ABC$        ABCで終わっていたら
  [ABC]       A,B,Cのいずれか1文字
  [A-Z]       A〜Zまでのいずれか1文字
  [A-Za-z0-9] A〜Z, a〜z, 0-9までのいずれか1文字
  [^ABC]      A,B.C以外の文字 
  [^A-Z]      A〜Z以外の文字
  A|B|C       AまたはBまたはC
  \nなど      エスケープシーケンス文字の\nなど
  (ABC)       ABCという文字列。カッコ部分は後で参照可能です。

これらを組み合わせてたとえば「Vinoの変数名に用いることができる文字」は次のように表わされる。

^[A-Za-z_][A-Za-z0-9_]*$

正規表現中では下記の文字は特殊な文字(メタ文字)として扱われるので、
これらの文字を表わすには \+, \*, \?, ...のように表す。

+ * ? . ( ) [ ] { } | \

括弧(...)で囲んだ部分は、正規表現内では in[1], in[2], in[3], ...として参照できます。
1, 2, 3, ...は、正規表現中で括弧が現れる順番を示す。


   ^(...)\1    最初の3文字がもう一度繰り返す(ABCABCなど)

また、正規表現の外ではマッチの結果を次のように参照できる。


in[0], in[1], in[2], ...  (  )の部分にマッチした文字列
in.last                   最後にマッチした(  )部分
in                        マッチした部分の文字列
in.head                   マッチした部分から前側の文字列
in.tail                   マッチした部分から後側の文字列

たとえば、次のように使用することができる。


Rex( '^([0-9][0-9]):([0-9][0-9]):([0-9][0-9])$' ).match(
    time,
    func {
        hour : in[0] ;
        min  : in[1] ;
        sec  : in[2] ;

        ...
    }
) ;

----

例外処理をどうするかという大きな問題が残っていましたね…。
うーん。
基本的に try-catch 構文は使うつもりが無いのです。

イメージとしては、sys と同じように
exception というグローバルなインスタンスがあって、
そこに

   exception.throw'error' ) ; -- エラー

とこんな感じで投げると強制終了すると。

で、強制終了してほしくない場合は、あらかじめ

{
    exception.catch'error', { ... } ) ;

    ... -- ここで起きた throw 'error' を拾う。
} ;     -- で catch されたら引数の関数が実行された後、強制終了は免れて、
        -- このスコープの外に飛んでくる。

としたいのだが…そんなことがライブラリでできるのか?ってことだよね。
もう少し良い案がないか考え中…。


{
    exception 'ErrorMaggage' ; -- break 構文と同じように書く

    ...

    catch  -- dtor (デストラクタ)の構文と同じように書く
    {
        message     : string         in[0] ;
        stack_trace : vector[stringin[1] ;

        -- exception が実行されると catch まで飛ぶ

        sys.put( message ) ; -- ErrorMasage が表示される
    }

    ...

    exception 'ErrorMaggage' ; -- catch の後ろでも書ける

} ;


1章に戻ります。



Vino言語(1/4) (2/4) (3/4) (4/4)

last update 2003/03/22
since 2002/09/16



やまざきのおすすめエレクトロニクス


やまざきのおすすめ本

やまざきのおすすめDVD

やまざきのおすすめCD



Copyright(c) 1998-2006.
YAMAZAKI Satoshi.
All rights reserved.

since 1997/12/15


このページのURLをメールで送る(友人・知人に教えてあげる)
このページを「お気に入り」に追加する(忘れないように…)
● お手紙はこちら↓。仕事の話は大歓迎です。(忙しくて返信できなかったらごめんなさい。)