Icon土日夜


■  Icon > Icon土日夜  はじめに                      風つかい      目次

  Iconは アリゾナ大学の Icon Projectによって、開発されているテキスト処理
言語です。
  Iconは table,set,list,record,等の豊富な data構造と Back trackingを含む
強力な制御構造を備えていますので、テキスト解析に威力を発揮します。

  英語の国で開発されている言語ですが、日本語の処理にも不自由しませんので
日本でも、もっともっと 使われてよい言語と思います。

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

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

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

  この講座は、主に PCVANのPIGのテキストデータ処理会議室にアップロードした
ものに加筆・修正を行ったものです。
  Iconは PDSですので、この入門講座も同じ扱いとします。(転載・編集自由)
               (This textbook is in the public domain.)

目次
はじめに
(1) jtrim(1)
(2) jtrim(2)
(3) jtrim(3)
(4) jtrim(4)
(5) jtrim(5)
(6) AWK風 program(1)
(7) AWK風 program(2)
(8) AWK風 program(3)
(9) AWK風 program(4)
(10) AWK風 program(5)
(11) AWK風 program(6)
(12) AWK風 program(7)
(13) AWK風 program(8)
(14) AWK風 program(9)
(15) record
(16) 構造体 tree表示(1)
(17) 構造体 tree表示(2)
(18) n進数計算
(19) table書き出し
(20) table読み込み(1)
(21) table読み込み(2)
(22) 構造体 copy
(23) 引用符
(24) Windows Icon 9.3.1
(25) Icon Newsletter No.54
むすび

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: ECHO / 遊佐未森
(icon400.txt 1998/02/18 PCVAN PIG)

■  Icon > Icon土日夜(1) jtrim(1)              風つかい      目次

  はやいもので、Icon入門講座を始めてもう1年になります。昨年の秋に始め
た頃は、こんなに書くことがあるとは思っていませんでした。
  始めてみますと、結構ネタが出てきまして、未だ当分は続けられそうです。

  シリーズにしようと思っていた訳ではないのですが、100Kbyte位に書込みが
たまりますと、ひとまず まとめ ということで、libraryに入れています。

  4回まとめて、第5回目の始めです。 さて そのサブタイトルですが、
  【Icon土日夜】にしました。   【Iconどに〜ちょ】 と読んで下さい。
  某電話会社のCMからパクったタイトルです。(汗)
  私は、カタギの勤め人ですので、この原稿をいつも、土曜、日曜、平日の夜
に書いているもんで、そのものズバリ。
と、いうわけで今回はこのタイトルにします。

  さて、今回は、テキストに含まれる空白の削除 について、少々。
  先日、テキストデータ末尾の空白削除をする必要がありました。
  日本文では、全角文字の間に、半角文字が結構混在しますので、全角と半角
の spaceを削除しないといけません。   こういう仕事は、sedで簡単・高速に
処理できます。

-----^ TRIM.SED ( date:97-11-29 time:16:07 ) ---------------<cut here
#! sed -f
####################
# 過剰 space削除
####################
# 日本語対応の sedを使用すること。
# trim.sed 97/11/29 windy comment 追加
# trim.sed 97/08/02 windy 風つかい H.S.
# This file is in the public domain.
# ↓半角 space3個
s/   +/  /g               # 3個以上の半角 spaceは 半角 space2個へ
#      ↑半角 space2個
# ↓全角 space2個
s/  +/ /g              # 全角 spaceの連続は 全角 space1個へ
#       ↑全角 space1個
s/[  ]+$//               # 末尾の半角/全角 spaceを 削除
#  ↑半角 spaceと全角 space
-----$ TRIM.SED ( lines:16 words:67 ) ----------------------<cut here

  ・半角 spaceを減らす
  ・全角 spaceを減らす
  ・末尾の半角 spaceと全角 spaceの削除
という3つの処理を行いました。

  で、これを Iconでやってみようという訳です。

  Iconには、trimという末尾の空白を削除する関数があります。
  Iconは、英語の国の方が作った言語ですので、空白は、半角 spaceとなって
います。  この辺を日本語対応に拡張します。

  spaceは表示とか印刷上、半角/全角の判読が不可能です。いちいちコメント
を付けていくのもメイドいので
            半角 space " "  は、"s"  に、
            全角 space " " は、"□" に
と換えて programを作ることにします。  trim.sedは、次のようになります。

-----^ TRIM-.SED ( date:97-11-29 time:16:08 ) --------------<cut here
#! sed -f
####################
# 過剰 space削除
####################
# 日本語対応の sedを使用すること。
# trim.sedを説明用に、半角" "-> "s", 全角" " -> "□"としたもの
# trim-.sed 97/11/29 windy 風つかい H.S.
# This file is in the public domain.
s/sss+/ss/g               # 3個以上の半角 spaceは 半角 space2個へ
s/□□+/□/g              # 全角 spaceの連続は 全角 space1個へ
s/[s□]+$//               # 末尾の半角/全角 spaceを 削除
-----$ TRIM-.SED ( lines:11 words:49 ) ---------------------<cut here

  ところで、全角、半角は英語では何と訳しているのかと思って、 Ken Lundeさんの
日本語情報処理(Understanding Japanese Information Processing)を 見てみまし
たら、
    全角は、full-width   半角は、half-width
と、訳してありました。
  全幅、半幅とかに意訳してありますね。  確かに、"角"と言われても分からない
ですよね。  "角"って、どこから来たんでしょうね?
  漢字は 四角の形が多いので、日本人の私には、全角、半角と聞いても そんなに
違和感は無いのですが。

  それではまず、重複 spaceの削除からです。早速 programを。
  trim_mという procedureを作ります。
  ちょっと汎用化して、n個以上の半角文字ssを m個の ssへ置換する procedureと
しました。
-----^ TRIM1.ICN ( date:97-11-29 time:20:14 ) --------------<cut here
####################
# trim拡張のテスト
####################
# 講座用に、半角 space -> "s",全角 space ->"□"としている。
# trim1.icn 97/11/29 windy 風つかい H.S.
# This file is in the public domain.
link sjis_e  # jimage <-日本語対応 image()

procedure main()
  s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
  s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
  s3 := "ssss□□□ss"
  s4 := ""

  write("元データ")
  write("s1: ",jimage(s1))
  write("s2: ",jimage(s2))
  write("s3: ",jimage(s3))
  write("s4: ",jimage(s4))

  write("\n2文字以上の 半角 space(の連続)は、半角 space 1個に変換")
  write("s1: ",jimage(trim_m(s1,"s")))
  write("s2: ",jimage(trim_m(s2,"s")))
  write("s3: ",jimage(trim_m(s3,"s")))
  write("s4: ",jimage(trim_m(s4,"s")))

  write("\n3文字以上の 半角 space(の連続)は、半角 space 2個に変換")
  write("s1: ",jimage(trim_m(s1,"s",3,2)))
  write("s2: ",jimage(trim_m(s2,"s",3,2)))
  write("s3: ",jimage(trim_m(s3,"s",3,2)))
  write("s4: ",jimage(trim_m(s4,"s",3,2)))
end


####################
# n個以上連続した半角文字を m(<n)個へ圧縮
####################
# trim_m    1997/11/29 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      ss : 圧縮対象文字(半角)(1文字)
#      n  : 圧縮対象文字数
#      m  : 圧縮後の文字数 (<m)
# This file is in the public domain.

procedure trim_m(s,ss,n,m)
  # default
  /s  := &subject                 # 指定が無ければ、走査対象
  /ss := " "                      # 指定が無ければ、space
  /n  := 2    ; sn := repl(ss,n)  # 指定が無ければ、2
  /m  := 1    ; sm := repl(ss,m)  # 指定が無ければ、1

  s1 := ""    # 戻り値の初期値
  s ? {          # sを走査対象として、
                   #    n文字連続した 対象文字の連続 を見つけたら
                   # ↓その位置 +m文字の位置まで の文字列を足しこみ、
    while  s1 ||:= tab(find(sn)+m) do tab(many(ss))
                                    # ↑走査位置をその後ろの対象文字以外
                                    #   の位置まで移動
    return s1 ||:= tab(0)     # 残りの部分を足し込み
  }
end

# find(s) : 走査対象文字列の中の s文字列を探す。findの値は sの先頭位置
# tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分
#           の文字列となる。
#           文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字
#           の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。
-----$ TRIM1.ICN ( lines:67 words:204 ) --------------------<cut here

  trim1.exe を動かした結果です。
-----^ TRIM1 ( date:97-11-29 time:20:15 ) ------------------<cut here
元データ
s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
s3: "ssss□□□ss"
s4: ""

2文字以上の 半角 space(の連続)は、半角 space 1個に変換
s1: "s□□sあい□うsえおs□sか□□□□きくsけこs□□sz"
s2: "zsz□□sあい□うsえおs□sか□□□□きくsけこs□□s"
s3: "s□□□s"
s4: ""

3文字以上の 半角 space(の連続)は、半角 space 2個に変換
s1: "ss□□ssあい□うssえおs□sか□□□□きくsけこs□□ssz"
s2: "zssz□□ssあい□うssえおs□sか□□□□きくsけこs□□ss"
s3: "ss□□□ss"
s4: ""
-----$ TRIM1 ( lines:17 words:35 ) -------------------------<cut here

  次回は、全角文字の連続を圧縮する programを作ってみましょう。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Always /篠原美也子
(icon401.txt 1997/11/29 PCVAN PIG)

■  Icon > Icon土日夜(2) jtrim(2)              風つかい      目次

  秋になると、なんとなく「枯葉」(Autumn Leaves)なんかを聞きたくなりますが、
Jazzのアップテンポで聞く「枯葉」は、つむじ風の中を舞う枯葉かな〜 なんぞと
思いながら、さて重複文字の圧縮の続きです。

  前回、同じ半角文字の連なりをやりましたが、今回は、全角文字です。
  jtrim_mzという procedureを作ります。考え方は前回の trim_mと同じですが
同じ文字の n文字の連続を検出した後に、別の文字の位置へ移動するのに細工が
必要です。  半角文字なら manyで 移動できましたが、全角文字には相当する関数
がありません。
  SJIS対応の jmanyという関数を以前作っていますが、これは相当重い procedure
なので、全角文字専用ということで、ここでは matchを繰り返し使って相当処理を
行っています。

-----^ TRIM2.ICN ( date:97-11-29 time:22:53 ) --------------<cut here
####################
# trim拡張のテスト
####################
# 講座用に、半角 space -> "s",全角 space ->"□"としている。
# trim2.icn 97/11/29 windy 風つかい H.S.
# This file is in the public domain.
link sjis_e  # jimage <-日本語対応 image()

procedure main()
  s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
  s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
  s3 := "ssss□□□ss"
  s4 := ""

  write("元データ")
  write("s1: ",jimage(s1))
  write("s2: ",jimage(s2))
  write("s3: ",jimage(s3))
  write("s4: ",jimage(s4))

  write("\n2文字以上の 全角 space(の連続)は、全角 space 1個に変換")
  write("s1: ",jimage(jtrim_mz(s1,"□")))
  write("s2: ",jimage(jtrim_mz(s2,"□")))
  write("s3: ",jimage(jtrim_mz(s3,"□")))
  write("s4: ",jimage(jtrim_mz(s4,"□")))

  write("\n3文字以上の 全角 space(の連続)は、全角 space 2個に変換")
  write("s1: ",jimage(jtrim_mz(s1,"□",3,2)))
  write("s2: ",jimage(jtrim_mz(s2,"□",3,2)))
  write("s3: ",jimage(jtrim_mz(s3,"□",3,2)))
  write("s4: ",jimage(jtrim_mz(s4,"□",3,2)))
end


####################
# n個以上連続した全角文字を m(<n)個へ圧縮
####################
# jtrim_mz  1997/11/29 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      ss : 圧縮対象文字(全角)(1文字)
#      n  : 圧縮対象文字数
#      m  : 圧縮後の文字数 (<m)
# This file is in the public domain.

procedure jtrim_mz(s,ss,n,m)
  # default
  /s  := &subject                 # 指定が無ければ、走査対象
  /ss := " "                     # 指定が無ければ、全角 space
  /n  := 2    ; sn := repl(ss,n)  # 指定が無ければ、2
  /m  := 1                        # 指定が無ければ、1

  s1 := ""    # 戻り値の初期値
  s ? {          # sを走査対象として、
                   #    n文字連続した 対象文字の連続 を見つけたら
                   # ↓その位置 +(m*2)文字の位置まで の文字列を足しこみ、
    while s1 ||:= tab(find(sn)+(m*2)) do {
      while tab(match(ss))
      # ↑走査位置を その後ろの対象文字以外の 位置まで 移動
    }
    return s1 ||:= tab(0)     # 残りの部分を足し込み
  }
end

# match(s): 現在走査位置から、走査対象文字列と s文字列が一致しているか
#           判定。  一致すれば、matchの値は一致文字列の次の位置となる。
# find(s) : 現在走査位置以降で、走査対象文字列の中の s文字列を探す。
#           見つかれば、findの値は sの先頭位置となる。
# tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分
#           の文字列となる。
#           文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字
#           の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。
-----$ TRIM2.ICN ( lines:71 words:213 ) --------------------<cut here

  前回の trim1.icnで余計なことをしていましたね。 smという文字列を作った
んですが、結局使っていませんでした。(汗)

  trim2.exeの結果です。
-----^ TRIM2 ( date:97-11-29 time:22:53 ) ------------------<cut here
元データ
s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
s3: "ssss□□□ss"
s4: ""

2文字以上の 全角 space(の連続)は、全角 space 1個に変換
s1: "ssss□ssあい□うssssえおs□sか□きくsけこs□sssz"
s2: "zssz□ssあい□うssssえおs□sか□きくsけこs□ssss"
s3: "ssss□ss"
s4: ""

3文字以上の 全角 space(の連続)は、全角 space 2個に変換
s1: "ssss□□ssあい□うssssえおs□sか□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□きくsけこs□□ssss"
s3: "ssss□□ss"
s4: ""
-----$ TRIM2 ( lines:17 words:35 ) -------------------------<cut here

  次回は、文字列末尾の space削除をやります。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Autumn Leaves / Wynton Kelly
(icon402.txt 1997/11/29 PCVAN PIG)

■  Icon > Icon土日夜(3) jtrim(3)              風つかい      目次

  今日は、雨で星は見えないのですが、近ごろは夕暮れになると、南天に木星と
金星がひときわ明るく見えます。少々曇っていても見えますね。あと土星と火星
も見えるんだそうですが、どれがどれかよく分かりません。

  さて、今回は、文字列末尾の space削除です。  でも、その前に文字列先頭の
space削除をやった方が、分かりやすいので先にやります。
  早速 programです。 jtrim_lという procedureを作ります。Test programでは
都合で、jtrim_l1という名前にしています。

-----^ TRIM3.ICN ( date:97-11-30 time:02:15 ) --------------<cut here
####################
# trim拡張のテスト
####################
# 講座用に、半角 space -> "s",全角 space ->"□"としている。
# trim3.icn 97/11/30 windy 風つかい H.S.
# This file is in the public domain.
link sjis_e  # jimage <-日本語対応 image() 入門講座3(18)参照

procedure main()
  s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
  s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
  s3 := "ssss□□□ss"
  s4 := ""

  write("元データ")
  write("s1: ",jimage(s1))
  write("s2: ",jimage(s2))
  write("s3: ",jimage(s3))
  write("s4: ",jimage(s4))

  write("\n先頭の 全角/半角 spaceを削除")
  write("s1: ",jimage(jtrim_l1(s1,"s","□")))
  write("s2: ",jimage(jtrim_l1(s2,"s","□")))
  write("s3: ",jimage(jtrim_l1(s3,"s","□")))
  write("s4: ",jimage(jtrim_l1(s4,"s","□")))

end


####################
# 先頭の半角スペース、全角スペースを取り去る
####################
# jtrim_l1  1997/11/30 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      s1 : 削除対象文字
#      s2 : 削除対象文字
# 注意    : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは
#           2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること
#           は無いので問題ない。その他の文字では保証されない。
# delete leading spaces
procedure jtrim_l1(s,s1,s2)
  /s  := &subject
  /s1 := " "         # "\x20"          半角 space
  /s2 := " "        # "\x81\x40"      全角 space
  s ? {              # 走査対象を sとして、
    while tab(match(s1 | s2)) # spaceだったら、走査位置を、その次の文字へ
                              # 移動し続ける。 space以外に到着すると失敗して
                              # 走査位置は space以外の文字の先頭になっている。
    return tab(0)    # space以外の文字から末尾まで
  }
end

# match(s): 現在走査位置から、走査対象文字列と s文字列が一致しているか
#           判定。  一致すれば、matchの値は一致文字列の次の位置となる。
# tab(nn) : 走査位置を nnまで移動する。その時の tabの値は、移動した部分
#           の文字列となる。
#           文字列の最後の文字の後ろの位置は、0。よって tab(0)は最後の文字
#           の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。
-----$ TRIM3.ICN ( lines:58 words:171 ) --------------------<cut here

  trim3.exeの結果です。
-----^ TRIM3 ( date:97-11-30 time:02:16 ) ------------------<cut here
元データ
s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
s3: "ssss□□□ss"
s4: ""

先頭の 全角/半角 spaceを削除
s1: "あい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
s3: ""
s4: ""
-----$ TRIM3 ( lines:11 words:20 ) -------------------------<cut here

  で、末尾の space削除はどうするかと言うと、末尾から同じ処理をやれば
良いということになります。 早速 programです。
  jtrim_tという procedureを作ります。Test programでは、都合で、jtrim_t1
という名前にしています。
  末尾から逆方向に走査するのは面倒なので、文字列を反転しておいて順方向
に走査して処理します。

-----^ TRIM4.ICN ( date:97-11-30 time:02:17 ) --------------<cut here
####################
# trim拡張のテスト
####################
# 講座用に、半角 space -> "s",全角 space ->"□"としている。
# trim4.icn 97/11/30 windy 風つかい H.S.
# This file is in the public domain.
link sjis_e  # jimage <-日本語対応 image() 入門講座3(18)参照

procedure main()
  s1 := "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
  s2 := "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
  s3 := "ssss□□□ss"
  s4 := ""

  write("元データ")
  write("s1: ",jimage(s1))
  write("s2: ",jimage(s2))
  write("s3: ",jimage(s3))
  write("s4: ",jimage(s4))

  write("\n末尾の 全角/半角 spaceを削除")
  write("s1: ",jimage(jtrim_t1(s1,"s","□")))
  write("s2: ",jimage(jtrim_t1(s2,"s","□")))
  write("s3: ",jimage(jtrim_t1(s3,"s","□")))
  write("s4: ",jimage(jtrim_t1(s4,"s","□")))

end


####################
# 末尾の半角スペース、全角スペースを取り去る
####################
# jtrim_t1  1997/11/30 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      s1 : 削除対象文字
#      s2 : 削除対象文字
# 注意    : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは
#           2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること
#           は無いので問題ない。その他の文字では保証されない。
# delete trailing spaces
procedure jtrim_t1(s,s1,s2)
  /s  := &subject
  /s1 := " "         # "\x20"     半角 space
  /s2 := "□"        # "\x81\x40" 全角 space
  s3  := reverse(s1)
  s4  := reverse(s2)

  reverse(s) ? {     # 走査対象を sの反転文字列として、
    while tab(match(s3 | s4)) # 半角 spaceか、全角spaceの反転文字だったら、
                              # 走査位置を、その次の文字へ移動し続ける。
                              # その他の文字に到着すると失敗する。
                              # 走査位置は その他の文字の先頭になっている。
    return reverse(tab(0))  # 反転文字列の「その他文字から末尾まで」の
                            # 反転文字列   →すなわち、先頭から 末尾 space
  }                         # の手前までの文字列
end

# reverse(s) : 文字列 sの反転文字列
# match(s)   : 現在走査位置から、走査対象文字列と s文字列が一致しているか
#              判定。  一致すれば、matchの値は一致文字列の次の位置となる。
# tab(nn)    : 走査位置を nnまで移動する。その時の tabの値は、移動した部分
#              の文字列となる。
#              文字列の最後の文字の後ろの位置は、0。 よって tab(0)は最後の
#              文字の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。
-----$ TRIM4.ICN ( lines:64 words:193 ) --------------------<cut here

  trim4.exeの結果です。
-----^ TRIM4 ( date:97-11-30 time:02:18 ) ------------------<cut here
元データ
s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss"
s3: "ssss□□□ss"
s4: ""

末尾の 全角/半角 spaceを削除
s1: "ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz"
s2: "zssz□□ssあい□うssssえおs□sか□□□□きくsけこ"
s3: ""
s4: ""
-----$ TRIM4 ( lines:11 words:20 ) -------------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: The Cat / Jimmy Smith
(icon403.txt 1997/11/30 PCVAN PIG)

■  Icon > Icon土日夜(4) jtrim(4)              風つかい      目次

  あと、2時間程で、今年も師走になります。今年も、もう残りひと月と思うか、
未だひと月もあると思うか。とりあえず、ひと月あれば、【Iconどに〜ちょ】は
まとまりそうな気がします。

  さて、jtrim(1)〜(3)の programを まとめて、 jtrimという programに
しようと思います。 しかし、いつも同じような filterの programを作っていま
すので、共通にできそうな部分をまとめた procedureを作っておこうと思いたち
ました。  で、できたのが次の procedureです。
  file読込み・書出し、拡張子判定、モニター表示のあたりをまとめています。

-----^ FILT_PAT.ICN ( date:97-11-30 time:22:00 ) -----------<cut here
####################
# filter programの雛形
####################
# 1行データ処理 procedureから呼んで filter programを作成する
# filt_pat.icn  Rev.02 1997/11/30 windy 引数拡張
# filt_pat.icn  Rev.01 1997/11/06 windy 風つかい H.S.
# arg   : args      : command line引数を引き継ぐ
#                     args[1]は input.file名 と想定
#                     wild cardsは未対応
#         filt_proc : filter programの1行文処理 procedure
#         Usage_main: "Usage: 実行file名 " に引き続く message
#         out_ext   : output.fileの拡張子名(指定しなければ標準出力)
#         in_ext    : input.fileの拡張子名
#         neg       : input.fileの拡張子名チェックを反転
# This file is in the public domain.
link string_e,  # pre_char #入門講座4 Icon迷い道(5)参照
     file_e     # f_name   #入門講座4 Icon回り道(4)の exe_nameと同じもの
                # check_ext  #入門講座4 Icon迷い道(6)参照

procedure filt_pat(args,filt_proc,Usage_main,out_ext,in_ext,neg)
  /Usage_main := "input.file"
  Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成
  if *args > 0 then {
    if args[1] == ("/?" | "-?") then stop(Usage)             # Usage出力
    else {
      filename := map(args[1])       # 第1引数を input.file名とみなす
      if \in_ext then {              # 入力拡張子指定があれば、
        # input.fileの拡張子チェック
        check_ext(in_ext,filename,neg) |
                      stop("input.file name error : ",filename)
      }
      # input.file open
      in_dir := open(filename) |
                      stop("cannot open input.file : ",filename) 

      if \out_ext then {      # 出力拡張子指定があれば、
        out_ext  := map(out_ext)
        line_no  := 0                # 行No  動作状態 monitor用
        # output.file open
        # output.file名作成
        f_new := (pre_char(filename) || "." || out_ext)
        out_dir := open(f_new,"a") | {  # append modeで open
                     close(in_dir)
                     stop("cannot open output.file : ",f_new)
                   }
        write(&errout,filename," -> ",f_new)      # 動作モニター
      }
    }
  }
  # 1行づつ input.fileから読み込んで、指定 procedureで処理をして
  # output.fileに書き出す。
  while write(out_dir,filt_proc(read(in_dir))) do {
    if (\out_ext & (*args >0))
    then writes(&errout," ",right(line_no +:= 1,4)) # monitor表示
  }
  if (\out_ext & (*args >0)) then {
    close(in_dir)            # input.file close
    close(out_dir)           # output.file close
    write(&errout)           # monitor表示 カーサー戻し
  }
end
-----$ FILT_PAT.ICN ( lines:61 words:252 ) -----------------<cut here

  この雛形の procedureを使った sampleです。
-----^ TEST404A.ICN ( date:97-11-30 time:22:01 ) -----------<cut here
####################
# filt_pat の Test program
####################
# 入力ファイルの行頭に行番号を付けるだけの program
# test404.icn Rev.01 1997/11/30 windy 風つかい H.S.
# This file is in the public domain.
link filt_pat

procedure main(args)
  filt_pat(args,add_no)
  # 引数 : args,proc  ,Usage,out_ext,in_ext,neg
end


procedure add_no(line)
  static  line_no                # static宣言
  initial { line_no := 0 }       # 最初に呼ばれた時にだけ実行
  return  right(line_no +:= 1,4) || " " || line  # 行番号を付加
end
-----$ TEST404A.ICN ( lines:19 words:62 ) ------------------<cut here

  動きがちょっとメンドイので、test404aと filt_patの関係を図にしておきます。

      (用途に応じて作成)                       (汎用 procedure)
     - test404a -----------                -- filt_pat -----------
    |  main()              |              |                       |
    |    filter procを呼ぶ |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |                      |              |   filt_pat()          |
    |                      |              |     入出力 file open  |
    |                      |              |     入力 file1行読込み|
    | -------------------- |              |                       |
    |  行番号付加 proc<-------<-------<----------  1行 filter proc|
    |  add_no()            |              |        を呼ぶ         |
    |        ----------------->------->----------> 加工後 data    |
    |                      |              |                       |
    |                      |              |     出力 fileへ書出し |
    |                      |              |    (file末尾迄 繰返し)|
    |                      |              |     入出力 file close |
     ----------------------                -----------------------

  念のため結果を確認しておきます。
  test404a < trim.sed > test404a とした時の結果です。

-----^ TEST404A ( date:97-11-30 time:22:02 ) ---------------<cut here
   1 #! sed -f
   2 ####################
   3 # 過剰 space削除
   4 ####################
   5 # 日本語対応の sedを使用すること。
   6 # trim.sed 97/11/29 windy comment 追加
   7 # trim.sed 97/08/02 windy 風つかい H.S.
   8 # This file is in the public domain.
   9 # ↓半角 space3個
  10 s/   +/  /g               # 3個以上の半角 spaceは 半角 space2個へ
  11 #      ↑半角 space2個
  12 # ↓全角 space2個
  13 s/  +/ /g              # 全角 spaceの連続は 全角 space1個へ
  14 #       ↑全角 space1個
  15 s/[  ]+$//               # 末尾の半角/全角 spaceを 削除
  16 #  ↑半角 spaceと全角 space
-----$ TEST404A ( lines:16 words:83 ) ----------------------<cut here

  次回は、jtrimをまとめます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 海になりたい青 / 篠原美也子
(icon404.txt 1997/11/30 PCVAN PIG)

■  Icon > Icon土日夜(5) jtrim(5)              風つかい      目次

  今回は、jtrimのまとめです。前回作った filter program用 雛形 procedureの
filt_patを使って、まとめています。 jtrim_t1はミスがありましたので、修正し
ました。

-----^ TRIM5.ICN ( date:97-11-30 time:22:47 ) --------------<cut here
####################
# 重複 spaceを圧縮/末尾 spaceを削除
####################
# 講座用に、半角 space -> "s",全角 space ->"□"としている。
# trim5.icn 1997/11/30 windy 風つかい H.S.
# This file is in the public domain.
link filt_pat  # filt_pat            # filter programの雛形

procedure main(args)
  filt_pat(args,jtrim,     ,"trm"  )
  #引数 -> args,proc ,Usage,out_ext,in_ext,neg
end


####################
# 重複 spaceを圧縮/末尾 spaceを削除 の1行分処理 procedure
####################
procedure jtrim(s)
  s1 := trim_m1(s,"s",3,2)           # 半角 space圧縮
  s2 := jtrim_mz(s1,"□")            # 全角 space圧縮
  s3 := jtrim_t1(s2,"s","□")        # 末尾 space削除
  return s3
end


####################
# n個以上連続した半角文字を m(<n)個へ圧縮
####################
# trim_m1   1997/11/30 windy linkの都合上 名前変更
# trim_m    1997/11/29 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      ss : 圧縮対象文字(半角)(1文字)
#      n  : 圧縮対象文字数
#      m  : 圧縮後の文字数 (<m)
# This file is in the public domain.

procedure trim_m1(s,ss,n,m)
  # default
  /s  := &subject                 # 指定が無ければ、走査対象
  /ss := " "                      # 指定が無ければ、space
  /n  := 2    ; sn := repl(ss,n)  # 指定が無ければ、2
  /m  := 1    ; sm := repl(ss,m)  # 指定が無ければ、1

  s1 := ""    # 戻り値の初期値
  s ? {          # sを走査対象として、
                   #    n文字連続した 対象文字の連続 を見つけたら
                   # ↓その位置 +m文字の位置まで の文字列を足しこみ、
    while  s1 ||:= tab(find(sn)+m) do tab(many(ss))
                                    # ↑走査位置をその後ろの対象文字以外
                                    #   の位置まで移動
    return s1 ||:= tab(0)     # 残りの部分を足し込み
  }
end


####################
# n個以上連続した全角文字を m(<n)個へ圧縮
####################
# jtrim_mz  1997/11/29 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      ss : 圧縮対象文字(全角)(1文字)
#      n  : 圧縮対象文字数
#      m  : 圧縮後の文字数 (<m)
# This file is in the public domain.

procedure jtrim_mz(s,ss,n,m)
  # default
  /s  := &subject                 # 指定が無ければ、走査対象
  /ss := " "                     # 指定が無ければ、全角 space
  /n  := 2    ; sn := repl(ss,n)  # 指定が無ければ、2
  /m  := 1                        # 指定が無ければ、1

  s1 := ""    # 戻り値の初期値
  s ? {          # sを走査対象として、
                   #    n文字連続した 対象文字の連続 を見つけたら
                   # ↓その位置 +(m*2)文字の位置まで の文字列を足しこみ、
    while s1 ||:= tab(find(sn)+(m*2)) do {
      while tab(match(ss))
      # ↑走査位置を その後ろの対象文字以外の 位置まで 移動
    }
    return s1 ||:= tab(0)     # 残りの部分を足し込み
  }
end


####################
# 末尾の半角スペース、全角スペースを取り去る
####################
# jtrim_t1 Rev.02 1997/11/30 windy /s2 := "□" -> " "
# jtrim_t1 Rev.01 1997/11/30 windy 風つかい H.S.
# arg: s  : 変換対象文字列
#      s1 : 削除対象文字
#      s2 : 削除対象文字
# 注意    : s1,s2は、指定しないこと。 Shift-JISの 全角/半角 spaceでは
#           2バイト目に "\x20"が来ること や 1バイト目に "\x40"が来ること
#           は無いので問題ない。その他の文字では保証されない。
# delete trailing spaces

procedure jtrim_t1(s,s1,s2)
  /s  := &subject
  /s1 := " "         # "\x20"     半角 space
  /s2 := " "        # "\x81\x40" 全角 space  Rev.02
  s3  := reverse(s1)
  s4  := reverse(s2)

  reverse(s) ? {     # 走査対象を sの反転文字列として、
    while tab(match(s3 | s4)) # 半角 spaceか、全角spaceの反転文字だったら、
                              # 走査位置を、その次の文字へ移動し続ける。
                              # その他の文字に到着すると失敗する。
                              # 走査位置は その他の文字の先頭になっている。
    return reverse(tab(0))  # 反転文字列の「その他文字から末尾まで」の
                            # 反転文字列   →すなわち、先頭から 末尾 space
  }                         # の手前までの文字列
end

# reverse(s) : 文字列 sの反転文字列
# match(s)   : 現在走査位置から、走査対象文字列と s文字列が一致しているか
#              判定。  一致すれば、matchの値は一致文字列の次の位置となる。
# find(s)    : 現在走査位置以降で、走査対象文字列の中の s文字列を探す。
#              見つかれば、findの値は sの先頭位置となる。
# tab(nn)    : 走査位置を nnまで移動する。その時の tabの値は、移動した部分
#              の文字列となる。
#              文字列の最後の文字の後ろの位置は、0。 よって tab(0)は最後の
#              文字の後ろ迄、走査位置を移動し、その間の文字列を値として持つ。
-----$ TRIM5.ICN ( lines:124 words:441 ) -------------------<cut here

  この programに trim5 < trim5.dat として、次のデータを食わせると、
-----^ TRIM5.DAT ( date:97-11-30 time:17:14 ) --------------<cut here
ssss□□ssあい□うssssえおs□sか□□□□きくsけこs□□sssz
zssz□□ssあい□うssssえおs□sか□□□□きくsけこs□□ssss
ssss□□□ss

-----$ TRIM5.DAT ( lines:4 words:3 ) -----------------------<cut here

  こんな結果となります。
-----^ TRIM5.TRM ( date:97-11-30 time:22:04 ) --------------<cut here
ss□ssあい□うssえおs□sか□きくsけこs□ssz
zssz□ssあい□うssえおs□sか□きくsけこ


-----$ TRIM5.TRM ( lines:4 words:2 ) -----------------------<cut here

  というところで、jtrim関係は、ここらへんでおしまいにします。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 満たされた月 / 篠原美也子
(icon405.txt 1997/11/30 PCVAN PIG)

■  Icon > Icon土日夜(6) AWK風 program(1)      風つかい      目次

  寒い〜。先週から結構寒くなってきました。キーボードを打つ手が凍えると
いう程ではないですが、夜の原稿書きは、ついつい酔っぱらいタイピングが多
くなります。

  さて、filter programの 雛形 procedureを 紹介しましたが、これを使うと
AWKに近い構成の programが書けます。 そこで、殆ど AWKという構成のための
procedureを考えてみました。
  1行毎の処理の部分はできていますので、あとは
    ・組み込み変数
    ・BEGIN,END
   が、あれば大体似た構成にできますね。

  と言うわけで、早速。
  BEGIN, ENDは、存在するとは限りませんので、存在するかどうかのチェック
\BEGIN, \END をやっています。 \filt_proc チェックを入れると、BEGINだけ
とか ENDだけの programもサポートできます が、それはもう filterじゃない
だろう(笑) ということで、はしょってあります。

-----^ FILT_PA4.ICN ( date:97-12-14 time:23:21 ) -----------<cut here
####################
# filter programの雛形
####################
# 1行データ処理 procedureから呼んで AWK風 filter programを作成する
# filt_patに、AWKにならって、FNR,ARGS,FILENAME,BEGIN,END を追加したもの。
# filt_pa4.icn  Rev.02 1997/12/14 windy AWK風 global変数を追加
# filt_pa4.icn  Rev.01 1997/12/02 windy 風つかい H.S.
# arg   : ARGS      : command line引数を引き継ぐ
#                     ARGS[1]は input.file名 と想定
#                     wild cardsは未対応
#         filt_proc : filter programの1行文処理 procedure
#         Usage_main: "Usage: 実行file名 " に引き続く message
#         out_ext   : output.fileの拡張子名(指定しなければ標準出力)
#         in_ext    : input.fileの拡張子名
#         neg       : input.fileの拡張子名チェックを反転
# This file is in the public domain.
global FNR, ARGS, FILENAME, BEGIN, END
link string_e,  # pre_char #入門講座4 Icon迷い道(5)参照
     file_e     # f_name   #入門講座4 Icon回り道(4)の exe_nameと同じもの
                # check_ext  #入門講座4 Icon迷い道(6)参照

procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg)
  /Usage_main := "input.file"
  Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成
  if *ARGS > 0 then {
    if ARGS[1] == ("/?" | "-?") then stop(Usage)             # Usage出力
    else {
      FILENAME := map(ARGS[1])       # 第1引数を input.file名とみなす
      if \in_ext then {              # 入力拡張子指定があれば、
        # input.fileの拡張子チェック
        check_ext(in_ext,FILENAME,neg) |
                      stop("input.file name error : ",FILENAME)
      }
      # input.file open
      in_dir := open(FILENAME) |
                      stop("cannot open input.file : ",FILENAME) 

      if \out_ext then {      # 出力拡張子指定があれば、
        out_ext  := map(out_ext)
        line_no  := 0                # 行No  動作状態 monitor用
        # output.file open
        # output.file名作成
        f_new := (pre_char(FILENAME) || "." || out_ext)
        out_dir := open(f_new,"a") | {  # append modeで open
                     close(in_dir)
                     stop("cannot open output.file : ",f_new)
                   }
        write(&errout,FILENAME," -> ",f_new)      # 動作モニター
      }
    }
  }
  ##################
  # BEGIN 節
  ##################
  if \BEGIN then BEGIN()             # BEGINが存在すれば、BEGIN()を実行

  ##################
  # MAIN
  ##################
  # 1行づつ input.fileから読み込んで、指定 procedureで処理をして
  # output.fileに書き出す。
  FNR := 0
  while line := read(in_dir) do {    # ある行で、filt_procが失敗しても残り
    FNR +:= 1                        # の行の処理が行われるように、いったん
    if (\out_ext & (*ARGS >0))       # 行を lineにセット。
    then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示
    write(out_dir,filt_proc(line))   # filt_procが失敗してもこの行だけ失敗
  }
  if (\out_ext & (*ARGS >0)) then {
    close(in_dir)            # input.file close
    close(out_dir)           # output.file close
    write(&errout)           # monitor表示 カーサー戻し
  }

  ##################
  # END 節
  ##################
  if \END then END()                 # ENDが存在すれば、END()を実行

end
-----$ FILT_PA4.ICN ( lines:80 words:307 ) -----------------<cut here

  サンプル programです。指定 fileの先頭20行に、行番号を付加して出力
するものです。
-----^ TEST406E.ICN ( date:97-12-15 time:00:49 ) -----------<cut here
####################
# filt_pa4 の Test program
####################
# 入力ファイルの行頭に行番号を付けて出力する program
# test406e.icn Rev.01 1997/12/14 windy 風つかい H.S.
# This file is in the public domain.
link filt_pa4

procedure main(ARGS)
  filt_pat(ARGS,add_no)
  # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg
  # ARGS, FNR, FILENAME, BEGIN, END は global変数(filt_pa4にて宣言)
end

####################
# BEGIN 節
####################
procedure BEGIN()
  # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は
  # global宣言すること。
  write(&errout,"始めで〜す。")
  write("----- ",FILENAME)
end

####################
# 1行毎の処理 (filt_patの1行読込み毎に呼ばれる)
####################
# FNR は、行番号
# 5行おきに4桁の行番号、それ以外は行番号の1位を付加
# 20行迄
procedure add_no(line)
  if FNR > 20 then return &fail
#  if FNR > 20 then return      # これだと、20行以降は空行出力となる。
  return ( if (FNR % 5) =0 then right(FNR,4)
                           else "   "        || FNR[-1]  ) || " " || line
end

####################
# END 節
####################
procedure END()
  # 終了処理(例:総計出力とか)、終了メッセージ出力などを行う。
  write("-----")
  write(&errout,"終わりで〜す。")
end
-----$ TEST406E.ICN ( lines:45 words:127 ) -----------------<cut here

  動きがちょっとメンドイので、test406eと filt_pa4の関係を図にしておきます。

      (用途に応じて作成)                       (汎用 procedure)
     - test406e -----------                -- filt_pa4 -----------
    |  main()              |              |                       |
    |    filter procを呼ぶ |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |                      |              |   filt_pat()          |
    |                      |              |     入出力 file open  |
    |                      |              |     入力 file1行読込み|
    | -------------------- |              |                       |
    |  開始 proc     <--------<-------<---------- 開始処理 procを |
    |  BEGIN()             |              |       を呼ぶ          |
    |        ----------------->------->---------->                |
    | -------------------- |              |                       |
    |  1行処理 proc  <--------<-------<---------- 1行処理  procを |
    |  add_no()            |              |       を呼ぶ          |
    |        ----------------->------->---------->                |
    |                      |              |     出力 fileへ書出し |
    |                      |              |    (file末尾迄 繰返し)|
    | -------------------- |              |                       |
    |  終了 proc     <--------<-------<---------- 終了処理 procを |
    |  END()               |              |       を呼ぶ          |
    |        ----------------->------->---------->                |
    |                      |              |     入出力 file close |
     ----------------------                -----------------------

  test406e test406e.icn > test406e とした時の結果です。

-----^ TEST406E ( date:97-12-15 time:00:49 ) ---------------<cut here
----- test406e.icn
   1 ####################
   2 # filt_pa4 の Test program
   3 ####################
   4 # 入力ファイルの行頭に行番号を付けて出力する program
   5 # test406e.icn Rev.01 1997/12/14 windy 風つかい H.S.
   6 # This file is in the public domain.
   7 link filt_pa4
   8 
   9 procedure main(ARGS)
  10   filt_pat(ARGS,add_no)
   1   # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg
   2   # ARGS, FNR, FILENAME, BEGIN, END は global変数(filt_pa4にて宣言)
   3 end
   4 
  15 ####################
   6 # BEGIN 節
   7 ####################
   8 procedure BEGIN()
   9   # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は
  20   # global宣言すること。
-----
-----$ TEST406E ( lines:22 words:83 ) ----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: A&M Songs of Burt Bacharack
BGD: あんず酒
(icon406.txt 1997/12/15 PCVAN PIG)

■  Icon > Icon土日夜(7) AWK風 program(2)      風つかい      目次

  今回も AWK風 programの続きです。 前回のものに更に、定義 fileの読み込み処理
を追加してみました。

  時々使っている programを題材にします。  表形式の text dataを、ちょっとだけ
いじりたい時に使います。  1文字分印刷の際にはみ出るので spaceを削ろうとか、
欄の間が狭いので、1文字分だけ spaceを追加しようというような場合です。

  こんな定義 fileを使います。
-----^ FORMAT.INI ( date:97-12-15 time:23:56 ) -------------<cut here
# 【format処理定義】
# d  削除文字
# m  出力時、前にスペースを入れる
# a  出力時、後にスペースを入れる
# 【処理サンプル】
#  d  d  m  dm  da  md ma  ad am  ddd
#abcdefghijklmnopqrstuvwxyz0123456abcde     <- 使用前
#abdegh ijk mnoq rs tv wx yz0 23  456de     <- 使用後
sam=  d  d  m  dm  da  md ma  ad am  ddd
   #abcdefghijklmnopqrstuvwxyz0123456abcde
dat=     ddd   a   a          dd     mmm
-----$ FORMAT.INI ( lines:11 words:56 ) --------------------<cut here

  で、programです。やっていることは、入門講座4の TB2CSVをほぼ同じです。
定義 fileの読み込みは filter雛形 procedureの方でやって、こちらで解析し
ています。
-----^ FORMAT.ICN ( date:97-12-16 time:00:32 ) -------------<cut here
####################
# 表形式データ整形
####################
# 表形式 text dataの欄を整形する。1字分 spaceを追加したり、データの1部
# を削除するもの。
# 【処理定義】 format.iniにて。
# d  削除文字
# m  出力時、前にスペースを入れる
# a  出力時、後にスペースを入れる
# 【処理サンプル】
#  d  d  m  dm  da  md ma  ad am  ddd
#abcdefghijklmnopqrstuvwxyz0123456abcde     <- 使用前
#abdegh ijk mnoq rs tv wx yz0 23  456de     <- 使用後
# 
# format.icn Rev.01 97/12/15 windy filter procedureを使用
# form.icn   Rev.01 96/09/23 windy 風つかい H.S.
# This file is in the public domain.
global form
link string_e,  # cp_split        # Icon入門講座4 Icon迷い道(8)参照
     file_e,    # key_check       # Icon入門講座4 Icon迷い道(3)参照
     filt_pa5

procedure main(ARGS)
  filt_pat(ARGS,format2)
  # 引数 : ARGS, filt_proc, Usage_main, out_ext, in_ext, neg
  # ARGS, FNR, FILENAME, BEGIN, END, INI は global変数(filt_pa5にて宣言)
end

####################
# BEGIN 節
####################
procedure BEGIN()
  # 開始メッセージ出力、初期設定などを行う。 filt_patで使う変数は
  # global宣言すること。
  \INI | stop("no .INI file")     # <-INIが無ければエラー
  form  := cp_split(key_check(INI,FILENAME)) | stop("no format data")
         # ↑      #↑ 入力ファイルの名前の先頭で、  # ↑該当指定無し
         # |      # INIファイルのどの指定を使うか判断する。
         # |data変換指定を listへ変換
  # 例
  #    0000000001111111111222222222233333333
  #    1234567890123456789012345678901234567
  #sam=  d  d  m  dm  da  md ma  ad am  ddd   <- こういうデータを、
  #[["d",3,6],["d",6,9],["m",9,12],["d",12,13],...["d",36,37]] へ変換する。

  return
end

####################
# 1行毎の処理 (filt_patの1行読込み毎に呼ばれる)
####################
procedure format2(line)
  s := ""                  # 戻り値
  line ? {                 # lineを走査対象として
    every L := !form do {  # formから処理指定を順に取り出して
      case L[1] of {       # 処理種別にて
        "d" : { s ||:=  tab(L[2]) ;  move(1)         } # 1文字削除
        "m" : { s ||:= (tab(L[2]) || " " || move(1)) } # その前に " "追加
        "a" : { s ||:= (tab(L[2]) || move(1) || " ") } # その後に " "追加
        default : stop(".INI error")
      }
    }
    return s ||:= tab(0)   # 残りを足しこむ
  }
end
-----$ FORMAT.ICN ( lines:65 words:261 ) -------------------<cut here

  長くなりますので、残りは、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: シルエット・ロマンス/ゼロ
(icon407.txt 1997/12/16 PCVAN PIG)

■  Icon > Icon土日夜(8) AWK風 program(3)      風つかい      目次

  今回も AWK風 programの続きです。定義 fileの読み込み対応の filter雛形
procedureです。

-----^ FILT_PA5.ICN ( date:97-12-16 time:00:28 ) -----------<cut here
####################
# filter programの雛形
####################
# 1行データ処理 procedureから呼んで AWK風 filter programを作成する
# 
# filt_patに、AWKにならって、FNR,ARGS,FILENAME,BEGIN,END を追加し、
#             定義 file読み込み処理を追加
# filt_pa5.icn  Rev.01 1997/12/15 windy 風つかい H.S.
# arg   : ARGS      : command line引数を引き継ぐ
#                     ARGS[1]は input.file名 と想定
#                     wild cardsは未対応
#         filt_proc : filter programの1行文処理 procedure
#         Usage_main: "Usage: 実行file名 " に引き続く message
#         out_ext   : output.fileの拡張子名(指定しなければ標準出力)
#         in_ext    : input.fileの拡張子名
#         neg       : input.fileの拡張子名チェックを反転
# This file is in the public domain.
global FNR, ARGS, FILENAME, BEGIN, END, INI
link string_e, # pre_char #入門講座4 Icon迷い道(5)参照
     file_e    # f_name   #入門講座4 Icon回り道(4)の exe_nameと同じ
               # get_inil, check_ext # 入門講座4 Icon迷い道(6)参照

procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg)
  /Usage_main := "input.file"
  Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成
  if *ARGS > 0 then {
    if ARGS[1] == ("/?" | "-?") then stop(Usage)             # Usage出力
    else {
      FILENAME := map(ARGS[1])       # 第1引数を input.file名とみなす
      if \in_ext then {              # 入力拡張子指定があれば、
        # input.fileの拡張子チェック
        check_ext(in_ext,FILENAME,neg) |
                      stop("input.file name error : ",FILENAME)
      }
      # input.file open
      in_dir := open(FILENAME) |
                      stop("cannot open input.file : ",FILENAME) 

      if \out_ext then {      # 出力拡張子指定があれば、
        out_ext  := map(out_ext)
        line_no  := 0                # 行No  動作状態 monitor用
        # output.file open
        # output.file名作成
        f_new := (pre_char(FILENAME) || "." || out_ext)
        out_dir := open(f_new,"a") | {  # append modeで open
                     close(in_dir)
                     stop("cannot open output.file : ",f_new)
                   }
        write(&errout,FILENAME," -> ",f_new)      # 動作モニター
      }
    }
  }

  # config file読み込み
  INI := get_inil("INI") # list
  # テキスト変換指定

  ##################
  # BEGIN 節
  ##################
  if \BEGIN then BEGIN()             # BEGINが存在すれば、BEGIN()を実行

  ##################
  # MAIN
  ##################
  # 1行づつ input.fileから読み込んで、指定 procedureで処理をして
  # output.fileに書き出す。
  FNR := 0
  while line := read(in_dir) do {    # ある行で、filt_procが失敗しても残り
    FNR +:= 1                        # の行の処理が行われるように、いったん
    if (\out_ext & (*ARGS >0))       # 行を lineにセット。
    then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示
    write(out_dir,filt_proc(line))   # filt_procが失敗してもこの行だけ失敗
  }
  if (\out_ext & (*ARGS >0)) then {
    close(in_dir)            # input.file close
    close(out_dir)           # output.file close
    write(&errout)           # monitor表示 カーサー戻し
  }

  ##################
  # END 節
  ##################
  if \END then END()                 # ENDが存在すれば、END()を実行

end
-----$ FILT_PA5.ICN ( lines:86 words:317 ) -----------------<cut here

  処理例です。こういう fileを formatに食わせますと、
-----^ SAMPLE.TXT ( date:97-12-15 time:23:53 ) -------------<cut here
abcdefghijklmnopqrstuvwxyz0123456abcde
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456
-----$ SAMPLE.TXT ( lines:2 words:2 ) ----------------------<cut here

  こういう dataへ変換されます。
-----^ SAMPLE ( date:97-12-16 time:20:07 ) -----------------<cut here
abdegh ijk mnoq rs tv wx yz0 23  456de
ABDEGH IJK MNOQ RS TV WX YZ0 23  456
-----$ SAMPLE ( lines:2 words:18 ) -------------------------<cut here

  処理定義を変えた例です。
-----^ DATA.TXT ( date:97-12-16 time:20:08 ) ---------------<cut here
abcdefghijklmnopqrstuvwxyz0123456abcde
ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456
-----$ DATA.TXT ( lines:2 words:2 ) ------------------------<cut here

  結果は、こうなります。
-----^ DATA ( date:97-12-16 time:20:08 ) -------------------<cut here
abcdeijkl mnop qrstuvwxyz23456 a b cde
ABCDEIJKL MNOP QRSTUVWXYZ23456
-----$ DATA ( lines:2 words:9 ) ----------------------------<cut here

  さて、次回は、wild cards file指定対応に してみたいと 思います。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: シルエット・ロマンス/ゼロ
(icon408.txt 1997/12/16 PCVAN PIG)

■  Icon > Icon土日夜(9) AWK風 program(4)      風つかい      目次

  さて、いよいよ、AWK風 programの最後(の予定)の wild cards対応 です。
  AWKでは、file指定に wild cards 指定ができます。 wild cards対応の
procedureとしては、Icon入門講座(16)で、wild.icnを紹介しています。
  また、Icon入門講座4の(6)あたりでその修正をしています。これを使えば、
まあ、wild cards対応が できる ハズ です。

  もう1つやりたいことがあります。AWKの wild cards 指定を使っている時に、
ここは、AWKには、合わないのかな〜? という点がありました。

  wild cards指定して、複数 fileの処理をやっていて、ある fileの処理が終わ
った時点ですぐ、特定の処理をしたいと言う場合に、
  個々の fileの末尾が、直接には検出できませんので、細工が必要です。
    ・FILENAMEが変わったら  とか
    ・FNRが1になったら     とかで、
  次の file処理に入ったので、前の file末尾を過ぎた。
と判断するか、
    ・AWKの自動行読み込み を使わず、自前で getline()で読み込んで、失敗し
      たら fileの末尾だ。
てなことをやっていました。

  これは、AWKに file毎の BEGIN, ENDという機能が盛り込んで無いので、仕方が
ないのです。 この辺のところが、私が AWK以外でもっと色んなことができる言語
が無いかと 探し始めた発端です。  そして、Iconのたどり着いた訳です。

  せっかく、Iconで AWK風 programの雛形 を作ろうというのですから、  入れて
みたい思います。
  盛り込むとなれば、file毎の BEGIN, ENDを作れば良いのですから、FBEGINとか
FENDとかをサポートすれば良い訳です。

  という訳で、作りました。  まず、sample programです。 text fileを読み込ん
で、行毎に、file毎の行番号と file通しの行番号を、付加して出力します。
-----^ TEST409.ICN ( date:97-12-19 time:22:10 ) ------------<cut here
####################
# filt_pa6 の Test program
####################
# 入力ファイルの行頭に行番号を付けるだけの program
# test409.icn Rev.01 1997/12/19 windy 風つかい H.S.
# This file is in the public domain.
link filt_pa6,  # filt_pat  # filter雛形
     string_e   # top_cut   # Icon入門講座2 (5)参照

procedure main(ARGS)
                            #↓何かをセットすれば良い。"" でも良い。
  filt_pat(ARGS,add_no,,,,,"f_sort")
  # 引数 : AARGS,filt_proc,Usage,out_ext,in_ext,neg,f_sort
end

####################
# BEGIN
####################
procedure BEGIN()
  write("始めで〜す。")
end

####################
# FBEGIN
####################
procedure FBEGIN()
  #     ↓ FILENAMEが存在しないとき(標準入力の場合)は fail
  write(\FILENAME ? top_cut('\\')," の始めだよ。") 
                  # ↑directory削除
end

####################
# 各行に関する処理 (filt_patから1行読込み毎に呼ばれる)
####################
# FNR は、行番号(global)
procedure add_no(line)
  return  right(NR,2) || " " || right(FNR,2) || " " || line  # 行番号を付加
end

####################
# FEND
####################
procedure FEND()
  write(\FILENAME ? top_cut('\\')," の終わりだよ。") 
end

####################
# END
####################
procedure END()
  write("終わりで〜す。")
end
-----$ TEST409.ICN ( lines:52 words:116 ) ------------------<cut here

  sample dataです。
-----^ TEST409A.DAT ( date:97-12-18 time:23:06 ) -----------<cut here
The
Icon
Programming
Language
-----$ TEST409A.DAT ( lines:4 words:4 ) --------------------<cut here

-----^ TEST409B.DAT ( date:97-12-18 time:23:07 ) -----------<cut here
THE
ICON
PROGRAMMING
LANGUAGE
-----$ TEST409B.DAT ( lines:4 words:4 ) --------------------<cut here

  test409 test409b.dat test.409a.dat と実行しますと、結果は次のように
なります。
-----^ TEST409 ( date:97-12-19 time:22:52 ) ----------------<cut here
始めで〜す。
test409a.dat の始めだよ。
 1  1 The
 2  2 Icon
 3  3 Programming
 4  4 Language
test409a.dat の終わりだよ。
test409b.dat の始めだよ。
 5  1 THE
 6  2 ICON
 7  3 PROGRAMMING
 8  4 LANGUAGE
test409b.dat の終わりだよ。
終わりで〜す。
-----$ TEST409 ( lines:14 words:34 ) -----------------------<cut here

  複数 file指定をした場合には、file名順に sortしてから処理を始めています。
  雛形 procedureは、次回にやります。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Memphis Underground / Herbie Mann
BGD: Jasmine Tea
(icon409.txt 1997/12/19 PCVAN PIG)

■  Icon > Icon土日夜(10) AWK風 program(5)    風つかい      目次

  さて、wild cards指定可能な filter programの雛形 procedureの続きです。
  file指定がある場合は wild cards指定の展開を行います。 無い場合(標準
入力)と処理が大分異なるため、filt_pat を、分割しています。
-----^ FILT_PA6.ICN ( date:97-12-19 time:22:07 ) -----------<cut here
####################
# filter programの雛形
####################
# 1行データ処理 procedureから呼んで AWK風 filter programを作成する
# AWKにならって、FNR,ARGS,FILENAME,BEGIN,END,NR を global変数に持つ。
# 定義 file読み込み処理付き。wild cards対応。
# file毎の BEGIN,ENDサポート。(FBEGIN,FEND)
# filt_pa6.icn  Rev.02 1997/12/19 windy file名 sort機能追加
# filt_pa6.icn  Rev.01 1997/12/18 windy 風つかい H.S.
# arg   : ARGS      : command line引数を引き継ぐ
#                     file名指定とみなす。 file名以外の引数が必要なら
#                     先頭に置いて、BEGIN節で処理し、削除しておくこと。
#         filt_proc : filter programの1行文処理 procedure
#         Usage_main: "Usage: 実行file名 " に引き続く message
#         out_ext   : output.fileの拡張子名(指定しなければ標準出力)
#         in_ext    : input.fileの拡張子名
#         neg       : input.fileの拡張子名チェックを反転
#         f_sort    : wild cardsを展開した file名を sortする場合 セット
# This file is in the public domain.
global FNR, ARGS, FILENAME, BEGIN, END, INI, NR, FBEGIN, FEND
link string_e, # pre_char #入門講座4 Icon迷い道(5)参照
     file_e    # f_name   #入門講座4 Icon回り道(4)の exe_nameと同じ
               # get_inil, check_ext #入門講座4 Icon迷い道(6)参照
               # wild     #入門講座(16), Icon入門講座4(6)参照

procedure filt_pat(ARGS,filt_proc,Usage_main,out_ext,in_ext,neg,f_sort)
  /Usage_main := "input.file"
  Usage := ("Usage: " || map(f_name()) || " " || Usage_main) # Usage作成

  # .INI file読み込み
  INI := get_inil("INI") # list

  # Usage 処理
  if ARGS[1] == ("/?" | "-?") then stop(Usage)             # Usage出力

  NR := 0                        # 累積行数
  ##################
  # BEGIN 節  programの最初に1回実行
  ##################
  if \BEGIN then BEGIN()         # BEGINが存在すれば、BEGIN()を実行

  if *ARGS > 0 then {            # 引数あり (= file 指定あり)
    # file指定解析
    L := wild(ARGS) | stop(Usage)    # wild cards指示 -> file名 list
    L := if \f_sort then sortf(L,1)  # file名 sort指示があれば
    every LL := !L do {          # 全ての fileについて
      FILENAME := map(LL[1])     # input.file名
      filt_pat2(FILENAME,filt_proc,out_ext,in_ext,neg)
    } # end of every
  } # end of then
  # file指定無し
  else {                         # 標準入力
    filt_pat3(FILENAME,filt_proc,out_ext,in_ext,neg)
  } # end of else

  ##################
  # END 節  programの最後に1回実行
  ##################
  if \END then END()                 # ENDが存在すれば、END()を実行

  return
end


####################
# file指定がある場合の file毎の処理
####################
procedure filt_pat2(FILENAME,filt_proc,out_ext,in_ext,neg)
  if \in_ext then {          # 入力拡張子指定があれば、
    # input.fileの拡張子チェック
      check_ext(in_ext,FILENAME,neg) |
               stop("input.file name error : ",FILENAME)
  }
  # input.file open
  in_dir := open(FILENAME) |
              stop("cannot open input.file : ",FILENAME) 
  if \out_ext then {      # 出力拡張子指定があれば、
    out_ext  := map(out_ext)
    line_no  := 0                # 行No  動作状態 monitor用
    # output.file open
    # output.file名作成
    f_new := (pre_char(FILENAME) || "." || out_ext)
    out_dir := open(f_new,"a") | {  # append modeで open
      close(in_dir)
      stop("cannot open output.file : ",f_new)
    }
    write(&errout,FILENAME," -> ",f_new)      # 動作モニター
  }
  filt_pat3(FILENAME,filt_proc,out_ext,in_dir,out_dir)

  if \out_ext  then {
    close(in_dir)            # input.file close
    close(out_dir)           # output.file close
    write(&errout)           # monitor表示 カーサー戻し
  }

  return
end


####################
# file毎の処理
####################
procedure filt_pat3(FILENAME,filt_proc,out_ext,in_dir,out_dir)
  FNR := 0                   # file毎の 行数
  ##################
  # FBEGIN 節  fileの最初に1回実行
  ##################
  if \FBEGIN then FBEGIN()   # FBEGINが存在すれば、FBEGIN()を実行

  ##################
  # MAIN
  ##################
  # 1行づつ input.fileから読み込んで、指定 procedureで処理をして
  # output.fileに書き出す。
  while line := read(in_dir) do {
    FNR +:= 1  ; NR +:= 1
    if (\out_ext & (*ARGS >0))       # 行を lineにセット。
    then writes(&errout," ",right(FNR +:= 1,4)) # monitor表示
    write(out_dir,filt_proc(line))
  }

  ##################
  # FEND 節  fileの最後に来る度に実行
  ##################
  if \FEND then FEND()       # FENDが存在すれば、FEND()を実行

return

end
-----$ FILT_PA6.ICN ( lines:130 words:443 ) ----------------<cut here

  と、いうところで、AWK風 programの説明は、おしまいにします。後、1回
位、応用 programを説明するかも知れません。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Memphis Underground / Herbie Mann
BGD: Jasmine Tea
(icon410.txt 1997/12/19 PCVAN PIG)

■  Icon > Icon土日夜(11) AWK風 program(6)    風つかい      目次

  あったかい日が続いていましたが、急に寒くなりました。ブルブル。こういう日
には、おうちで Iconしましょう。
  AWK風 programの続きです。今回も、表形式 dataの加工です。 表形式 dataの
一部の項目を、別の変換表を使って 置換したいことが、時々あります。 そんな
時に使うものです。

  まず、いつものように、定義 fileから紹介しましょう。
-----^ CONV_TB.INI ( date:97-12-23 time:18:17 ) ------------<cut here
####################
# 変換処理定義
####################
# 先頭に "#"があれば comment行

# 変換 指定(同一文字が続く部分を変換 blockとみなす。)
# a,b,c...は、異なった文字なら何でも差し支え無い。
$0=aaaa  bbbbbb    ccc

# 変換 data file名 データ種別(s:文字列,n:数字列)・桁数
# 文字列と数字列は、左つめされるか右つめされるかの違い。
# $0,$1,$2,..は、異なった文字(列)なら何でも差し支え無い。
# $1,$2,$3,..は、順に変換 blockに対応していく。
$1=conv_tb1.dat s10
$2=conv_tb2.dat s8
$3=conv_tb3.dat s4

#aaaa  bbbbbb    ccc             <- こういう指定をすると
#ABCDef123456ghijYOK             <- 使用前
#あいうえおef株式会社ghij横浜    <- 使用後

# conv_tb1.dat
# #key data
# ABCD あいうえお
# EFGH かきくけこ

# conv_tb2.dat
# #key   data
# 123456 株式会社
# 123457 有限会社

# conv_tb3.dat
# #key data
# YOK 横浜
# TYO 東京
-----$ CONV_TB.INI ( lines:35 words:79 ) -------------------<cut here

  $0の部分で、変換する部分を指定します。 この例では、3箇所を変換します。
  $1,$2,$3 の部分で、変換 table file名と、その属性(文字列か数字列かと桁数)
を指定しています。

  さて、2つ程、procedureを作ります。
    ・cs_split : 変換指定文字列を、扱いやすく listにするもの。
    ・read_stb : 変換 table fileを読み込んで、tableに格納するもの。

  では、cs_splitから、早速 programです。 procedureと その test programが
含まれています。 なんとか splitという名前の procedureを 幾つか作っていま
すが、同じ様で少しづつ違った処理です。
  また、文字列出力が見易くなるように、目盛りを出力する procedureも作って
みました。

-----^ CS_SPLIT.ICN ( date:97-12-23 time:22:29 ) -----------<cut here
####################
# cs_split の test program
####################
# cs_split.icn Rev.01 1997/12/23 windy 風つかい H.S.
# This file is in the public domain.
link struct_e    # show_wl  Icon入門講座(10)参照

procedure main()
  s :=   "aaaa  bbbbbb    ccc"   # 置換指定の sample
  scale(*s +1)                   # 目盛り
  write(s)                       # sample文字列
  show_wl(cs_split(s))           # cs_splitした結果の2重 list表示

  s :=   " aaaa  bbb bbb ccc "   # 参考
  scale(*s +1)
  write(s)
  show_wl(cs_split(s))

  s :=   " "                     # 指定文字無し だと、どうなるかな。
  scale(*s +1)
  write(s)

  s :=   ""                      # 空文字列 だと、どうなるかな。
  scale(*s +1)
  write(s)
end


####################
# 文字列処理指定の文字列を解析
####################
# 処理指定 英文字1文字
# args : s : string 指定文字列
#        c : cset   指定しない部分に対応する文字
# value: 2重 list(処理指定を順に詰めたもの)
#        [1]:指定文字, [2]:開始位置, [3]:次の指定文字の開始位置
# 指定例   00000000011111111112
#          12345678901234567890
# s1 :=   "ABCDef123456ghijYOK"
# s2 :=   "aaaa  bbbbbb    ccc"
# s2を    [["a",1,5],["d",7,13],["c",17,20]] と変換する。
# 備考 : 表データの一部を置換するプログラムのために作成。上の例の用に、
#        データ例と並べて指定が可能なプログラムにするため

procedure cs_split(s,c)
  /s  := &subject                   # default
  /c  := ' '                        # default -> ' '
  L   := []                         # 戻り値用 list
  s ? {
    while tab(ps := upto(~c)) do {  # c以外のの文字まで skip
      cc := move(1)                 # その文字を記憶
      tab(pe := many(cc))           # その文字以外の文字迄 skip
      put(L,[cc,ps,pe])             # 文字、開始位置、次の文字の開始位置
                                    # を list に追加
    }
  }
  return L
end


####################
# 文字列の目盛り
####################
# 文字列
procedure scale(n)
  s1 :=  "00000000011111111112222222222333333333344444444445555555555" ||
        "66666666667777777777"
  s2 :=  "12345678901234567890123456789012345678901234567890123456789" ||
        "01234567890123456789"
  write(left(s1,n))
  write(left(s2,n))
  return
end
-----$ CS_SPLIT.ICN ( lines:73 words:213 ) -----------------<cut here

  走らせた結果は、次のようになります。
-----^ CS_SPLIT ( date:97-12-23 time:11:01 ) ---------------<cut here
00000000011111111112
12345678901234567890
aaaa  bbbbbb    ccc
 a 1 5
 b 7 13
 c 17 20

00000000011111111112
12345678901234567890
 aaaa  bbb bbb ccc 
 a 2 6
 b 8 11
 b 12 15
 c 16 19

00
12
 
0
1

-----$ CS_SPLIT ( lines:21 words:36 ) ----------------------<cut here

  続きは、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Gently / 辛島美登里
BGD: Jasmine Tea
(icon411.txt 1997/12/23 PCVAN PIG)

■  Icon > Icon土日夜(12) AWK風 program(7)    風つかい      目次

  さて、もう1つの procedureです。 変換 table fileを読み込んで、tableに
格納するものです。
  次のような 3つの fileを読みこむものとします。

-----^ CONV_TB1.DAT ( date:97-12-23 time:15:40 ) -----------<cut here
#key data
ABCD あいうえお
EFGH かきくけこ
-----$ CONV_TB1.DAT ( lines:3 words:6 ) --------------------<cut here

-----^ CONV_TB2.DAT ( date:97-12-23 time:15:38 ) -----------<cut here
#key   data
123456 株式会社
123457 有限会社
-----$ CONV_TB2.DAT ( lines:3 words:6 ) --------------------<cut here

-----^ CONV_TB3.DAT ( date:97-12-23 time:15:32 ) -----------<cut here
#key data
YOK 横浜 Yokohama
TYO 東京 Tokyo
-----$ CONV_TB3.DAT ( lines:3 words:8 ) --------------------<cut here

  表 dataの読み込み procedureと その test programです。
  read_stbは、行を読み込んで、listに変換し、tableに格納します。
  その際、行を読み込んだ直後と、行を listに変換した後に、別の procedureを
呼んで dataを加工できるようにしています。  方式は、filt_patで、使ったもの
と同じです。

-----^ READ_STB.ICN ( date:97-12-23 time:22:39 ) -----------<cut here
####################
# read_stb.icn の test program
####################
# read_stb.icn 1997/12/23 windy 風つかい H.S.
# This file is in the public domain.
link string_e, # split  # Icon入門講座(7)、Icon入門講座3(1)参照
     struct_e  # tree_x # Icon入門講座3(17)、Icon入門講座4(1)の
                        # x2tを使い、every write(x2t(x))とした procedure

procedure main()
  L := []
  # tableを読み込んで、順に listに格納
  put(L,read_stb("conv_tb1.dat"),
        read_stb("conv_tb2.dat",,,test411b),
        read_stb("conv_tb3.dat",,test411a),
        read_stb("conv_tb3.dat",,,test411c)
     )
  tree_x(L)             # 構造体 tree表示
end


#####################
# 変換 table読み込み
#####################
# arg      : [1]: string file name to read
#            [2]: 読み込み時の欄区切り文字
#            [3]: 読み込み時の 行毎処理 procedure(事前処理)
#            [4]: 読み込み時の 行毎処理 procedure(listに変換後処理)
# value    : table : key:column1 -> value:column2
# function : 指定の file(表形式 data)を読み込んで、tableを作成
#            欄の先頭を keyとして、次を valueにして tableへ格納
#            read_proc1が指定されていなければ、行頭が "#"なら、comment行
#            として読み飛ばす。

procedure read_stb(f_name,c,read_proc1,read_proc2)
  dir := open(f_name) | stop("cannot open ",fname)  # file読み込み
  T := table()                                 # table生成
  /c := ' \t'                                  # default
  while s := read(dir) do {                    # file読み込み
    if /read_proc1 then {                      # 行毎処理指定が無ければ、
      s ?  if match("#") then next             # comment行読み飛ばし
    }
    if \read_proc1 then  s := read_proc1(s) | next  # 行毎処理指定があれば
                                                    # それを実行。
    s ? {
      L := split(s,c)                          # 行を cで、listに分割
      if \read_proc2 then {                    # 行毎処理指定があれば、
        L := read_proc2(L) | next              # その処理を行う。
      }
      insert(T,L[1],L[2])                      # tableへ格納
    }  # end of s
  }  # end of while
  close(dir)
  return T
end


# read_proc1の sample
procedure test411a(s)
  return s ? if match("#") then return &fail   # comment行読み飛ばし
                           else s || " Test"
end


# read_proc2の sample
procedure test411b(L)
  L[1] -:= 123000       # 1番目の要素から 12300引く
return L
end

# read_proc2の sample
procedure test411c(L)
  L[2] := [L[2:0]]      # listの2番目以降を、listにして 2番目に入れる。
return L
end

-----$ READ_STB.ICN ( lines:76 words:251 ) -----------------<cut here


  動きを図にすると、次のようになります。

  (1)  conv_tb1.dat読込み                      (汎用 procedure)
     - main() -------------                -- read_stb -----------
    |  main()              |              |                       |
    |    conv_tb1.dat読込  |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |    table入手   <--------<---        |   read_mtb()          |
    |    list Lに格納      |      |       |     1行読込み        |
    |                      |      |       |     行毎処理(事前)    |
    |                      |      |       |       read_proc1を    |
    |                      |      |       |       呼ぶ(指定無し)  |
    |                      |      |       |     listへ分解        |
    |                      |      |       |     行毎処理(事後)    |
    |                      |      |       |       read_proc2を    |
    |                      |      |       |       呼ぶ(指定無し)  |
    |                      |      |       |     tableへ格納       |
    |                      |       ---<------- (file末尾迄 繰返し)|
    |                      |              |                       |
     ----------------------                -----------------------

  (2)  conv_tb2.dat読込み                      (汎用 procedure)
     - main() -------------                -- read_stb -----------
    |  main()              |              |                       |
    |    conv_tb2.dat読込  |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |    table入手   <--------<---        |   read_mtb()          |
    |    list Lに格納      |      |       |     1行読込み        |
    |                      |      |       |     行毎処理(事前)    |
     ----------------------       |       |       read_proc1を    |
                                  |       |       呼ぶ(指定無し)  |
     - test411b -----------       |       |     listへ分解        |
    |                      |      |       |     行毎処理(事後)    |
    |  test411b()    <--------<-- | --<--------   read_proc2を    |
    |    data加工          |      |       |       呼ぶ            |
    |      ---------->-------->-- | -->----->   tableへ格納       |
    |                      |       ---<------- (file末尾迄 繰返し)|
    |                      |              |                       |
     ----------------------                -----------------------

  (3)  conv_tb3.dat読込み                      (汎用 procedure)
     - main() -------------                -- read_stb -----------
    |  main()              |              |                       |
    |    conv_tb3.dat読込  |              |                       |
    |      ---------->-------->------->-----> file読み込み        |
    |    table入手   <--------<---        |   read_mtb()          |
    |    list Lに格納      |      |       |     1行読込み        |
    |                      |      |       |     行毎処理(事前)    |
     ----------------------     - | --<--------   read_proc1を    |
                               /  |       |       呼ぶ            |
     - test411a -----------   / - | -------->   listへ分解        |
    |                      | / /  |       |     行毎処理(事後)    |
    |  test411a()    <------- /   |       |       read_proc2を    |
    |    data加工          | /    |       |       呼ぶ(指定無し)  |
    |      ---------->------      |       |     tableへ格納       |
    |                      |       ---<------- (file末尾迄 繰返し)|
    |                      |              |                       |
     ----------------------                -----------------------

  (4)  conv_tb3.dat読込み                      (汎用 procedure)
     - main() -------------                -- read_stb -----------
    |  main()              |              |                       |
    |    conv_tb3.dat読込  |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |    table入手   <--------<---        |   read_mtb()          |
    |    list Lに格納      |      |       |     1行読込み        |
    |                      |      |       |     行毎処理(事前)    |
     ----------------------       |       |       read_proc1を    |
                                  |       |       呼ぶ(指定無し)  |
     - test411c -----------       |       |     listへ分解        |
    |                      |      |       |     行毎処理(事後)    |
    |  test411c()    <--------<-- | --<--------   read_proc2を    |
    |    data加工          |      |       |       呼ぶ            |
    |      ------------------->-- | -->----->   tableへ格納       |
    |                      |       ---<------- (file末尾迄 繰返し)|
    |                      |              |                       |
     ----------------------                -----------------------

  走らせた結果です。  変換 tableは、更に1つの listに格納して、その状態
を表示しています。

-----^ READ_STB ( date:97-12-23 time:15:45 ) ---------------<cut here
<list 1>
 + <table 1>
 | + string "あいうえお" <- string "ABCD"
 | + string "かきくけこ" <- string "EFGH"
 + <table 2>
 | + string "有限会社" <- integer457
 | + string "株式会社" <- integer456
 + <table 3>
 | + string "東京" <- string "TYO"
 | + string "横浜" <- string "YOK"
 + <table 4>
   + <list 13> <- string "TYO"
   | + <list 12>
   |   + string "東京"
   |   + string "Tokyo"
   + <list 10> <- string "YOK"
     + <list 9>
       + string "横浜"
       + string "Yokohama"
-----$ READ_STB ( lines:19 words:87 ) ----------------------<cut here

  続きは、次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Gently / 辛島美登里
BGD: Jasmine Tea
(icon412.txt 1997/12/23 PCVAN PIG)

■  Icon > Icon土日夜(13) AWK風 program(8)    風つかい      目次

  さて、表形式 dataの一部の項目を、別の変換表を使って 置換する programの
まとめです。

  filter program作成の 雛形 procedureの filt_patを使って、まとめます。
  icon411は、cs_splitと read_stbが含まれる fileです。

-----^ CONV_TB.ICN ( date:97-12-23 time:22:57 ) ------------<cut here
####################
# 表形式 dataの一部を、別の表 data により置換する program
####################
# conv_tb.icn Rev.01 1997/12/23 windy 風つかい H.S.
# This file is in the public domain.
global PAT,          # 変換指示 list
       CONV_TB,      # 変換 tableが、順に入ってる list
       ATR,          # 変換 tableの、valueの属性・桁指定 list
       ERROR_DIR     # 変換 errorの行への tag jump用 fileの file handle
link file_e,   # get_inil # Icon入門講座4(13)
     struct_e, # tree_x   # Icon入門講座3(17)、Icon入門講座4(1)の
                          # every write(x2t(x)) だけの procedure
     filt_pa6, # filt_pat # filter 雛形 procedure
     icon411   # cs_split # 変換指定解析
               # read_stb # table file読み込み

####################
# filt_patを呼ぶための procedure
####################
procedure main(ARGS)        #↓何かをセットすれば良い。"" でも良い。
  filt_pat(ARGS,conv_tb,,,,,"f_sort")
  # 引数 : ARGS,filt_proc,Usage,out_ext,in_ext,neg,f_sort
end


####################
# 1行毎の処理 (filt_patの1行読込み毎に呼ばれる)
####################
# PAT, CONV_TB, ATRを全て、1つの listに入れると programは、スッキリする
# が、非常にわかりにくくなるのでやめ。
procedure conv_tb(line)
  s := ""                  # 戻り値
  line ? {                 # lineを走査対象として
    every i := 1 to *PAT do {  # ATRから 処理指定を 順に取り出して
      s ||:= tab(PAT[i][2])    # 変換部より前を sに 足しこみ
      ss  := tab(PAT[i][3])    # 変換対象文字列
      if member(CONV_TB[i],ss) then {  # tableの keyにあれば
        case ATR[i][1] of {    # 属性(文字列か、数字か)
          "s" : s ||:=  left(CONV_TB[i][ss],ATR[i][2:0])
          "n" : s ||:= right(CONV_TB[i][ss],ATR[i][2:0])
          default : stop(".INI error")
        }
      }
      else {
        s ||:= repl("?",ATR[i][2:0])       # 指定桁数分の "?"
        # error fileに書込み
        write(ERROR_DIR,FILENAME," ",FNR,": ",ss," ",line)
      }
    }
    return s ||:= tab(0)   # 残りを足しこむ
  }
end


procedure BEGIN()
  PAT := [] ; CONV_TB := [] ; ATR := [] # list生成
  #INI := get_inil("INI")    # 定義 file読み込み -> filt_patある
  get(INI)                   # "$0"読み飛ばし
  PAT := cs_split(get(INI))  # 処理指定を、cs_splitで処理して、PATへ代入
  while get(INI) do {        # "$1",...読み飛ばし。その後のみ使用
    get(INI) ? L := split()  # 変換 file指定と 属性指定を listへ
    put(CONV_TB,read_stb(L[1]))  # 変換 table fileを読み込み tableへ格納し
                                 # 更にその tableを list CONV_TBへ格納
    put(ATR,L[2])            # 変換 tableの属性を list ATRへ格納
  }
  # error log file を open
  ERROR_DIR := open(s := "error.log","w") | stop("cannot open ",s) # clear
  ERROR_DIR := open(s := "error.log","a") | stop("cannot open ",s)

  write("PAT")     ; tree_x(PAT)
  write("CONV_TB") ; tree_x(CONV_TB)
  write("ATR")     ; tree_x(ATR)
  write()
  return
end


procedure END()
  close(ERROR_DIR)           # error log file を close
  return
end
-----$ CONV_TB.ICN ( lines:81 words:312 ) ------------------<cut here

  こういう data fileを変換します。
-----^ TEST411.DAT ( date:97-12-23 time:18:02 ) ------------<cut here
ABCDef123456ghijYOK
EFGHef123457ghijTYO
ABCDef123458ghijXYZ
-----$ TEST411.DAT ( lines:3 words:3 ) ---------------------<cut here

  結果です。 結果出力の前に、変換情報が入っている list(PAT,CONV_TB,ATR)
の内容を書出しています。
-----^ CONV_TB ( date:97-12-23 time:18:27 ) ----------------<cut here
PAT
<list 6>
 + <list 7>
 | + string "a"
 | + integer1
 | + integer5
 + <list 8>
 | + string "b"
 | + integer7
 | + integer13
 + <list 9>
   + string "c"
   + integer17
   + integer20
CONV_TB
<list 4>
 + <table 1>
 | + string "あいうえお" <- string "ABCD"
 | + string "かきくけこ" <- string "EFGH"
 + <table 2>
 | + string "有限会社" <- string "123457"
 | + string "株式会社" <- string "123456"
 + <table 3>
   + string "東京" <- string "TYO"
   + string "横浜" <- string "YOK"
ATR
<list 5>
 + string "s10"
 + string "s8"
 + string "s4"

あいうえおef株式会社ghij横浜
かきくけこef有限会社ghij東京
あいうえおef????????ghij????
-----$ CONV_TB ( lines:34 words:106 ) ----------------------<cut here

  変換できなかった部分は、error logに書出します。
-----^ ERROR.LOG ( date:97-12-23 time:22:58 ) --------------<cut here
d:\icon\lec45\test411.dat 3: 123458 ABCDef123458ghijXYZ
d:\icon\lec45\test411.dat 3: XYZ ABCDef123458ghijXYZ
-----$ ERROR.LOG ( lines:2 words:8 ) -----------------------<cut here

  これで、AWK風 programのお話は(多分)おしまいです。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Get Back / Ike & Tina Turner
BGD: Jasmine Tea
(icon413.txt 1997/12/23 PCVAN PIG)

■  Icon > Icon土日夜(14) AWK風 program(9)    風つかい      目次

  ううっ。(11)の書込みを見直していましたら、ミスがみつかりました。
  many(c)の仕様を勘違いしていました。
  many(c)は、現在の走査位置(&pos)から走査して、c以外の文字の出現位置を
見つける関数ですが、現在走査位置がいきなり c以外だったら failするという
仕様になっています。
  s :=   " aaaa  bbbbbbc d ef" の  c,d,e,fのように、1文字の指定の場合に
うまく動きませんでした。  ということで修正です。

-----^ CS_SPLIT.ICN ( date:97-12-27 time:10:27 ) -----------<cut here
####################
# cs_split の test program
####################
# cs_split.icn Rev.02 1997/12/27 windy cs_split修正
# cs_split.icn Rev.01 1997/12/23 windy 風つかい H.S.
# This file is in the public domain.
link struct_e    # show_wl  Icon入門講座(10)参照

procedure main()
  s :=   "aaaa  bbbbbb    ccc"   # 置換指定の sample
  scale(*s +1)                   # 目盛り
  write(s)                       # sample文字列
  show_wl(cs_split(s))           # cs_splitした結果の2重 list表示

  s :=   " aaaa  bbb bbb ccc "   # 参考
  scale(*s +1)
  write(s)
  show_wl(cs_split(s))

  s :=   " aaaa  bbbbbbc d ef"   # (Rev.02)(Rev.01ではうまく動かない。)
  scale(*s +1)
  write(s)
  show_wl(cs_split(s))

  s :=   " "                     # 指定文字無し だと、どうなるかな。
  scale(*s +1)
  write(s)

  s :=   ""                      # 空文字列 だと、どうなるかな。
  scale(*s +1)
  write(s)
end


####################
# 文字列処理指定の文字列を解析
####################
# 処理指定 英文字1文字
# args : s : string 指定文字列
#        c : cset   指定しない部分に対応する文字
# value: 2重 list(処理指定を順に詰めたもの)
#        [1]:指定文字, [2]:開始位置, [3]:次の指定文字の開始位置
# 指定例   00000000011111111112
#          12345678901234567890
# s1 :=   "ABCDef123456ghijYOK"
# s2 :=   "aaaa  bbbbbb    ccc"
# s2を    [["a",1,5],["d",7,13],["c",17,20]] と変換する。
# 備考 : 表データの一部を置換するプログラムのために作成。上の例の用に、
#        データ例と並べて指定が可能なプログラムにするため

procedure cs_split(s,c)
  /s  := &subject                   # default
  /c  := ' '                        # default -> ' '
  L   := []                         # 戻り値用 list
  s ? {
    while tab(ps := upto(~c)) do {  # c以外の文字まで skip
      cc := move(1)                 # その文字を記憶
      tab(pe := (many(cc) | &pos))  # その文字以外の文字迄 skip(Rev.02)
              # ↑many(c)は、現在の走査位置(&pos)の文字が、c以外だったら
              # failするので。 | &posを付加。  これが無いと、変換指定が
              # 1文字の時にうまく動かない。
      put(L,[cc,ps,pe])             # 文字、開始位置、次の文字の開始位置
                                    # を list に追加
    }
  }
  return L
end


####################
# 文字列の目盛り
####################
# 文字列
procedure scale(n)
  s1 :=  "00000000011111111112222222222333333333344444444445555555555" ||
        "66666666667777777777"
  s2 :=  "12345678901234567890123456789012345678901234567890123456789" ||
        "01234567890123456789"
  write(left(s1,n))
  write(left(s2,n))
  return
end
-----$ CS_SPLIT.ICN ( lines:82 words:243 ) -----------------<cut here

  many(c)が失敗した場合の手当をするやり方の他に、失敗しないように1文字分
戻してあげるというやり方もあります。
-----
      cc := move(1)                 # その文字を記憶
      move(-1)                      # many(c)対策
      # ↑many(c)は、現在の走査位置(&pos)の文字が、c以外だったら
      # failするので、戻す。
      tab(pe := many(cc))           # その文字以外の文字迄 skip
-----

  また、現在走査位置の文字を取り出すのに move(1)を使わず、&posで文字列
から取り出すやり方もあります。  これが、一番素直かな。
-----
      cc := s[&pos]                 # その文字を記憶
      tab(pe := many(cc))           # その文字以外の文字迄 skip
-----

  動かした結果です。
-----^ CS_SPLI2 ( date:97-12-27 time:10:21 ) ---------------<cut here
00000000011111111112
12345678901234567890
aaaa  bbbbbb    ccc
 a 1 5
 b 7 13
 c 17 20

00000000011111111112
12345678901234567890
 aaaa  bbb bbb ccc 
 a 2 6
 b 8 11
 b 12 15
 c 16 19

00000000011111111112
12345678901234567890
 aaaa  bbbbbbc d ef
 a 2 6
 b 8 14
 c 14 15
 d 16 17
 e 18 19
 f 19 20

00
12
 
0
1

-----$ CS_SPLI2 ( lines:31 words:60 ) ----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Pureness / 岡本真夜
BGD: Jasmine Tea
(icon414.txt 1997/12/27 PCVAN PIG)

■  Icon > Icon土日夜(15) record                 風つかい      目次

  年が変わって、あらら、もう下旬になってしまいました。  今年は、横浜では、
正月早々、大雪がありまして、雪かきで忙しくて。(まさか)
  今日のTVで、関東で降る雪は水分が多いとか言っていました。東北の雪だと
サラサラしていて、 水分は8%位ですが、 関東の雪では、その4倍位のベタ雪
が多いそうです。
  津軽恋女では 7種類の雪が降る と唄っています。 こな雪、つぶ雪、わた雪、
ざらめ雪、みず雪、かた雪、氷雪。  横浜にいると、雪の表現で使うのは、精々
粉雪とベタ雪 くらいでしょうか。
  何かで、エスキモーには、40種類以上の雪の表現があるとか 読みましたが、
カタギの方見ると program言語なんて、多分、数種しかないと思われているんで
しょうが、 実際は、1000種類以上あるみたいですから、雪に 数10種あっても
オカシクはありませんね。(比べる問題じゃないような気もします。あはは)

  さて、今年の入門講座では、今までやりたいと思って なかなか できてません
        ・数式展開
        ・簡単な assembler

の説明したいと思います。  できれば、更に 構文解析 tool(parser)あたりまで
できると良いんですけれど。  この辺は、Iconの libraryには、ちゃんとそれら
しき procedureとか、parser program(IBPAG: Icon-Based Parser Generator)も
あるんですが、勉強が追い付いていません。

  さて、今回は、今年の希望とは 裏腹 に、recordがテーマです。
  Iconには、listという data構造があります。階層構造の dataを表わすのに非常
に便利ですので、多用しています。 
  しかし、階層が深い listを使いますと、programを書いているときは良いんです
が、しばらく経った後に読んだ時に、サッパリ分からなくなっています。

  例えば、入門講座3 Icon雑記帳(15)ビデオ問題/簡易解法 で、こんな所が
あります。
      if (L_out[i][1][1]           +LL[3])  <= t_max then { # ダビング可能?

  L_outは、3階層の listですが、iは多分 loopを回しているんでしょうが、その
後の [1][1] とかは、書いた本人が、なんだっけ!?  となります。
  すぐ下の commentには、
              # [i]: テープ番号
              # [i][1]: 詰め込み時間 (初期値 : [0,"分"])

と あります。 i は tape No、次の [1]は詰め込み時間と 単位を入れた listで、
その次の [1]は、詰め込み時間と commentを読んで分かりますが、もっと直感的に
できないものかと、実は思っていました。
  例えば、L_out.tape_no.time_rec.time という風に、名前で呼べないものかな。
                ↑[i]   ↑[1]    ↑[1]
  名前で呼ぶ? ううっ。どこかで聞いたような。そうだ、recordは、そんなことが
できるんだった。
  そうか、recordは、こんな時に使うんだろう。と、教典(The Icon Programming
Language)を、読み直してみましたら、ヤッパそうみたい。

  簡単な test  programで試してみます。

-----^ REC.ICN ( date:98-01-17 time:21:24 ) ----------------<cut here
####################
# recordの習作
####################
# rec.icn Rev.1.1 1998/01/17 windy 風つかい H.S.
# This file is in the public domain.
record r1(a,b)              # record構成宣言
record r2(x,y,z)            # record構成宣言

procedure main()
  R1   := r1(10)            # record R1を生成(R1.aを 10とする。)
  R1.b := r2(20,30,40)      # R1.bに record を代入。 R1.a.xを 20,
                            # R1.a.yを 30, R1.a.zを 40とする。

  write(R1.a)               # R1.aを書き出し
  write(R1.b.x)             # R1.b.xを書き出し
  write(R1.b.y)             # R1.b.yを書き出し
  write(R1.b.z)             # R1.b.zを書き出し
end
-----$ REC.ICN ( lines:18 words:63 ) -----------------------<cut here

  結果です。
-----^ REC ( date:98-01-17 time:21:24 ) --------------------<cut here
10
20
30
40
-----$ REC ( lines:4 words:4 ) -----------------------------<cut here

  それから、以前の説明(Icon日記(29) record)で、間違った説明をして
いますね。「 recordの scope(有効範囲)は、global(全域)です。」は
間違いで、「 record構成宣言の scopeは、 global(全域)です。」のミスで
す。すみません。
  構成宣言が globalなのは、ある procedureが 別の procedureに、recordで
dataを渡したとき、受け取った側で、再度 record構成宣言しなくても 良いた
めには、当然ですね。

  recordが、便利に使えそうですので、次回は 構造体 tree表示 procedureを
record対応への拡張を、やってみたいと思います。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 津軽恋女 / 新沼謙治
BGD: Jasmine Tea
(icon415.txt 1998/01/25 PCVAN PIG)

■  Icon > Icon土日夜(16) 構造体 tree表示(1)  風つかい      目次

  気象予報士の方が、TVで、今年は暖冬なので大雪が降りやすいと言っています
が、シロ〜トには良く分かりません。  

  さて、今回は、構造体を tree表示する procedureを record対応にします。
ついでに、これまでに見つかったミスもいくつか修正しています。
  せっかくですので、 早速、program中に recordを使いました。

  recordは listに似ていますので、最初は単純に listかどうか判定している部分
を listでも recordでも良いようにと変更してみたましたが、うまく動きません。
  問題は typeでした。 dataの typeを判断する関数 type()を使っているのですが
  recordに対して、type()を使っても "record"とは返って来ないのですね。

  record構成宣言で
       record type_id(type,multi)       # record構成宣言
と、宣言しておいて、
       X_record := type_id()            # 要素が (&null,&null)の record
と、 recordを生成しておいて、 type(X_record) としますと、"type_id"と返って
来ます。

  record構成宣言する度に、新しい typeが発生します。この辺でハマりましたが
なんとか record対応にできました。

  typeの扱いが複雑になりますので、type判定 procedureを追加しています。

-----^ X2TREE08.ICN ( date:98-01-18 time:18:14 ) -----------<cut here
####################
# 構造体の構成を tree表示
####################
# x2tree08.icn 1998/01/18 windy 風つかい H.S.
# 機能追加: x2tree07を record対応に拡張
# ミス修正: 1) list,set,table,record以外を指定するとコケた。
#           2) x2t,x2treeのそこかしこ。
# This file is in the public domain.

####################
# 構造体の構成を tree表示
####################
# args  : [1]: なんでも良い [2]:treeの列の進み
# Usage : tree_x(x,step)
global T_serial
record type_id(type,multi)       # record構成宣言
link sjis_e  # jimage

procedure tree_x(x,step)
  every write(x2t(x,step))
end


####################
# 構造体の構成を tree状に見せる generator (recursive)
####################
# args  : [1]: なんでも良い [2]:treeの列の進み
# value : sequence of string (treeの1行分)
# Usage : every write(x2t(x))

procedure x2t(x,step)
# generator
# topの処理
  n_type := 8               # type表示の桁数
  T_serial := table()       # serial No 登録用 table生成
  ss := repl(" ", \step | 0)

  TI_x := type_x(x)         # typeチェック
  if TI_x.multi ~== "multi" # list,set,table,recordでなければ
  then return left(TI_x.type,n_type)  || jimage(x)      # 書き出す
  else {                    # list,set,table,recordなら
    suspend "<" || TI_x.type || " " || (m := string(serial(x))) || ">"
                                       #↑serial No
    # その typeに対する serial No 登録用 setが無ければ生成
    if /(T_serial[TI_x.type]) then T_serial[TI_x.type] := set()
    insert(T_serial[TI_x.type],m)      #←serial No 登録
    # serial Noを T_serial[TI_x.type]に登録
    suspend " " || ss || x2tree(x,ss)  # 更に解析
  }

end


####################
# x2t の sub-procedure
####################
procedure x2tree(x,ss)
  n := *x                   # 枝の末端検出用カウンタ
  n_type := 8               # type表示の桁数

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

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

  else { # table
    every xkey := key(x) do { # tableの keyを1つ づつ取り出す
      n -:= 1
      TI_key := type_x(xkey)
      key_disp := if TI_key.multi == "multi"
        then " <- <" || TI_key.type || " " || string(serial(xkey)) || ">"
        else " <- " || left(TI_key.type,n_type) || jimage(xkey)
      # valueの取り出し
      xx := x[xkey]
      TI_xx  := type_x(xx)
      val_disp := if TI_xx.multi == "multi"
        then "+ <" || TI_xx.type || " " || string(m := serial(xx)) || ">"
        else "+ " || left(TI_xx.type,n_type)  || jimage(xx)

      # 以降は list,set,table,recordとほぼ同じ。
      # 書き出しの際に key_disp を付加するところだけが異なる。
      case TI_xx.multi of {   # 構造体の typeにより、
        "string" : suspend val_disp || key_disp
        #↓list,set,table,recordなら、typeを書出して、その中身をまた解析する。
        "multi"  : {
          # その typeに対する serial No 登録用 setが無ければ生成
          if /(T_serial[TI_xx.type]) then T_serial[TI_xx.type] := set()
          #↓再帰構造で なければ。
          #(T_serial[TI_xx.type)]に既に登録済みなら再帰構造)
          if not member(T_serial[TI_xx.type],m) then {
            insert(T_serial[TI_xx.type],m)    #←serial No 登録
            # serial Noを T_serial[TI_xx.type]へ登録
            suspend val_disp || key_disp
            suspend (if n > 0 then "| " else "  ") || ss || ss || x2tree(xx,ss)
                              #↑枝の途中 #↑枝の末端            # 再帰↑
            delete(T_serial[TI_xx.type],m)    #←serial No 登録を削除
          }
          else {  # 再帰構造 ならば、書き出すとキリが無いので打止め
            suspend val_disp || key_disp || " (Recursion)"
          }
        }
        #↓その他なら、typeと値を書き出す。
        default  : suspend val_disp || key_disp
      }
    }
  }
end


####################
# type判定
####################
procedure type_x(x)
  TI := type_id()             # record生成
  TI.type :=type(x)
  case TI.type of {
     "string"                    :  TI.multi := "string"
    ("cset" | "file" | "integer" | "null" | "procedure" |
     "real" | "co-expression")   :  TI.multi := "single"
    ( "set"  | "list" | "table") :  TI.multi := "multi"
    default                      :  TI.multi := "multi"  # record
  }
  return TI
end
-----$ X2TREE08.ICN ( lines:154 words:594 ) ----------------<cut here

  行数制限がありますので、この procedureの test programは次回にします。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子
BGD: Rolling-K
(icon416.txt 1998/01/25 PCVAN PIG)

■  Icon > Icon土日夜(17) 構造体 tree表示(2)  風つかい      目次

  さて、今回は、前回作った 構造体 tree表示 procedureの test programです。
従来のものの後に、recordの testの部分を追加しています。  更に、今までは
いきなり構造を持たない stringや integerなどが指定されると動作がオカシク
なりました。この修正の確認部分も追加しています。

-----^ X2TREE8~.ICN ( date:98-01-18 time:16:51 ) -----------<cut here
####################
# test driver for x2tree08.icn
####################
# x2tree8~.icn 1998/01/18 windy 風つかい H.S.
# This file is in the public domain.
record r1(a,b)              # record構成宣言
record r2(x,y,z,w)          # record構成宣言
link x2tree08

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()

  # recordの test
  R1   := r1(10)          # record R1を生成。R1.aを 10とする。
  R2   := r2("2X","2Y")   # R2を生成。R2.xを "2X"、 R2.y を "2Y"とする。
  R3   := r1("1A","1B")   # R3を生成。R3.aを "1A"、 R3.b を "1B"とする。
  R1.b := R2              # R2を R1.bに代入。
  R2.z := R1              # 再帰
  R2.w := R3
  every write(x2t(R1) \20)
  write()

  every write(x2t(R1.a) \20)
  every write(x2t("ABCD") \20)

end
-----$ X2TREE8~.ICN ( lines:54 words:155 ) -----------------<cut here

  結果です。 recordの type名のところには、 record構成宣言した、"r1"とか
"r2"とかが出てきます。
-----^ X2TREE8~ ( date:98-01-18 time:18:10 ) ---------------<cut here
<list 1>
 + string  "A"
 + string  "B"
 + <list 2>
 | + string  "C"
 | + string  "D"
 | + <list 3>
 |   + string  "E"
 |   + string  "F"
 |   + <list 1>
 |     + string  "A"
 |     + string  "B"
 |     + <list 2> (Recursion)
 |     + <list 3> (Recursion)
 + <list 3>
   + string  "E"
   + string  "F"
   + <list 1>
     + string  "A"
     + string  "B"

<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>
 |   + string  "C" <- string  "C"
 |   + <list 3> <- string  "E" (Recursion)
 |   + string  "A" <- <list 1>
 |   + string  "G" <- string  "A"
 + string  "A" <- <list 1>
 + string  "G" <- string  "A"

<set 5>
 + string  "K"
 + <set 4>
 | + <set 5>
 | | + string  "K"
 | | + <set 4> (Recursion)
 | | + string  "J"
 | | + <list 64>
 | |   + string  "H"
 | |   + string  "I"
 | + string  "M"
 | + string  "L"
 + string  "J"
 + <list 64>
   + string  "H"
   + string  "I"

<r1 1>
 + integer 10
 + <r2 1>
   + string  "2X"
   + string  "2Y"
   + <r1 1>
   | + integer 10
   | + <r2 1> (Recursion)
   + <r1 2>
     + string  "1A"
     + string  "1B"

integer 10
string  "ABCD"
-----$ X2TREE8~ ( lines:73 words:284 ) ---------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子
(icon417.txt 1998/01/25 PCVAN PIG)

■  Icon > Icon土日夜(18) n進数計算              風つかい      目次

  時々、n進数の計算が必要になることがあります。 月は、1月〜12月 ですし
時は24時間とか、分、秒は、60が単位ですし、いろんなところで出てきます。
  国際単位(SI単位)には、秒しか無いのですが、時刻の表現に通常使う年、月、
日、時、分までは、SI単位にしろという話は無いみたいですね。

  時刻で時々、うるう秒というのがありますね。この時は、0秒から60秒迄存在し
ます。
  しかし大抵の softwareは、うるう秒迄は 配慮していませんので、私の知っている
範囲では、computerの時計を合わせ直すか、computer用マスター時計で、うるう秒の
前の 10秒を各々 1.1秒 ずつにして60秒目が発生しないようにするとかしています。
  厳密な時刻が必要な場合は、どうやっているんでしょうか。60秒目が存在しても
良いような programになっているんでしょうね。

  さて、そういう10進数以外の 数字を扱うための procedureを作ってみました。
  defaultでは、月計算を行うようにしています。

-----^ ADD_NO.ICN ( date:98-02-11 time:21:44 ) -------------<cut here
####################
# n進数の整数の足し算
####################
# add_no.icn Rev.1.2 1998/02/11 windy comment修正
# add_no.icn Rev.1.1 1998/02/11 windy 風つかい H.S
# This file is in the public domain.

####################
# increment No (limit付き)
####################
# arg: [1]: n:    integer 対象数
#      [2]: mini: integer 最小値
#      [3]: max:  integer 最大値
# value    [result,carry]

procedure inc_no(n,mini,max)
  /mini :=  1
  /max  := 12
  return if n = max then [mini,+1]
                    else [n+1, 0]
end

####################
# decrement No (limit付き)
####################
# arg: [1]: n:    integer 対象数
#      [2]: mini: integer 最小値
#      [3]: max:  integer 最大値
# value    [result,carry]

procedure dec_no(n,mini,max)
  /mini :=  1
  /max  := 12
  return if n = mini then [max,-1]
                     else [n-1, 0]
end

####################
# add No (limit付き)
####################
# arg: [1]: n:    integer
#      [2]: m:    integer
#      [3]: mini: integer
#      [4]: max:  integer
# value    [result,carry]

procedure add_no(n,m,mini,max)
  /mini  :=  1
  /max   := 12
  /m     :=  0
  radix  := max-mini+1               # 基数

  org_0  := n-mini +m                # 0 開始数での計算

  if org_0 >= 0 then {               # 正の数(か 0)
    carry  := org_0 / radix          # 桁上がり
    result := org_0 % radix +mini
  } else {                           # 負の数
    carry  := (org_0 +1) / radix -1  # 桁下がり
    result := (org_0 -carry*radix ) % radix +mini
  }

  return  [result,carry]
end
-----$ ADD_NO.ICN ( lines:64 words:210 ) -------------------<cut here

  test programです。

-----^ ADD_NO~.ICN ( date:98-02-11 time:21:45 ) ------------<cut here
####################
# test program for add_no.icn
####################
# add_no~.icn Rev.1.2 1998/02/11 windy comment修正
# add_no~.icn Rev.1.1 1998/02/11 windy 風つかい H.S.
# This file is in the public domain.
link add_no

procedure main()
  write("10進 0-9  -> +1 : 普通の桁上がり")
  every writes(" ",(L := inc_no(0 to 9,0,9))[1],":",L[2])
  write("\n10進 1-10 -> +1")
  every writes(" ",(L := inc_no(1 to 10,1,10))[1],":",L[2])
  write("\n12進 1-12 -> +1: 月の計算")
  every writes(" ",(L := inc_no(1 to 12))[1],":",L[2])
  write("\n\n10進 0-9  -> -1 : 普通の桁下がり")
  every writes(" ",(L := dec_no(0 to 9,0,9))[1],":",L[2])
  write("\n10進 1-10 -> -1")
  every writes(" ",(L := dec_no(1 to 10,1,10))[1],":",L[2])
  write("\n12進 1-12 -> -1: 月の計算")
  every writes(" ",(L := dec_no(1 to 12))[1],":",L[2])
  write("\n\n12進 7 -> +0〜13 : 月の計算")
  every writes(" ",(L := add_no(7,0 to 13))[1],":",L[2])
  write("\n12進 7 -> +14〜27 : 月の計算")
  every writes(" ",(L := add_no(7,14 to 27))[1],":",L[2])
  write("\n12進 7 -> -0〜-13 : 月の計算")
  every writes(" ",(L := add_no(7,0 to -13 by -1))[1],":",L[2])
  write("\n12進 7 -> -14〜27 : 月の計算")
  every writes(" ",(L := add_no(7,-14 to -27 by -1))[1],":",L[2])
  write()
end
-----$ ADD_NO~.ICN ( lines:31 words:162 ) ------------------<cut here

  結果です。

-----^ ADD_NO~ ( date:98-02-11 time:21:45 ) ----------------<cut here
10進 0-9  -> +1 : 普通の桁上がり
 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 0:1
10進 1-10 -> +1
 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 1:1
12進 1-12 -> +1: 月の計算
 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 11:0 12:0 1:1

10進 0-9  -> -1 : 普通の桁下がり
 9:-1 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0
10進 1-10 -> -1
 10:-1 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0
12進 1-12 -> -1: 月の計算
 12:-1 1:0 2:0 3:0 4:0 5:0 6:0 7:0 8:0 9:0 10:0 11:0

12進 7 -> +0〜13 : 月の計算
 7:0 8:0 9:0 10:0 11:0 12:0 1:1 2:1 3:1 4:1 5:1 6:1 7:1 8:1
12進 7 -> +14〜27 : 月の計算
 9:1 10:1 11:1 12:1 1:2 2:2 3:2 4:2 5:2 6:2 7:2 8:2 9:2 10:2
12進 7 -> -0〜-13 : 月の計算
 7:0 6:0 5:0 4:0 3:0 2:0 1:0 12:-1 11:-1 10:-1 9:-1 8:-1 7:-1 6:-1
12進 7 -> -14〜27 : 月の計算
 5:-1 4:-1 3:-1 2:-1 1:-1 12:-2 11:-2 10:-2 9:-2 8:-2 7:-2 6:-2 5:-2 4:-2
-----$ ADD_NO~ ( lines:22 words:174 ) ----------------------<cut here

  以前作った、年月の+1月、−1月 procedureを inc_noと dec_noを使って
書き換えてみました。

-----^ MONTH2.ICN ( date:98-02-11 time:21:46 ) -------------<cut here
####################
# 年月データ(YYMM)の+−1月計算
####################
# month2.icn Rev.1.1 1998/02/11 windy comment修正.
# month2.icn Rev.1.1 1998/02/11 windy 風つかい H.S.
# This file is in the public domain.
link add_no

procedure main()
  every writes(" ",inc_month("9901" | "9902" | "9911" | "9912" |
                             "0001" | "0002"))
  write()
  write("↑+1月")
  every writes(" ",          "9901" | "9902" | "9911" | "9912" |
                             "0001" | "0002")
  write()
  write("↓−1月")
  every writes(" ",dec_month("9901" | "9902" | "9911" | "9912" |
                             "0001" | "0002"))
  write()
end


procedure dec_month(YYMM)
# 年月データ −1月
  yy := (numeric(YYMM[1:3])+100) ; mm := numeric(YYMM[3:0]) # 年月を数字に変換
  L := dec_no(mm)
  # 年データを文字列へ変換し、2桁で右寄せであまりに"0"を詰める。月も同じ。
  #                                       ↓文字列の連結
  return right(string(yy +:= L[2]),2,"0") || right(string(L[1]),2,"0")
end

procedure inc_month(YYMM)
# 年月データ +1月
  yy := (numeric(YYMM[1:3])) ; mm := numeric(YYMM[3:0]) # 年月を数字に変換
  L := inc_no(mm)
  return right(string(yy +:= L[2]),2,"0") || right(string(L[1]),2,"0")
end
-----$ MONTH2.ICN ( lines:38 words:125 ) -------------------<cut here

  念のため結果を。

-----^ MONTH2 ( date:98-02-11 time:21:46 ) -----------------<cut here
 9902 9903 9912 0001 0002 0003
↑+1月
 9901 9902 9911 9912 0001 0002
↓−1月
 9812 9901 9910 9911 9912 0001
-----$ MONTH2 ( lines:5 words:20 ) -------------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Je l'aime - チェンバロに恋して - / 曽根麻矢子
(icon418.txt 1998/02/11 PCVAN PIG)

■  Icon > Icon土日夜(19) table書き出し          風つかい      目次

  梅は咲いたか、桜はまだかいな? の季節になりました。   今年は暖冬ですの
で、梅はもう先月から咲いていますが、桜は未だ未だですね。

  program言語は、言語の一種と思います。すると、programを書くのは文章を書
くのと同じということになります。
  文章をうまく書くのは、理科系の方より文化系の方のほうが、普通うまい とい
う気がします。
  ということで、多分理科系の方が多い programerの書く programは大抵 分かり
難いということになりますね。

  さて、tableは、AWKや Perlや pythonにも有りますが、とても便利なものです。
  AWKを勉強していた時、tableがうまく使えると programがスッキリして 分かり
やすくなり、おまけに 速い programになって、これは スゴイ と感動した覚えが
あります。

  私の場合、tableを書き出す機会は、余り無いのですが、たまにやって悩みまし
たので、汎用の書き出し用の procedureを作ってみました。
  細かい加工は、その時その時で変わりますので、別の 加工用 procedureを呼べ
るようにしてあります。

-----^ SHOW_TBL.ICN ( date:98-02-11 time:23:18 ) -----------<cut here
####################
# table の key/value(list/record でも良い) 表示用 procedure
####################
# keyで sortして、keyと value(valueが list/record ならその要素)を 生成
####################
# show_tbl.icn Rev1.2 98/02/11 windy comment修正
# show_tbl.icn Rev1.1 98/02/07 windy show_tbを generatorにする。
# show_tb.icn  Rev1.2 98/02/06 windy show,show2,show_tb,sortshowを統合
# show_tb.icn  Rev1.1 95/11/12 windy 風つかい H.S.
# arg:    [1]: T: table
#         [2]: c: character: 出力区切り文字
#         [3]: proc1: procedure: keyを加工して出力する際の procedure
#         [4]: proc2: procedure: valueを加工して出力する際の procedure
# value:  string
# output: key c value[1] c value[2] c ...       valueが list,record
#         key c value c value c ...             valueが string,number
# Usage:  every s := show_tbl(T,c,proc1,proc2) do write(s)
#         every write(show_tbl(T,c,proc1,proc2))
# 注      tableの key,valueは、最終的には印字可能であること。
# This file is in the public domain.

procedure show_tbl(T,c,proc1,proc2)
  /c := "\t"                        # default(出力区切り文字) tab

  L := sort(T,3)                    # keyで sort -> key,value交互の list

             # ↓keyを取り出し proc1が定義してあれば その処理
  while s := if /proc1 then get(L) else proc1(get(L))  do {

    # valueを取り出して、proc2が定義してあれば その処理をして
    x := if /proc2 then get(L) else proc2(get(L))
    if type_r(x) == ("list" | "record")  # typeを check
    # list か recordなら その要素を
    then every s ||:= (c || !x) else s ||:= (c || x)
                                    # ↑それ以外ならそのまま
  suspend s
  }
end


####################
# recordなら "record"と返す type
####################
# arg:   任意
# value: string

procedure type_r(x)
  return if match("record",image(x)) then "record" else type(x)
end
-----$ SHOW_TBL.ICN ( lines:49 words:210 ) -----------------<cut here

  show_tbを使って、table内容を書き出す test programです。
-----^ SHOW_TB2.ICN ( date:98-02-11 time:23:20 ) -----------<cut here
####################
# show_tbl の test program
####################
# Rev.1.2 show_tb2.icn 1998/02/11 windy comment修正
# Rev.1.1 show_tb2.icn 1998/02/07 windy 風つかい H.S.
# This file is in the public domain.
link show_tbl, # show_tbl
     hexcvt    # hexstring(BIPL) 10進数 -> 16進数変換

procedure main()
  T1 := table()                           # table生成
  #    key↓value↓key↓value↓key↓value↓
  L1 := ["γ","春子","β","夏子","α","秋子"]
  while insert (T1,get(L1),get(L1))       # tableへ格納
  every write(show_tbl(T1," "))           # table内容書き出し
  write()

  T2 := table()                           # table生成
  #   key1↓ value1↓      key2↓ value2↓       key3↓ value3↓
  L2 := ["C",["A1","B1","C1"],"B",["A2","B2","C2"],"A",["A3","B3","C3"]]
  while insert (T2,get(L2),get(L2))       # tableへ格納
  every write(show_tbl(T2," "))           # table内容書き出し
  write()

  T3 := table()
  #   key↓value↓ key↓ value↓ key↓ value↓
  L3 := ["Z",[10,16],"Y",[100,256],"X",[1000,1024]]
  while insert (T3,get(L3),get(L3))       # tableへ格納
  every write(show_tbl(T3," ",image,test_form))    # table内容書き出し
end

# 書き出し時の処理
# L の 第1要素は4桁の16進数へ変換し、第2要素は4桁右詰め処理
procedure test_form(L)
  return [hexstring(L[1],4),right(L[2],4)]
end
-----$ SHOW_TB2.ICN ( lines:36 words:121 ) -----------------<cut here

  結果です。
-----^ SHOW_TB2 ( date:98-02-11 time:23:21 ) ---------------<cut here
α 秋子
β 夏子
γ 春子

A A3 B3 C3
B A2 B2 C2
C A1 B1 C1

"X" 03E8 1024
"Y" 0064  256
"Z" 000A   16
-----$ SHOW_TB2 ( lines:11 words:27 ) ----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: SMILE / 岡本真夜
(icon419.txt 1998/02/11 PCVAN PIG)

■  Icon > Icon土日夜(20) table読み込み(1)    風つかい      目次

  前回、table書き出しをやりましたので、今回は、table読み込みです。
別 fileから tableを読み込むのは、第12回の AWK風 program(7)でやって
います。  似たような処理ですが、今回は 複数の tableがファイルに含まれて
いるケースをやります。

  次のような tableを含んだ fileがあるとします。 以前使った 惑星の dataと、
単純な曜日 dataです。
  こういう tableを programに読み込んで、programの中で、table参照できるように
しようという訳です。

-----^ READ_MTB.DAT ( date:98-02-12 time:22:18 ) -----------<cut here
####################
# read_mtb test用 data file
####################
# read_mtb.dat Rev.1.1 1998/02/12 windy 風つかい H.S.
# 先頭が #の行は無視, 空行は無視
#  ^-----5 table_id  table開始、数字は欄の数、その後ろは comment
#  $----- table終了
# This file is in the public domain.

^-----5 PLANET  valueが複数欄の場合
# 惑星   日本名   距離   半径   質量
#                 億km   千km   /Earth
Mercury  水星     0.58   2.44    0.06
Venus    金星     1.08   6.05    0.82
Earth    地球     1.50   6.38    1.0
Mars     火星     2.28   3.40    0.11
Jupiter  木星     7.78  71.49  317.83
Saturn   土星    14.29  60.27   95.16
Uranus   天王星  28.75  25.56   14.54
Neptune  海王星  45.04  24.76   17.15
Pluto    冥王星  59.15   1.14    0.01
$-----
^-----2 WEEK valueが単一の場合
# code  曜日  
1       日    # Sunday
2       月    # Monday
3       火    # Tuesday
4       水    # Wednesday
5       木    # Thursday
6       金    # Friday
7       土    # Saturday
$-----
-----$ READ_MTB.DAT ( lines:32 words:128 ) -----------------<cut here

  tableのブロックを処理しやすくするために、tableの始めと終わり、欄数、id を
持たせています。
  こういう形式の fileを読み込むために、次の procedureを 作りました。
  引数の proc1,proc2は読み込み時の加工処理が必要なら指定するものです。

-----^ READ_MTB.ICN ( date:98-02-13 time:07:55 ) -----------<cut here
#####################
# 変換 table読み込み
#####################
# read_mtb.icn 1998/02/13 windy comment修正
# read_mtb.icn 1998/01/18 windy 風つかい H.S.
# arg      : [1]: f_name: string:    filename to read
#            [2]: c1:     cset:      読み込み時の欄区切り文字
#            [3]: c2:     cset:      comment開始文字
#            [4]: proc1:  procedure: 読み込み時の行毎処理(事前処理)
#                                    comment削除 procedure指定を想定。
#            [5]: proc2:  procedure: 読み込み時の行毎処理((key 以外の部分)
#                                    複数 columnの場合の処理を想定。
# value    : record(table,id)
#             table: table:  key:column1 -> value:column2_
#             id:    string
# function : 指定の file(表形式 data)を読み込んで、tableを作成 (generator)
#            c1で 2分割し 先頭を keyとし、以降を valueにして tableへ格納。
#            valueの部分に対して、別 procedureにて加工できる。
#            "AAA BBB"     -> key: "AAA", value: "BBB"
#            "AAA BBB CCC" -> key: "AAA", value: "BBB CCC"
#            tableの先頭 ^-----5 id ....
#                              ↑欄の数
#            tableの末尾 $-----
# This file is in the public domain.
record mtb_read(table,id)          # record構成宣言

procedure read_mtb(f_name,c1,c2,proc1,proc2)
  s_start := "^-----"
  s_end   := "$-----"
  /c1     := ' \t'                 # default(space or tab) 欄区切り文字
  /c2     := '#'                   # default comment開始文字
  n       := 0                     # tableの欄の数(兼、table出力中 flag)
  T       := mtb_read()            # record生成
  dir := open(f_name) | stop("read_mtb: cannot open: ",f_name) # file読み込み

  while s := read(dir) do {        # file読み込み
    if \proc1 then s := proc1(s,c1,c2,n,T.id) | next # 行毎処理指定があれば
                                   # それを実行。 T.idは &nullかも。
    s ? {
      if tab(match(s_start)) then {       # table開始
        T.table := table()                # table生成
        n := numeric(tab(upto(c1))) | stop("read_mtb table error: ",s)
        tab(many(c1))                     # 
        T.id := tab(upto(c1) | 0)         # table_id
        next
      }
      if match(s_end)  then {             # table終了
        suspend T                         # table,table_id出力
        n := 0                            # clear flag
        T.id := &null                     # clear table_id
        next
      }
      if n > 1 then {                     # 有効行(みたい)なら
        tab(upto(~c1))
        column1  := tab(many(~c1)) | next # 第1 column
        tab(upto(~c1))
        column2_ := trim(tab(0),c1)       # 第2 column以降
        if \proc2 then column2_ :=proc2(column2_,c1,c2,n,T.id)  # 行毎処理
                                          # 指定があれば、その処理を行う。
        insert(T.table,column1,column2_)  # tableへ格納
      }
    }  # end of s ? {
  }  # end of while
  close(dir)
end
-----$ READ_MTB.ICN ( lines:65 words:296 ) -----------------<cut here

  sample programです。  2つの tableを読み込んで、list Lに読み込んで tree
形式で内容を表示します。  実際の programでは 各々適当な名前の tableに代入
して、参照 tableとして使います。

-----^ READ_MT2.ICN ( date:98-02-12 time:23:16 ) -----------<cut here
####################
# read_mtb.icn の test program
####################
# read_mt2.icn 1998/02/12 windy 風つかい H.S.
# This file is in the public domain.
link read_mtb, # read_mtb table読込み
     string_e, # split    string -> list
     struct_e  # tree_x   構造体 tree表示

procedure main()
  L := []               # tree表示用 buffer
  # tableを読み込んで、順に listに格納
  every TT := read_mtb("read_mtb.dat",,,del_comment,pla) do { 
    put(L,TT.table)
    write(TT.id)
  }
  tree_x(L)             # 構造体 tree表示
end


####################
# PLANET部の処理
####################
# arg  : [1]: s:  string: 対象文字列
#        [2]: c1: character:  欄の区切り文字
#        [3]: c2: character:  commentの始まりの文字
#        [4]: n:  table欄数(含む key)
#        [5]: id: table_id
# value: string    table_idが "PLANET"以外
#        record    table_idが "PLANET"の場合
record pla_rec(jname,distance,radius,mass)

procedure pla(s,c1,c2,n,id)
  if id == "PLANET" then {        # table_idが "PLANET"なら
    L := split(s,c1)              # 欄分割 -> list
    every i := 2 to 4 do L[i] := numeric(L[i]) # 2番目以降を 数字変換
    R := pla_rec ! L              # invocation(listを recordへ assign)
    return R
  }
  else return s                   # table_idが "PLANET"以外なら そのまま
end


####################
# 行末の comment削除
####################
# arg  : [1]: s: string: 対象文字列
#        [2]: c1: character:  欄の区切り文字
#        [3]: c2: character:  commentの始まりの文字
#        [4]: n:  table欄数(含む key)
#        [5]: id: table_id
# 注     c2が、comment開始以外で使用されているケースには対応していない。
# value: string

procedure del_comment(s,c1,c2,n,id)
  s ? {
    if match(c2) then fail        # 先頭が、c2なら fail(いきなり comment)
    return tab(upto(c2) | 0)      # commentより手前
  }
end
-----$ READ_MT2.ICN ( lines:60 words:212 ) -----------------<cut here

  長くなりましたので、残りは次回に。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子
(icon420.txt 1998/02/14 PCVAN PIG)

■  Icon > Icon土日夜(21) table読み込み(2)    風つかい      目次

  table読み込みの続きです。  動きがちょっとメンドイので、read_mt2と
read_mtbの関係を図にしておきます。

      (用途に応じて作成)                       (汎用 procedure)
     - read_mt2 -----------                -- read_mtb -----------
    |  main()              |              |                       |
    |    table読み込み     |              |                       |
    |      ------------------->------->-----> file読み込み        |
    |    table,id入手<--------<---        |   read_mtb()          |
    |    list Lに格納      |      |       |     table区切り検出   |
    |    id表示            |      |       |     id取り出し        |
    | (tableがあれば繰返し)|      |       |     欄数取り出し      |
    |    Lを tree表示      |      |       |     1行読み込み      |
    | -------------------- |      |       |     読み込み時の加工  |
    |    comment削除 <--------<-------<---------- proc1()を呼ぶ   |
    |  del_comment()       |      |       |                       |
    |        ----------------->------->----------> 加工後 data    |
    |                      |      |       |     key/value分割     |
    | -------------------- |      |       |     valueを加工       |
    |    欄分割、等  <--------<-------<---------- proc2()を呼ぶ   |
    |  pla()               |      |       |                       |
    |        ----------------->------->----------> 加工後 data    |
    |                      |      |       |     tableへ格納       |
    |                      |      |       |    (table末尾迄繰返し)|
    |                      |       ---<-------- table,idを返す    |
    |                      |              |    (tableがある限り   |
    |                      |              |              繰り返し)|
     ----------------------                -----------------------

  動かした結果です。

-----^ READ_MT ( date:98-02-12 time:23:44 ) ----------------<cut here
PLANET
WEEK
<list 1>
 + <table 1>
 | + <pla_rec 7> <- string  "Uranus"
 | | + string  "天王星"
 | | + real    28.75
 | | + real    25.56
 | | + real    14.54
 | + <pla_rec 1> <- string  "Mercury"
 | | + string  "水星"
 | | + real    0.58
 | | + real    2.44
 | | + real    0.06
 | + <pla_rec 5> <- string  "Jupiter"
 | | + string  "木星"
 | | + real    7.78
 | | + real    71.49
 | | + real    317.83
 | + <pla_rec 2> <- string  "Venus"
 | | + string  "金星"
 | | + real    1.08
 | | + real    6.05
 | | + real    0.82
 | + <pla_rec 6> <- string  "Saturn"
 | | + string  "土星"
 | | + real    14.29
 | | + real    60.27
 | | + real    95.16
 | + <pla_rec 3> <- string  "Earth"
 | | + string  "地球"
 | | + real    1.5
 | | + real    6.38
 | | + real    1.0
 | + <pla_rec 8> <- string  "Neptune"
 | | + string  "海王星"
 | | + real    45.04
 | | + real    24.76
 | | + real    17.15
 | + <pla_rec 4> <- string  "Mars"
 | | + string  "火星"
 | | + real    2.28
 | | + real    3.4
 | | + real    0.11
 | + <pla_rec 9> <- string  "Pluto"
 |   + string  "冥王星"
 |   + real    59.15
 |   + real    1.14
 |   + real    0.01
 + <table 2>
   + string  "火" <- string  "3"
   + string  "木" <- string  "5"
   + string  "月" <- string  "2"
   + string  "土" <- string  "7"
   + string  "水" <- string  "4"
   + string  "日" <- string  "1"
   + string  "金" <- string  "6"
-----$ READ_MT ( lines:57 words:291 ) ----------------------<cut here

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子
(icon421.txt 1998/02/14 PCVAN PIG)

■  Icon > Icon土日夜(22) 構造体 copy            風つかい      目次

  昨日、今日と 暖かい天気が続いています。今日は結構 強い南風でしたので、
春一番かな。

  さて、今回は、構造体の copyです。多分、今まで使っていないと思います。
  では、通常の代入はコピーじゃないのかというと、違うんですね。
  例えば、list L を生成しておいて、それを LLへ代入します。
  Lの要素を変更すれば LLの要素も変更されますし、LLの要素を変更すれば Lの
要素も変更されています。 試しにやってみますと、

-----^ COPY01.ICN ( date:98-02-14 time:17:25 ) -------------<cut here
####################
# copyの test program
####################
# copy01.icn Rev.1.1 1998/02/14 windy 風つかい H.S.
# This file is in the public domain.
procedure main()
  L  := ["AA","BB","CC"]                 # list Lを生成
  LL := L                                # Lを LLへ assign
  writes("LL: ") ; every writes(" ",!LL) ; write()  # LLの要素を書き出し
  L[1] := "XX"                           # 元の Lの第1要素を変更
  writes("LL: ") ; every writes(" ",!LL) ; write()  # LLの要素を書き出し
  LL[2] := "YY"                          # LLの第2要素を変更
  writes("L:  ") ; every writes(" ",!L)  ; write()  # Lの要素を書き出し
end
-----$ COPY01.ICN ( lines:14 words:78 ) --------------------<cut here

  結果は、こうなります。

-----^ COPY01 ( date:98-02-14 time:17:26 ) -----------------<cut here
LL:  AA BB CC
LL:  XX BB CC
L:   XX YY CC
-----$ COPY01 ( lines:3 words:12 ) -------------------------<cut here

  これは、Lも LLも同じ listを示しているためです。
                       ("XX"へ変更)
                          L[1]        L[2]        L[3]
                           ↓          ↓          ↓
                          +------+    +------+    +------+
             L-------->   | "AA" |----| "BB" |----| "CC" |
                   --->   +------+    +------+    +------+
                  /        ↑          ↑          ↑
  (LL := L)  LL --         LL[1]       LL[2]      LL[3]
                                    ("YY"へ変更)

  procedure の引数として、構造体を指定した時も同様です。
  recordを使って試してみます。

-----^ COPY02.ICN ( date:98-02-14 time:22:31 ) -------------<cut here
####################
# copyの test program
####################
# copy02.icn Rev.1.2 1998/02/14 windy copy_2引数修正(分かり易くするため)
# copy02.icn Rev.1.1 1998/02/14 windy 風つかい H.S.
# This file is in the public domain.
record copy_test(aaa,bbb,ccc)

procedure main()
  R := copy_test("AA","BB","CC")         # record R を生成
  writes("R: ") ; every writes(" ",!R)  ; write()  # R の要素を書き出し
  copy_2(R)
  writes("R: ") ; every writes(" ",!R)  ; write()  # R の要素を書き出し
end

procedure copy_2(RR)
  RR.aaa := "ZZ"
  return
end
-----$ COPY02.ICN ( lines:19 words:69 ) --------------------<cut here

  copy_2()の内部で、要素を変更すると、main()で見ても 変更されています。

-----^ COPY02 ( date:98-02-14 time:22:32 ) -----------------<cut here
R:  AA BB CC
R:  ZZ BB CC
-----$ COPY02 ( lines:2 words:8 ) --------------------------<cut here

  図にするとこんな具合です。
                          R.aaa       R.bbb       R.ccc
  main()                   ↓          ↓          ↓
  ↑         R  ------>   +------+    +------+    +------+
  ====================    | "AA" |----| "BB" |----| "CC" |
  ↓         RR ------>   +------+    +------+    +------+
  copy_2()                 ↑          ↑          ↑
                          RR.aaa      RR.bbb      RR.ccc
                       ("ZZ"へ変更)

  このように要素自体はコピーしないという仕様は、構造体を使うとメモリーを
沢山 消費するので、なるべく避けるためだそうです。

  copy関数は、要素自体も実際にコピーして、別の要素にしたい場合に使います。
  setを使って試してみます。

-----^ COPY03.ICN ( date:98-02-15 time:12:47 ) -------------<cut here
####################
# copyの test program
####################
# copy03.icn Rev.1.2 1998/02/15 windy 説明の都合で修正
# copy03.icn Rev.1.1 1998/02/14 windy 風つかい H.S.
# This file is in the public domain.
procedure main()
  S  := set(["AA","BB","CC"])            # set Sを生成
  S2 := S                                # Sを S2へ assign
  S3 := copy(S)                          # Sの複製を作成し、S3へ assign
  delete(S3,"AA")                        # S3から "AA"を削除
  writes("S:  ") ; every writes(" ",!S)  ; write()  # S の要素を書き出し
  writes("S2: ") ; every writes(" ",!S2) ; write()  # S2の要素を書き出し
  writes("S3: ") ; every writes(" ",!S3) ; write()  # S3の要素を書き出し
end
-----$ COPY03.ICN ( lines:15 words:84 ) --------------------<cut here

  Sを copyした S3を変更しても Sや S2はかわりません。

-----^ COPY03 ( date:98-02-15 time:12:47 ) -----------------<cut here
S:   AA CC BB
S2:  AA CC BB
S3:  CC BB
-----$ COPY03 ( lines:3 words:11 ) -------------------------<cut here

  図にするとこうなります。
                        +-- set ---------------------------+
             S  ------> | +------+    +------+    +------+ |
                        | | "AA" |    | "BB" |    | "CC" | |
  (S2 := S)  S2 ------> | +------+    +------+    +------+ |
                        +----------------------------------+

                        +-- set ---------------------------+
             S3 ------> | +------+    +------+    +------+ |
  (S3 := copy(S))       | | "AA" |    | "BB" |    | "CC" | |
                        | +------+    +------+    +------+ |
                        +----------------------------------+
                          (↑"AA"を削除)

  copyは、構造体を programの中で使っていて、構造体の要素を変更しても、変更前
の状態を保存しておく必要がある時に使います。
  しかし、入門講座では、今まで使ったことはありません。殆どの場合に使わなくとも
すませられるみたいです。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 華麗なるハープ名演集 / 吉野直子・篠崎史子
(icon422.txt 1998/02/14 PCVAN PIG)

■  Icon > Icon土日夜(23) 引用符                 風つかい      目次

  昨日は、暖かだったんですが 今日は一転して 雪が降っていました。来週から
コートが脱げるかな?  なんて思っていたんですが。

  さて、今日は、引用符(quotation mark)の関係を。 通常、英文では、" や ' で
文字列処理をくくるやるです。  文字列処理をしていて、引用符でくくってあると
特別な処理をするケースがあります。

  Icon入門講座4の Icon迷い道(7)で CSV(comma separated value)を表に変換
するところで、文字列 dataを " で くくってあるのを 処理しました。
  結構、メンドイんですよね。 くくってあるだけなら両端の " を除けばいいので
すが、文字列中に 文字として " 自体が 出てきたときの扱いが面倒で。

  今回は それより簡単で 引用符でくくってある部分 を無視して 特定文字の位置
を見つけるものです。

-----^ QUOTE01.ICN ( date:98-02-15 time:22:33 ) ------------<cut here
####################
# 引用符で囲まれた文字列 を無視する処理
####################
# quote01.icn Rev.1.1 1998/02/15 windy 風つかい H.S.
# This file is in the public domain.
link struct_e # scale

procedure main()
  s := "ABCDE\'ABCDE\'ABCDE\'ABCDE\'"
  scale(s)
  s ? every write(qq_upto('A'))
  s ? write(qq_upto('Z') | "no such a position") 
  write()
  s := "ABCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE"
  scale(s)
  s ? every write(qq_upto('A'))
  s ? write(qq_upto('Z') | "no such a position") 
  write()
  s := "ABCDE\'A\'\'BCDE\'ABCDE\'ABCDE\'ABCDE\'ABCDE"
  scale(s)
  s ? every write(qq_upto('A'))
  s ? write(qq_upto('Z') | "no such a position") 
end

####################
# 引用符で囲まれ無い部分を対象にした upto
####################
# arg:  [1]: 検索対象 cset
#       [2]: 引用符   cset
#       [3]: string
# value:     integer (文字位置)
# 引用符を表わすのに、引用符2つ続ける方式に対応している。
# 日本語対応は、していない。

procedure qq_upto(c1,c2,s)
  /s  := &subject                   # default
  /c2 := '\"\''                     # default
  s ? {                             # sを走査対象として
    while tab(ps := upto(c1 ++ c2)) do {    # 探している文字か 引用符だったら
      if any(c1) then {             # 探している文字だったら
        suspend ps                  # 文字位置を返す
        move(1)                     # 1文字 skip
      } else {                      # 引用符だったら
        c_quote := move(1)          # 1文字 skip
        while tab(upto(c_quote)+1 | 0) do { # 引用部を skip
                                   #↑ 引用符が閉じていないケースだが...
          if not any(c_quote) then break    # 引用文字以外なら
          else move(1)              # 引用符だったら、引用符自体を表わして
        }                           # いるので、引用状態を継続
      }
    }
  }
end
-----$ QUOTE01.ICN ( lines:53 words:184 ) ------------------<cut here

  動かした結果です。
-----^ QUOTE01 ( date:98-02-15 time:22:34 ) ----------------<cut here
0000000001111111111222222
1234567890123456789012345
ABCDE'ABCDE'ABCDE'ABCDE'
1
13
no such a position

000000000111111111122222222223333333
123456789012345678901234567890123456
ABCDE'ABCDE'ABCDE'ABCDE'ABCDE'ABCDE
1
13
25
no such a position

00000000011111111112222222222333333333
12345678901234567890123456789012345678
ABCDE'A''BCDE'ABCDE'ABCDE'ABCDE'ABCDE
1
15
27
no such a position
-----$ QUOTE01 ( lines:22 words:29 ) -----------------------<cut here

  ついでに、文字列から、引用符で囲まれた 以外の 空白を削除する procedure
も作ってみました。
-----^ QUOTE02.ICN ( date:98-02-15 time:22:33 ) ------------<cut here
####################
# 引用符で囲まれた 以外の空白を削除
####################
# quote02.icn Rev.1.1 1998/02/15 windy 風つかい H.S.
# This file is in the public domain.
link struct_e # scale

procedure main()
  s := "A C E \'A C E\'AB  E\'  C  \'  CDE"
  scale(s)
  s ? write(qdel_space())
end

####################
# 引用符で囲まれた部分以外の空白を削除
####################
# arg:  [1]: 引用符   cset
#       [2]: string
# value:     string
# 日本語対応していない。(SJISでは、2byte目に引用符が現れるケース)

procedure qdel_space(c,s)
  /s  := &subject
  /c  := '\"\''
  ss := ""
  s ? {
    while ss ||:= tab(upto(' ' ++ c)) do {
      if any(' ') then {    # 空白だったら
        tab(upto(~' '))     # 空白以外迄 skip
      } else {              # 引用符だったら
        ss ||:= move(1)             # 1文字(引用符)を 足しこみ
        ss ||:= tab(upto(c)+1 | 0)  # 引用部を 足しこみ
                              #↑ 引用符が閉じていないケースだが...
                              #   その部分は無視しよう。
      }
    }
    ss ||:= tab(0)          # 残りを足しこみ
    return ss
  }
end
-----$ QUOTE02.ICN ( lines:40 words:129 ) ------------------<cut here

  結果です。
-----^ QUOTE02 ( date:98-02-15 time:22:34 ) ----------------<cut here
0000000001111111111222222222233
1234567890123456789012345678901
A C E 'A C E'AB  E'  C  '  CDE
ACE'A C E'ABE'  C  'CDE
-----$ QUOTE02 ( lines:4 words:17 ) ------------------------<cut here

  日本語対応も 以前紹介しました SJIS対応 procedureを使えば できます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
 < IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: Je'laime チェンバロに恋して / 曽根麻矢子
(icon423.txt 1998/02/15 PCVAN PIG)


■  Icon > Icon土日夜(24) Windows Icon 9.3.1     風つかい      目次

  comp.lang.iconに、Windows95/NT版 Iconの新バージョンのアナウンスが、
流れていましたので、ご紹介します。
  本体機能は、Ver9.3と変わっていないようですが、インストーラやヘルプ
が充実してきました。
  サイズは zipファイルで、4M あります。

 ftp://ringer.cs.utsa.edu/pub/icon/nt/binaries/  に置いてあります。
 README                489 bytes Wed Nov 26 06:19:00 1997 
 winicon.zip          4085 Kb    Wed Nov 26 06:14:00 1997 Zip Compressed Data

  この zipファイルと解凍しますと、次のようなファイルが現れます。
DATA     AR        508,651  97-11-26   5:50 DATA.AR
GIPL     AR      1,302,489  97-11-26   5:50 GIPL.AR
IPL      AR      1,139,927  97-11-26   5:50 IPL.AR
README   TXT         2,968  97-11-26   5:50 README.TXT
SETUP    CFG         1,458  97-11-26   5:50 SETUP.CFG
SETUP    EXE       105,744  97-11-26   5:50 SETUP.EXE
TROUBLE  TXT         1,557  97-11-26   5:50 TROUBLE.TXT
UNINSTAL CFG           494  97-11-26   5:50 UNINSTAL.CFG
UNINSTAL EXE        60,464  97-11-26   5:50 UNINSTAL.EXE
WINICON  AR      1,242,933  97-11-26   5:50 WINICON.AR
        10 個           4,366,685 バイトのファイルがあります 

  この中の setup.exeを実行すれば、インストールされます。
やってみますと、34M位HDDを食いました。

  PC/ATコンパチマシンなら、問題なくインストールできますが、
98マシンの場合で、 A: または B: ドライブにインストールしようとすると、
どうも HDDを FDDと勘違いするみたいで、diskを入れろと催促されてインス
トールでません。
  作者の Jeffery教授に問い合わせたところ、とりあえず細工してくれとのことで、
setup.exeと同じディレクトリーに THISDISK というファイル名で、

インストーラが聞きに来る度に、順に、
------最初は
DiskNumber=1
NextDiskNumber=2
------次は
DiskNumber=2
NextDiskNumber=3
------次は
DiskNumber=3
NextDiskNumber=4
------次は
DiskNumber=4
------
  と置いてあげて、イントーラをだましてあげると良いとのことで、やったら
うまくいきました。

>From: jeffery@ringer.cs.utsa.edu (Clinton L. Jeffery)
>Newsgroups: comp.lang.icon
>Subject: Windows Icon 9.3.1 release announcement
>Date: 26 Nov 1997 06:38:58 -0600
>Organization: University of Texas at San Antonio
>Lines: 25
>Distribution: inet
>Message-ID: <65h592$jp8@pandora.cs.utsa.edu>
>
>
>The Microsoft Windows distribution of Version 9.3.1 of the Icon Programming
>Language is available from ftp://ringer.cs.utsa.edu/pub/icon/nt/binaries/
>
>This release corresponds to the forthcoming graphics book, described at
>www.cs.arizona.edu/icon/.  Windows Icon programmers will all want this
>release because of:
>
>* standard Windows installation (and uninstallation) via a setup.exe file
>* creation of a program group and program items for launching Windows Icon
>* bundling of console-mode (non-graphics) binaries for NT and Win95
>* improved functionality of the integrated development environment, Wi
>* comprehensive on-line documentation in keyword-searchable Windows Help
>  format, including the Icon Program Library and VIB interface builder
>* vastly improved support for Windows 3.1/Win32s users
>* performance improvements in tasks such as reading image files
>* bug fixes
>
>Windows Icon will continue to evolve, but this is a major milestone and I
>would greatly appreciate positive or negative feedback, suggestions, and bug
>reports if you use this software.
>-- 
>Clint Jeffery
>jeffery@cs.utsa.edu
>The University of Texas at San Antonio

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 全部だきしめて/Takuro Yoshida & LOVE2 ALL STARS
(icon424.txt 1997/12/05 PCVAN PIG)

■  Icon > Icon土日夜(25) Icon Newsletter No.54  風つかい      目次

  Iconの Newsletter No.54が、Icon-WEBに、掲載されましたので、お知らせ
します。 URLは、次の通りです。
        http://www.cs.arizona.edu/icon/inl/inl54/inl54.htm

  目次を引用しておきます。

No. 54 -- December 1, 1997
Contents
     The Curse of DOS 
     New Icon Program Library Release 
     Status of the Graphics Book 
     Unicon 
     Chinese Icon Book 
     From Our Mail 
     Updated Icon Web Site 
     Icon Mirror Site 
     Using Icon to Spin the Web 
     An Introduction to Wi 

  目次の中にも出ていますが、Program Libraryが更新されています。
  次のところから FTPできます。
     BIPLが基本 Libraryで、GIPLがグラフィック Libraryです。
     機種対応にいろいろな圧縮形式を用意してあります。

ftp://ftp.cs.arizona.edu/icon/library
Index of /icon/library
    Name            Last modified     Size 
    bipl.hqx        02-Dec-97 20:43   1.9M   基本 Library
    bipl.taz        02-Dec-97 17:20   1.7M 
    bipl.tgz        02-Dec-97 17:20   1.2M 
    bipl.zip        02-Dec-97 17:20   1.4M 
    gipl.hqx        02-Dec-97 20:43   1.5M   Graphic Library
    gipl.taz        02-Dec-97 17:20   2.7M 
    gipl.tgz        02-Dec-97 17:20   1.9M 
    gipl.zip        02-Dec-97 17:20   1.0M 
    info.hqx        02-Dec-97 20:43    63K 
    info.taz        02-Dec-97 17:20    39K 
    info.tgz        02-Dec-97 17:20    30K 
    info.zip        02-Dec-97 17:20    17K 
    mipl.hqx        02-Dec-97 20:43   109K 
    mipl.taz        02-Dec-97 17:20   191K 
    mipl.tgz        02-Dec-97 17:20   112K 
    mipl.zip        02-Dec-97 17:20    69K 
    README          02-Dec-97 17:25     1K 
18 files

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: 全部だきしめて/Takuro Yoshida & LOVE2 ALL STARS
(icon425.txt 1997/12/05 PCVAN PIG)

■  Icon > Icon土日夜  むすび                        風つかい       目次

  秋の夜長から 始めた Icon土日夜 ですが、冬も過ぎ 春はすぐそこ となりました
ので、このへんで おしまいとします。

  今回の入門講座をやっての収穫は、record ですね。
  Icon教典 (The Icon Programming Language)には、勿論 載っているんですが、
こんなに便利なものとは、思っていませんでした。
  というか、何に使うんだろう? と、思っていました。

    ・listは、本を読めば、便利さはすぐ分かります。
      recordは、listの要素指定を分かりやすくするもので、深い階層の listを
      listを使い始めないと、便利さは分からないみたいです。

  ついでに言うと、
    ・generatorの便利さも、これまた 使ってみないと分かりません。
      back trackingだけにしか 使えないのか と思っていましたが、使い始める
      と はまります。

  未だ未だ、他にも Iconの便利な機能を、知らないでいると 思います。
  例えば、講座で、未だ取り上げていない関数に、bal()をいう関数があります。
  数式処理に威力を発揮するらしいのですが、理解できていません。
  このあたりを 使いこなすと、テキスト【解析】らしくなるのかな? と思って
  います。

  で〜、入門講座は、未だ未だ続きますが、Icon土日夜 は このへんで。

  ところで、Icon関係の fileを libraryに uploadしていますが、先日 download
総計が 1000件を越えました。

  入門講座を読んだり Iconを試して頂ける方が増えますと やはり励みになります。
ありがとうございます。

          <1998/02/11>     PIG  SLABO    FPL FGALTS file計
          BIPL.LZH           -     15      -     37     52
          DE386.LZH          -     19      -    104    123
          ICONLEC4.LZH       1      6     13     33     53
          ICONLEC3.LZH       3     13     29    113    158
          ICONLEC2.LZH       5     17     67    129    218
          ICON_LEC.LZH       7     35    124    231    397
          ------------------------------------------------
          SIG/forum計       16    105    233    647   1001

  そうそう、Icon-WEBに Icon Projectのメンバーが紹介されていました。
      http://www.cs.arizona.edu/icon/iconproj/iconproj.htm

  で、メンバーの顔がご覧になれます。

風つかい (TRA11936@biglobe.ne.jp/PFF01531@niftyserve.or.jp)
< IconのWWWは、http://www.cs.arizona.edu/icon/index.html>
BGM: ECHO / 遊佐未森
(icon426txt 1998/02/18 PCVAN PIG)