Icon散歩道


                                                   Rev.01 1997/11/24 風つかい
■  Icon > Icon散歩道  はじめに                      風つかい        目次

  Iconは アリゾナ大学の Ralph E Griswold教授のグループによって開発されてい
るテキスト処理言語です。

  Iconは テキスト解析に 威力を発揮する 豊富なデータ構造と 強力な制御構造を
を備えています。 英語の国で開発されている言語ですが、日本語の処理も不自由
しませんし、もっともっと使われてよい言語と思います。

  しかし、未だ 日本語の入門書が ありませんので、 AWKについて、ある程度の
知識を お持ちになっている方を 対象として、入門講座を書きました。

   ・テキスト解析言語Icon入門講座
        ---AWKerのための Icon入門---
   ・Icon日記 
        ---テキスト解析言語Icon入門講座2---
   ・Icon雑記帳
        ---テキスト解析言語Icon入門講座3---

  この Icon散歩道は その続編として、その後 作ったプログラムや 前の 講座で
書き落とした ものを、まとめたものです。
  前の 3編の講座と いっしょに ご覧になって Iconを使って頂けると うれしい
です。
  Iconのプログラムおよびライブラリーは、次の所から 入手できます。
            http://www.cs.arizona.edu/icon/index.html

  この講座は、主に PCVANのPIGのテキストデータ処理会議室にアップロードした
ものに加筆・修正を行ったものです。
  Iconは PDSですので、この入門講座も同じ扱いとします。(転載・編集自由)
               (This textbook is in the public domain.)
目次
はじめに
(1) 再び構造体 tree表示(1)
(2) suspend...do...
(3) 再び5クイーン
(4) 再び構造体 tree表示(2)
(5) 再び構造体 tree表示(3)
(6) 再び wild.icn(1)
(7) 再び wild.icn(2)
(8) 再び dir2tree
(9) 再び x2tree(1)
(10) 再び x2tree(2)
(11) Icon迷い道 (1)system()
(12) Icon迷い道 (2)download数 集計
(13) Icon迷い道 (3)CSV:定義ファイルの読込
(14) Icon迷い道 (4)CSV:定義ファイルの解析
(15) Icon迷い道 (5)CSV:拡張子変更(1)
(16) Icon迷い道 (6)CSV:拡張子変更(2)
(17) Icon迷い道 (7)CSV:CSV2TB
(18) Icon迷い道 (8)CSV:TB2CSV
(19) ちょっと Icon(1)data整形(1)
(20) ちょっと Icon(2)data整形(2)
(21) ちょっと Icon(3)data整形(3)
(22) ちょっと Icon(4)data整形(4)
(23) Icon回り道 (1)重複しないランダムな10個の数(1)
(24) Icon回り道 (2)重複しないランダムな10個の数(2)
(25) Icon回り道 (3)重複しないランダムな10個の数(3)
(26) Icon回り道 (4)Usageが...
(27) Icon回り道 (5)a < b が、値を持つ
(28) ちょっと Icon(5)Wicon beta8
(29) ちょっと Icon(6)Icon Newsletter No.53
(30) ちょっと Icon(7)Icon Ver.9.3(Windows95/NT)
むすび

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 愛の言霊/サザン・オールスターズ
(iconlec4.txt 1997/11/24)

■  Icon > Icon散歩道(1) 再び 構造体tree表示(1)風つかい      目次

  Icon雑記帳 に引き続き、Icon迷い道 じゃなかった Icon散歩道 を始めます。
  今回こそは、テキスト解析らしい programを作ってみたいと思います。

  テキスト解析といっても、
        ・簡単な数式解析  と
        ・簡単なアセンブラ あたり
  を目標にしています。

  と、思っていたのですが、Icon雑記帳を読み返していたら、う〜む。ミスが
見つかりました。  その修正から始めます。

  Icon入門講座をやっていまして、アップロードする原稿や programは、その前
に、チェックしている つもりなのですが、大抵 1つや 2つのミスが 含まれて
います。
  しかし、気がつくのは、大抵、アップロードした後に、自分のメッセージを
読みだしコマンドで、読んだ時です。  もう手遅れのタイミングです。
  アップロードするまでは、若干緊張しています。  それが終わった後に、少し
ホッとした気分で、自分のメッセージを読み返す訳なのですが、  そういう時に
自分のミスが見つかります。別の自分にならないと、見つからないみたいです。

  書いた後に、1日位 寝かせておいて、その後に もう1回チェックすると良い
のですが、こらえ性が無くて。  修行が足りないな〜。

  と、言うわけで、Icon雑記帳(19)の x2tree03.icnの修正版です。
内容は、コメントに書き込んでありますので、ご覧下さい。
-----^ X2TREE05.ICN ( date:97-05-06 time:01:17 ) -----------<cut here
# 構造体の構成を tree状に見せる generator (recursive)
# x2tree05.icn Rev.1.2 1997/05/05 windy comment修正
# x2tree05.icn Rev.1.1 1997/05/04 windy
# Icon雑記帳(19)の x2tree03.icn のミス(3つも!(汗))を、修正。
# 1) 再帰構造判定のために、serial Noを使ったが、serial Noは、type毎に
#    振られるのを知らなかった。serial No登録用 setを type毎に (list,
#    set,table)分けた。
# 2) 登録 setからの、serial No 削除処理(delete) の位置が、間違っていた。
#    suspend...do...の do...の位置ではまずい。更に構造(list等)があって
#    自分自身を呼んだ時、その構造の要素の表示処理の度に、戻って来てその
#    度に do...が実行される。よって、期待以外の時に serial Noが削除され
#    てしまう。  素直に suspendの後ろの行に置く。
# 3) 初期化処理を x2treeで initial {...}でやっていた。    x2t()を 使う
#    program内で 別の構造体 tree表示のために、再び x2t()を呼んだ 時に
#    実行されなくて状態が残る。  initial {...}ではなくて、x2t()からの
#    フラグで 初期化指示する方式に変えた。
# This file is in the public domain.
link jimage

procedure x2t(x)
# generator
# topの処理
  suspend "<" || type(x) || " " || string(serial(x)) || ">"
                                         #↑listの serial No
  suspend "  " || x2tree(x,"")
                          #↑初期化フラグ
end

procedure x2tree(x,init)
# generator
# show the tree structure of x
  static T      # serial No 登録用 set登録用 table    static宣言を して
                # おかないと、再帰したときに、未定義 errorとなる。
  if \init then { # Rev.1.2
    T := table()       
    T["list"]  := set() # ここは、table(set())とすると、全て同じ setが
    T["set"]   := set() # 割り当てられてしまうので、個別に初期化する。
    T["table"] := set()
    if (t := type(x)) == ("list" | "set" | "table")
    then insert(T[t],serial(x))    # serial Noを T[type(x)]に登録
  }
  n := *x                   # 枝の末端検出用カウンタ
  every xx := !x do {       # 構造体の要素を1つ づつ取り出す
    n -:= 1
    case t := type(xx) of { # 構造体のタイプにより、
      "string"            : suspend "+ " || left(t,7) || " " || jimage(xx)
      #↓list,set,tableなら、typeを書出して、その中身をまた解析する。
      "list" | "set" | "table" : {
        #↓再帰構造で なければ。(T[type(xx)] に既に登録済みなら再帰構造)
        if not member(T[t],m := serial(xx)) then {
          insert(T[t],m)    # serial Noを T[type(xx)]へ登録
          suspend "+ <" || t || " " || string(m) || ">"
          suspend (if n > 0 then "|   " else "    ") || x2tree(xx)
                            #↑枝の途中 #↑枝の末端     # 再帰↑
          delete(T[t],m)    #←serial No 登録を削除
        }
        else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
          return "+ <" || t || " " || string(m) || "> (Recursion)"
        }
      }
      #↓その他なら、typeと値を書き出す。
      default             : suspend "+ " || left(t,7) || " " || image(xx)
    }
  }
end

# test driver
procedure main()
  #listの test
  L1 := ["A","B"]
  L2 := ["C","D"]
  L3 := ["E","F"]
  put(L1,L2)
  put(L2,L3)
  put(L1,L3)               # 別枝 test
  put(L3,L1)               # listの再帰
  every write(x2t(L1) \20) # \20は、テストをドジッた時に、20個で止めるため。

  write()
  #tableの test
  T := table()
  T["A"] := "G"
  T["C"] := L2[1]
  T["E"] := L3
  T[L1] := L1[1]
  put(L3,T)                # tableの再帰
  every write(x2t(T) \20)

  write()
  #setの test
  L4 := ["H","I"]
  S1 := set(["L","M"])
  S  := set(["J","K",L4])
  insert(S,S1)
  insert(S1,S)             # setの再帰
  every write(x2t(S) \20)

end
-----$ X2TREE05.ICN ( lines:98 words:380 ) -----------------<cut here
( comment修正のため、差し替え)

  linkしている jimage.icnは、Icon雑記帳に含まれています。
  この jimage.icnは 更に Icon日記に含まれる sjis4.icnを linkしています。

  結果は、次のようになります。  テストケースを増やしましたが、まだ漏れ
が、あるかもしれません。尚、構造体の recordへの配慮が 抜けていますが、
これは、私が使わないもので、省いてあります。  それは、仕様です。(笑)
-----^ X2TREE05 ( date:97-05-04 time:20:59 ) ---------------<cut here
<list 1>
  + string  "A"
  + string  "B"
  + <list 2>
  |   + string  "C"
  |   + string  "D"
  |   + <list 3>
  |       + string  "E"
  |       + string  "F"
  |       + <list 1> (Recursion)
  + <list 3>
      + string  "E"
      + string  "F"
      + <list 1> (Recursion)

<table 2>
  + string  "C"
  + <list 3>
  |   + string  "E"
  |   + string  "F"
  |   + <list 1>
  |   |   + string  "A"
  |   |   + string  "B"
  |   |   + <list 2>
  |   |   |   + string  "C"
  |   |   |   + string  "D"
  |   |   |   + <list 3> (Recursion)
  |   |   + <list 3> (Recursion)
  |   + <table 2> (Recursion)
  + string  "A"
  + string  "G"

<set 8>
  + string  "K"
  + <set 7>
  |   + string  "M"
  |   + string  "L"
  |   + <set 8> (Recursion)
  + <list 38>
  |   + string  "H"
  |   + string  "I"
  + string  "J"
-----$ X2TREE05 ( lines:42 words:155 ) ---------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Goodbye Day /来生たかお
(icon_301.txt 1997/05/05 PCVAN PIG)

■  Icon > Icon散歩道(2) suspend...do...          風つかい      目次

  前回、Icon雑記帳(19)で取り上げた x2tree03.icnのミスを 修正しました
が、私は、どうも suspend...do...の構文が、理解できていない と思います。
  そこで、動作確認の実験 programを作ってみました。

  こういう構成の programです。
  main()                 test_a()                test_b()
  ------------------      ------------------      ------------------
 | main()           |    |                  |    |                  |
 |  every test_a()   <--- suspend...test_b() <--- suspend...        |
 |                  |    |         do...    |    |         do...    |
  -----------------       ------------------      ------------------

  実験 programです。
-----^ DO_01.ICN ( date:97-05-04 time:23:28 ) --------------<cut here
# suspend...do...の動作の確認1
# do_01.icn 1997/05/04 windy
# This file is in the public domain.

# main()は test_aの出力を書き出すだけ
procedure main()
  write("suspend...do.. の実行順序の確認実験1")
  write()
  write("メイン先頭")
  every s := test_a("MM")    do write("メイン出力 ",s)
  write("メイン末尾")
end

# teat_aは test_b(s)の先頭に、文字列 "AA "を加えるだけ
procedure test_a(s)
  write("     A先頭")
  suspend "AA " || test_b(s) do write("     A do")
  write("     A末尾")
end

# 2出力の generator
# 1つは sに文字列 "B1 "を加え、もう1つは sに文字列 "B2 "を加える
procedure test_b(s)
  write("          B先頭")
  suspend "B1 " || s         do write("          B1 do")
  write("          B中間")
  suspend "B2 " || s         do write("          B2 do")
  write("          B末尾")
end
-----$ DO_01.ICN ( lines:29 words:91 ) ---------------------<cut here

  動作結果は、次のように なります。 test_a() ,test_b() の do...の部分 の
実行タイミングと 回数に着目して下さい。
-----^ DO_01 ( date:97-05-04 time:23:28 ) ------------------<cut here
suspend...do.. の実行順序の確認実験1

メイン先頭
     A先頭
          B先頭
メイン出力 AA B1 MM
     A do
          B1 do
          B中間
メイン出力 AA B2 MM
     A do
          B2 do
          B末尾
     A末尾
メイン末尾
-----$ DO_01 ( lines:15 words:25 ) -------------------------<cut here

  私は、動作タイミングを 全く誤解していました。
  つい、generatorではない procedureを 呼んだ時と 同じ順番と 思っていました。
 実際に 実験してみるもんですね。

  ついでに、test_a()で 2つ suspendする 場合の 実験 programも あげておき
ます。
-----^ DO_02.ICN ( date:97-05-05 time:22:43 ) --------------<cut here
# suspend...do...の動作の確認2
# do_02.icn Rev.1.2 1997/05/04 windy comment修正
# do_02.icn Rev.1.1 1997/05/05 windy
# This file is in the public domain.

# main()は test_aの出力を書き出すだけ
procedure main()
  write("suspend...do.. の実行順序の確認実験2")
  write()
  write("メイン先頭")
  every s := test_a("MM")    do write("メイン出力 ",s)
  write("メイン末尾")
end

# teat_aは test_b(s)の先頭に、文字列 "A1 "か "A2 "を 加えるだけ
procedure test_a(s)
  write("     A先頭")
  suspend "A1 " || test_b(s) do write("     A1 do")
  write("     A中間")
  suspend "A2 " || test_b(s) do write("     A2 do")
  write("     A末尾")
end

# 2出力の generator
# 1つは sに文字列 "B1 "を加え、もう1つは sに文字列 "B2 "を加える
procedure test_b(s)
  write("          B先頭")
  suspend "B1 " || s         do write("          B1 do")
  write("          B中間")
  suspend "B2 " || s         do write("          B2 do")
  write("          B末尾")
end
-----$ DO_02.ICN ( lines:32 words:112 ) --------------------<cut here
(コメント修正のため、差し替え)

  結果です。
-----^ DO_02 ( date:97-05-04 time:23:29 ) ------------------<cut here
suspend...do.. の実行順序の確認実験2

メイン先頭
     A先頭
          B先頭
メイン出力 A1 B1 MM
     A1 do
          B1 do
          B中間
メイン出力 A1 B2 MM
     A1 do
          B2 do
          B末尾
     A中間
          B先頭
メイン出力 A2 B1 MM
     A2 do
          B1 do
          B中間
メイン出力 A2 B2 MM
     A2 do
          B2 do
          B末尾
     A末尾
メイン末尾
-----$ DO_02 ( lines:25 words:45 ) -------------------------<cut here

  イケイケ評価(Goal-directed evaluation) を 行うために test_a(), test_b()
の 全組み合わせ を試している のが 分かります。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: いとおしいグレイ/篠原美也子
(icon_302.txt 1997/05/05 PCVAN PIG)

■  Icon > Icon散歩道(3) 再び 5クイーン          風つかい      目次

  前回 suspend...do...の構文 の動作確認を 行いましたが、他の programでも
誤解して 使っているところが 無いかと、探しました。
  Icon日記の 5-Queensの programでも、Queenの置き直しのところで、使ってい
ます。  ここは、特に do...を使う必要は、ありませんね。

-----^ 5QUEEN1D.ICN ( date:97-05-04 time:20:02 ) -----------<cut here
# 5-Queensの解の書き出し
# 5x5のチェス盤に 5個の Queenを互い取られない位置に置く。
# 5queen1d.icn Rev.1.1 1997/05/04 windy
# This file is in the public domain.
# Icon教典(The Icon Programming Language)の 8-Queens program
# に、手を加えたもの。
# 動作は、Icon日記(24)〜(26)を参照して下さい。
# Queenの 置き直しは、suspend ... do ...の do...を 使わなくて
# も良いことに 気付いて 修正したもの。
#
#    行・列の番号        右上がり対角線   右下がり対角線
#         列→(column)   番号→                     ←番号
#          1 2 3 4 5          1 2 3 4 5      5 4 3 2 1  
#    行  1Q・・・・        Q//// 6    6 Q\\\\
#    ↓  2・・Q・・        //Q// 7    7 \\Q\\
#  (row) 3・・・・Q        ////Q 8    8 \\\\Q
#        4・Q・・・        /Q/// 9    9 \Q\\\
#        5・・・Q・        ///Q/        \\\Q\
#                                                       
#  上の図のように置き終わった状態では、
#           行          右上がり対角線    右下がり対角線
#    row   12345       up   123456789     down 123456789
#    col  "13524"      col "1..32.54."    col "..53142.."
#
procedure main()
  # Queenが1行から5行まで全て置けたら、列位置を順に書き出す。
  # q(1),...,q(5)が全て成功しなければ writeの引数は成功しない。
  every write(q(1)," ",q(2)," ",q(3)," ",q(4)," ",q(5))
             #↑Queenを順に1行ずつ置いていって、全部置けたら成功
             # 置けないときは、順に1行ずつ戻って別の置き方を試す。
             # とにかく、【イケイケ】で、答えが出るまで試す。
             # 答えのある限り試す。
write()
end

procedure q(r)
# r番目の行の Queenを、1〜5列に置いて試すための generator
# 戻り値は、置けた列の No
  suspend place(r,1 to 5)
                  # ↑ 1列〜5列迄試す。
end

procedure place(r,c)
# Queenを r行 c列に置いてみる。置けないと失敗。置けると列 Noを返す。
  static up,down,col    # 既に置かれた Queenを記憶。
                        # 列位置と影響する対角線2方向の位置を記憶する。
  initial{              # 初期値( Queenを何処にも置いていない状態)
    up   := repl(".",9) # 右上がり対角線管理
    down := repl(".",9) # 右下がり対角線管理
    col  := repl(".",5) # 列番号管理
  }

  if col[c] == up[r + c -1] == down[5 - c + r] == "."
  # ↑r行 c列に置けるかの check(全部 "."ならあいている。)

  then {
    suspend col[c] := up[r + c -1] := down[5 - c + r] := c
     #        ↑ c番目の列に Queenを置く。
     # 置いた列・右上がり対角線・右下がり対角線に cを代入している。
     # 置いたことを示すだけなら "."以外の文字ならなんでも良いが、
     # 戻り値を列番号にするために cを代入。

     # 続行時の処理
    col[c] := up[r + c -1] := down[5 - c + r] := "."
     #        ↑ c番目から Queenを取り去る。
     # 続行は、次の行の Queenが置けなかった時、または全部の Queenが
     # 置けて、別の置き方を 試す時に起こる。
  }
end
-----$ 5QUEEN1D.ICN ( lines:69 words:272 ) -----------------<cut here

  結果です。  修正前と、同じ結果になります。
-----^ 5QUEEN1D ( date:97-05-04 time:20:02 ) ---------------<cut here
1 3 5 2 4
1 4 2 5 3
2 4 1 3 5
2 5 3 1 4
3 1 4 2 5
3 5 2 4 1
4 1 3 5 2
4 2 5 3 1
5 2 4 1 3
5 3 1 4 2

-----$ 5QUEEN1D ( lines:11 words:50 ) ----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: いとおしいグレイ/篠原美也子
(icon_303.txt 1997/05/05 PCVAN PIG)

■  Icon > Icon散歩道(4) 再び 構造体tree表示(2)風つかい      目次

  Icon散歩道(1)で、x2tree03.icnの ミス修正版を 説明しましたが、どうし
て ミスに気がついたか というと、実は、Version Upをしようと、思いまして、
テスト・ケースを増やしてみて、気がつきました。

  今回は、その Version Upです。 Iconの tableは、AWKでいう 連想配列です。
tableは、key と valueを持っています。  前の programでは、valueしか表示し
ません。
  x2treeは、programの動作確認 のための toolとして作りましたが、

          tableでは、value表示だけでなく、key表示も欲しい!

  ということで、key表示を追加します。

  尚、Iconでは、keyにも 構造体(list,set,table)が、使えます。
  しかし、keyに 構造体を使っても、そちらは tree表示はしません。
  (そんな 複雑 tree表示は、思いつかないよ〜。)

-----^ X2TREE06.ICN ( date:97-05-05 time:03:26 ) -----------<cut here
# 構造体の構成を tree状に見せる generator (recursive)
# x2tree06.icn Rev.1.1 1997/05/05 windy
# x2tree05.icn にて、tableの場合は key表示を追加したもの。
# This file is in the public domain.
link jimage

procedure x2t(x)
# generator
# topの処理
  suspend "<" || type(x) || " " || string(serial(x)) || ">"
                                         #↑listの serial No
  suspend "  " || x2tree(x,"")
                          #↑初期化フラグ
end

procedure x2tree(x,init)
# generator
# show the tree structure of x
  static T      # serial No 登録用 set登録用 table    static宣言を して
                # おかないと、再帰したときに、未定義 errorとなる。
  if \init then {   # 初期化を initialでやると、同じ program内で別の
                    # 構造体 tree表示のために、再び x2tを 呼んだ時に
                    # 実行されなくて状態が残るので、フラグで初期化指示
    T := table()       
    T["list"]  := set() # ここは、table(set())とすると、全て同じ setが
    T["set"]   := set() # 割り当てられてしまうので、個別に初期化する。
    T["table"] := set()
    if (t := type(x)) == ("list" | "set" | "table")
    then insert(T[t],serial(x))    # serial Noを T[type(x)]に登録
  }

  n := *x                   # 枝の末端検出用カウンタ

  if (tt := type(x)) ~== "table" then { # not table
    every xx := !x do {       # 構造体の要素を1つ づつ取り出す
      n -:= 1
      t  := type(xx)
      val_disp := if t == ("list" | "set" | "table")
              then "+ <" || t || " " || string(m := serial(xx)) || ">"
              else "+ " || left(t,7)  || jimage(xx)

      case t of { # 構造体のタイプにより、
        "string"            : suspend val_disp
        #↓list,set,tableなら、typeを書出して、その中身をまた解析する。
        "list" | "set" | "table" : {
          #↓再帰構造で なければ。(T[type(xx)] に既に登録済みなら再帰構造)
          if not member(T[t],m) then {
            insert(T[t],m)    # serial Noを T[type(xx)]へ登録
            suspend val_disp
            suspend (if n > 0 then "|   " else "    ") || x2tree(xx)
                              #↑枝の途中 #↑枝の末端     # 再帰↑
            delete(T[t],m)    #←serial No 登録を削除
          }
          else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
            return val_disp || " (Recursion)"
          }
        }
        #↓その他なら、typeと値を書き出す。
        default             : suspend val_disp
      }
    }
  }

  else { # table
    every xkey := key(x) do {       # tableの keyを1つ づつ取り出す
      n -:= 1
      tk := type(xkey)
      xx := x[xkey]
      t  := type(xx)
      val_disp := if t == ("list" | "set" | "table")
              then "+ <" || t || " " || string(m := serial(xx)) || ">"
              else "+ " || left(t,7)  || jimage(xx)
      key_disp := if tk == ("list" | "set" | "table")
              then " <- <" || tk || " " || string(serial(xkey)) || ">"
              else " <- " || left(tk,7) || jimage(xkey)

      case t of { # 構造体のタイプにより、
        "string" : suspend val_disp || key_disp

        #↓list,set,tableなら、typeを書出して、その中身をまた解析する。
        "list" | "set" | "table" : {
          #↓再帰構造で なければ。(T[type(xx)] に既に登録済みなら再帰構造)
          if not member(T[t],m) then {
            insert(T[t],m)    # serial Noを T[type(xx)]へ登録
            suspend val_disp || key_disp
            suspend (if n > 0 then "|   " else "    ") || x2tree(xx)
                              #↑枝の途中 #↑枝の末端     # 再帰↑
            delete(T[t],m)    #←serial No 登録を削除
          }
          else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
            return val_disp || key_disp || " (Recursion)"
          }
        }
        #↓その他なら、typeと値を書き出す。
        default  : suspend val_disp || key_disp
      }
    }
  }

end

# test driver
procedure main()
  #listの test
  L1 := ["A","B"]
  L2 := ["C","D"]
  L3 := ["E","F"]
  put(L1,L2)
  put(L2,L3)
  put(L1,L3)               # 別枝 test
  put(L3,L1)               # listの再帰
  every write(x2t(L1) \20) # \20は、テストをドジッた時に、20個で止めるため。

  write()
  #tableの test
  T := table()
  T["A"] := "G"
  T["C"] := L2[1]
  T["E"] := L3
  T[L1] := L1[1]
  put(L3,T)                # tableの再帰
  every write(x2t(T) \20)

  write()
  #setの test
  L4 := ["H","I"]
  S1 := set(["L","M"])
  S  := set(["J","K",L4])
  insert(S,S1)
  insert(S1,S)             # setの再帰
  every write(x2t(S) \20)

end
-----$ X2TREE06.ICN ( lines:133 words:507 ) ----------------<cut here

  行数制限が ありますので、結果は次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: いとおしいグレイ/篠原美也子
(icon_304.txt 1997/05/05 PCVAN PIG)

■  Icon > Icon散歩道(5) 再び 構造体tree表示(3)風つかい      目次

  x2treeに、tableの key表示を追加した programの動作結果です。
  tableの部分が、若干、混みあった表示になりますが、test toolですので、

                       まあ、いんじゃない。
と、納得しましょう。

-----^ X2TREE06 ( date:97-05-05 time:03:26 ) ---------------<cut here
<list 1>
  + string "A"
  + string "B"
  + <list 2>
  |   + string "C"
  |   + string "D"
  |   + <list 3>
  |       + string "E"
  |       + string "F"
  |       + <list 1> (Recursion)
  + <list 3>
      + string "E"
      + string "F"
      + <list 1> (Recursion)

<table 2>
  + string "C" <- string "C"
  + <list 3> <- string "E"
  |   + string "E"
  |   + string "F"
  |   + <list 1>
  |   |   + string "A"
  |   |   + string "B"
  |   |   + <list 2>
  |   |   |   + string "C"
  |   |   |   + string "D"
  |   |   |   + <list 3> (Recursion)
  |   |   + <list 3> (Recursion)
  |   + <table 2> (Recursion)
  + string "A" <- <list 1>
  + string "G" <- string "A"

<set 8>
  + string "K"
  + <list 44>
  |   + string "H"
  |   + string "I"
  + <set 7>
  |   + string "M"
  |   + string "L"
  |   + <set 8> (Recursion)
  + string "J"
-----$ X2TREE06 ( lines:42 words:167 ) ---------------------<cut here

  keyに、構造体を 使った場合でも keyの type表示の下に、treeを作れば良い
ような気がします。  とりあえず、気がつかなかったことにしよう。(笑)
  (tableの要素に また tableが出てくるケースなんか、ツライだろうし。)

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: そのままの君でいて/岡本真夜
(icon_305.txt 1997/05/05 PCVAN PIG)

■  Icon > Icon散歩道(6) 再び wild.icn(1)      風つかい      目次

  近ごろ、"再び" というタイトルが多いですね〜。う〜む。以前の講座のミス
が、みつかるのが多いな〜。

  ということで、今回は Icon入門講座(16)で 作った wild.icnの修正版で
す。

  Iconの Program 例えば、abcd.icnを compileして、動かした結果のfile名を
以前は、abcd.txtとしていたんですが、txtの拡張子をつけるのも面倒というこ
とで、近ごろは、ただ abcdとしています。

これを、YAB形式にしようと、IYAB(Icon入門講座(18))を動かすとどうも
結果がオカシくなります。

  調べてみますと、IYABは、拡張子無しの file名を指定するとおかしくなりま
す。
  更に調べると、iyab.icnは、wild.icnを linkしていますが、wild.icnで既に
オカシイ。  あれれ、wild.icnは、拡張子なしの file名の手当をしていたはず
だか???  と、思って、良くみると、あれま、ミスコーディング をしていま
す。
            if not upto('.',line) then line ||= "."

というミスをやらかしていました。  つう、ことで、修正版です。

-----^ WILD.ICN ( date:97-05-10 time:00:42 ) ---------------<cut here
# wild cards file指定 の fileの情報を "dir" を発行して 調べて
# listにして 返す。
# response fileも指定可。(@file_list)
# Icon入門講座(16)を参照して下さい。
# This file is in the public domain.
# 
# wild.icn Ver.1.5 1997/05/10 windy comment修正(引数は list)
# wild.icn Ver.1.4 1997/05/05 windy 拡張子無し手当修正 "||=" → "||:="
# wild.icn Ver.1.1 1996/10/26 windy
#
# Usage: wild([file(s) or @file_list_file])
#        sortf(wild([file(s) or @file_list]),1)   file名で sortする時
#        注意:引き数は listなので、間違えないこと。
# value: [i][1] full path付き file名、[i][2] file size
#        [i][3] 日付、[i][4] 時刻      i : 1 〜  fileの数
# 該当 fileが無ければ失敗(fail)
link dir2lst                     # ← Icon入門講座 に含まれています。

procedure wild(args)
###################
# file指定 command行処理
###################
  tmp   := "$$$tmp.$$$"                 # temporary file名設定
  if s := getenv("TMP") then tmp := s || "\\" || tmp
  #↑環境変数に temporary directoryが設定してあれば
                                        # file名 の前 に追加
  fn_list := []                         # file名等 格納 list

# command lineの file指定 をもとに、"dir" commandを発行し、tmpへ。
  if *args = 0 then fail                # file指定なし
    else {
    every arg := !args do {  # command line引数 listから順に取り出し。
      case arg[1] of {       # caseを使ってみたかったのだ。
        "@"      : {     # response file指定
          dir := open(arg[2:0]) | stop("cannot open " || arg[2:0])
          while line := read(dir) do {
            if not upto('.',line) then line ||:= "."  # Rev.1.4
            #↑ 拡張子が無い時には、 "."を追加。
            system("dir " || line || " >>" || tmp)    # "dir"発行
          }
          close(dir)
        }
        default  : {     # file指定
          if not upto('.',arg) then arg ||:= "."      # Rev.1.4
           system("dir " || arg || " >>" || tmp)      # "dir"発行
        }
      } # end of case
    } # end of every
  } # end of else

  dir := open(tmp) | stop("cannot open " || tmp) # fileオープン

# "dir" の結果格納 fileから、file指定部分を 抜き出して listへ。
  while line := read(dir) do            # tmp fileから1行づつ読込。
    put(fn_list,dir2lst(line))          # file情報を抜き出して、
                                        # listへ格納
  close(dir)
  remove(tmp)                           # 証拠隠滅
####################
# command解析終了
####################
  if *fn_list = 0 then fail             # 該当 file無し
  else return fn_list

end
-----$ WILD.ICN ( lines:65 words:298 ) ---------------------<cut here

  test programでも、test caseを 落としていますので、追加しました。

-----^ WILD~.ICN ( date:97-05-08 time:23:07 ) --------------<cut here
# a test driver and a stub for wild.icn
# Usage: wild~ > wild.rst
# Rev.1.2 1997/05/05 windy 拡張子無しのテストケース追加
# Rev.1.1 1996/12/01 windy
# This file is in the public domain.
link wild, show_l
procedure main()
  write("test for wild.icn\n")

  # "abc" という名前のファイルは存在しないこと。
  write((L := ["abc"])[1])
  show_wl(wild(L)) | write(L[1],"は見つからない。\n")

  # wild card
  write((L := ["*.*"])[1])
  show_wl(wild(L))

  write((L := ["*.icn"])[1])
  show_wl(wild(L))

  write((L := ["wi*.*"])[1])
  show_wl(wild(L))

  # response file
  write((L := ["@WILD_FL.DAT"])[1])
  show_wl(wild(L))

  # 複数指定
  every writes(" ",!(L := ["*.icn","*.dat"])) ; write()
  show_wl(wild(L))

  # "AAA", "AAA.TXT" の 2つの fileを用意しておくこと。
  every writes(" ",!(L := ["AAA"])) ; write()   # 追加 Rev.1.2
  show_wl(wild(L))

  write((L := ["wild~.*"])[1])
  show_wl(wild(L))

end
-----$ WILD~.ICN ( lines:39 words:102 ) --------------------<cut here

  というだけでは、シャクなので、次回は、wildの応用 programを。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_306.txt 1997/05/10 PCVAN PIG)

■  Icon > Icon散歩道(7) 再び wild.icn(2)      風つかい      目次

  PIG広場の方で、fileの名前と拡張子を 入れ換える 話題が 出ています。
  そのネタをいただいて、Iconでやったらということで、programを 作ってみま
した。

  Iconには、fileの rename関数があります。 wild.icnで、該当 fileを 探して
rename関数で、renameするという programです。
  この programでは、log.* ファイルの拡張子とファイル名を入れ換え、その後
もう1度、入れ換えて、元に戻しています。

-----^ REN01.ICN ( date:97-05-10 time:00:37 ) --------------<cut here
# log.*  fileの  file名と拡張子  の交換
# ren01.icn 1997/05/10 windy
# This file is in the public domain.
link wild, split, top         # ←Icon入門講座にある procedure

procedure main()
  L := wild(["log.*"])        # log.* の file list入手
  name_ex(L)                  # file名と 拡張子名を 交換

  L := wild(["*.log"])        # *.log の file list入手
  name_ex(L)                  # file名と 拡張子名を 再び交換
                              # (元に戻す。)
end

# file名と拡張子  の交換
procedure name_ex(L)
  if /L then return           # 該当 file無し
  write("\nfile名<->拡張子")
  every LL := !L do {
    s := top_cut("\\",LL[1])      # 現file名から directory部を 削除
                    # ↑file名
    LLL := split(s,".")           # file名を "."で分割して listへ
    write(s," -> ",s2 := LLL[2] || "." || LLL[1]) # 動作モニター
                       #↑拡張子          ↑file名
    rename(s,s2)                  # rename
  }
  return
end
-----$ REN01.ICN ( lines:28 words:109 ) --------------------<cut here

  この programを 作っている最中に 動かな〜い。!? と  悩んでいましたが
wild.icnの引数は listなのに、stringと勘違いしていました。
  今後は、間違えないようにと、wild.icnに、commentを追加しました。

  動作モニター用出力を fileに 落としたものです。
-----^ REN01 ( date:97-05-10 time:00:40 ) ------------------<cut here

file名<->拡張子
LOG.97 -> 97.LOG
LOG.95 -> 95.LOG
LOG.96 -> 96.LOG

file名<->拡張子
95.LOG -> LOG.95
96.LOG -> LOG.96
97.LOG -> LOG.97
-----$ REN01 ( lines:10 words:20 ) -------------------------<cut here

  test用に用意した、ファイルです。
-----^ LOG.95 ( date:97-05-10 time:00:39 ) -----------------<cut here
95
-----$ LOG.95 ( lines:1 words:1 ) --------------------------<cut here
-----^ LOG.96 ( date:97-05-10 time:00:39 ) -----------------<cut here
96
-----$ LOG.96 ( lines:1 words:1 ) --------------------------<cut here
-----^ LOG.97 ( date:97-05-10 time:00:39 ) -----------------<cut here
97
-----$ LOG.97 ( lines:1 words:1 ) --------------------------<cut here

  まだ、"再び" の話題は 続きます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_307.txt 1997/05/10 PCVAN PIG)

■  Icon > Icon散歩道(8) 再び dir2tree            風つかい      目次

  ミスが多い と言いつつ、相変わらず、やっていますね〜。
          再び wild.icn(7)->  再び wild.icn(2)  ですね。
  (このテキストでは直っています。)

  ところで、Icon入門講座シリーズを、アリゾナ大学の Icon-WEBに 置いて頂く
ように、Icon入門講座 (ICON_LEC.LZH)と Icon日記 (ICONLEC2.LZH) の  fileを
Icon Projectに、送ってお願いしていたんですが、置いて頂けました。場所は、

            ftp://ftp.cs.arizona.edu/icon/contrib/Japanese/

  です。 /icon/contrib/ は 寄贈 program (contribution)の directoryです。
ここに、Japaneseという directoryを作っていただきました。

  英文なら E-mailか FTPで、送ればいいんですが、日本語の SHIFT-JISの file
ですので、printしたものと、FDを送ってみました。
  とても、全文を英訳する力は、ありませんので、

     「 printed materialの programの部分で 内容は 想像して下さい。」

と お願いした文章を、四苦八苦して 書きました。(汗)

近ごろ、カタカナ部分を なるべく 英語で書いていますが それは Icon Project
で、内容を 想像しやすいように ということで、やっています。(あはは)

  内容は、こちらにアップしたものと 殆ど同じです。(その後 みつかった文章
や綴り(特に英語)の誤記を多少 修正しています。program自体は同じです。)

  さて、今回は、Icon雑記帳(20)〜(22)で、やりました dir2tree の修
正です。

  dir2treeは、私のHDDの Icon関係 directoryの中の sub-directoryで test
しました。 で 先日、Icon雑記帳の fileを、Icon-Projectの送ろうと そのFD
の directory treeを、表示しようとしましたら、programが、コケました。

                    root directoryじゃ、動かなひ〜。

  dir /s の command を 実行したときに、
     ・root directoryでは A:\とか directory名称の後ろに、\ が、つきますが
     ・sub-directoryでは、つきません。
  \ がつく caseの手当を忘れていました。つうことで、その点を修正しました。

-----^ D2TREE.ICN ( date:97-05-10 time:00:48 ) -------------<cut here
# ディレクトリーを tree表示する。
# d2tree.icn Ver.1.1 1997/05/10 windy
# This file is in the public domain.
# Icon雑記帳(20)〜(22)の dir2tree.icn の root directoryの対応
# 漏れを修正した。(root directoryだけは directory名称に "\\"が付く。)
# Usage : d2tree directory_name
# "dir /s" を発行して 得た ディレクトリー情報を tree 表示する。
link x2tree07      # test用

procedure main(args)
  #######################
  # directory情報を得る。
  #######################
  dir_name := if *args > 0 then args[1] else ""
  tmp   := "$$$tmp.$$$"        # テンポラリファイル名設定
  # ↓環境変数に、テンポラリーディレクトリ名が、設定してあればファイル名
  #   の前に追加
  if s := getenv("TMP") then tmp := s || "\\" || tmp
  # コマンドラインの ディレクトリー名指定 をもとに、"dir /s" コマンド を
  # 発行して tmpへ出力
  system("dir /s " || dir_name || " >" || tmp)

  # directory data sample ↓こんなデータが tmpに格納されます。
  #1              16
  #ディレクトリは D:\ICON\LEC24\TEST_A
  #
  #.              <DIR>        97-04-29  21:51 .
  #..             <DIR>        97-04-29  21:51 ..
  #TEST_B         <DIR>        97-04-29  21:52 TEST_B
  #BBB      TXT            10  97-04-29  21:56 BBB.TXT
  #TEST_CCC TXT            15  97-04-29  21:57 TEST_CCC.TXT
  #TEST_C         <DIR>        97-04-29  21:55 TEST_C
  #AAA                      6  97-04-29  21:56 AAA
  #         3 個                  31 バイトのファイルがあります 
  #  
  #一覧のファイル総数:

  ######################
  # dir /s (dir_name)結果から、directory毎の情報を listへ 登録
  ######################
  dir := open(tmp) | stop("cannot open " || tmp)    # tmpファイルオープン
  L_dir := []               # directory情報登録用 list
  T_dir := table()          # sub-directory list参照 table

  while line := read(dir) do {
    # directory情報を directory毎に、一旦 list(LL)にまとめて、登録する。
    line ? {
                        #↓listにまとめた directory情報を登録
      if find("個") then put(\T_dir[c_dir] | L_dir,LL) 
                            #↑tableに c_dirが存在すれば
      if match(" ") then next          # ごみ行を無視
      if match("一") then break        # "一覧の..."が来たら終わり
      L := p_split()                   # lineを " "で分割→[1]:開始位置
                                       #                   [2]:要素
           #↓lineの1番目の要素
      case L[1][2] of {
        "ディレクトリは" : {
          LL := []  # directory data buffer
          #  ↓lineの2番目の要素の開始位置
          if line[-1] == "\\" then c_dir := line[L[2][1] : -1] # root対応
                              else c_dir := line[L[2][1] :  0] #
          put(LL,[c_dir])
          #↑listにして LLに追加
        }
        "."        : next              # 無視
        ".."       : put(LL[1],line)   # その directory自身の情報。
                                       # トップの directory以外では必要
                                       # ないが、全てにつき格納
        default    : { if find("<DIR>")  # sub-directoryだったら
                       then {
                         put(LL,LLL := [line]) # 内容を bufferに追加
                         insert(T_dir,c_dir || "\\" || L[1][2] ,LLL)
                         # ↑sub-directory名称を keyにして tableへ登録
                       }
                       else put(LL,line) # 通常 fileならそのまま追加
                     }
      } # end of case
    } # end of line ?
  } # end of while
  close(dir)
  remove(tmp)                          # delete tmp

  #######################
  # directory情報の表示
  #######################
#  every write(x2t(L_dir) \25)              # list 内容確認用表示
#  every write(x2t(T_dir) \25)              # table内容確認用表示
#  stop()
  every write(d2t(L_dir))

end

########################
# directory tree表示
########################
procedure d2t(L)
# top directoryの名前/time_stamp処理
  L1 := get(L)    # Lには1個しか要素が無い。それを取り出す。
  L2 := get(L1)   # そのまた top (directory_name,time_stamp)を取り出す。

  dir_top := L2[2][14:-3] | "\\       <DIR>"
  # top directoryの名前と time stamp      ↓root directory対応
  suspend L2[1] || dir_top
  suspend "  "  || d2tree(L1)     # tree化処理
  #       ↑tree書出し初期位置
end

procedure d2tree(L)
# directoryの処理
# show the tree structure of directory
  n := *L                   # Lの size(末尾要素検出用)
  every LL := !L do {       # listの要素を1つづつ取り出す
    n -:= 1                 # 要素カウンタ−1
    case t := type(LL) of { # 要素の typeにより、
      "string"  : suspend "+ " || LL        # file
      "list"    : {                         # sub-directory
        suspend "+ " || get(LL)             # sub-directory自体表示
        LLL := get(LL)                      # sub-directoryの中身を取り出し
        get(LLL)                            # 先頭要素を読み飛ばし
                #↓最後の要素でないなら
        suspend (if n > 0 then "|   " else "    ") || d2tree(LLL)
      }
      default   : stop("error")
    }
  }
end

########################
# stringを cを区切りにして分割して、開始位置と要素を返す。
########################
# 動作は、Icon入門講座(7) Iconの特徴(5)スキャンを参考にして下さい。
procedure p_split(line,c)
  /c := ' \t'                               # default
  /line := &subject                         # default
  list := []                                # 戻り値用 list
  line ? {
    while tab(ps := upto(~c)) do
      put(list,[ps,tab(pe := many(~c))])
  }
  return list
end
-----$ D2TREE.ICN ( lines:141 words:544 ) ------------------<cut here

  結果と x2tree07.icnの説明は、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_308.txt 1997/05/11 PCVAN PIG)

■  Icon > Icon散歩道(9) 再び x2tree(1)        風つかい      目次

  まず、前回の 「再び dir2tree」の続きです。 FDの root directoryからの
treeを 表示してみました。

-----^ ICON_FD2.DIR ( date:97-05-10 time:23:55 ) -----------<cut here
A:\       <DIR>
  + NOT_ARCH       <DIR>        97-05-03  21:00 NOT_ARCH
  |   + ICON_LEC DOC         3,038  97-04-23  23:17 ICON_LEC.DOC
  |   + ICON_LEC TXT       116,916  97-04-23  23:15 ICON_LEC.TXT
  |   + ICONLEC2 DOC         2,686  97-04-23  23:19 ICONLEC2.DOC
  |   + ICONLEC2 TXT       125,700  97-04-23  23:20 ICONLEC2.TXT
  |   + ICONLEC3 DOC         2,746  97-05-08  12:47 ICONLEC3.DOC
  |   + ICONLEC3 TXT       105,141  97-05-08  12:47 ICONLEC3.TXT
  + OTHER          <DIR>        97-05-03  21:00 OTHER
  |   + ICON_LEC ENG         3,109  97-04-23  23:30 ICON_LEC.ENG
  |   + ICONLEC2 ENG         2,869  97-04-23  23:32 ICONLEC2.ENG
  |   + ICONLEC3 ENG         2,924  97-05-09  20:00 ICONLEC3.ENG
  |   + CONTRIB  TXT         2,309  97-04-26  13:57 CONTRIB.TXT
  |   + CONTRIB2 TXT           752  97-05-09  19:39 CONTRIB2.TXT
  + ICON_LEC LZH        42,239  97-04-26  10:07 ICON_LEC.LZH
  + ICONLEC2 LZH        44,737  97-04-26  10:07 ICONLEC2.LZH
  + ICONLEC3 LZH        33,723  97-05-08  12:48 ICONLEC3.LZH
-----$ ICON_FD2.DIR ( lines:17 words:123 ) -----------------<cut here


  さて、今回は、「再び x2tree」というタイトルですが、これは ミスではなく
機能アップです。(汗)

  x2treeは、構造体を使った programの testの際に便利なのですが、 treeの列
の進みを指定できる ように して置かなかったので、階層が多い 構造体の tree
表示では、列の端が、画面から外れてしまします。

  そこで、treeの列の進みを指定できるように修正しました。

-----^ X2TREE07.ICN ( date:97-05-08 time:21:54 ) -----------<cut here
# 構造体の構成を tree状に見せる generator (recursive)
# x2tree07.icn Rev.1.1 1997/05/08 windy
# x2tree06.icn にて、列の進みを設定可にしたもの
# This file is in the public domain.
link jimage

procedure x2t(x,step)
# generator
# topの処理
  suspend "<" || type(x) || " " || string(serial(x)) || ">"
                                         #↑listの serial No
  ss := repl(" ", \step | 0)
  suspend " " || ss || x2tree(x,ss,"")
                          #↑初期化フラグ
end

procedure x2tree(x,ss,init)
# generator
# show the tree structure of x
  static T          # serial No 登録用 set登録用 table  static宣言をして
                    # おかないと、再帰したときに、未定義 errorとなる。
  if \init then {   # 初期化を initialでやると、同じ program内で別の
                    # 構造体 tree表示のために、再び x2tを 呼んだ時に
                    # 実行されなくて状態が残るので、フラグで初期化指示
    T := table()       
    T["list"]  := set() # ここは、table(set())とすると、全て同じ setが
    T["set"]   := set() # 割り当てられてしまうので、個別に初期化する。
    T["table"] := set()
    if (t := type(x)) == ("list" | "set" | "table")
    then insert(T[t],serial(x))    # serial Noを T[type(x)]に登録
  }

  n := *x                   # 枝の末端検出用カウンタ

  if (tt := type(x)) ~== "table" then { # not table
    every xx := !x do {       # 構造体の要素を1つ づつ取り出す
      n -:= 1
      t  := type(xx)
      val_disp := if t == ("list" | "set" | "table")
              then "+ <" || t || " " || string(m := serial(xx)) || ">"
              else "+ " || left(t,7)  || jimage(xx)

      case t of { # 構造体のタイプにより、
        "string"            : suspend val_disp
        #↓list,set,tableなら、typeを書出して、その中身をまた解析する。
        "list" | "set" | "table" : {
          #↓再帰構造で なければ。(T[type(xx)] に既に登録済みなら再帰構造)
          if not member(T[t],m) then {
            insert(T[t],m)    # serial Noを T[type(xx)]へ登録
            suspend val_disp
            suspend (if n > 0 then "| " else "  ") || ss || ss || x2tree(xx,ss)
                              #↑枝の途中 #↑枝の末端           # 再帰↑
            delete(T[t],m)    #←serial No 登録を削除
          }
          else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
            return val_disp || " (Recursion)"
          }
        }
        #↓その他なら、typeと値を書き出す。
        default             : suspend val_disp
      }
    }
  }

  else { # table
    every xkey := key(x) do {       # tableの keyを1つ づつ取り出す
      n -:= 1
      tk := type(xkey)
      xx := x[xkey]
      t  := type(xx)
      val_disp := if t == ("list" | "set" | "table")
              then "+ <" || t || " " || string(m := serial(xx)) || ">"
              else "+ " || left(t,7)  || jimage(xx)
      key_disp := if tk == ("list" | "set" | "table")
              then " <- <" || tk || " " || string(serial(xkey)) || ">"
              else " <- " || left(tk,7) || jimage(xkey)

      case t of { # 構造体のタイプにより、
        "string" : suspend val_disp || key_disp

        #↓list,set,tableなら、typeを書出して、その中身をまた解析する。
        "list" | "set" | "table" : {
          #↓再帰構造で なければ。(T[type(xx)] に既に登録済みなら再帰構造)
          if not member(T[t],m) then {
            insert(T[t],m)    # serial Noを T[type(xx)]へ登録
            suspend val_disp || key_disp
            suspend (if n > 0 then "| " else "  ") || ss || ss || x2tree(xx,ss)
                              #↑枝の途中 #↑枝の末端            # 再帰↑
            delete(T[t],m)    #←serial No 登録を削除
          }
          else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
            return val_disp || key_disp || " (Recursion)"
          }
        }
        #↓その他なら、typeと値を書き出す。
        default  : suspend val_disp || key_disp
      }
    }
  }

end
-----$ X2TREE07.ICN ( lines:101 words:448 ) ----------------<cut here

  test programと その結果は、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_309.txt 1997/05/11 PCVAN PIG)

■  Icon > Icon散歩道(10) 再び x2tree(2)      風つかい      目次

  前回の 「再び x2tree」の続きです。test programとその結果です。
  test programが長くなりましたので、分けました。

-----^ X2TREE7~.ICN ( date:97-05-08 time:21:54 ) -----------<cut here
# test driver for x2tree07.icn
# x2tree7~.icn 1997/05/08 windy
# This file is in the public domain.
link x2tree07

procedure main()
#  #listの test
  L1 := ["A","B"]
  L2 := ["C","D"]
  L3 := ["E","F"]
  put(L1,L2)
  put(L2,L3)
  put(L1,L3)               # 別枝 test
  put(L3,L1)               # listの再帰
  every write(x2t(L1) \20) # \20は、テストをドジッた時に、20個で止めるため。
  write()
  #tableの test
  T := table()
  T["A"] := "G"
  T["C"] := L2[1]
  T["E"] := L3
  T[L1] := L1[1]
  put(L3,T)                # tableの再帰
  every write(x2t(T) \20)

  write()
  #setの test
  L4 := ["H","I"]
  S1 := set(["L","M"])
  S  := set(["J","K",L4])
  insert(S,S1)
  insert(S1,S)             # setの再帰
  every write(x2t(S) \20)

  write()
  every write(x2t(L1,1) \20)
  every write(x2t(S,1) \20)
  every write(x2t(T,1) \20)

  write()
  every write(x2t(L1,2) \20)
  every write(x2t(S,2) \20)
  every write(x2t(T,2) \20)

end

-----$ X2TREE7~.ICN ( lines:46 words:111 ) -----------------<cut here

  同じデータで、順番に、列の進みを増やしています。
-----^ X2TREE07 ( date:97-05-11 time:00:43 ) ---------------<cut here
<list 1>
 + string "A"
 + string "B"
 + <list 2>
 | + string "C"
 | + string "D"
 | + <list 3>
 |   + string "E"
 |   + string "F"
 |   + <list 1> (Recursion)
 + <list 3>
   + string "E"
   + string "F"
   + <list 1> (Recursion)

<table 2>
 + string "C" <- string "C"
 + <list 3> <- string "E"
 | + string "E"
 | + string "F"
 | + <list 1>
 | | + string "A"
 | | + string "B"
 | | + <list 2>
 | | | + string "C"
 | | | + string "D"
 | | | + <list 3> (Recursion)
 | | + <list 3> (Recursion)
 | + <table 2> (Recursion)
 + string "A" <- <list 1>
 + string "G" <- string "A"

<set 8>
 + string "K"
 + <list 44>
 | + string "H"
 | + string "I"
 + <set 7>
 | + string "M"
 | + string "L"
 | + <set 8> (Recursion)
 + string "J"

<list 1>
  + string "A"
  + string "B"
  + <list 2>
  |   + string "C"
  |   + string "D"
  |   + <list 3>
  |       + string "E"
  |       + string "F"
  |       + <list 1> (Recursion)
  + <list 3>
      + string "E"
      + string "F"
      + <list 1> (Recursion)
<set 8>
  + string "K"
  + <list 44>
  |   + string "H"
  |   + string "I"
  + <set 7>
  |   + string "M"
  |   + string "L"
  |   + <set 8> (Recursion)
  + string "J"
<table 2>
  + string "C" <- string "C"
  + <list 3> <- string "E"
  |   + string "E"
  |   + string "F"
  |   + <list 1>
  |   |   + string "A"
  |   |   + string "B"
  |   |   + <list 2>
  |   |   |   + string "C"
  |   |   |   + string "D"
  |   |   |   + <list 3> (Recursion)
  |   |   + <list 3> (Recursion)
  |   + <table 2> (Recursion)
  + string "A" <- <list 1>
  + string "G" <- string "A"

<list 1>
   + string "A"
   + string "B"
   + <list 2>
   |     + string "C"
   |     + string "D"
   |     + <list 3>
   |           + string "E"
   |           + string "F"
   |           + <list 1> (Recursion)
   + <list 3>
         + string "E"
         + string "F"
         + <list 1> (Recursion)
<set 8>
   + string "K"
   + <list 44>
   |     + string "H"
   |     + string "I"
   + <set 7>
   |     + string "M"
   |     + string "L"
   |     + <set 8> (Recursion)
   + string "J"
<table 2>
   + string "C" <- string "C"
   + <list 3> <- string "E"
   |     + string "E"
   |     + string "F"
   |     + <list 1>
   |     |     + string "A"
   |     |     + string "B"
   |     |     + <list 2>
   |     |     |     + string "C"
   |     |     |     + string "D"
   |     |     |     + <list 3> (Recursion)
   |     |     + <list 3> (Recursion)
   |     + <table 2> (Recursion)
   + string "A" <- <list 1>
   + string "G" <- string "A"
-----$ X2TREE07 ( lines:124 words:501 ) --------------------<cut here

  当分は、ミスに気がつきませんように。(笑)

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_310.txt 1997/05/11 PCVAN PIG)

■  Icon > Icon迷い道(1) system()                 風つかい      目次

  Icon散歩道の方では、次は 多項式の展開 をやってみるつもりなんですが、
結構 道が険しくて、次のお話しが書けません。

  (a+b+c)^2 を a^2+b^2+c^2+2ab+2ac+2bcに、変換する程度の処理を、考えて
いるのですが、どうやって programを 組めば良いのか 思いつきません。

  そちらは、しばらく考えてみるとして、何にも書かないのもさみしいので、
近ごろ書いた programを紹介します。

  niftyと PCVANの log fileから OSL/Libraryの Icon関係 fileタイトルの部分
を抜き出すものです。    YOTさんの ygrepを使わさせて頂いています。

  ygrepの引数になる文字列を作って、system()関数に与えるだけです。
  MS-DOSの batch programで書ける内容ですが、re-directが できないとかの
制限がありますので、Iconから呼んでいます。

  command line引数に、日付(月日)を与えると その日付の log fileを、
与えなければ、その日の log fileを検索します。

  map関数を使って、 keywordの &dateから日付を 抜き出しています。
  &dateは、1997/06/04という形式をしています。これから 0604の部分を
抜き出すものです。
  すると、使っている式は
    map("679A","123456789A","1997/06/04")
  となります。

  map関数は、本来は文字変換の関数です。  その解釈ですと、前の式は
文字列 "679A"を 次の 規則で変換することになります。

    1 -> 1           すると、ご覧のように "679A"は、ちょうど月日の部分
    2 -> 9         の数字に変換されます。
    3 -> 9           ちょっと、パズルみたいですが、このやり方を 覚えて
    4 -> 7         おくと便利です。
    5 -> /           部分文字列指定の
    6 -> 0               &date[[6:8] || &date[9:0]
    7 -> 6         と同じ結果になります。
    8 -> /
    9 -> 0
    A -> 4

  さて、 programです。
-----^ IDLG.ICN ( date:97-06-04 time:23:49 ) ---------------<cut here
# niftyと PCVANの logから Icon関係 download数 の部分を切り出し
# idlg.icn Rev.1.3 1997/06/04 windy file-name変更 idl.icn -> idlg.icn
#                                   comment追加
# idl.icn  Rev.1.2 1997/06/01 windy 不正 date検出強化
# idl.icn  Rev.1.1 1997/05/23 windy Kazetuskai H.S.
# YOTさんの ygrep(超高速・多機能 grep)を使用。
# Usage:  idlg または idlg MMDD

procedure main(args)
  # 日付指定が あればその日付 無ければその日 の log fileを対象にする。
                                        # ↓format変換(月日抜き出し)
  date := right(numeric(args[1]),4,"0") | map("679A","123456789A",&date)
                                                  # 1997/06/04の形式↑
  # ygrepの呼び出しパラメータ生成
  # nifty用              ↓ OR検索
  s1 := "ygrep \"{icon,bipl,de386}.*lzh\"" || " nif" || date || ".log "
  # PCVAN用    ↓一致行の前の行も出力
  s2 := "ygrep -B1 \"{icon,bipl,de386}.*lzh\"" || " van" || date || ".log "

  write(&errout,s1)
  system(s1)            # nifty log検索

  write(&errout,s2)
  system(s2)            # PCVAN log検索

end
-----$ IDLG.ICN ( lines:26 words:105 ) ---------------------<cut here

  結果は、こんなものです。(単なる grepの結果です。汗)
-----^ DL970605.G ( date:97-06-05 time:00:18 ) -------------<cut here
  82  PFF01531 97/05/03   33393    2 B ICONLEC3.LZH テキスト処理言語Icon入門講座3
(中略)
  17  PFF01531 96/12/08   41893  133 B ICON_LEC.LZH テキスト処理言語Icon入門講座
  89.ICONLEC3.DOC   TRA11936  97/ 5/ 3   0002747   0000005
     ICONLEC3.LZH   TRA11936  97/ 5/ 3   0033385   0000003
(中略)
 413.DE386_93.DOC   TRA11936  97/ 5/11   0003329   0000029
     DE386_93.LZH   TRA11936  97/ 5/11   0206581   0000012
-----$ DL970605.G ( lines:24 words:165 ) -------------------<cut here

  迷い道から、抜け出せるかな〜。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_351.txt 1997/06/06 PCVAN PIG)

■  Icon > Icon迷い道(2)download数 集計           風つかい      目次

  前回、Iconから ygrepを呼んで、log fileから Icon関係 fileのタイトル行を
切り出す programをご覧にいれました。  更に 集計表まで 出してくれるといい
ということで、Iconだけで集計 programを書いてみました。

-----^ DL970607 ( date:97-06-07 time:00:35 ) ---------------<cut here
<1997/06/07>     PIG  SLABO    PFL FGALTS file計
BIPL.LZH           -     11      -     19     30
DE386.LZH          -     12      -     40     52
ICONLEC3.LZH       3     11      3     46     63
ICONLEC2.LZH       3     16     41     67    127
ICON_LEC.LZH       6     32     91    134    263
------------------------------------------------
SIG/forum計       12     82    135    306    535
-----$ DL970607 ( lines:8 words:43 ) -----------------------<cut here

  listで 集計表を 作っておきます。 logを1行づつ 読みながら fileの titleの
行から download数を 切り出して 表を更新します。      log fileが 終わると、
集計表を出力しています。

-----^ IDL.ICN ( date:97-06-05 time:00:21 ) ----------------<cut here
# niftyとPCVANの logファイルから Icon関係 fileの download数抽出
# idl.icn  Rev.1.2 1997/06/05 windy file-name変更 idl2.icn -> idl.icn
#                                   comment追加
# idl2.icn Rev.1.1 1997/06/04 windy Kazetsukai H.S.
# This file is in the public domain.
# Usage: idl または idl MMDD

procedure main(args)
  # download数 格納 list(2重 list)
        #↓ [1]:PIG [2]:SLABO [3]:FPL [4]:FGALTS
  L := [ [ 0 ,0, 0 ,0],  # L[1] ICON_LEC.LZH
         [ 0 ,0, 0 ,0],  # L[2] ICONLEC2.LZH
         [ 0 ,0, 0 ,0],  # L[3] ICONLEC3.LZH
         ["-",0,"-",0],  # L[4] DE386.LZH    PIG,FPLには uploadしていない。
         ["-",0,"-",0] ] # L[5] BIPL.LZH     PIG,FPLには uploadしていない。

  # file名称 作成
  # command line引数が数字に変換できれば、file日付に使う。できなければ、
  # その日の日付を file日付に使う。
  f_date := right(numeric(args[1]),4,"0") |
                  map("679A","123456789A",&date)
                 #↑ &dateの 6,7,9,10番目の文字を抜き出す。(map関数の応用)
                 #   &dateは 1997/06/04の形式
  f_nif := "nif" || f_date || ".log "   # nifty log file名生成
  f_van := "van" || f_date || ".log "   # PCVAN log file名生成

####################
# nifty 処理
####################
# nifty log file例
#1              16               33  37
#  17  PFF01531 96/12/08   41893  130 B ICON_LEC.LZH テキスト処理言語Icon入門講座
  dir_nif := open(f_nif) | stop("cannot open ",f_nif)
  write(&errout,f_nif)
  size_nif := 15      # Icon関係 file検出のための照合字数

  while line := read(dir_nif) do {      # log fileを1行づつ読み込んで
    nn := numeric(line[33:37])          # download数 切り出し
    case line[1:size_nif+1] of {
      # download数を listに登録
      "  17  PFF01531 " : L[1][4] := nn # FGALTS ICON_LEC.LZH
      "  20  PFF01531 " : L[2][4] := nn # FGALTS ICONLEC2.LZH
      "  21  PFF01531 " : L[3][4] := nn # FGALTS ICONLEC3.LZH
      " 163  PFF01531 " : L[4][4] := nn # FGALTS DE386_93.LZH
      " 124  PFF01531 " : L[5][4] := nn # FGALTS BIPL93.LZH
      "  78  PFF01531 " : L[1][3] := nn # FPL    ICONLEC1.LZH
      "  81  PFF01531 " : L[2][3] := nn # FPL    ICONLEC2.LZH
      "  82  PFF01531 " : L[3][3] := nn # FPL    ICONLEC3.LZH
    }
  }
  close(dir_nif)

####################
# PCVAN処理
####################
# PCVAN log file 例
#1                 19                               52     59
# 219.ICON_LEC.DOC   TRA11936  96/12/ 8   0002421   0000032
#     ICON_LEC.LZH   TRA11936  96/12/ 8   0041893   0000032
  dir_van := open(f_van) | stop("cannot open ",f_van)
  write(&errout,f_van)
  size_van := 18      # Icon関係 file検出のための照合字数

  while line := read(dir_van) do {      # log fileを1行づつ読み込んで
    nn := numeric(line[52:59])          # download数 切り出し
    case line[1:size_van+1] of {
      # SIG検出
      (" 219.ICON_LEC.DOC " | " 243.ICONLEC2.DOC " |
       " 256.ICONLEC3.DOC " ) : mode := "LAB" # SLABO処理中

      ("  79.ICON_LEC.DOC " | "  84.ICONLEC2.DOC " |
       "  89.ICONLEC3.DOC ")  : mode := "PIG" # PIG処理中

      # download数を listに登録
       "     ICON_LEC.LZH " : if mode == "LAB" then L[1][2] := nn # SLABO
                                               else L[1][1] := (nn-1) # PIG
                                               # download test分 ↑
       "     ICONLEC2.LZH " : if mode == "LAB" then L[2][2] := nn # SLABO
                                               else L[2][1] := nn # PIG
       "     ICONLEC3.LZH " : if mode == "LAB" then L[3][2] := nn # SLABO
                                               else L[3][1] := nn # PIG
       "     DE386_93.LZH " :                       L[4][2] := nn # SLABO
       "     BIPL93.LZH   " :                       L[5][2] := nn # SLABO
    }
  }
  close(dir_van)

####################
# 表にして出力
####################
  f_name := [ "ICON_LEC.LZH ",     # file名称 list
              "ICONLEC2.LZH ",
              "ICONLEC3.LZH ",
              "DE386.LZH    ",
              "BIPL.LZH     ",
              "SIG/forum計  "  ]
  size_f_name := *f_name[1]

  sig    := [ "    PIG",           # SIG/forum名称 list
              "  SLABO",
              "    PFL",
              " FGALTS",
              " file計"  ]
  size_sig := *sig[1]

  # 日付生成                            ↓fdateに"/"を挿入。(map関数の応用)
  writes(left("<" || &date[1:6]  || map("12/34",1234,f_date) ||
              ">",size_f_name))
  every writes(!sig)               # SIG/forum名出力
  write()

  L_sum_col := [0,0,0,0,0]         # SIG/forum毎の download数 集計用 list
  every i := *L to 1 by -1 do {    # listの末尾から(逆順出力のため)
    writes(f_name[i])              # file名出力
    sum_line := 0                  # file毎の download数 集計
    every j := 1 to *L[i] do {     
      writes(right((nnn := L[i][j]),size_sig))      # file毎 download数
      sum_line     +:= (nnnn := numeric(nnn) | 0)   # 数字なら足し込む
      L_sum_col[j] +:= nnnn                         # 数字なら足し込む
    }
    write(right(sum_line,size_sig))   # file毎 daownload数 出力
    L_sum_col[-1] +:= sum_line        # 総計に足し込む
  }
  write(repl("-",*L_sum_col * size_sig +size_f_name))  # 仕切り線

  writes(f_name[-1])               # "SIG/forum計  "の文字を出力
                                   # (f_nameの最後の要素)
  every writes(right(!L_sum_col,size_sig))          # SIG/forum毎の計
  write()

end
-----$ IDL.ICN ( lines:131 words:617 ) ---------------------<cut here

(追記 97/11/24現在では次の download数になっています。)
-----^ DL971124 ( date:97-11-24 time:10:16 ) ---------------<cut here
<1997/11/24>     PIG  SLABO    FPL FGALTS file計
BIPL.LZH           -     14      -     33     47
DE386.LZH          -     17      -     89    106
ICONLEC3.LZH       3     12     18     95    128
ICONLEC2.LZH       5     16     56    111    188
ICON_LEC.LZH       7     34    109    196    346
------------------------------------------------
SIG/forum計       15     93    183    524    815
-----$ DL971124 ( lines:8 words:43 ) -----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(icon_352.txt 1997/06/07 PCVAN PIG)

■  Icon > Icon迷い道(3)CSV:定義ファイルの読込    風つかい      目次

  夏の盛りから、担当している 某 projectの関係で、某所に拉致されており
ましたが、一区切りつきましたので娑婆に戻って、気がつけばもう秋深し。

  Icon講座は、どこまで書いたか記憶の彼方です。
  確か、CSVデータ(コンマ区切りデータ)を、 表形式の テキストデータに
変換するprogram を作って upload しようとしていた ような 気がします。

  リハビリと兼ねて、思い出しながら 続きをやってみたい と思います。
  しかし、某 projectは未だ続いていますので、Icon講座が 途絶えましたら、
また 某所に拉致されたな と思って下さい。(笑)

  さて、CSVデータというのは、こんなデータです。

"なかやまみほ","中山美穂",1970,3,1,"O",158,80,60,84,45,"東京都小金井市"

  コンマ区切りのデータで、文字列は " で くくってあります。 文字列中に " が
現れる場合は、"" で表わすものとします。
  CSVといっても、細かい点で仕様が違うものが、いくつかあるようですが、ここ
ではこの仕様とします。

  例のようなデータが並んでいる データファイルを、表形式のデータへ 変換した
り、表形式のデータを逆に CSVデータへ変換するものを作ってみます。

  例のデータを表形式にするためには、各欄を何文字の表にするかの情報をどこか
で定義しないといけません。  たとえばこんな感じです。各欄の文字数を定義する
ついでに、文字か数字かの情報もまとめて定義しています。

-----^ CSV2TB.CFG ( date:97-10-27 time:00:02 ) -------------<cut here
####################
# csv -> 表データ  変換指定ファイル
####################
# 行頭が "#"あるいは行に "="が含まれ無いなら、無視。(コメント)
# 処理対象ファイル名の先頭の文字にて、処理指定を識別する。
# ファイル識別文字("="の手前の文字)は、英字大文字。
# 変換指示は、","区切りのデータを何桁のデータとして扱うかを、指示。
# 変換指定例
#   s14 : 14桁の文字列、n4 : 4桁の数字、s0 : その欄は無視(n0でも良い)
# csvデータより、指定桁が大きい場合は、後ろに " "が追加される。
# 変換指定が無い部分の csvデータは無視される。
####################

# テスト用サンプルデータ
#   "なかやまみほ","中山美穂",1970,3,1,"O",158,80,60,84,45,"東京都小金井市",10
SAM= s13            s9        n4   n2n2 s0 n3  n3 n3 n3 n3 s12              n2

-----$ CSV2TB.CFG ( lines:17 words:52 ) --------------------<cut here

  ということで、こんな定義ファイルを読みこむための procedureを 先ず 作って
みることにします。

  早速、programです。定義ファイルを読み込んで listへ格納する programと
その listに格納されている keyと stringをチェックする2つの procedureが
含まれています。
-----^ GET_INL.ICN ( date:97-10-27 time:23:59 ) ------------<cut here
####################
# 初期化ファイル・定義ファイルの読み込み(文字列ダブリ対応)
####################
# args : string(拡張子名)
# value: list (初期設定値の [key1,value1,key2,value2,...])
# Usage: L_INI := get_inil("INI")
#        実行ファイル名の拡張子を INIに変えたものを初期化ファイルとみなす。
#        初期化ファイルの形式は、下記の形式
#          Nantara=Kantara Dotara
#          ["Nantara","Kantara Dotara"]が valueとなる。
#          "="が、含まれ無い行は無視される。(コメント行に使える)
# 備考 : ある keyの文字列が他の keyの文字列に含まれる場合は、
#        keyは降順に書き込むこと。(長い順にチェックしないと無視されるので)
#        ABC=D:\icon\
#        AB=D:\icon\my_procs\
# This file is in the public domain.

link file_e        # f_name()
procedure get_inil(ext)
  L := []          # list生成
  /ext := "INI"    # 拡張子 default
  dir := open(f_name() || "." || ext) | # 初期化ファイルを
         fail                           #
  while line := read(dir) do {          # 1行ずつ読み込み
    line ?  {                           # lineを走査対象として
                        #↓2番目の式を値とする
      put(L,tab(upto('=')),2(move(1),tab(0)))
    } # ↑'='迄の文字列      ↑        ↑残りの文字列
  }   # ↑を keyとして   "="文字スキップ
  return L
end


####################
# 文字列の先頭が Lの keyにあれば、valueを返す
####################
# args : [1]:list [key1,value1,key2,value2,...]の形式
#        [2]:string
# value: keyが文字列の先頭と一致すれば、keyに対応した value
# 備考 : Lは再使用不可。
# This file is in the public domain.

procedure key_check(L,s)
  /s := &subject
  while ss := get(L) do {  # keyを取り出して、
    # keyが文字列の先頭に一致すれば、valueを返す。不一致なら読み飛ばし。
    if match(ss,s) then return get(L) else get(L)
  }
  fail                     # 一致しなければ、fail
end
-----$ GET_INL.ICN ( lines:50 words:165 ) ------------------<cut here
(差し替え)

  f_name()は以前 exe_name()という名前で紹介しました procedureです。
実行ファイル名を取り出す procedureです。 私は f_name()を、現在は file_e.icn
という procedureのファイルの中に入れていますので、file_eを linkしています。

  get_inilの test programを次に。 定義ファイルを読み込んで読み込んだ結果
の listの表示を行う部分と key_checkを行った結果の表示を 行う部分が含まれ
ています。
-----^ GET_INL~.ICN ( date:97-10-27 time:23:55 ) -----------<cut here
# test procedure for get_inil
# This file is in the public domain.
link view_e, # x2t()
     file_e  # get_inil(), key_check()
procedure main()
  every write(x2t(get_inil()))
  every write(x2t(get_inil("CFG")))
  write(key_check(get_inil("CFG"),"lmnopqr") | "error")
  write(key_check(get_inil("CFG"),"lmno") | "error")
  write(key_check(get_inil("CFG"),"lmn") | "error")
  write(key_check(get_inil("CFG"),"abcd") | "error")
end
-----$ GET_INL~.ICN ( lines:12 words:40 ) ------------------<cut here

  tree表示 の x2t()は、view_eに、get_inil(),key_checkは、file_eに入れている
ため 各々を linkしています。

  定義ファイルのサンプルです。
-----^ GET_INL~.INI ( date:97-10-27 time:23:57 ) -----------<cut here
# test data for get_inl~
ABC=abc_ini
DEFG=デーイーエフジー
hijk=123,456

-----$ GET_INL~.INI ( lines:5 words:8 ) --------------------<cut here

  もう1つの定義ファイルサンプルです。
-----^ GET_INL~.CFG ( date:97-10-27 time:23:56 ) -----------<cut here
# test data for get_inl~
hijk=123,456,789
lmno=lmnoだ
pqrs=
lmn=lmnだ

-----$ GET_INL~.CFG ( lines:6 words:9 ) --------------------<cut here

  結果はこうなります。
-----^ GET_INIL ( date:97-10-27 time:00:30 ) ---------------<cut here
<list 1>
 + string "ABC"
 + string "abc_ini"
 + string "DEFG"
 + string "デーイーエフジー"
 + string "hijk"
 + string "123,456"
<list 84>
 + string "hijk"
 + string "123,456,789"
 + string "lmno"
 + string "lmnoだ"
 + string "pqrs"
 + string ""
 + string "lmn"
 + string "lmnだ"
lmnoだ
lmnoだ
lmnだ
error
-----$ GET_INIL ( lines:20 words:50 ) ----------------------<cut here

  というところで、今日はこのくらいにします。  次回は、定義ファイルを
解析するあたりをやってみます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Smile/岡本真夜
(icon_353.txt 1997/10/27 PCVAN PIG)

■  Icon > Icon迷い道(4)CSV:定義ファイルの解析    風つかい      目次

  今日は、定義ファイルの解析の部分をやります。定義ファイルは、CSVデータと
並べて次のように指定したいのです。

SAM= s4     s1 n1n2 n3   s16
#   "地球","E",1,15,256,"ちきゅうはまるい"

  順に、地球              -> s4
        E                 -> s1
        1                 -> n1
        15                -> n2
        256               -> n3
        ちきゅうはまるい  -> s16

  と指定している訳です。

  programでは、CSVデータの欄に対応した指定を listに格納しておくことに
します。 前回の定義ファイルの読込みでは、

SAM= s4     s1 n1n2 n3   s16     という stirngを

["SAM"," s4     s1 n1n2 n3   s16"] と 変換して、"SAM"で listデータを
サーチして、" s4     s1 n1n2 n3   s16" という文字列を 取り出すところまで
済んでいます。

  今回は、この指定文字列を、欄毎の指定が順に詰まった listへ変換する部分
を作ります。

  指定が全てスペース区切りなら、以前紹介しました splitとかで listに変換
できるのですが、今回のデータは スペースが無い部分もあります ので、 別の
方法が必要です。

  指定が、アルファベット1文字と数字の組み合わせですので、その組み合わせ
を検索して、listに順に格納する procedureを作ります。
  こういう データ変換 procedureを 簡単に作れるところが、Iconの良いところ
です。

  というところで、programです。 Test programも一緒に入れています。
-----^ CN_SPLIT.ICN ( date:97-10-29 time:00:42 ) -----------<cut here
####################
# 文字列処理指定の文字列を解析
####################
# cn_split.icn 1997/10/29 windy comment追加
# cn_split.icn 1997/08/20 windy 風つかい H.S.
# This file is in the public domain.

# Test program
procedure main()
  s := "s4     s1 n1n2 n3   s16"
  s ? every write(!cn_split())
end

####################
# 文字列処理指定の文字列を解析
####################
# 処理指定(英文字1文字を想定)+処理文字数
# args : c1 : cset(処理指定1バイト文字セット) 
#        c2 : cset(処理文字数、数字n桁)
#        s  : 指定文字列
# value: list(処理指定を順に詰めたもの)
# 例   : "s4     s1 n1n2 n3   s16"      ->    [s4,s1,n1,n2,n3,s16] と変換
#        "地球","E",1,15,256,"ちきゅうはまるい"
# 備考 : csvデータを表データに変換するプログラムのために作成
#        上の例の用に、データ例と並べて指定が可能なプログラムにするため

procedure cn_split(s,c1,c2)
  /s  := &subject                   # default
  /c1 := &letters                   # 英文字の大文字・小文字のセット
  /c2 := &digits                    # 数字のセット '0123456789'
  L   := []                         # 戻り値用 list
  s ? {
    while tab(upto(c1)) do {        # c1迄スキップ
      ss := ""                      # 
      ss := tab(many(c1))           # c1以外の文字迄スキップし、その間の文字
                                    # を ssへ
      put(L,ss ||:= tab(many(c2)))  # c2以外の文字迄スキップし、その間の文字
                                    # を ssへ足しこむ
    }
  }
  return L
end
-----$ CN_SPLIT.ICN ( lines:42 words:140 ) -----------------<cut here

  cn_split.exeを実行した結果です。
-----^ CN_SPLIT ( date:97-10-29 time:00:42 ) ---------------<cut here
s4
s1
n1
n2
n3
s16
-----$ CN_SPLIT ( lines:6 words:6 ) ------------------------<cut here

  あと、もう一つ procedureを準備しますが、それは次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Smile/岡本真夜
(icon_354.txt 1997/10/29 PCVAN PIG)

■  Icon > Icon迷い道(5)CSV:拡張子変更(1)      風つかい      目次

  さて、今日は 拡張子を変更する procedureについて説明します。この procedure
は、CSVデータのファイル名を foo.csvとしますと、CSVデータを表形式データに変換
したデータのファイルは拡張子を変えて、foo.txtという名称にするためのものです。

  まず ファイル名の '.' の前の部分と 後ろの部分を分ける procedureを作ります。
  早速、programです。
-----^ DOT.ICN ( date:97-10-30 time:00:33 ) ----------------<cut here
####################
# 文字列 sの 文字 cより手前と後ろの部分を得る。
####################
# 文字列 sの 文字 cより手前と後ろの部分を得る。
# 尚、文字 cは、1個か もしくは無い場合を想定、複数の場合は top_get()や
# top_cut() を使う。
# ファイル名の拡張子を除いた部分や拡張子を得る場合とか、数字の小数点以下や
# 以上の値を得る場合に使用。
# dot.icn 1997/10/30 windy comment修正
# dot.icn 1997/08/15 windy 風つかい H.S.
# This file is in the public domain.

####################
# cより手前の部分を得る。
####################
# args : (1):文字列, (2):文字(セット)
# value: 文字列
#        cが含まれ無い場合は、引数文字列

procedure pre_char(s,c)
  /c := '.'                  # default
  s ? return tab(upto(c) | 0)
end


####################
# cより後ろの部分を得る。
####################
# args : (1):文字列, (2):文字(セット)
# value: 文字列
#        cが含まれ無い場合は、""(空文字列)

procedure post_char(s,c)
  /c := '.'                  # default
  s ? return if tab(upto(c)) then 2(move(1),tab(0)) else ""
end
-----$ DOT.ICN ( lines:36 words:102 ) ----------------------<cut here

  この部分の Test programです。
-----^ DOT~.ICN ( date:97-10-30 time:00:43 ) ---------------<cut here
# test procedure for dot.icn
# dot~.icn 1997/10/30 windy comment修正
# dot~.icn 1997/08/15 windy 風つかい H.S.
# This file is in the public domain.
link dot

procedure main()
  write(s := "abcd.efg"," ",pre_char(s)," ",post_char(s))
  write(s := "abcd"," ",pre_char(s)," ",post_char(s))
  write(s := ".efg"," ",pre_char(s)," ",post_char(s))
  write(s := "abcd."," ",pre_char(s)," ",post_char(s))
  write(s := "123.45"," ",pre_char(s)," ",post_char(s))
  write(s := "123"," ",pre_char(s)," ",post_char(s))
  write(s := ".45"," ",pre_char(s)," ",post_char(s))
  write(s := "123."," ",pre_char(s)," ",post_char(s))
end
-----$ DOT~.ICN ( lines:16 words:69 ) ----------------------<cut here

  dot~.exeの結果です。
-----^ DOT~ ( date:97-10-30 time:00:36 ) -------------------<cut here
abcd.efg abcd efg
abcd abcd 
.efg  efg
abcd. abcd 
123.45 123 45
123 123 
.45  45
123. 123 
-----$ DOT~ ( lines:8 words:18 ) ---------------------------<cut here

  ちょっと、長くなりましたので、続きは次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Blow by Blow / Jeff Beck
(icon_355.txt 1997/10/30 PCVAN PIG)

■  Icon > Icon迷い道(6)CSV:拡張子変更(2)      風つかい      目次

  さて、拡張子を変更する procedureのつづきです。 前回 作りました '.' の前の
部分と 後ろの部分を分ける procedureを使って、拡張子を変更したりチェックした
りする procedureを作ります。

-----^ EXT.ICN ( date:97-10-30 time:00:48 ) ----------------<cut here
####################
# 拡張子名変更・チェック
####################
# ext.icn 1997/10/30 windy comment修正
# ext.icn 1997/08/25 windy 風つかい H.S.
link dot

####################
# 拡張子名変更ファイル名生成
####################
# 拡張子名が ext1ならば、拡張子を ext2に変更したファイル名を生成
# args : (1):許容チェック拡張子名, (2):新拡張子, (3):ファイル名,(4):反転
# value: string: 新ファイル名
#        拡張子が ext1で無ければ、失敗
# 備考 : negに、何か値をセットすると条件を反転(拡張子が、ext1で無ければ
#        ...という動作となる。

procedure change_ext(ext1,ext2,f_name,neg)
  return if /neg                              # ↓'.'以前の文字列
  then 2(map(ext1)  == map(post_char(f_name)),pre_char(f_name) || "." || ext2)
                           # ↑'.'以降の文字列(=拡張子)
                # ↓↑比較式は、成功すれば右辺値になる。
  else 2(map(ext1) ~== map(post_char(f_name)),pre_char(f_name) || "." || ext2)
end


####################
# 拡張子名チェック
####################
# 拡張子名が extかどうかチェック
# args : (1):許容拡張子名, (2):ファイル名 ,(3):反転
# value: string: ファイル名
#        拡張子が extでなければ、失敗
#        拡張子無しのチェックは、extに ""(空文字列)をセット
# 備考 : negに、何か値をセットすると条件を反転(拡張子が、extなら失敗)

procedure check_ext(ext,f_name,neg)
  return if /neg
  then 2(map(ext)  == map(post_char(f_name)),f_name)
  else 2(map(ext) ~== map(post_char(f_name)),f_name)
end
-----$ EXT.ICN ( lines:41 words:113 ) ----------------------<cut here

  Test programです。
-----^ EXT~.ICN ( date:97-10-30 time:01:08 ) ---------------<cut here
####################
# 拡張子名変更・チェック Test program
####################
# ext~.icn 1997/10/30 windy comment修正
# ext~.icn 1997/08/25 windy 風つかい H.S.
link ext

procedure main()
  write("拡張子チェック:check_ext test")
  write(s1 := "def"," ",s2 := "abc.def"," ",check_ext(s1,s2) | "error")
  write(s1 := "DEF"," ",s2 := "abc.def"," ",check_ext(s1,s2) | "error")
  write(s1 := "def"," ",s2 := "abc.DEF"," ",check_ext(s1,s2) | "error")
  write(s1 := "def"," ",s2 := "abc"," ",check_ext(s1,s2) | "error")
  write(s1 := ""," ",s2 := "abc.def"," ",check_ext(s1,s2) | "error")
  write(s1 := ""," ",s2 := "abc"," ",check_ext(s1,s2) | "error")

  write("拡張子変更:change_ext test")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3) | "error")
  write(s1 := "DEF"," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3) | "error")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.DEF"," ",
              change_ext(s1,s2,s3) | "error")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.txt"," ",
              change_ext(s1,s2,s3) | "error")
  write(s1 := ""," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3) | "error")
  write(s1 := ""," ",s2 := "xyz"," ",s3 := "abc"," ",
              change_ext(s1,s2,s3) | "error")

  write("拡張子チェック:check_ext 条件反転 test")
  write(s1 := "def"," ",s2 := "abc.def"," ",check_ext(s1,s2,"") | "error")
  write(s1 := "DEF"," ",s2 := "abc.def"," ",check_ext(s1,s2,"") | "error")
  write(s1 := "def"," ",s2 := "abc.DEF"," ",check_ext(s1,s2,"") | "error")
  write(s1 := "def"," ",s2 := "abc"," ",check_ext(s1,s2,"") | "error")
  write(s1 := ""," ",s2 := "abc.def"," ",check_ext(s1,s2,"") | "error")
  write(s1 := ""," ",s2 := "abc"," ",check_ext(s1,s2,"") | "error")

  write("拡張子変更:change_ext 条件反転 test")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3,"") | "error")
  write(s1 := "DEF"," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3,"") | "error")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.DEF"," ",
              change_ext(s1,s2,s3,"") | "error")
  write(s1 := "def"," ",s2 := "xyz"," ",s3 := "abc.txt"," ",
              change_ext(s1,s2,s3,"") | "error")
  write(s1 := ""," ",s2 := "xyz"," ",s3 := "abc.def"," ",
              change_ext(s1,s2,s3,"") | "error")
  write(s1 := ""," ",s2 := "xyz"," ",s3 := "abc"," ",
              change_ext(s1,s2,s3,"") | "error")
end
-----$ EXT~.ICN ( lines:52 words:296 ) ---------------------<cut here

  ext~.exeの結果です。
-----^ EXT~ ( date:97-10-30 time:00:53 ) -------------------<cut here
拡張子チェック:check_ext test
def abc.def abc.def
DEF abc.def abc.def
def abc.DEF abc.DEF
def abc error
 abc.def error
 abc abc
拡張子変更:change_ext test
def xyz abc.def abc.xyz
DEF xyz abc.def abc.xyz
def xyz abc.DEF abc.xyz
def xyz abc.txt error
 xyz abc.def error
 xyz abc abc.xyz
拡張子チェック:check_ext 条件反転 test
def abc.def error
DEF abc.def error
def abc.DEF error
def abc abc
 abc.def abc.def
 abc error
拡張子変更:change_ext 条件反転 test
def xyz abc.def error
DEF xyz abc.def error
def xyz abc.DEF error
def xyz abc.txt abc.xyz
 xyz abc.def abc.xyz
 xyz abc error
-----$ EXT~ ( lines:28 words:86 ) --------------------------<cut here

  ということで、やっと次回 CSVデータを 表形式データに 変更する programが
まとまります。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Blow by Blow / Jeff Beck
(icon_356.txt 1997/10/30 PCVAN PIG)

■  Icon > Icon迷い道(7)CSV:CSV2TB                風つかい      目次

  さて、CSVデータを表形式データへ変換する programのまとめです。
CSVデータのファイルから、1行ずつデータを読込んで、CSVデータを表形式データ
に変換して、書き出していきます。

-----^ CSV2TB.ICN ( date:97-10-26 time:21:08 ) -------------<cut here
####################
# CSV(comma区切りデータ)を 表形式に変換
####################
# csv2tb.icn   Rev.1.2 1997/10/26 windy .cfg変換指定をtableからlistへ変更
# csv2tb.icn   Rev.1.1 1997/08/26 windy .cfg変換指定方式へ変更、名称変更
# csv2tbl.icn  Rev.1.1 1994/11/03 windy 風つかい H.S.
# Usage   : csv2tb [format] input.csv
#           format例 : "s14 s0 n4"
#           command lineの format指定が無い場合は current directoryの
#           csv2tb.cfgにて format指定されているものと見なす。
#             SA=s14 s0 n4
#           指定のやり方 : s14 :文字列 12桁、n4 :数字 4桁。 s0 :その欄は無視
#           変換後のデータは、input.txtというファイルへ出力される。
# This file is in the public domain.
link string_e,  # cn_split
     file_e     # get_inil, change_ext, key_check

procedure main(args)   # argsは command line引数(list)。
                       # 名前は args以外でも良い。
  Usage := (map(f_name()) || " s14 s0 n4 input.csv")
           #↑map()は、デフォルトでは、大文字→小文字変換
  new_ext := "txt"     # 表形式へ変換したデータのファイルの拡張子指定

# 引数チェック
  case *args of {  # *argsは、argsのサイズを示す。ここでは引数の数。
    0 : stop(Usage)# 引数エラー
    1 : {    # 変換指定が command lineに無いので、.cfgを読み込む。
      f_csv := map(args[-1],&lcase,&ucase)      # [-1]は最後の要素を指定
             # ↑英大文字へ変換
      L_cfg := get_inil("CFG") | stop("cannot open .CFG file")
             # ↑定義 file読込み
      form  := cn_split(key_check(L_cfg,f_name(f_csv)))    # テキスト変換指定
             # ↑      #↑ csvファイルの名前の先頭で、cfgファイルのどの指定を
             # |      # 使うか判断する。
             # |data変換指定を listへ変換
    }
    default : {    # ファイル指定以外の引数を formにセット。
      f_csv := args[-1]
      form  := args[1:-1]
    }              # ↑[1:-1]は、最初の要素から最後の要素までの範囲指定
  }
  # open files
  intext  := open(f_csv) | stop("cannot open ",f_csv)
  # 拡張子が "csv" ならば、new_txtへ変換したものを、出力ファイル名とする。
  outtext := open(f_new := change_ext("csv",new_ext,f_csv),"a") |
             stop("file error")
  write(&errout,f_csv," -> ",f_new)        # 動作モニター

# display form data
#  every writes(&errout," ",!form) ; write(&errout)

  # main
  no := 0                                  # モニター用表示の行番号初期値
  while line := read(intext) do {          # ファイルを1行ずつ読み込み、
    write(outtext,csv2tb(line,form))       # form指定に従い変換
    writes(&errout," ",right(no +:= 1,4))  # モニター用表示
  }
  write(&errout,"")                        # カーサー復帰

  # close files (無くても動く)
  close(intext)
  close(outtext)
end


####################
# csvデータ1行変換 procedure
####################
# args : [1]: string csvデータ(1行)、[2]: list 変換指定文字+桁の list、
#        [3]: 桁揃え追加文字
# value: string 表形式に変換された文字列(1行)

procedure csv2tb(line,form,s_fill)
  /s_fill := " " # 指定が無ければ、spaceと見なす。
                 # 原データ中の spaceと桁揃えのために付加する spaceを区別を
                 # する時使用。例えば、データ中の " "を "_"とかに変換する。
  if line[1] == "#" then {       # 行の先頭が "#"ならコメント行
    return line
  }

  l_list := split_csv(line)      # 行データを、","区切りで、listに変換。

  ##################
  # 指定桁合わせ
  ##################
  i := 1     # 欄番号
  s_line := ""                   # 文字列足し込み用の空文字列
  while i <= *form do {          # 変換指定の数分、ループ
    if not (form[i][2:0] == "0") then {  # 0桁指定でなければ
      if form[i][1] == "s"
      # 文字列指定だったら、左詰め
      then s_line ||:= (left(map(string(l_list[i])," ",s_fill),
                        form[i][2:0]) || " ")
      # 数字指定だったら、右詰め
      else s_line ||:= (right(l_list[i],form[i][2:0]) || " ")
    }
    i +:= 1
  }
  return s_line[1:-1]   # 末尾の spaceの  つけ過ぎを削除。
end


####################
# csvデータを listに変換
####################
# args : string csvデータ(1行)
#        文字列データは 両端を \" で囲まれているものとする。
#        文字列中の \"は、\"\"で表わされているものとする。
# value: list 欄データを順に listに詰めたもの
# 備考 : 3状態の状態遷移マシン  state : "init": 初期状態,
#        "string":文字列処理状態,  "number":数字処理状態

procedure split_csv(line)
  state := "init"       # 動作状態管理変数に、初期状態をセット
                        # "string":文字列処理状態, "number":数字処理状態
  L     := []           # 戻り値用 空 list
  line ? {
    repeat {
#      write(&errout,&pos," ",state)
      case state of {
        "init"     : {  # 初期状態
          buf   := ""              # 文字列足し込み用バッファー初期化
          s := move(1) | fail      # 次の1文字を get
          if s == "\""             # stringデータの始め記号なら
          then state := "string"   # 状態 -> 文字列処理
          else {
            state := "number"      # 状態 -> 数字処理
            move(-1)               # &pos戻し
          }
        }
        "number"   : {  # 数字データ処理状態
          put(L,tab(upto(',') | 0)) # 次の ","迄の文字列を list Lに追加
          move(1)      | break     # skip "," または行末でループを抜ける。
          state := "init"          # 状態 -> 初期状態
        }
        "string"   : {  # 文字列データ処理状態
          buf ||:= tab(upto("\"")) # 次の "\""迄の文字列を bufに追加
          move(1)                  # skip \"(必ずあるはず。)
          if (s := move(1))        # 行末チェック
          then {                   # 行末でなければ
            if s == ","            # データ区切り記号
            then {                 # 前の \"は、stringの終わりだった。
              put(L,buf)           # bufの内容を listへ追加
              state := "init"      # 状態 -> 初期状態
            }
            else {                 # 前の \"は、escapeだった。
              buf ||:= s           # bufに足し込み
              state := "string"    # 状態 -> 文字列処理
            }
          }
          else {                   # 行末なのでループを抜ける。
            put(L,buf)             # bufの内容を listへ追加
            break
          }
        }
        default    : stop("state error")  # ここへは、来ないハズ。
      }
    }
  }
  return L

end
-----$ CSV2TB.ICN ( lines:162 words:594 ) ------------------<cut here

  動作は、コメントでお分かりいただけるかと思います。
  link指定は、これまで作った procedureを指定しているのですが、  私の
  libraryに合わせた指定となっています。 お試しの時は、適当に修正をお願い
  します。(手抜きだな〜。汗)

  次回は、表形式データを、CSV形式データに変換する programを作ります。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Sun & Moon/岡本真夜
(icon_357.txt 1997/10/31 PCVAN PIG)

■  Icon > Icon迷い道(8)CSV:CSV2TB                風つかい      目次

  さて、今回は、表形式データを CSVデータへ変換する programです。この program
でも、定義ファイルを使いますが、次のような形式です。
-----^ TB2CSV.CFG ( date:97-10-26 time:21:20 ) -------------<cut here
####################
# 表データ -> csvファイル変換指定ファイル
####################
# 行頭が "#"あるいは行に "="が含まれ無いなら、無視。(コメント)
# 処理対象ファイル名の先頭文字にて、処理指定を識別する。
# ファイル識別文字("="の手前の文字)は、英字大文字。
# 変換指示は、
# s: 文字データ先頭指示、n: 数字データ先頭指示、d: 削除データ先頭指示
####################

# テスト用サンプルデータ
   #なかやまみほ  中山美穂  1970  3  1 O 158  80  60  84  45 東京都小金井
SAM=s            ds        dn   dn dn dsdn  dn  dn  dn  dn  ds           
-----$ TB2CSV.CFG ( lines:13 words:47 ) --------------------<cut here

  上の定義ファイルの場合に、変換指示の文字の位置を検出する必要があります。
ということで、早速その procedureです。 1行の表データ CSVデータへ変換する
programも Test programとして含んでいます。 show_wlは、以前紹介しました
2重 list表示 procedure、replaceは BIPLに含まれる procedureです。
-----^ CP_SPLIT.ICN ( date:97-10-31 time:00:09 ) -----------<cut here
####################
# 表形式データ→CSVデータ変換 programの習作
####################
# cp_split.icn 1997/10/31 windy comment修正
# cp_split.icn 1997/08/25 windy 風つかい H.S.
link view_e,  # show_wl
     strings  # replace

procedure main()
          #0   0 0 00 1  1       2 2   2 3 
          #1   5 7 89 1  5       3 5   9 1
  s1 :=   "地球  E 115256ちきゅうはまるい"
  s2 :=   "s   d sdnn n  s       d s   d "
  write(s1,"\n",s2)
  write(right("",*s1,"1234567890"))
  L  := cp_split(s2)
  show_wl(L)                        # 2重 list 表示

  # csv変換の例
  ss := ""
  every i := 1 to *L do {
    ss ||:= case (LL := L[i])[1] of {
              "s" : { "\"" || replace(s1[LL[2]:LL[3]],"\"","\"\"") || "\"\," }
              "n" : {         s1[LL[2]:LL[3]] || "\,"   }
            # "d" の部分は無視する。
            }
  }
  write(ss[1:-1])
end

####################
# 文字列処理指定の文字列を解析
####################
# 処理指定 英文字1文字
# args : c : cset(処理指定1バイト文字セット) 
#        s : 指定文字列
# value: 2重 list(処理指定を順に詰めたもの)
#        [1]:指定文字, [2]:開始位置, [3]:次の指定文字の開始位置
# 指定例   0   0 0 00 1  1       2 2   2 3
#          1   5 7 89 1  5       3 5   9 1
# s1 :=   "地球  E 115256ちきゅうはまるい"
# s2 :=   "s   d sdnn n  s       d s   d "
# s2を    [["s",1,5],["d",5,7], ... ,["d",29,31]] と変換する。
# 備考 : 表データの整形( csv変換、等)のプログラムのために作成
#        上の例の用に、データ例と並べて指定が可能なプログラムにするため

procedure cp_split(s,c)
  /s  := &subject                   # default
  /c  := &letters                   # 英文字の大文字・小文字のセット
  L   := []                         # 戻り値用 list
  s ? {
    tab(ps := upto(c))              # c迄スキップ
    move(1)                         # その文字をスキップ
    while tab(upto(c)) do {         # 次の c迄スキップし、
      put(L,[s[ps],ps,&pos])        # 文字、開始位置、次の文字の開始位置
                                    # を list に追加
      ps := &pos                    # ps更新
      move(1)                       # その文字をスキップ
    }
    put(L,[s[ps],ps,*s+1])          # 残りの部分を処理
  }
  return L
end
-----$ CP_SPLIT.ICN ( lines:63 words:253 ) -----------------<cut here

  cp_split.exeの実行結果です。
-----^ CP_SPLIT ( date:97-10-31 time:00:11 ) ---------------<cut here
地球  E 115256ちきゅうはまるい
s   d sdnn n  s       d s   d 
123456789012345678901234567890
 s 1 5
 d 5 7
 s 7 8
 d 8 9
 n 9 10
 n 10 12
 n 12 15
 s 15 23
 d 23 25
 s 25 29
 d 29 31

"地球","E",1,15,256,"ちきゅう","まる"
-----$ CP_SPLIT ( lines:16 words:46 ) ----------------------<cut here

  というところで、まとめです。
-----^ TB2CSV.ICN ( date:97-10-26 time:21:16 ) -------------<cut here
####################
# 表形式データを CSV(comma区切りデータ)に変換
####################
# tb2csv.icn   Rev.1.2 1997/10/26 windy .cfg変換指定をtableからlistへ変更
# tb2csv.icn   Rev.1.1 1997/08/26 windy .cfg変換指定方式へ変更、名称変更
# tbl2csv.icn  Rev.1.1 1994/10/30 windy 風つかい H.S.
# Usage   : tb2csv input.txt
#           tb2csv.cfgにて format指定を行う。
   #なかやまみほ  中山美穂  1970  3  1 O 158  80  60  84  45 東京都小金井
#SA=s            ds        dn   dn dn dsdn  dn  dn  dn  dn   s           
#  変換後のデータは、input.csvというファイルへ出力される。
# This file is in the public domain.
link string_e,  # cp_split
     file_e     # get_inil, change_ext, key_check

procedure main(args)   # argsは command line引数(list)。
                       # 名前は args以外でも良い。
  Usage := (map(f_name()) || " input.txt")
           #↑map()は、デフォルトでは、大文字→小文字変換
  new_ext := "csv"     # 表形式へ変換したデータのファイルの拡張子指定

# 引数チェック
  if *args ~= 1 then stop(Usage) # 引数エラー
  f_txt := map(args[1],&lcase,&ucase)
          # ↑英大文字へ変換
  # config file読み込み
  L_cfg := get_inil("CFG") | stop("cannot open .CFG file")
  # テキスト変換指定
  form  := cp_split(key_check(L_cfg,f_name(f_txt)))
         # ↑      #↑ csvファイルの名前の先頭で、cfgファイルのどの指定を
         # |      # 使うか判断する。
         # |data変換指定を listへ変換
  # open files
  intext  := open(f_txt) | stop("cannot open ",f_csv)
  # 拡張子が、"csv"で無ければ、"csv"を変換後のファイル名とする。
  outtext := open(f_new := change_ext("csv",new_ext,f_txt,""),"a") |
             stop("file ext error")                      #↑反転条件
  write(&errout,f_txt," -> ",f_new)        # 動作モニター

# display form data
#  every writes(&errout," ",!form) ; write(&errout)

  # main
  no := 0                                  # モニター用表示の行番号初期値
  while line := read(intext) do {          # ファイルを1行ずつ読み込み、
    write(outtext,tb2csv(line,form))       # form指定に従い変換
    writes(&errout," ",right(no +:= 1,4))  # モニター用表示
  }
  write(&errout,"")                        # カーサー復帰

  # close files (無くても動く)
  close(intext)
  close(outtext)
end


####################
# 表データ -> csvデータ1行変換 procedure
####################
# args : [1]: string 表データ(1行)、[2]: list 変換指定(2重 list)
# value: string csv形式に変換された文字列(1行)

procedure tb2csv(s,L)
  ss := ""
  every i := 1 to *L do {
    ss ||:= case (LL := L[i])[1] of {
              "s" : { "\"" || replace(s[LL[2]:LL[3]],"\"","\"\"") || "\"\," }
              "n" : {                 s[LL[2]:LL[3]]              ||    "\,"}
            # "d" の部分は無視する。
            }
  }
  return ss[1:-1]
end          #↑最後の余分な "\,"を削除
-----$ TB2CSV.ICN ( lines:73 words:275 ) -------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Sun & Moon/岡本真夜
(icon_358.txt 1997/10/31 PCVAN PIG)

■  Icon > ちょっと Icon(1)data整形               風つかい      目次

(niftyserveの FGALTSに「AWK天国/なんだ簡単じゃねえか!」という会議室が
  ありますが、そこで data整形の話題が でました。
  それをネタに FGALTSの「スクリプト天国/何でもかんでも」の会議室で、
  Iconの紹介を したものです。)

  次のような dataを
-----^ TEST03.DAT ( date:97-05-17 time:13:32 ) -------------<cut here
1,相川 七瀬
1,安室 奈美恵
3,大黒 摩季
3,岡本 真夜
3,尾崎 亜美
3,辛島 美登里
7,篠原 ともえ
7,篠原 美也子
7,篠原 涼子
10,竹内 まりあ
10,中島 みゆき
10,中山 美穂
10,中村 あゆみ
10,久松 史奈
10,松任谷 由美
10,森川 美穂
10,山下 久美子
18,遊佐 未森
-----$ TEST03.DAT ( lines:18 words:36 ) --------------------<cut here

  次のように、整形します。 先頭の数字が変わったら改行、1行の dataは、
3つまで、オリジナル dataの先頭の数字は、整形後は先頭にだけ。
-----^ SHAPE01 ( date:97-05-17 time:16:08 ) ----------------<cut here
1,相川 七瀬,安室 奈美恵
3,大黒 摩季,岡本 真夜,尾崎 亜美
3,辛島 美登里
7,篠原 ともえ,篠原 美也子,篠原 涼子
10,竹内 まりあ,中島 みゆき,中山 美穂
10,中村 あゆみ,久松 史奈,松任谷 由美
10,森川 美穂,山下 久美子
18,遊佐 未森
-----$ SHAPE01 ( lines:8 words:26 ) ------------------------<cut here
  という風に、整形するというのが、仕様です。)

  AWK部屋で、1行データを 3個づつまとめる データ整形の話題が、出ました
が、Iconでやったらどんな風になるか、ちょっと、ご覧にいれようと思います。
  まず、AWKのスクリプトは、大体こんな風になります。
-----^ SHAPE01.AWK ( date:97-05-16 time:19:52 ) ------------<cut here
# N個 区切りスクリプト
# shape01.awk Rev.1.2 1997/05/16 windy printf 引数修正
# shape01.awk Rev.1.1 1997/05/14 windy
# Usage: jgawk -f shape01.awk data_file >kekka
# data sample(/line)  :  1,"A"
# This file is in the public domain.

BEGIN{
  FS = "," # 行内の data区切りを ","に変更
  No = 0   # データ種別番号
  n  = 1   # (同一データ種別番号の)データ個数カウンタ
  N  = 3   # 区切り数
}

{
  if($1 != No){                     # data種別 Noが変わったら
    No = $1                         # data種別 No更新
    if(n % N != 1 ){ print ""}      # top dataで無ければ、改行出力
    n  = 1                          # data個数 reset
  }
  if(n % N == 1)   {                # N個 区切りの先頭ならデータ種別 No出力
#    printf($1)                      #
    printf($1 FS $2)                # Rev1.2
  }
#  printf(FS $2)                     #
  printf(FS $3 FS $4)               # Rev1.2
  if(n % N == 0)   { print ""}      # N個 区切り数最後なら、改行出力
  n++                               # data数カウントアップ
}

END{
  if(n % N != 1)   { print ""}      # 最後の行が N個でなければ、改行出力
}
-----$ SHAPE01.AWK ( lines:33 words:147 ) ------------------<cut here

  これを、Iconで書くと、次のようになります。 関数名・演算子記号以外は
殆ど、変わりません。
(programの後ろの方に関数・演算子記号の解説をつけました。)

  尚、AWKでは、command line 引数に file名を 指定すると、自動的に
その fileを オープンして、data fileとして、読み込んでくれます。
  Iconは、自動的には、やりません。  programで fileをオープンします。

  また、AWKでは、行を 自動的に FSで分割して、配列に してくれますが、
Iconは やりませんので、必要なら その処理を行う procedureを作成して
linkする必要が、あります。

  逆に言えば、Iconでは、行をどう料理しようが、programする人の自由です。
-----^ SHAPE01.ICN ( date:97-05-17 time:13:11 ) ------------<cut here
# N個 区切りプログラム
# shape01.icn 1997/05/16 windy
# Usage: shape01 data_file >kekka
# data sample(/line)  :  1,"A"
# shape01.awk を、そのまま、Iconに移し変えたもの。
# This file is in the public domain.
link split6

procedure main(args)
              # ↑command line 引数 (list)
  Usage := "shape01 data_file >kekka"

  # command line 引数チェック(引数が無ければ使用方法表示)
  if *args = 0 then stop(Usage)

  # data fileオープン(エラーならエラー表示)
  dir := open(args[1]) | stop("cannot open ",args[1]) 
             # ↑command line引数の1番目

  fs := '\,'           # 行内の data区切り
  No := 0              # データ種別番号
  n  := 1              # (同一データ種別番号の)データ個数カウンタ
  N  := 3              # 区切り数

  while line := read(dir) do {     # 1行づつ順次読み込んで、
    L := split(line,fs)            # fsにて dataを分割して、listへ
    if numeric(L[1]) ~= No then {  # データ種別 Noが変わったら
      if (n % N) ~= 1 then write() # top dataで無ければ、改行出力
      No := numeric(L[1])          # データ種別 No更新
      n  := 1                      # data個数 reset
    }
    if (n % N) = 1 then writes(No) # N個 区切りの先頭ならデータ種別 No出力
#    if (n % N) = 1 then writes(No,fs,L[2]) # 
    writes(fs,L[2])                # データ出力
#    writes(fs,L[3],fs,L[4])        # データ出力
    if (n % N) = 0 then write()    # N個 区切り数最後なら、改行出力
    n +:= 1                        # data数カウントアップ
  }
  if (n % N) ~= 1 then write()     # 最後の行が N個でなければ、改行出力

end

# 解説
# *args   : argsの size(この場合は、引数の個数)
# stop(s) : 文字列 sを出力して、programを stopする関数
# read()  : text-mode file 読み込み関数
# numeric : 文字→数字変換関数
# =       : 数字の比較
# :=      : 代入
# +:=     : n +:= m は、 n := n +m の略記
# ~       : 否定
# writes  : printf 相当(改行無し出力)
# write   : print  相当(改行付き出力)
# "abc"   : 文字列 abc
# 'xyz'   : 'x' 'y' 'z' を要素とする集合
# L[3]    : L (list)の 3番目の要素
# link    : 他の fileの procedureを linkする指定
-----$ SHAPE01.ICN ( lines:57 words:273 ) ------------------<cut here

  linkする xplit06.icnがあふれましたので、続きは、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Vivien/篠原美也子
(nif0516a.txt 1997/05/16 niftyserve fgalts, 1997/05/17 PCVAN SLABO)

■  Icon > ちょっと Icon(2)data整形               風つかい      目次

  1行データを 3個づつまとめる データ整形 の お話しの続きです。
  前回の programで使っている 文字列分割の procedureです。

-----^ SPLIT6.ICN ( date:97-05-17 time:13:09 ) -------------<cut here
# 文字列分割→list格納 procedure
# split6.icn Rev.1.3 1997/05/17 windy comment修正
# split6.icn Rev.1.1 1997/05/14 windy
# icont -c split6.icn とすると、split6.u1,split6.u2という中間言語 fileが
# できる。この形にしておくと、他の procedureから linkできる。
# Usage: L := split(line,c)
# This file is in the public domain.
# Icon入門講座(5)あたりに詳しい説明があります。

# arg      : [1]:文字列, [2]:文字(集合)
# value    : list
procedure split(line,c)
  /c := ' \t'                  # 引数に cがセットして無ければ、spaceか tab
  list := []                   # 出力 data足しこみ用 空 list
  line ? {                     # lineを、走査対象として
    # ↓くり返し
    while tab(upto(~c)) do     # c以外の文字へ 走査位置を移動

      put(list,tab(many(~c)))  # c以外の文字以外の文字(すなわち c)まで
  }                            # 走査位置を移動。  移動した間の文字列を
                               # listへ格納
  return list
end

# 解説
# /c      : c が null(未定義)ならば
# 'ab'    : 文字 aと、文字 b を要素とする集合
# while ... do : ...を繰り返す。
# tab(n)  : nの位置まで、走査位置を移動。この関数の値は、移動した部分の
#          文字列となる。
# upto(c) : 走査対象の文字列 の中で、現在の走査位置以降で、文字集合 cの
#           中の いずれかの文字が 現れる位置。 位置が複数ある場合は、順
#           次その位置を見つける。(すなわち、generator)
# many(c) : 現在の走査位置以降で、文字集合 cに含まれる文字 以外の文字が
#           現れる位置
# put(L,x): L(list)の末尾に xを追加する。
-----$ SPLIT6.ICN ( lines:36 words:144 ) -------------------<cut here

  細かく解説しますと、Icon入門講座に書いた内容を、全部説明しないと、
いけなくなります。 program中の commentで、ご想像を お願いします。

  しかし AWKと同じ機能だけでは、面白く無いので、次回は、少しいじって
みましょう。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Vivien/篠原美也子
(nif0516b.txt 1997/05/16 niftyserve fgalts, 1997/05/17 PCVAN SLABO)

■  Icon > ちょっと Icon(3)data整形               風つかい      目次

  1行データを 3個づつまとめる データ整形 の お話しの続きです。
  前の programに Iconの機能を、多少ちりばめてみます。 でも、同じ機能の
  programですから、動いた結果は同じです。(汗)

  ・読み込んだ dataの各行の分割のところで、最初の ","で、行データを分割す
    るプログラムにします。

  ・行データを、table(AWKの連想配列)に格納します。
   (格納する必要は 無いのですが、tableのサンプルとして。)
    そうしますと、AWKの連想配列と同じく、取り出すときに、格納した順番とは
    なりません。 そこで、tableに格納した dataを keyで sortして出力します。
    tableは sortすると、listになります。( dataに順番を与えるには、listに
    しないといけないので、Iconの言語仕様が そうなっています。)

  ・出力処理で、Iconでは、せっかく case構文が、サポートされています
    ので、使ってみます。  多少、動作が分かりやすくなると思います。

  ・整形結果を 出力した後に、使った tableと listの構造が どうなってい
    るかを、x2tという procedureを使って書き出します。(これは、参考用
    です。本来の動作とは関係ありません。)

    x2tを説明しますと、 Icon入門講座1〜3全部を、説明しないといけなく
    なりますので、まあ そういう機能の procedureだと、 ここでは、考えて
    下さい。(Icon入門講座3(19)の x2tree03 にミス修正(汗)と機能
    アップ(tableの場合 valueだけでなく keyも出力するように) したもの
    です。)

-----^ SHAPE02.ICN ( date:97-05-17 time:10:17 ) ------------<cut here
# N個 区切り program
# shape02.icn Rev.1.2 1997/05/17 windy comment修正
# shape02.icn Rev.1.1 1997/05/16 windy
# Usage: shape02 data_file >kekka
# data sample(/line)  :  1,"A"
# This file is in the public domain.
link x2tree06
procedure main(args)
  Usage := "shape02 data_file >kekka"
  if *args = 0 then stop(Usage)
  dir := open(args[1]) | stop("cannot open ",args[1]) 

  fs := '\,'           # 行内の data区切り
  N  := 3              # 区切り数
  T1 := table()        # tableを生成(初期値 無し)

  while line := read(dir) do {  # 1行づつ順次読み込んで、
    line ? {                    # lineを走査対象として
      ps := upto(fs)            # ps : lineの中で、最初に fsが見つかった位置
      n  := numeric(line[1:ps]) # lineの psより前の部分を数字変換
      s  := line[ps+1:0]        # lineの psより後の部分
      /T1[n] := []              # table T1の keyに、nが無ければ、nを key
                                # として valueに [] (空 list)を 登録
      put(T1[n],s)              # tableの key n の value (list)に sを追加
    }
  }

  L1 := sort(T1,1)               # T1 を keyで sortし、 listへ変換

  write("整形結果")
  every L2 := !L1 do {           # L1から、要素(list) を順次取り出して
    No := L2[1]                  # 1番目の要素(数字)を Noに代入
    n := 0                       # 同じ Noの要素のカウンタ
    every s := !L2[2] do {       # 2番目の要素(list) から要素(文字列)を
                                 # 順次取り出して
      n +:= 1                    # 同じ Noの要素のカウンタ +1
      case (n % N) of {          # nを Nで割った余りによって
        1       : { writes(No)       # No出力
                    writes(fs,s) }   # データ出力
        2       :   writes(fs,s)
        0       : { writes(fs,s)
                    write()     }    # 改行出力
        default : stop("case error") # それ以外だったら
      }
    }
    if (n % N) ~= 0 then write() # 最後の出力行の要素数が、N以外だったら
  }                              # 改行出力

  # 動作参考用
  write("\nT1 (table) 構\造")  # "構" は "\x8d5c" なので、"\x5c"を補う。
  every write(x2t(T1))         # x2tは 構造体の内容を tree表示する procedure
                               # x2tree06.icnに含まれる。
  write("\nL1 (list)  構\造") 
  every write(x2t(L1))

end

# 解説
# /T1[n]  : T1[n]の null (未定義) check
# table   : table(AWKの連想配列)を生成     ()内には、初期値を指定できる
# every ... !L : 構造体 Lの要素を順次取り出して
-----$ SHAPE02.ICN ( lines:61 words:277 ) ------------------<cut here

  動かした時の結果です。
-----^ SHAPE02 ( date:97-05-17 time:18:12 ) ----------------<cut here
整形結果
1,相川 七瀬,安室 奈美恵
3,大黒 摩季,岡本 真夜,尾崎 亜美
3,辛島 美登里
7,篠原 ともえ,篠原 美也子,篠原 涼子
10,竹内 まりあ,中島 みゆき,中山 美穂
10,中村 あゆみ,久松 史奈,松任谷 由美
10,森川 美穂,山下 久美子
18,遊佐 未森

T1 (table) 構造
<table 1>
  + <list 6> <- integer18
  |   + string "遊佐 未森"
  + <list 5> <- integer10
  |   + string "竹内 まりあ"
  |   + string "中島 みゆき"
  |   + string "中山 美穂"
  |   + string "中村 あゆみ"
  |   + string "久松 史奈"
  |   + string "松任谷 由美"
  |   + string "森川 美穂"
  |   + string "山下 久美子"
  + <list 4> <- integer7
  |   + string "篠原 ともえ"
  |   + string "篠原 美也子"
  |   + string "篠原 涼子"
  + <list 2> <- integer1
  |   + string "相川 七瀬"
  |   + string "安室 奈美恵"
  + <list 3> <- integer3
      + string "大黒 摩季"
      + string "岡本 真夜"
      + string "尾崎 亜美"
      + string "辛島 美登里"

L1 (list)  構造
<list 7>
  + <list 9>
  |   + integer1
  |   + <list 2>
  |       + string "相川 七瀬"
  |       + string "安室 奈美恵"
  + <list 8>
  |   + integer3
  |   + <list 3>
  |       + string "大黒 摩季"
  |       + string "岡本 真夜"
  |       + string "尾崎 亜美"
  |       + string "辛島 美登里"
  + <list 10>
  |   + integer7
  |   + <list 4>
  |       + string "篠原 ともえ"
  |       + string "篠原 美也子"
  |       + string "篠原 涼子"
  + <list 11>
  |   + integer10
  |   + <list 5>
  |       + string "竹内 まりあ"
  |       + string "中島 みゆき"
  |       + string "中山 美穂"
  |       + string "中村 あゆみ"
  |       + string "久松 史奈"
  |       + string "松任谷 由美"
  |       + string "森川 美穂"
  |       + string "山下 久美子"
  + <list 12>
      + integer18
      + <list 6>
          + string "遊佐 未森"
-----$ SHAPE02 ( lines:71 words:285 ) ----------------------<cut here

  次回、もう少し、いじってみます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Vivien/篠原美也子
(nif0516b.txt 1997/05/16 niftyserve fgalts, 1997/05/17 PCVAN SLABO)

■  Icon > ちょっと Icon(4)data整形               風つかい      目次

  相変わらず、1行データを 3個づつまとめる データ整形 の お話しの
  続きです。

  前回の programの出力部分に generatorを使ってみます。 generatorと
  いうのは、procedureで、複数の結果を、順次返す機能 を、持っている
  ものを言います。

  でも、全体は、同じ 機能の programですから、 動いた結果も、相変わ
  らず 同じです。(笑)

-----^ SHAPE03.ICN ( date:97-05-17 time:10:46 ) ------------<cut here
# N個 区切り program
# shape03.icn Rev.1.3 1997/05/17 windy comment修正
# shape03.icn Rev.1.1 1997/05/15 windy
# Usage: shape03 data_file >kekka
# data sample(/line)  :  "1","A"
# This file is in the public domain.
link retrieve

procedure main(args)
  Usage := "shape03 data_file >kekka"
  if *args = 0 then stop(Usage)    # command line 引数 check
  dir := open(args[1]) | stop("cannot open ",args[1])  # file open

  # 初期設定
  fs := '\,'           # 行内の data区切り
  N  := 3              # 区切り数
  T1 := table()        # 空の tableを生成

  # data fileを読み込み tableに格納 (tableは AWKの連想配列と同じ)
  while line := read(dir) do {     # 1行づつ順次読み込んで、
    line ? {                       # 読み込んだ 行を 走査対象として
      ps := upto(fs)               # 最初の fsの位置を得る
      n  := numeric(line[1:ps])    # fsより前が n (numeric :文字→数字変換)
      s  := line[ps+1:0]           # fsより後が s 
      /T1[n] := []                 # T1に nが keyとして存在しないなら
                                   # T1に nを keyとして、空 listを登録
      put(T1[n],s)                 # tableの key n の value (list)に sを追加
    }
  }

  L1 := sort(T1,1)                 # T1を keyで sort(結果は listの list)

  write("整形結果")
  every L2 := !L1 do {             # L1の要素を 順次取り出して
    No := L2[1]                    # data種別 No
    every L3 := retrieve(L2[2],3) do { # L2[2]の要素を 3個づつ取り出す。
      writes(No)                   # data種別 No を出力
      every writes(fs,!L3)         # L3の要素を 順次出力
      write()
    }
  }

end
-----$ SHAPE03.ICN ( lines:43 words:194 ) ------------------<cut here

  generatorです。 shape03.icnから、3個区切りでデータを返す指定で
呼ばれています。

-----^ RETRIEVE.ICN ( date:97-05-17 time:10:48 ) -----------<cut here
# x(list または string)の要素を n個区切りにして、部分 list(またはstring)
# を、順次返す generator
# 元の listは保存
# Usage: every XX := retrieve(X) do {...}
# retrieve.icn Rev.1.2 1997/05/17 windy comment修正
# retrieve.icn Rev.1.1 1997/05/16 windy
# This file is in the public domain.
# link retr  # test用

procedure retrieve(X,n)
  /n := 1                       # default

  every m := 1 to *X by n do {  # mを 1から n飛びで 順次増加させて
    suspend \X[m+:n]            # listの m番目の要素から n個要素が
                                # 存在すれば それを値として返す。
  }
  suspend X[(*X -n+1) < \m :0]  # n個区切りで、余った要素を返す。
end

# 解説
# *X       : Xの size(要素数または長さ)
# /n       : /は nが null(指定が無い時)の check。   存在すればその値を持つ。
# X[m+:n]  : list(または string)の mの位置から n個分の部分。
# \X[m+:n] : \は X[m+:n]が、存在すればという check。存在すればその値を持つ。
#            \mも同様に mの値が存在すれば、その値を持つ。
# suspend  : 複数の値を返す return
# a < b    : 数字比較 a < b が成立すれば、bを値として持つ。
-----$ RETRIEVE.ICN ( lines:27 words:131 ) -----------------<cut here

  programだけで、余り説明の無い 書きこみでしたが、

    ・なかなか 変わった programだから、一度動かしてみよう。  とか
    ・機能が 色々ありそうだから、試してみよう。              とか

  お考えの方が いらっしゃると うれしいです。

  おまけに、retrieve.icnの test programを付けておきます。
-----^ RETR.ICN ( date:97-05-17 time:19:23 ) ---------------<cut here
# retrieve.icnの test procedure
# retr.icn Rev.1.3 1997/05/17 windy comment修正, test case 追加
# retr.icn Rev.1.2 1997/05/16 windy stringの testc ase追加
# retr.icn Rev.1.1 1997/05/16 windy
# test時は、retrieve.icnが、この procedureを linkする。
# This file is in the public domain.
link show_l

procedure main()
  # test data
  L0 := []
  L1 := ["A1"]
  L2 := ["A2","B2"]
  L3 := ["A3","B3","C3"]
  L4 := ["A4","B4","C4","D4"]
  L5 := ["A5","B5","C5","D5","E5"]
  L6 := ["A6","B6","C6","D6","E6","F6"]

  # test
  every L := retrieve(L0,2) do show_sl(L) ; write()
  every L := retrieve(L1,2) do show_sl(L) ; write()
  every L := retrieve(L2,2) do show_sl(L) ; write()
  every L := retrieve(L3,2) do show_sl(L) ; write()
  every L := retrieve(L4,2) do show_sl(L) ; write()
  every L := retrieve(L5,2) do show_sl(L) ; write()
  every L := retrieve(L6,2) do show_sl(L) ; write()

  # test case 追加 Rev.1.2
  s0 := ""
  s1 := "A"
  s2 := "AB"
  s3 := "ABC"
  s4 := "ABCD"
  s5 := "ABCDE"
  s6 := "ABCDEF"

  every writes(" ",retrieve(s0,2)) ; write()
  every writes(" ",retrieve(s1,2)) ; write()
  every writes(" ",retrieve(s2,2)) ; write()
  every writes(" ",retrieve(s3,2)) ; write()
  every writes(" ",retrieve(s4,2)) ; write()
  every writes(" ",retrieve(s5,2)) ; write()
  every writes(" ",retrieve(s6,2)) ; write()        # Rev.1.3 追加

end
-----$ RETR.ICN ( lines:45 words:189 ) ---------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Vivien/篠原美也子
(nif0516c.txt 1997/05/16 niftyserve fgalts, 1997/05/17 PCVAN SLABO)

■  Icon > Icon回り道(1)重複しないランダムな 10個の数    風つかい      目次

(PCVANの SLABOで、乱数の話題がでていました。Iconで乱数をつかったこと
 がありませんでしたので、話題に相乗りして Iconでもやってみました。
  テーマは、3桁の重複しない乱数を得る、というものです。)

  ということで、私も Iconの乱数機能を 使ったことが、ありませんでした
ので、どういう programになるか やってみました。。

  Iconでは、?10 と書きますと、1〜10迄の乱数を発生できます。 正確には
乱数列の最初の数字を得ることができます。
  同じ program内で、次にこの式 (?10) を 実行すると、乱数列の2番目の
数字が得られます。
  ちなみ、文字列では、?"ABCDEFG" と書くと "ABCDEFG"から randomに1文
字(1-byte character)取り出せます。

  Iconでは、この乱数列は programを何度実行しても同じ乱数列となります。
違う乱数列を得るためには、keywordの &randomを変えると可能だそうです。
  1 〜 n までの randomな数 を m個 発生させる programは次のようになり
ます。

-----^ RANDOM01.ICN ( date:97-05-30 time:23:22 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# random01.icn 1997/05/30 windy Kazetsukai H.S.
# This file is in the public domain.

procedure main(args)                 
  Usage := "random01 最大値 発生数"

  # command line引数を 数字に変換して、n(最大値),m(生成数)にセット。
  # 数字に変換できなければ、Usageを表示して stop
  {(n := numeric(args[1])) & (m := numeric(args[2]))} | stop(Usage)
                                                      #↑前の 2項のどちらか
                                                      # 失敗したとき
  every writes(" ",rand(n) \m)
                         # ↑generatorの生成数限定
  write()
end

# 1 〜 n迄の数を生成する generator(順次、値を発生する procedure)
procedure rand(n)
  repeat    { suspend  ?n }
  #↑くり返し #↑     #↑ ?nは、1 〜 nの random数を生成
end           #suspendは、generatorの場合に使う return
-----$ RANDOM01.ICN ( lines:22 words:82 ) ------------------<cut here


  random01 999 10 とした時の結果です。 何度実行しても同じ数列が出てきます。
(そういう仕様です。)
-----^ RANDOM01 ( date:97-05-31 time:13:07 ) ---------------<cut here
 212 413 316 510 422 306 80 737 51 717
-----$ RANDOM01 ( lines:1 words:10 ) -----------------------<cut here


  生成される数に最少数を設ける には、生成した数がその最少制限数より小さ
ければ無視する というやり方が あります。  そのやり方でやりますと、

-----^ RANDOM02.ICN ( date:97-05-31 time:13:12 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ★ l 以上の値のものだけという制限付き
# random02.icn 1997/05/31 windy Kazetsukai H.S.
# This file is in the public domain.

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (l := numeric(args[3])) } | stop(Usage)
                            #↑前の 3項の いずれかが 失敗したとき

  every writes(" ",(l <= rand(n)) \m)
                   #↑ a < b は、b が aより大きければ bの値、さもなくば失敗
  write()
end

procedure rand(n)
  repeat { suspend ?n }
end
-----$ RANDOM02.ICN ( lines:20 words:78 ) ------------------<cut here


  random02 999 10 100とした時の結果です。  random01 999 10 100の結果
から、100未満の数字を除いた数列になっています。

-----^ RANDOM02 ( date:97-05-31 time:13:13 ) ---------------<cut here
 212 413 316 510 422 306 737 717 138 336
-----$ RANDOM02 ( lines:1 words:10 ) -----------------------<cut here


  生成する数の最少値制限の別のやり方です。  制限の値だけ最大値を小さい
範囲で生成しておいて、後で制限の値を足すやり方です。

-----^ RANDOM03.ICN ( date:97-05-31 time:13:14 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ★ 最小値 l の制限の仕方を、ちょっと変更
# random03.icn 1997/05/31 windy Kazetsukai H.S.
# This file is in the public domain.

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (l := numeric(args[3])) } | stop(Usage)

  every writes(" ", rand(n,l) \m)
  write()
end

# 最少値の値だけ、小さな範囲の乱数列を発生させて、後で最小値を足す。
procedure rand(n,l)
  repeat { suspend  ?(n-l+1) +l-1 }
end
-----$ RANDOM03.ICN ( lines:19 words:69 ) ------------------<cut here


  random03 999 10 100とした時の結果です。 

-----^ RANDOM03 ( date:97-05-31 time:13:14 ) ---------------<cut here
 290 471 384 559 479 375 171 763 145 745
-----$ RANDOM03 ( lines:1 words:10 ) -----------------------<cut here

  ちょっと、長くなりましたので、続きは次へ。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(pcv0531a.txt 1997/05/31 PCVAN SLABO)

■  Icon > Icon回り道(2)重複しないランダムな 10個の数    風つかい      目次

  続きです。 乱数列 program実行の度に、同じ乱数列が出てくるのでは、まずい
ときには、乱数の種を 乱数にする procedureが BIPL(Icon基本 library)に 有り
ますので、それを linkして、乱数列発生の前に実行します。

-----^ RANDOM04.ICN ( date:97-05-31 time:14:41 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ☆ l 以上の値のものだけ という制限付き。
# ★ 発生する数を 実行する度に 変える。
# random04.icn 1997/05/31 windy Kazetsukai H.S.
# This file is in the public domain.
link random  # BIPLの random.icnを link。randomizeを使用

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (l := numeric(args[3])) } | stop(Usage)

  randomize()     # ←乱数の種を変える。

  every writes(" ",(l <= rand(n)) \m)
  write()
end

procedure rand(n)
  repeat { suspend ?n }
end
-----$ RANDOM04.ICN ( lines:22 words:81 ) ------------------<cut here


  random04 999 10 100 >> random04 を3回実行した時の結果です。
-----^ RANDOM04 ( date:97-05-31 time:14:42 ) ---------------<cut here
 915 779 671 354 132 841 951 141 188 431
 991 377 762 412 594 935 972 385 197 257
 719 544 516 449 344 185 504 279 790 634
-----$ RANDOM04 ( lines:3 words:30 ) -----------------------<cut here


  おっと、重複しない数という条件もありましたね。
すると 生成した数を覚えておいて、同じ数が出てきたら無視するという処理が
必要になります。
  構造体の set (集合)に、生成した順に登録していくやり方を使いますと
次のようになります。

-----^ RANDOM05.ICN ( date:97-05-31 time:13:19 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ☆ l 以上の値のものだけ という制限付き。
# ☆ 発生する数を 実行する度に 変える。
# ★ 重複を避ける。
# random05.icn 1997/05/31 windy Kazetsukai H.S.
# This file is in the public domain.
link random  # BIPLの random.icnを link。randomizeを使用

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (l := numeric(args[3])) } | stop(Usage)

  randomize()     # ←乱数の種を変える。

  every writes(" ", uniq_rand(n,l) \m)
  write()
end

# 重複を避ける procedure
procedure uniq_rand(n,l)
  static S
  S := set()
  every nn := rand(n,l) do {
    if not member(S,nn) then {
      insert(S,nn)
      suspend nn
    }
  }
end

procedure rand(n,l)
  suspend  |(?(n-l+1) +l-1)
         #↑ |は、式の前に付くと、くり返し generatorとなる。
end
-----$ RANDOM05.ICN ( lines:36 words:111 ) -----------------<cut here
  乱数列の発生のためのくり返し実行の部分も気分で変えています。
  repeatの代わりに | という表現を使ってみました。
  これは数列・文字列のくり返し発生を指定する式になります。| と数列・文字列
を指定する式の間は空けてはいけません。
 | と次の式の間を空けると、 programの前の方の  | stop(Usage) のように
alternation(左側の式が失敗すると右側の式を実行)になってしまいます。


  random05 999 10 100 としたときの結果です。
-----^ RANDOM05 ( date:97-05-31 time:13:18 ) ---------------<cut here
 439 469 993 330 931 528 935 653 196 586
-----$ RANDOM05 ( lines:1 words:10 ) -----------------------<cut here


  あっ、数字を小さい順に出さないといけないんでしたね。
すると sortが必要になります。 前の programで setに数字を登録しましたので、
それを sortして出力します。   setへの登録は、既に前に setに登録されていて
も無視されます(上書きなのか、登録されないのか分かりません)ので、その
チェックは外しました。

-----^ RANDOM06.ICN ( date:97-05-31 time:01:28 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ☆ l 以上の値のものだけ という制限付き。
# ☆ 発生する数を 実行する度に 変える。
# ☆ 重複を避ける。
# ★ sortして出力
# random06.icn 1997/05/31 windy Kazetsukai H.S.
# This file is in the public domain.
link random  # BIPLの random.icnを link。randomizeを使用

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (l := numeric(args[3])) } | stop(Usage)

  randomize()     # ←乱数の種を変える。

  every writes(" ", uniq_rand(n,m,l))
  write()
end

# 重複を避ける procedure
procedure uniq_rand(n,m,l)
  static S
  S := set()
  while *S < m do insert(S,rand(n,l))
  every suspend !sort(S)
end

procedure rand(n,l)
  suspend  |(?(n-l+1) +l-1)
end
-----$ RANDOM06.ICN ( lines:32 words:103 ) -----------------<cut here

  random06 999 10 100 としたときの結果です。

-----^ RANDOM06 ( date:97-05-31 time:13:20 ) ---------------<cut here
 241 292 388 400 495 711 896 904 937 969
-----$ RANDOM06 ( lines:1 words:10 ) -----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(pcv0531b.txt 1997/05/31 PCVAN SLABO)

■  Icon > Icon回り道(3)重複しないランダムな 10個の数    風つかい      目次

  3桁の数字という条件で、そのものズバリ 文字数が3桁 というやり方を書き落と
しました。そういう条件の場合は、次のようになります。

-----^ RANDOM07.ICN ( date:97-06-01 time:23:49 ) -----------<cut here
# Iconで 1 〜 n までの randomな数 を m個 発生させるテスト
# ★ d桁の数だけという制限付き
# random07.icn 1997/06/01 windy Kazetsukai H.S.
# This file is in the public domain.

procedure main(args)                 
  Usage := "random01 最大値 発生数 最小値"

  {(n := numeric(args[1])) & (m := numeric(args[2])) &
   (d := numeric(args[3])) } | stop(Usage)
                            #↑前の 3項の いずれかが 失敗したとき

  every writes(" ", 1(nn := rand(n), *nn = d) \m)
                #  ↑                ↑ *は、桁数(文字数)を表わす。
  write()       #  |2つの式のうち1番目の式の値を値とする指定。
end

procedure rand(n)
  repeat { suspend ?n }
end
-----$ RANDOM07.ICN ( lines:20 words:79 ) ------------------<cut here

  rndom07 999 10 2 とした場合の結果です。
-----^ RANDOM07.2 ( date:97-06-01 time:23:50 ) -------------<cut here
 80 51 12 88 29 33 53 32 75 64
-----$ RANDOM07.2 ( lines:1 words:10 ) ---------------------<cut here

  rndom07 999 10 3 とすれば、こうなります。
-----^ RANDOM07.3 ( date:97-06-01 time:23:50 ) -------------<cut here
 212 413 316 510 422 306 737 717 138 336
-----$ RANDOM07.3 ( lines:1 words:10 ) ---------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: そのままの君でいて/岡本真夜
(pcv0601a.txt 1997/06/01 PCVAN SLABO)

■  Icon > Icon回り道(4)Usageが...                    風つかい      目次

  あれれ、random02.icnから random07.icnまで、全部 Usageのファイル名が
random01のままですね。あはは。よくやります。

  人手で修正するので、漏れがでますので、プログラム自身で作らせようと
こんな procedureを作ってみました。

  Iconには、プログラム名称を示す keywordがあります。 &prognameです。
&prognameには、ディレクトリー付きのファイル名が入ります。
  Usageでは、ディレクトリーと拡張子は、通常 不要ですので、それを削除
して使います。

  top_cut()という procedureで、ディレクトリーを削除して、
  top_get()という procedureで、拡張子を除いています。
(参考に &prognameそのものも表示するようにしています。)

-----^ EXE_NAME.ICN ( date:97-06-02 time:19:06 ) -----------<cut here
# Usageの file名訂正漏れを 防ぐための file名生成 procedure
# exe_name.icn 1997/06/02 windy Kazetsukai H.S.
# This file is in the public domain.

procedure exe_name()
  write(&progname)                           # test用
  return top_get('.',top_cut('\\',&progname))
end

####################
# 文字列の 先頭から特定文字までの部分 を取り去る。最長部分を取り去る。
####################
# arg   : cset
# value : string
# Usage : top_cut(c,s)
procedure top_cut(c,s)
  /s := &subject                         # sの指定がなければ &subject
  /c := ' \t'                            # cの指定がなければ spaceか tab
  s ? {                                  # sを走査対象とする。
    while tab(upto(c)) do tab(many(c))   # cが見つかる限り、走査位置を
                                         # その文字の後に移動。
    return tab(0)                        # 残りの文字列を返す。
  }
end


####################
# 文字列の 先頭から特定文字までの部分 を得る。最短部分を得る。
####################
# arg   : cset
# value : string
# Usage : top_get(c,s)
procedure top_get(c,s)
  /s := &subject                         # sの指定がなければ &subject
  /c := ' \t'                            # cの指定がなければ spaceか tab
  s ? {                                  # sを走査対象とする。
    return tab(upto(c) | 0)              # cまで走査位置を移動しその間の
  }                                      # 文字列を返す。cがみつからなけ
                                         # れば、末尾まで返す。
end
-----$ EXE_NAME.ICN ( lines:40 words:132 ) -----------------<cut here


  使用サンプルです。 Usageを表示するだけのプログラムです。

-----^ NAME01.ICN ( date:97-06-02 time:01:46 ) -------------<cut here
# Usageの file名の訂正漏れを防ぐための file名生成 procedure
# name01.icn 1997/06/02 windy Kazetsukai H.S.
# This file is in the public domain.
link exe_name

procedure main(args)                 
  Usage := exe_name() || " なんたらかんたら どうたらこうたら"
  write(Usage)
end
-----$ NAME01.ICN ( lines:9 words:32 ) ---------------------<cut here


  結果はこうなります。1行目は、&prognameを示しています。

-----^ NAME01 ( date:97-06-02 time:19:08 ) -----------------<cut here
D:\ICON\LEC35\NAME01.EXE
NAME01 なんたらかんたら どうたらこうたら
-----$ NAME01 ( lines:2 words:4 ) --------------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: そのままの君でいて/岡本真夜
(pcv0601b.txt 1997/06/01 PCVAN SLABO)

■  Icon > Icon回り道(5)a < b が値をもつ                 風つかい      目次

(Iconでは、比較式は成功すると、右辺の値を取りますが、その説明を PCVANの
  SLABOの会議室で ちょっと説明しましたので、参考になるかと。)

  一般的に、比較式は、成立すれば、右辺の値を持ちます。
    例えば、
         3 < 5   の値は、  5  です。
      "A" << "B" の値は、 "B" です。

  ですから、
         write(3 < 5)      は、"5" を出力しますし、
         write("A" << "B") は、"B" を出力します。

  ( < は数字の比較。<< は文字列の比較です。 write()は、数字の場合は
     文字に変換して出力します。)

  実際には、右辺を変数にして、変数が比較条件に一致すれば出力する
というような表現に使います。

  Iconでは、比較式に限らず、全ての式が値を持ちます。 そこで、
         write(if n < m then "NNN" else "MMM")

  というような表現もできます。これは、
         if n < m then write("NNN") else write("MMM")

  と同じことになります。じゃあ、この式の値はどうなるかというと、
  write()は引数と同じ値を持ちますので、出力文字と同じ値になります。

         write(if n < m then write("NNN") else write("MMM"))
  は、同じ文字を2度出力します。

  さて、条件が成立しない場合ですが、その場合はその式は【失敗】します。
【失敗する】というのは、その式が無いのと同じということになります。
  値としては nullとなります。というか、値が無いという言い方が良いかも
しれません。

  Iconの関数は、nullが引数ですと、通常は、その関数自体が失敗します。
  この仕様のために、表現を非常にコンパクトにできることも多いです。

  動作サンプルを次ぎに。
-----^ A_B.ICN ( date:97-06-06 time:20:17 ) ----------------<cut here
# This file is public domain.
# 式の値のサンプル
procedure main()
  write(3 < 5)
  wriet(3 > 5)               # この式は失敗します。
  write("A" << "B")
  n := 3
  m := 5
  write(if n < m then "NNN" else "MMM")
  if n < m then write("NNNN") else write("MMMM")
  write(if n < m then write("NNNNN") else write("MMMMM"))
end
-----$ A_B.ICN ( lines:12 words:52 ) -----------------------<cut here

  command lineから a_b > a_b とした時の結果です。
-----^ A_B ( date:97-06-06 time:20:17 ) --------------------<cut here
5
B
NNN
NNNN
NNNNN
NNNNN
-----$ A_B ( lines:6 words:6 ) -----------------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 河よりも長くゆるやかに/篠原美也子
(pcv0606a.txt 1997/06/06 PCVAN SLABO)

■  Icon > ちょっと Icon(5)Wicon beta8                   風つかい      目次

  Iconの WindowsNT/95対応版を近ごろいじっています。 日本語は未だ画面に
うまく出せないのですが、ちょっとご紹介します。

  Iconは、Arizona大学の Griswold教授(のグループ)が開発していますが、
WindowsNT/95対応の Icon(Wicon)は、Arizona大学にいて、その後 Texas大学
San Antonio校(UTSA)に移った Jeffery教授(のグループ)が開発しています。

  現在は、beta版で 8版になっています。  次の所から入手できます。
<UTSA>
ftp://ringer.cs.utsa.edu/pub/icon/nt/graphics/
Index of /pub/icon/nt/graphics/
    Name            Last modified     Size 
    docs.zip        26-Feb-97 16:47    38K 
    gprocs.zip      26-Feb-97 01:43   501K 
    iconhelp.zip    05-Mar-97 12:53   145K 
    keysyms.icn     08-Feb-96 00:00     3K 
    procs.zip       26-Feb-97 01:43   339K 
    READ.ME         06-Mar-97 00:53     4K 
    vdefns.icn      17-Jun-97 01:53     1K 
    vib.zip         26-Feb-97 02:31   122K 
    vibsrc.zip      26-Feb-97 01:43   261K 
    wi.bat          06-Mar-97 00:50   209K 
    wi.icn          06-Mar-97 00:50    14K 
    wi.zip          06-Mar-97 00:52    54K 
    wicon.zip       06-Mar-97 01:26   339K 

<Arizona>
ftp://ftp.cs.arizona.edu/icon/beta/windows
Index of /icon/beta/windows
    Name            Last modified     Size 
    docs.zip        06-Mar-97 20:12    38K 
    gprocs.zip      06-Mar-97 20:12   501K 
    iconhelp.zip    06-Mar-97 20:13   145K 
    keysyms.icn     06-Mar-97 20:23     3K 
    procs.zip       06-Mar-97 20:16   339K 
    READ.ME         06-Mar-97 20:21     4K 
    vib.zip         06-Mar-97 20:18   122K 
    vibsrc.zip      06-Mar-97 20:18   261K 
    wi.icn          06-Mar-97 20:23    14K 
    wi.zip          06-Mar-97 20:19    54K 
    wicon.zip       06-Mar-97 20:20   339K 

  UTSAが originalで、後で Arizona大学へも登録されたみたいです。

  MS-DOS版の Iconは、特に日本語対応版というのはありませんが、文字列
を 1byte単位で、走査・加工する機能が備わっていますので、日本語対応は
特に、Icon処理系をいじらなくても、Icon Programmer側で処理できます。

  Windows版も、日本語文字が画面に出せさえすれば、後は programmer側と
しては不便は無いと思って、なんとか日本語が表示できないかと色々試して
います。

  Windows版の Iconは、起動した状態で、2つの Windowが開きます。
1つは、editor-windowで、もう1つは console-windowです。

  ・editor-windowでは、日本語入力は、問題ありません。表示もOKだし
    保存して再度読みだしても大丈夫です。
    行末のCRLFが、CRCRLFになるようですが、動作は問題ありません。

  ・console-windowは、標準出力を表示する windowですが、日本語を出力
    すると化けます。

  ・programで、windowが開けます。開いた windowには、フォント指定が
    できます。  日本語のフォント指定も有効なものがあります。
    FixedSys と System は指定すると有効みたいです。
    しかし、特定コードを含む文字はうまく表示できません。

    Shift-JISコードを出力する次のような programを作って試してみました。
-----^ JCHAR02W.ICN ( date:97-07-05 time:21:53 ) -----------<cut here
# Show Japapense characters(Shift-JIS, output each character)
# This file is in the public domain.
# jchar02w.icn 1997/07/05 windy 風つかい H.S.
link hexcvt, convert,       # BIPL    基本 procedure library
     wopen                  # GIPL    Window支援 procedure library

procedure main(args)
  Usage := "jchar02w first_byte(hex) of the top char of char blocks. ex: 81"
  if *args < 1 then stop(Usage)    # 引数無し
  jchar_out(inbase10(args[1],16))  # 引数を数字に変換
end

procedure jchar_out(n1)
# Shift-JISの文字出力 上位 n1、下位 \x40-\x7E,\x80-\xFC の文字を出力
# arg : [1]:block_no
  # window open
  WOpen("size=550,250","bg=pale red",
        "label=" || (s1 := hexstring(n1,2)) || "40-" || s1 ||
        "FC : each character") | stop("can't open window")
  Font("FixedSys")          # font指定
  WWrite("dummy")           # 最初の文字がうまく表示されない件の対策
  WWrite(s1,"40 -> ",s1,"7E")
  WWrite("<0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F>")
  every  n2 := 16r40 to 16r7E do {      # Shift-JIS文字出力(前半)
    if ((16r40 < n2) % 32 = 0) then WWrite()     # 32文字で改行
    WWrites(char(n1) || char(n2))   # otuput each character(2 bytes)
  }
  WWrite()

  WWrite()
  WWrite(s1 := hexstring(n1,2),"80 -> ",s1,"FC")
  WWrite("<0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F>")
  every  n2 := 16r80 to 16rFC do {      # Shift-JIS文字出力(後半)
    if ((16r80 < n2) % 32 = 0) then WWrite()
    WWrites(char(n1) || char(n2))   # output each character(2 bytes)
  }
  WWrite()

  WDone()     # q/Qキー入力待ち(Qまたはqを押すと windowを close)
  return
end
-----$ JCHAR02W.ICN ( lines:41 words:245 ) -----------------<cut here

  これを、引数 91で動かしますと、
9140 -> 917E
<0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F>
繊羨腺舛船薦詮賎践選遷銭銑閃鮮前善漸然全禅繕膳糎噌塑岨措曾曽楚狙
疏疎礎祖租粗素組蘇訴阻遡鼠僧創双叢倉喪壮奏爽宋層匝惣想捜掃挿掻

9180 -> 91FC
<0 1 2 3 4 5 6 7 8 9 A B C D E F 0 1 2 3 4 5 6 7 8 9 A B C D E F>
操早曹巣槍槽??燥争痩相窓糟総綜聡草荘葬??藻??走送遭鎗????像増憎臓
蔵贈造促側則即息捉束測足速俗属賊族続卒袖其揃存孫尊損村遜他多太汰
詑?チ堕妥惰打柁舵楕陀駄騨体堆対?マ?ミ帯待怠態戴?ヨ泰滞胎腿苔袋貸退?゚
隊????代台大第醍題鷹滝瀧??啄??托??????濯琢託鐸濁諾????蛸只

という結果で、?の部分の文字がうまく表示できません。
(MS-DOSで動く同じ programの出力に、Windows版の画面で化ける部分の
  修正を加えたものです。 ?は画面上は縦長■表示になっています。)

  元々英語版の WindowsNT/95用に開発されていますが、MS-DOS版のように、
日本語版の Windows上で動かして、日本語文字表示が、ほぼ支障ないように
なるといいなと思っています。

  ということで、 Jeffery教授に、日本語版 Windows95で、動かしたときの
レポートを 送っています。 日本語表示を検討してみよう言っていただいて
いますので、日本語もほぼ支障なく表示できる版ができるかもしれません。

  なにか参考書が無いかと聞かれましたので、私も読んでいないのですが、
  "Developing International Software for Windows 95 and Windows NT"
という本を紹介しました。役に立つと良いのですが。

  あちらには、日本語版 Windows95やNTはありませんので、テスト版を作って
いただいて、こちらでテストすることになります。
  ほぼ日本語表示に支障無い版ができましたら、またお知らせします。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 <IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 泣けちゃうほどせつないけれど/岡本真夜
(pcv0705a.txt 1997/07/05 PCVAN PIG,SLABO,niftyserve FPL,FGALTS)

■  Icon > ちょっと Icon(6)Icon Newsletter No.53         風つかい      目次

  Iconのサポートは、アリゾナ大学の Icon Project で行っていますが、年2回、
Newsletterを発行しています。
  以前は、希望者に冊子で配布していましたが、現在は WEBで見ることができ
ます。
  No.53が公開されていましたので、ご興味のある方は、のぞいて見て下さい。

http://www.cs.arizona.edu/icon/newsletter/inl53/inl53.html
No. 53 -- August 1, 1997
Contents
     Icon in Java 
     Icon Documentation in Japanese 
     Handbook of Programming Languages 
     Icon Analyst Promotional Offer 
     Programming Visualization Course 

  No.50以降は、http://www.cs.arizona.edu/icon/newsletter/inl.html から
linkが張ってあります。 目次をご参考に。

No. 52 -- April 1, 1997 
Contents
     Mail-Order Program Material 
     Teaching Icon 
     Web Links 
     Native Interface Components in Windows Icon 9.3 
     Programming Language Handbook 
     From Our Mail 
     Knowledge Explorer 

No. 51 -- December 1, 1996 
Contents
     Third Edition of The Icon Programming Language 
     Graphics Programming Book 
     Version 9.3 of Icon 
     Version 9.3 of the Program Library 
     New MS-DOS Implementation 
     Icon in Java 
     Teaching Icon 
     Web Links 
     Chicon 

No. 50 -- August 1, 1996 
Contents
     Third Edition of the Icon Book 
     New Implementations of Icon 
     Icon for Chinese Computing 
     Teaching Icon 
     Book Sale! 
     Web Links 
     From Our Mail 

尚、No.44以降は、次の所に pdf形式で置いてあります。 pdf形式ファイルの表示
には Acrobat Readerが必要ですが、http://www.adobe.co.jp/ から入手できます。

ftp://ftp.cs.arizona.edu/icon/doc
    inl44.pdf       10-Aug-95 00:00   124K 
    inl45.pdf       10-Aug-95 00:00   187K 
    inl46.pdf       17-Oct-95 00:00   270K 
    inl47.pdf       25-Nov-95 00:00   268K 
    inl48.pdf       25-Nov-95 00:00   378K 
    inl49.pdf       17-Mar-96 00:00   550K 
    inl50.pdf       14-Jul-96 00:00   563K 
    inl51.pdf       05-Dec-96 00:00   508K 
    inl52.pdf       27-Mar-97 22:31    82K  <-これはサイズがおかしいですね。
                                              壊れているみたい。
                                            (現在は、正常なものに置換されて
                                             います。)

  おまけに、Icon関係の WEB LINKをあげておきます。

http://www.cs.arizona.edu/icon/index.html
http://www.cs.utsa.edu/research/icon/icon.html
http://www.nmt.edu/tcc/help/lang/icon/homepage.html
http://www.eleves.ens.fr:8080/home/espie/icon/
http://www.crl.com/~spm/unicon/

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 <IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
(pcv0801a.txt 1997/08/01 PCVAN PIG,SLABO,niftyserve FPL,FGALTS)

■  Icon > ちょっと Icon(7)Icon Ver9.3 (Windows95/NT)    風つかい      目次

  Iconの Windows95/NT版が、新しい版がリリースされてました。
  今度の版は、フォントは限定されますが、日本語も画面に出せます。

  Iconは、Arizona大学の Griswold教授(のグループ)が 開発していますが、
WindowsNT/95対応の Icon(Wicon)は、Arizona大学にいて、その後 Texas大学
San Antonio校(UTSA) に移った Jeffery教授(のグループ)が開発しています。

  Windows95/NT版ファイルは、次のところから入手できます。
ftp://ringer.cs.utsa.edu/pub/icon/nt/graphics/
  README              4 Kb    Fri Aug 08 16:13:00 1997 
  docs.zip           34 Kb    Fri Aug 08 05:49:00 1997 Zip Compressed Data
  iconhelp.zip      605 Kb    Fri Aug 08 05:50:00 1997 Zip Compressed Data
  ipl.zip           866 Kb    Fri Aug 08 05:52:00 1997 Zip Compressed Data
  keysyms.icn         3 Kb    Thu Feb 08 00:00:00 1996 
  vib.zip           119 Kb    Fri Aug 08 05:52:00 1997 Zip Compressed Data
  vibsrc.zip         96 Kb    Fri Aug 08 05:52:00 1997 Zip Compressed Data
  wi.zip             53 Kb    Fri Aug 08 05:52:00 1997 Zip Compressed Data
  wicon.zip         631 Kb    Fri Aug 08 05:53:00 1997 Zip Compressed Data

  中身は、
  README          : 説明
  docs.zip        : Document
  iconhelp.zip    : Help file
  ipl.zip         : BIPL,GIPLの Procedure
  keysyms.icn     : GIPL(基本ライブラリー)に含まれるが修正されているとのこと。
  vib.zip         : Visual Interface Builder (Iconで書かれたグラフィック
                    インターフェース作成 ツールです。)
  vibsrc.zip      : 同上のソース
  wi.zip          : ランチャー
  wicon.zip       : コンパイラ(ソースから中間言語生成)と(中間言語)の
                    実行解釈実行
となっています。

  実際に動かすには、この他に BIPLが必要です。また、Graphicのサンプルプログラム
は、GIPL(グラフィックライブラリー)に入っています。
  ipl.zipは、GIPLの内 procedureを取り出したものです。

  BIPLと GIPLは次の所にあります。

ftp://ftp.cs.arizona.edu/icon/library/

  README              1 Kb    Sun Feb 16 13:08:00 1997 
  VQUEENS.NOTE      197 bytes Sun Jan 05 00:00:00 1997 
  bipl.lzh         1190 Kb    Wed Nov 27 00:00:00 1996 
  bipl.sea.hqx     1652 Kb    Wed Nov 27 00:00:00 1996 Macintosh BinHex Archive
  bipl.tar.Z       1445 Kb    Thu Nov 28 00:00:00 1996 Compressed Data
  bipl.tar.gz       967 Kb    Sun Feb 16 13:05:00 1997 GNU Zip Compressed Data
  gipl.lzh         1092 Kb    Wed Nov 27 00:00:00 1996 
  gipl.sea.hqx     1486 Kb    Wed Nov 27 00:00:00 1996 Macintosh BinHex Archive
  gipl.tar.Z       1821 Kb    Thu Nov 28 00:00:00 1996 Compressed Data
  gipl.tar.gz      1200 Kb    Sun Feb 16 13:05:00 1997 GNU Zip Compressed Data
  info.lzh           16 Kb    Wed Nov 27 00:00:00 1996 
  info.sea.hqx       40 Kb    Wed Nov 27 00:00:00 1996 Macintosh BinHex Archive
  info.tar.Z         20 Kb    Wed Nov 27 00:00:00 1996 Compressed Data
  info.tar.gz        14 Kb    Sun Feb 16 13:05:00 1997 GNU Zip Compressed Data
  vqueens.icn         7 Kb    Sun Jan 05 00:00:00 1997 

  インストールはこんな感じです。
【ディスクへの格納】
 D:\
  +wicon
  | |
  | +wi.bat                <--- wi.zipから
  | +noop.bat              <--- wicon.zipから
  | +wicont.exe            <--- wicon.zipから
  | +wiconx.exe            <--- wicon.zipから
  | +xxxx.hlp              <--- iconhelp.zipから
  | |
  |
  +gipl
  | +include
  | | +aaa.icn           <--- GIPLの include関係ファイルをそのまま入れる
  | +procs
  | | +bbb.u1            <--- GIPLの procedureを 中間言語にして入れておく
  | | +bbb.u2
  | +progs
  | | +ccc.icn           <--- GIPLのプログラム
  | +my_procs
  | | +ddd.u1            <--- 自分で作成した procedure
  | | +ddd.u2
  | +my_progs
  |   +fff.icn
  | 
  +bipl
  | +include
  | | +hhh.icn           <--- BIPLの include関係ファイルをそのまま入れる
  | +procs
  | | +iii.u1            <--- BIPLの procedureを 中間言語にして入れておく
  | | +iii.u2
  | |
  | +progs
  | | +jjj.icn           <--- BIPLの プログラム
  | +my_procs
  | | +kkk.u1            <--- 自分で作成した procedure
  | | +kkk.u2
  | +my_progs
  |   +lll.icn
  |

  という風にディスクに格納します。

【環境変数の設定】
  次の4つの環境変数をセットしておきます。
IPATH=d:\gipl\procs d:\gipl\my_procs d:\bipl\procs d:\bipl\my_procs
LPATH=d:\gipl\include d:\bipl\include
ICONFONT=FixedSys
WICONLOG=d:\wicon\Wicon.log

  IPATH は中間言語形式にした Iconの procedureを入れておくと、他のプログラム
からの link指定で、その procedureを引用できるディレクトリーの指定です。

  LPATH は ソースプログラムの一部として、他のプログラムの $include 指定で
その プログラムを引用できるディレクトリーの指定です。

  ICONFONT は、使用フォントの指定です。私の環境では、FixedSysと Systemが
有効みたいです。

  WICONLOG は、動作ログのファイル指定みたいです。(よく分からないのですが
  指定しないと、コンパイルの度に指定しろとメッセージがでるもので。)

【起動】
  WI.BATを起動すると、Wiconが起動されて、エディターウィンドウが開きます。
  そこから、Iconのソースプログラムを選択するか新しいソースファイル名を入力
  して、プログラムを修正/作成して、コンパイル(make)すれば、実行モジュール
  ができます。  この辺は、実際に動かして見たほうが早いでしょう。

【サンプル】
  GIPLにサンプルが入っていますので、動かしてみて下さい。
  その中の GPXTEST.ICNは、GIPLのサンプルプログラムで、グラフィック機能の動作
テストのプログラムです。面白い絵がでてきます。
  尚、vqueens.icnは修正版があります。GIPLの中のものは、ファイル不足エラーがで
ます。修正版が  ftp://ftp.cs.arizona.edu/icon/library/vqueens.icn  にあります。

【プログラムソース】
  プログラムソースは、
ftp://ringer.cs.utsa.edu/pub/icon/nt/src/  にあります。

  README              2 Kb    Wed Aug 06 01:48:00 1997 
  c.zip             155 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  cmn.zip            72 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  h.zip              83 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  msvc50.zip         15 Kb    Wed Aug 06 00:39:00 1997 Zip Compressed Data
  p.zip              42 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  r.zip             364 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  rtl.zip           100 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  rtt.exe           275 Kb    Fri Jan 26 00:00:00 1996 Binary Executable
  t.zip              88 Kb    Tue Aug 05 15:32:00 1997 Zip Compressed Data
  wincap.zip         40 Kb    Thu Feb 01 00:00:00 1996 Zip Compressed Data

【日本語の扱い】
  Iconの文字列処理は、1バイト単位で行います。日本語の文字の区切りを意識し
  たプログラム以外では、支障は起きません。日本語の文字の区切りを意識するの
  が必要ならそういう procedureを組めば可能です。
  しかし、画面出力はまた別問題です。Windows95/NT環境で、画面の文字を出力す
  る際には、現バージョンでは 次の制限があります。
    ・フォントの制限
        フォント指定が、自由にはできない。FixedSysと Systemの指定は有効みた
        いです。
    ・日本語出力のやり方
        コンソールウィンドウへの日本語文字出力や、生成したウィンドウへの日本
        語文字出力では、バイト単位で出力すると文字が化けます。文字(2バイト)
        単位で出力すれば大丈夫でした。
        ですから、文字列を表示させるには、支障はありません。
      (また、ファイルに出力する分には問題ありません)

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 <IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
(pcv0810a.txt 1997/08/10 PCVAN PIG,SLABO,niftyserve FPL,FGALTS)

■  Icon > Icon散歩道  むすび                        風つかい       目次

  散歩道では、テキスト解析をやろうと思っていたのですが、殆ど 以前の講座
のミス修正と 思いつき programの解説になってしまいました。

  散歩道で予定していました 数式解析とかは 全然 手をつけていませんが 秋も
終わりですので、この辺で Icon散歩道 を終わることにします。
  お付き合いいただきまして、ありがとうございました。

  では、また、お会いする日まで。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
(iconlec4.txt 1997/11/24)