Icon入門講座


Icon入門講座                                     1996/12/8 風つかい
 --- AWKerのためのIcon入門 ---                (TRA11936@pcvan.or.jp)
                                               (PFF01531@niftyserve.or.jp)
■  Icon > Icon入門講座なんぞをはじめようかな 風つかい

 近頃、2行以上のスクリプトを書く必要がある場合は、awkの替わりに Icon
(アイコン)というテキスト処理言語を使っています。

 sed や awk の1行野郎で済むものは、sed, awk ですましますが、ちょっと
頭をひねる必要のあるものは、Iconで書いています。

 Iconは、なかなかユニークな特徴を持った言語で、もっと使われていいので
はと思いますが、vanやnifのテキスト処理の会議室ではあまり話題には
上っていません。

 興味をもたれる人が増えるといいなということで、私も使いこなせている訳
ではありませんが、入門講座なんぞをはじめてみようかと思います。

 awk との比較みたいなかっこうで説明できるといいんですけれど、どうなる
ことやら。

 尚、Iconは PDSですので、私の文章もならって転載・編集等(そんな人い
るかいな?)自由とします。

目次
  第1回  Iconって何?
   1.Iconって何?
   2.Iconってフリーソフト?
   3.資料はありますか?
  第2回  Iconの入手方法は?
   1.取り敢えずIconを動かしてみたい。
   2.hello worldはどうやって動かすの?
  第3回  Iconの特徴は?(1)
   1.Iconの特徴は?
     1)テキスト解析言語とでも
     2)awkの処理の基本
  第4回  Iconの特徴は?(2)
     3)テキストファイルの読み込み
  第5回  Iconの特徴は?(3)
     4)パターンマッチの考え方
     5)データ構造
  第6回  Iconの特徴(4)制御構造
     6)プログラム制御構造
  第7回  Iconの特徴(5)スキャン
     7)文字列走査
  第8回  Iconの特徴(6)スキャン(続)
     8)文字列走査(続)
  第9回  データ構造 set
 第10回  データ構造 list
 第11回  データ構造 table
 第12回  procedure/scope
 第13回  prpcedure/scopeサンプル
 第14回  type変換、他
 第15回  エスケープ文字、他
 第16回  wild.icn
 第17回  Test Driver for wild
 第18回  iyab.icn
 第19回  vanlog.icn
 第20回  むすび。

風つかい
(TRA11936@pcvan.or.jp)
(icon_00.txt)



■  Icon > Icon入門講座(1) Iconって何? 風つかい    目次

 1.誰が作ったの?
   Icon(アイコン)は、米国アリゾナ大学のGriswold教授(のグループ)
  が、コンピュータ研究の際に作った、テキスト処理に重点をおいたプログ
  ラム言語です。
  そして現在もGriswold教授のグループでサポートされています。

   Griswold教授は、SNOBOL(スノーボウル)という強力なテキスト処理言
  語をその前に作って作っています。(私は使ったことは無いのですが。)

   しかし、SNOBOLは今風の構造化プログラム対応ではないので、とっつ
  きにくいため、全面的に作り替えたというふうなことをおっしゃっていま
  す。 今は、テキスト処理結果をグラフィック化処理して分かりやすく見
  せための機能拡張が行われつつあります。

   Griswold教授は、学生へのプログラミング教育の教材にも使われていま
  す。

   アリゾナ大学には、Icon言語のサポートグループ(icon-project)があり
  ます。質問等は、icon-project@cs.arizona.edu に送ると答えてもらえます。
  (勿論、英語でないと分からないと思いますが。)

 2.Icon ってフリーソフト?
   Iconは、Griswold教授(とそのグループ)が行っている研究の副産物と
  いうことで、PDS(Public Domain Software)とされています。

   実行形式と共に、ソースファイルも公開されています。またライブラリー
  も公開されています。

   誰でも、自由に使用や配布をして良いし、またソースをいじって、機能
  追加・変更等を行ってもかまわないということです。
   ということで、フリーソフトの細かい定義は別として、フリーソフトと
  いうことです。

   尚、icon-projectはアリゾナ大学としては非公式な組織の扱いとなって
  いるそうです。

 3.資料はありますか?
  1)WWW
   icon-project では、WWWでIconの情報を公開しています。ここで殆ど全て
  の情報(と情報源)がわかります。 urlは
          http://www.cs.arizona.edu/icon
  です。

  ここがIconのメインメニューとなっていまして、更に
   ・プロジェクト状況
   ・入門ドキュメント
   ・プログラム
   ・ライブライリー
   ・ドキュメント
  等を見たり、ファイルを入手したりできます。

  メニュー次に載せます。(96/11下旬頃のもの)

The Icon Programming Language

Icon is a high-level, general-purpose programming language with a large
repertoire of features for processing data structures and character strings.
Icon is an imperative, procedural language with a syntax reminiscent of C and
Pascal, but with semantics at a much higher level.

Book Sale!

Status Report

Language Information

    Dave Hanson's Brief Introduction
    John Shipman's Tutorial
    An Overview
    Reference Information
    Programming Corner
    
Implementations

    Versions
    Version 9.1
    FTP Area for Binaries
    FTP Area for Source
    
Program Library

    Indexes
    Technical Report
    Submission Guidelines
    FTP Area
    
Documentation

    Frequently Asked Questions
    Technical Reports
    The Icon Newsletter
    The Icon Analyst
    Third Edition of the Icon Language Book
    Graphics Book
    Other Documents

  2)本
   The Icon Programming Language

  という本が発行されています。 現在は第2版を購入できます。
  今は第3版の発行準備中です。予定は今年の11月中旬となっていますが
  今日現在のところ発行されたというアナウンスはありません。

  (1996/12/6付けの status report では印刷中となっています。もう注文できる
   みたいです。 追記1996/12/7)

  3)Newsletter
    Newsletterが年2回発行されています。 以前はもっと頻度が高かったのです
   が、WWWで情報公開できるようになったので、回数が削減されてきています。
  (そのうち無くなるかも?)
    NewsletterもWWWにて、公開されているため、現在はWWWが無い環境の方のため
   という意味合いになってきています。
   (WWWが以前は郵送料も含め無料だったのですが、今は有料。といっても印刷代
    +郵送料程度。)

  4)Icon Analyst
   年6回、プログラミングテクニックとか応用とかについて技術サポート
   資料が発行されています。(有料。と言っても印刷費+郵送料程度)

 尚、どんなものか試してみるだけなら、WWWから手に入る資料で十分です。

 じゃ、第1回はこの辺で。(後が続くのだろうか?)
                           【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)
(icon_01.txt)



■  Icon > Icon入門講座(2) Iconの入手方法は? 風つかい    目次へ

 1.Icon(アイコン)を、とりあえず動かしてみたいが?
    Iconは色んなマシン上で動きますが、Windows3.1/95の
   DOS窓で動くもの(386バージョン)を入手するとして説明します。
   (私がこのバージョンしか動かしたことが無いもので....)

  1)パッケージの入手

    ・ftp://ftp.cs.arizona.edu/icon/packages
     から入手できます。

     そこに使用環境毎のディレクトリーがあります。

 acorn          13-Jun-96 13:43      -
 amiga          22-Jun-96 16:17      -
 atari          21-Mar-96 00:00      -
 macintosh      21-Mar-96 00:00      -
 msdos          24-Mar-96 00:00      -
 mvs            24-Apr-96 00:00      -
 os2            21-Mar-96 00:00      -
 README         20-Mar-96 00:00     1K
 unix           21-Mar-96 00:00      -
 vms            21-Mar-96 00:00      -

で、ここで、msdosを選ぶと

 9.0            24-Mar-96 00:00      -
 de.lzh         24-Mar-96 00:00   339K
 de386.lzh      24-Mar-96 00:00   264K
 ds.lzh         01-Mar-96 00:00   1.4M
 README         24-Mar-96 00:00     1K

と、msdos用のファイルが現れますので de386.lzhを選んでダウンロードします。
(その他の環境の方は該当の機種のディレクトリーから入手して下さい。

 尚、msdosでEMS無しの環境の方は、de.lzhです。
 また、1.4Mの大きなds.lzhはCで書かれたソースファイルです。)

 圧縮に吉崎さんのLHAを使ってくれているのを見るとうれしいですね。
 日本のフリーソフトが世界で使われているのだと実感できます。

 2)ファイルの解凍
  ・ファイルの拡張子がLZHですので、LHAで解凍して下さい。
  ・すると以下のファイルができます。これをまた解凍します。
Listing of archive : DE386.LZH

  Name          Original    Packed  Ratio   Date     Time   Attr Type  CRC
--------------  --------  -------- ------ -------- -------- ---- ----- ----
  DOCS.LZH         23078     23078 100.0% 96-03-24 08:58:46 a--w -lh0- 593D
  ICON.LZH        245336    245336 100.0% 96-03-24 08:14:40 a--w -lh0- 0A1A
  README            1069       587  54.9% 96-03-24 08:17:08 a--w -lh1- 84A2
  SAMPLES.LZH       1456      1448  99.5% 96-03-24 08:10:44 a--w -lh1- D10E
--------------  --------  -------- ------ -------- --------
     4 files      270939    270449  99.8% 96-05-06 00:02:38

  ・DOCS.LZHからは、ドキュメントがでてきます。
   (英文です。はい。)
    ・IPD248 :MSDOS 32ビット版の使い方
    ・IPD266 :Icon Ver9.1の概要
    ・IPD267 :Ver8.0からの変更内容
    ・IPD46  :トラブルレポート用紙

Listing of archive : DOCS.LZH

  Name          Original    Packed  Ratio   Date     Time   Attr Type  CRC
--------------  --------  -------- ------ -------- -------- ---- ----- ----
  IPD248.DOC       11950      4875  40.8% 96-03-24 08:57:52 a--w -lh1- D0F9
  IPD266.DOC       19190      7364  38.4% 96-03-24 08:57:54 a--w -lh1- 4621
  IPD267.DOC       26971     10259  38.0% 96-03-24 08:57:56 a--w -lh1- 91A0
  IPD46.DOC          786       444  56.5% 96-03-24 08:57:56 a--w -lh1- 580D
--------------  --------  -------- ------ -------- --------
     4 files       58897     22942  39.0% 96-03-24 08:58:46

  ・ICON.LZHからは、
    ・icont.exe :Iconのコンパイラ(中間言語への変換)
    ・iconx.exe :実行モジュール(中間言語インタープリータ)
   が、でてきます。
Listing of archive : ICON.LZH

  Name          Original    Packed  Ratio   Date     Time   Attr Type  CRC
--------------  --------  -------- ------ -------- -------- ---- ----- ----
  ICONT.EXE       144097     78446  54.4% 96-03-24 08:13:28 a--w -lh1- 4CAD
  ICONX.EXE       291422    166823  57.2% 96-03-24 08:13:30 a--w -lh1- 0B06
--------------  --------  -------- ------ -------- --------
     2 files      435519    245269  56.3% 96-03-24 08:14:40

  ・SAMPLES.LZH からは、サンプルプログラムがでてきます。
Listing of archive : SAMPLES.LZH

  Name          Original    Packed  Ratio   Date     Time   Attr Type  CRC
--------------  --------  -------- ------ -------- -------- ---- ----- ----
  CROSS.ICN          700       362  51.7% 85-09-08 05:54:04 a--w -lh5- 085D
  HELLO.ICN           85        61  71.8% 86-09-28 00:24:08 a--w -lh5- 3952
  MEANDER.ICN        803       394  49.1% 85-09-10 15:02:26 a--w -lh5- 1D26
  ROMAN.ICN          612       343  56.0% 85-09-08 05:54:44 a--w -lh5- 25F4
  CROSS.DAT           56        52  92.9% 85-09-08 05:55:08 a--w -lh5- 97B0
  MEANDER.DAT         23        23 100.0% 85-09-10 15:02:40 a--w -lh0- C092
--------------  --------  -------- ------ -------- --------
     6 files        2279      1235  54.2% 96-03-24 08:10:44

  hello.icn が、よくある hello world プログラムです。
  Iconのプログラムは拡張子にicnを使います。


 2.hello world はどうやって動かすの?
   サンプルの中のhello.icn は次のようなものです。
   バージョン表示、対象ホスト表示と hello world を表示するものです。

-----^ HELLO.ICN ( date:86-09-28 time:00:24 ) --------------<cut here
procedure main()
   write(&version)
   write(&host)
   write("hello world")
end
-----$ HELLO.ICN ( lines:5 words:7 ) -----------------------<cut here

   awk との比較でいいますと、
   ・print が write になっていて、
   ・プログラム全体は procedure と endでくくられている。
   ・&version と &host はキーワード(Iconプログラム自体が持つ定数)
    (awk には相当のものはありません)

   このファイルを icont.exe を使ってコンパイルすると実行モジュールが
   できます。 icont.exeにパスが通っている環境で、コマンドラインから

    icont hello.icn

   とすると
    hello.exe

   ができます。 このexeファイルは、白鷺で処理した awkスクリプトと
   同じやりかたで作成したexeファイルと考えて下さい。
  (ファイルの先頭で、iconxを呼んで後続するスクリプト(iconの場合は
   中間言語コード)を引数として実行させる方式)

    iconx.exeにパスが通っている環境で、

        hello > hello.txt

      を実行しますと、結果は次のようになります。

-----^ HELLO.TXT ( date:96-11-17 time:01:47 ) --------------<cut here
Icon Interpreter Version 9.1.  November 21, 1995
PC 386 in 32-bit protected mode ex Watcom C/389 9.0
hello world
-----$ HELLO.TXT ( lines:3 words:19 ) ----------------------<cut here

 じゃ、第2回はこの辺で。(後が続くのだろうか?)
                           【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)
(icon_02.txt)



■  Icon > Icon入門講座(3) Iconの特徴は?(1) 風つかい    目次へ

 あれれ、ヘッダーを間違えていましたね。 Iocn じゃなくて Icon です。
                                           ~~              ~~
(追記: 当初ヘッダーのIconの綴りを間違えていたのです。)

 両手でタイプしていると、右手と左手の同期がとれなくて、字が入れ違って
しまうのが良くあります。 というか、左手が遅いので、右手で打つ次の文字
が先に来てしまうんですね。
 それをまたコピーして使うと軒並み間違ってしまうんですね〜。
 ま、いっか。 Icon入門講座の方はつづりが合っていたので。

 Iconって何なんだと聞かれてましたが、なんといったらいいんでしょうね〜。
 テキストデータ処理の中でも、【テキスト解析言語】とでもいったらいいの
かな〜?。

 ヘッダーの間違いだけで書き込むのもナンですので、 次の週末に予定して
いた分からのうち少し書いてアップしましょう。 さて、第3回です。

 1.Icon(アイコン)の特徴は何?

  1)テキスト(文章)解析言語とでも

    Iconは、テキストデータ処理の中でも、テキスト(文章・文書)解析
   向けに考えられたようです。
    文章が、どういう構成になっているかなんかの解析(構文解析)は得意
   の分野です。(でも私はその辺が良くは理解できていませんので...)

  2)awk の処理の基本

    まず、awk と比較できるところから説明したいので、 awkの処理の基本
    事項をあげてみます。

     (1) 1行づつ awkが、テキストファイル(デフォルト:標準入力)
       から読み込んで

     (2) その行を awkが、FS(Field Separater)に従って、分割し
       $1,$2,...へセットしてくれる。
       $0へは、行全体がセットされる。

     (3) スクリプトにて、$0,$1,$2...に対するマッチングパターンを
       指定し、一致が取れたとき(/取れないとき)のアクション
       指定する。

     (4) マッチングパターン指定には、正規表現を使う。

     (5) 組み込みデータ構造としては、連想配列がサポートされている。

     (6) プログラム制御構造としては、
        ・順次処理       ・・・順番にという当たり前の処理
        ・if ... then ... else
        ・while
        ・for
        ・do
        ・&&
        ・||
        ・ユーザー関数
        ・組み込み関数

    というようなところでしょうか。

    この中で、連想配列は、うまく使うとプログラムとても簡潔になり、
    世の中に、こんなにすばらしいものがあったのだ!。と【感動】した
    覚えがあります。

    今日、AWK についてあんましうろ覚えで書くのもナンだからと AWK教典
    (プログラム言語 AWK)を読み返していましたら、エピローグのところ
    に、連想配列はSNOBOLの表から思い付いたと書いてありました。
    ふむ、ふむ。だから、awk にも、Iconにも連想配列(Iconではテーブル)
    があるんだと納得しました。

    この後に、Iconとの違いを書く予定ですがそれは、週末に...


 ほんじゃ、第3回はこの辺で。
(後が続くのだろうか?   ・・・酒とタバコと音楽さえあれば...)
                           【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 愛よりも激しく、誰よりも愛しく/Favorite Blue
BGD: 薩摩白波5:5お湯割り             <- D: Drink
BGS: Mild Seven Menthol               <- S: Smoke
(icon_03.txt)



■  Icon > Icon入門講座(4) Iconの特徴は?(2) 風つかい    目次へ

 ううっ。また、前回の講座で、1か所Iocnになっていた。
 ・・・と嘆きつつも、メゲずに第4回です。
(追記 このテキストでは、もう直っています。)

 週1のペースでは、今年中に終わりそうもないので、少しペースをあげます。

 前回あげた awkの処理の基本項目について、Iconとの違いをみていきましょう。
 いずれの項目も 幾ばくか...大幅か...程度は色々ですが、違いがあります。

 3)テキストファイルの読み込み
    awkで処理対象のテキストファイルを読み込むとすると、コマンドラインから
   (1) jgawk -f nantara.awk kantara.txt    とするか
   (2) jgawk -f nantara.awk < kantara.txt   とすれば

   awk は賢く、kantara.txtを1行づつ読み込んで、nantara.awkで処理しやすい
   ように、その行を、FS(Field Separater デフォルト:" ")の指定に従って、
   欄(カラム)へ分解し、$1〜$nにセットしてくれます。

   で、Iconでは、
   nantara.icn をコンパイルした、nantara.exeがあったとします。
   (2)のように、 natara < kantara.txt  とやれば、nantara.icnで処理でき
   ます。(nantara.icnにファイル読み込み関数を使うのですが。)

   しかし、(1)のようにコマンドラインパラメータ指定しても自動的には読み込
   みは行われません。(nantara.icnの中でコマンドラインパラメータを解析し
   てファイルオープン手続きを行えば可能なのですが。)

   更に、読み込んだ行を走査して自動的に欄に分解するような事もしません。

   で・・・、自分でやるのです。そのための行解析の手段が提供されています。
   その手段は、データタイプの説明をした後でないと説明が難しいので、その後
   にします。

   (2)の形式の 標準入力からファイル読み込みを行い、標準出力に出すプログ
   ラムは以下のようになります。

-----^ SAMP_01.ICN ( date:96-11-20 time:23:35 ) ------------<cut here
procedure main()
  while line := read() do { # 1行読込みを繰り返す。失敗する迄。標準入力から。
    write(line)             # 出力。標準出力へ。
  }
end
-----$ SAMP_01.ICN ( lines:5 words:15 ) --------------------<cut here

   while の考え方はほぼ、awkと同じです。 後に書かれた式 line := read()
   が【成功】している間は繰り返すという意味になります。
   そしてその間は do以降を実行します。
   (式という言い方は正確ではないかも。Icon教典では、expressionです。)

   read()はファイルからの読み込み関数(awkの関数相当)で、1行読み込みを
   行い、【成功】時の関数の値は、読み込んだ行のデータです。
   デフォルトでは標準入力から読み込みます。
   (read()の括弧内にはファイルハンドルを指定できます。)

   := は代入です。 ここでは、変数lineにread()の値をセットしています。
   (ちなみに = は数データの比較記号につかいます。 == は文字データの
    比較記号です。)

   write()は出力関数です。(awkのprint相当) 出力ファイルはデフォルトでは
   標準出力です。 lineの値を出力しています。

   # は awkと同じくコメントの始まり記号です。

   awkなら

-----^ SAMP_02.AWK ( date:96-11-20 time:23:31 ) ------------<cut here
{
  print
}
-----$ SAMP_02.AWK ( lines:3 words:3 ) ---------------------<cut here

   に相当します。 これを、Iconでは samp_01.icn のように表すわけです。
   read()は、 awkの getline相当かな。


   これだけでは、あまり面白くないので、Icon独自の補足を少し。

  【ジェネレータ:generater】
    read()はIconでは、ジェネレータと呼ばれるもの の1種です。

   ジェネレータとは、値を次々に発生するもの のことです。データ発生器
   とでもいいましょうか。

   ファイルはふつう複数行からなりますので、read()は次々に行データを
   発生することができますのでジェネレータの仲間ということになります。

  【成功と失敗:success and failure】
    Iconでは、【成功】と【失敗】という考え方があります。
    あるプロセデュアがうまくいくと成功ということになり
    そのプロセデュアはある値を持ちます。

   先のread()ではファイルからデータが読み込めている間は成功していて
   その結果、値(行データ)を持ちます。

   すると  read()を使っている式 line := read() も成功します。
   その結果、値(この場合は同じく行データ)を持ちます。

   その結果、while line := read() も成功します。 そこで、do以降が
   実行されます。

   do { ... } は失敗することもあります。 write(line)ができない時です。
   例えば、ディスクエリアが無くなったときとかは、失敗します。

   通常は、
    ・ファイル末尾にきてデータが無くなり、read()が失敗し、
    ・その結果 line := read() が失敗し、
    ・その結果 while が失敗し、 while が終わります。

   ついでに、
   line := read() も値を持つと書きましたが、そのことからサンプル1は
   次のようにも書けます。

-----^ SAMP_03.ICN ( date:96-11-20 time:01:40 ) ------------<cut here
procedure main()
  while write(line := read())
end
-----$ SAMP_03.ICN ( lines:3 words:7 ) ---------------------<cut here

   すると、一旦 lineにread()をセットする必要もありませんので

-----^ SAMP_04.ICN ( date:96-11-20 time:01:41 ) ------------<cut here
procedure main()
  while write(read())
end
-----$ SAMP_04.ICN ( lines:3 words:5 ) ---------------------<cut here

   でも大丈夫です。

   Iconでは、ジェネレータ、成功&失敗 が重要な概念です。
   式そのものが値を持つという点は慣れると便利です。

 それでは、第4回はこの辺で。
(なんとか続いているが、この項は何時終わるのだろうか?)
                           【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 愛よりも激しく、誰よりも愛しく/Favorite Blue
BGD: 大関のものも レンジでチン
BGS: Mild Seven Menthol
(icon_04.txt)



■  Icon > Icon入門講座(5) Iconの特徴は?(3) 風つかい       目次へ

 Iconを手入れたいと思ったのは、BYTEの94/5月号の
  The Icon Prgramming Language
      A new way to deal with strings and structure
                                          Ralph E Griswold
という記事を読んでからでした。
 awkよりいろんな機能が組み込まれているし、なかなか変わった言語だな〜。
ちょうどperlに挫折しかけていたので、これなら頭の切り替えができて勉強しやすい。
ということで、使いはじめました。(その代わりperlは完全に挫折しましたが。)

 現在は、この記事はWWWでみることができます。urlは次の場所です。
        http://www.byte.com/art/9405/sec12/art2.htm
  http://www.byte.comのサーバには、過去の記事の検索機能がありますので、
  とにかくアクセスして、Icon programming で検索されても見つかると思います。

 では、第5回をはじめます。 ひき続き awkとIconとの違いです。

 4)パターンマッチの考え方
    awkの場合は
    (1) awkが、読み込んだ行を、先頭から走査して、
    (2) FSを探してFS以外の部分を順次 $1〜$nにセットします。
    (3) 更に、 awkはスクリプトで指定した $1〜$n とパターンの照合指定に
      従って照合し
    (4) アクションを決定します。

    awkでは、(1)、(2)は自動的にやってくれる訳で、プログラマーは (3)以降を
   プログラムするのですが、

   Iconの場合は (1)、(2)の部分からプログラムできます。
   (逆にやらないといけない訳です。)

   そのせいか、正規表現を使った照合機能はIcon自体には組み込まれていません。
   (ライブラリーにはありますので、必要なら使えます。)

   次のデータ構造の話をしないと、Iconが、(1)、(2)のあたりのサポートのため
   にどんな機能を持っているか説明しづらいので、早々に次にいきます。

 5)データ構造
     awkは、データタイプとして、次のタイプがある(と思います)。
     ・数  整数
         実数
     ・文字列
     ・連想配列
    −−−−−−−−−−−−これ以降はIconに比較してデータタイプといえる
                だろうというものです。
     ・正規表現文字セット      :[a-z]の様な文字の集合。
                      パターン指定にのみ使用可能。
                      Iconではcset
     ・正規表現文字列集合      :^#[0-9]+\/[0-9]+の様な文字列集合。
                      パターン指定にのみ使用可能
                      Iconにはありません。
     ・ファイル
     ・関数

    Iconでは次のデータタイプがあります。
     ・null              :awkでは不要。
     ・数  整数  integer      :awkと同じ
         実数  real       :awkと同じ
     ☆文字     cset       :文字(の集合)
     ・文字列    strings      :awkと同じ
     ☆集合     set        :(何かの)集合
     ☆リスト    list       :なんて説明しようか
     ・テーブル   table       :awkの連想配列相当
     ・ファイル   file
     ・procedure   procedure     :awkの関数相当
     ☆(訳不明)  co-expression   :よくわかりません

    では、 私がわかるものを、おおまかに説明します。
     ・null
       これは、 awkでは無いというより不要といった方が良いと思います。
       awkでは、変数を使っても特に初期化をする必要はありません。
       初期値は、0 か ""(空の文字列)のどちらかの適当な方に解釈され
      ます。
       Iconでは、初期値はnullです。というか初期化されていない状態を
      nullというんでしょうね。 最初に代入されたときにタイプが(大抵
      ・・・あんまし自信がありません。)決まります。
        awkでは、たとえばカウンターを使う時、初期値 0は特に設定しなく
      てインクリメントしてもよいのですが、Iconでは、初期値をセットし
      ないと、nullに演算したといって怒られます。

     ・数字は特に違いは無いと思います。

     ・cset
       文字の集合です。ここでいう文字とは、1バイトのキャラクターを意味
      します。 これに相当するものは、 awkにもあります。 正規表現で、
      [a-z]と書いたときには、アルファベットの小文字は全て適合するので
      アルファベットの小文字の集合と言えると思います。 それと同じもの
      です。 awkでは照合パターンの指定にしか使えませんが、Iconでは何時
      でも使えます。
       'abcdef1234'
      というような表記をします。これはアルファベットの aから fまでも文字
      と 1から4までの数字の集合です。
       よく使う文字セットには予め用意されています。
         &ucase        英字大文字 A-Z
         &lcase        英字小文字 a-z
         &ascii        ascci文字
         &letter       a-zとA-Z
         &digits       0-9
         &cset         全文字(256個)   でも何に使うんだろう?

      cset同士で演算ができます。
       和 c1 ++ c2
       差 c1 -- c2
       積 c1 ** c2

     ・string
       文字列です。 これは awkと同じです。
       "ABCDE" というように表します。

      string同士の接続ができます。
       接続 s1 || s2
      部分文字列を切り出せます。 文字の位置指定にて行います。
      位置は文字と文字の間を表しています。
        ・先頭の文字の手前が 1で順に数えます。
        ・末尾の文字の後ろは 0とも表示できます。
        ・後ろからも指定できます。 マイナス側に数えます。
        ・1文字だけ指定する場合は、後ろの指定は不要です。
         s[n:n+1] は、s[n]という表記でかまいません。

      例 "ABCDE"[1:3] は"AB"
        "ABCDE"[4:6] は"DE"
        "ABCDE"[4:0] は"DE"
        "ABCDE"[-2:0] は"DE"
        "ABCDE"[3:4]  は"C"
        "ABCDE"[3]    は"C"

     ・set
      集合です。なにかの集まりを示します。要素は制限がありません。
      csetでもstring でもlistでもsetでも。また混在しても構いません。

       setは、空の setを生成して、要素を挿入するか
      次に述べる listを setへ変換して生成するかで作成します。

     ・list
      順序つけされた、なにかの集まりです。これも要素は制限ありません。
      csetでもstring でもlistでもsetでも。また混在しても構いません。

      これは空のリストを定義して要素を追加するか、次の様に表記します。
         ["ABCD",123,["abc"]]
       文字列 "ABCD"と  数 123と "abc"を要素に持つリスト を要素に
      持つリストの例です。

      リストの要素は位置指定ができます。 ちょっと説明が面倒なので、
      別変数に代入して説明します。

         L := ["ABCD",123,["abc"]]

      L[1]    は "ABCD"      となります。
      L[2]    は 123         です。
      L[3]    は ["ABC"]     です。
      L[3][1] は "ABC"       です。
      L[1:3]  は ["ABC",123] です。

      リストには、先頭への要素の追加、先頭からの削除(兼取り出し)
            末尾への要素の追加、末尾からの削除(兼取り出し)
      ができます。

     ・table
       awkの連想配列と同じですが、生成指示が必要です。
         T := table()
      とかで生成します。()には初期値が指定できます。(指定しないと
      nullが初期値)
         T["abcd"] := 123
      と表記しますと、"abcd" をキーとして、データ 123をセットした
      ことになります。

     ・file
      ファイルへの入出力の時に使うファイルハンドルです。
      下記はキーワード指定できます。
       &output           ファイル出力のデフォルト指定なので
                通常は指定不要。
                write(line) は write(&output,line)を
                意味します。

       &input      ファイル入力のデフォルト指定なので
                通常は指定不要。
                read() は read(&input)を意味する。

       &errout      標準エラー出力指定。
                write(&errout,line)の様に使います。

     ・procedure
       なんでこれがタイプに分類されるのかよく理解していません。

     ・co-expression
       これは全く理解できていません。

 ふ〜。やっとデータ構造の所まできました。  あと制御構造をやったらパターン
マッチングの説明ができるようになって、それでIconの特徴の説明はおしまいとなり
ます。

 ほんじゃ、第5回はここらで。

                           【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: MOSAIC/遊佐未森
BGD: かりん酒5:5お湯割り
BGS: Mild Seven Menthol
(icon_05.txt)



■  Icon > Icon入門講座(6)Iconの特徴(4)制御構造 風つかい       目次へ

 おっと〜。 またやってしまった。 前回のcsetの説明の中で、&ucase と &lcase
の補足が逆です。 a-z とA-Z を逆に書いていました。
(追記 このテキストでは直っています。)

 では、第6回をはじめます。 しつこく awkとIconとの違いです。

 6)プログラム制御構造
   Icon は、制御構造として、次のものがあります。

    ・順次処理        :順番にという当たり前の処理
    ・if ... then ... else  :awkとほぼ同じ。
    ☆case          :分岐、選択。
    ☆every          :全ての要素に対して、繰り返す。
    ☆repeat         :繰り返す。
    ☆until          :条件が成功するまで繰り返す。
    ・while          :awkとほぼ同じ。
    ・&            :両方が成功したら成功。
    ・|            :いずれかが成功したら成功。
    ・関数          :awkの関数とほぼ同じ。組込みプロセデュア。
    ・procedure        :awkの関数とほぼ同じ。ユーザ関数。
    ☆fail          :強制的に失敗させる。

  ・if ... then ... else は、次の様に使います
   if ss == "TOKYO" then write("東京")     # == は文字列の照合記号
                       else write("不明")
      ssの場所にも、write("TOKYO")の場所にも、write("不明")の場所にも
      式が使えます  上の例は次の様に書けます。
      write(if ss == "TOKYO" then "東京" else "不明"))      


  ・case は、次のように使います。
      case ss of {
        "TOKYO"    :   write("東京")
        "YOKOHAMA" :   write("横浜")
        default    :   write("不明")
      }

   ss という変数が、 "TOKYO"     だったら、"東京"と出力し
            "YOKOHAMA"  だったら、"横浜"と出力し
            それ以外だったら、  "不明"と出力します。
      ssの場所にも、"TOKYO"の場所にも、write("東京")の場所にも式が使えます。
      上の例は、if ... then ... else と同様に、
     write( case ss of {
              "TOKYO"    :   "東京"
              "YOKOHAMA" :   "横浜"
              default    :   "不明"
            } )
       と書いても同じです。プログラム例を次にあげます。

-----^ SAMP_05.ICN ( date:96-11-22 time:23:19 ) ------------<cut here
procedure main()
# case の使用例
  write(loc("TOKYO"))          # procedure locを "TOKYO"を引数として呼ぶ。
  write(loc("YOKOHAMA"))
  write(loc("CHIBA"))
end

procedure loc(ss)
#             ↑ssは仮パラメータ
  return case ss of {
           "TOKYO"    :   ("東京")
           "YOKOHAMA" :   ("横浜")
            default   :   ("不明")
         }
end
-----$ SAMP_05.ICN ( lines:15 words:33 ) -------------------<cut here

   実際のプログラムでは、こういう単純データ変換は、テーブル(awkの連想配列)
  を使うのが順当なやり方だと思いますが、そこはサンプルということで...


  ・everyは次のように使います。ジェネレータ(データを次々に発生するもの)
   に対し順に処理を行います。

-----^ SAMP_06.ICN ( date:96-11-23 time:20:33 ) ------------<cut here
procedure main()
# every の使用例
# サンプル用データ
  ss := "ABCD1234"             # string
  LL := ["AB","CD",123]        # list
# ssの文字を1字づつ出力
  every i := 1 to *ss do {     # *は引き続くものの要素数を表わします。
    write(ss[i])               # *ss はssの文字数を表わします。
  }
# LLの要素を1つずつ出力
  every i := 1 to *LL do {     # *LL はLLの要素数を表わします。
    write(LL[i])
  }

# データを順に取り出す記号 ! を使うと簡潔に書けます。
# こちらが普通の記法
  every write(!ss)             # string  の先頭から順に取り出し出力
# こちらが普通の記法
  every write(!LL)             # list の先頭から順に取り出し出力

end
-----$ SAMP_06.ICN ( lines:21 words:68 ) -------------------<cut here


  ・repeat と until と while の使用例を次にあげます。

-----^ SAMP_07.ICN ( date:96-11-23 time:21:20 ) ------------<cut here
procedure main()
# repeat の使用例
# 1 〜10まで順に出力
  count := 0
  repeat {
    writes(" ",count +:= 1)     # writes は、改行を出力しないwrite
                                # n1 +:= n2 は n1 := n1 +n2 の省略記法
    if count = 10 then break    # break は、ループからの脱出
  }
  write()                       # 改行出力

# until の使用例
# 1 〜10まで順に出力
  count := 0
  until count = 10  do writes(" ",count +:= 1) # count = 10が成功するまで
                                               # do 以降を繰り返す。
  write()

# while の使用例
# 1 〜10まで順に出力
  count := 0
  while count < 10 do writes(" ",count +:= 1) # count < 10が成功している間
                                              # do 以降を繰り返す。
  write()
end

-----$ SAMP_07.ICN ( lines:26 words:96 ) -------------------<cut here

 尚、こういう簡単な条件だと、先ほどの every を使えば

   every i := 1 to 10 do write(" ",i) と書けます。


  ・& は awkの && に相当します。
   Iconでは、 & の左右に式が来ます。 awkでは条件式です。 awkでは条件式
   (パターン指定) とそれ以外の式(アクション式)が区別されていますが
   Iconではその区別がありません。

   式1 & 式2 は、式1を評価(実行)し、式1が成功したら、式2を評価
   (実行する。)と言う処理になります。

   例えば、以下の表記でも問題ありません。
    write("AAA") & write("BBB")         これは、
    if write("AAA") then write("BBB")      と同じです。
   "AAA" と "BBB" を順に出力します。


  ・| は awkの || に相当します。
   Iconの場合は  | の左右に式がきます。 左側の式が成功すると、右側の式は
   実行されません。 左側の式が失敗すると右側の式が実行されます。
   プログラム例を次に示します。コマンドライン引数(の1番目)をファイル
   名としてファイルオープンし成功したら、ファイルを読み込んで行の頭に行
   番号を付加します。 オープンできなかったら、エラーメッセージを出力し
   ます。

-----^ LINE_NO.ICN ( date:96-11-24 time:00:02 ) ------------<cut here
procedure main(args)
# add a line number to each line
  dir := open(args[1]) | stop("error")  # コマンドライン引数にてファイル
                                        # オープン。失敗なら、"error"を
                                        # 出力しストップ。
  line_no := 0
  while line := read(dir) do
  write(line_no +:= 1,":",line)
end
-----$ LINE_NO.ICN ( lines:9 words:33 ) --------------------<cut here

   別の言い方をしますと、 | は、ジェネレータを構成します。
    式1 | 式2は、式1と式2を発生するジェネレータであり、
     ・式1が成功すると成功し、式2の評価はしない。(実行しない。)
     ・式1が失敗すると、式2が評価される。
   と言う処理になります。

   every で、順次処理指定が前にきますと、まず式1が評価され次に、式2が
   評価されます。
   次の表記は、"AAA" と "BBB" を出力します。
    every write("AAA" | "BBB")


  ・failは、処理を強制的に失敗させるのに使います。


 でわ、では。第6回これくらいで。
 さ〜て、やっと次回に文字列走査処理(string  scannning)に移れます。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: HOPE/遊佐未森
BGD: ジャスミンティー
BGS: Mild Seven Menthol
(icon_06.txt)



■  Icon > Icon入門講座(7)Iconの特徴(5)スキャン 風つかい     目次へ

 2〜3回で、Iconの特徴を述べる予定でしたが、もう7回目になってしまいました。
説明するって大変なんですね〜。  やっと今回の文字列走査(string scanning)で
おしまいになる予定です。 これを早く説明したかったのですが、その前に説明して
おかないといけないことが沢山あって... でも、これでも awkの知識をお持ちの
方を前提にしていますので、まだ楽なんで、 awkの知識が無い方をターゲットに説明
するのだともっと大変でしょう。     では、第7回をはじめます。

 7)文字列走査(string scanning)
   まず、サンプルプログラムを。 スペースで区切られた文字列を順に出力する
   ものです。

-----^ SAMP_08.ICN ( date:96-11-24 time:18:12 ) ------------<cut here
procedure main()
# 文字列走査(string scanning )のサンプル
# スペースで区切られた文字列を出力
# 対象文字列
  line := " The Icon Programming Language"
#
  line ? {                           # 走査対象文字列を指定:line
                                     # 走査位置は先頭から

    while tab(upto(cc := ~' ')) do   # ' '以外の文字に出会ったら走査位置を
                                     # そこへ移動して、 do以降を実行
                                     # ~cというのは、c以外の文字を表わす。

      write(tab(many(cc)))           # ' '以外の文字以外の文字(すなわち' ')
                                     # に出会ったら走査位置をそこへ移動して
                                     # 移動した走査位置の間の文字列を出力。
  }
end
-----$ SAMP_08.ICN ( lines:18 words:50 ) -------------------<cut here

 結果はこうなります。
-----^ SAMP_08.RST ( date:96-11-24 time:18:13 ) ------------<cut here
The
Icon
Programming
Language
-----$ SAMP_08.RST ( lines:4 words:4 ) ---------------------<cut here

 処理を順に説明していきます。 まず、 ? の記法ですが、これは走査対象文字列と
走査処理を示しています。

 式1(走査対象文字列) ? 式2(走査処理)    と表記します。

 この表記を使ったときには、走査対象文字列指定は式1となります。
走査対象文字列にはキーワードが設けられています。 &subject です。
 サンプルプログラムでは、 &subject := lineということになります。

 Iconでは文字列の位置指定は文字と文字の間です。 位置指定が表しにくいので、
説明の便利のため、全角文字で対象文字列を示します。またスペースは■で表わしま
す。

最初の文字T(実際は半角)の左が1の位置です。TheとIconの間のスペース
の左側は5の位置となります。

                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 ■The■Icon■Programming■Language

 * 最初の &position (= 1)

 走査は、文字列の先頭から始めます。すなわち最初の走査位置は、1となります。
 この位置指定はキーワードが設けられています。 &position です。そこで最初は
&position = 1 です。

 while の後の式がまず実行されます。
 upto(c,s)関数は、文字列 sを走査対象として、文字セット(c)の位置を探す関数で
 す。 sを省略した場合は、対象文字列は &subjectです。
 文字が見つかった場合は成功して、uptoの値は、その探し出した文字の位置となり
ます。
                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 ■The■Icon■Programming■Language

 * 最初の &position (= 1)
   * スペース以外を見つけたときの uptoの値 (=2)

 uptoは、最初にスペース以外の文字として先頭のスペースの後のTの検出に成功し
てその値を 2とします。この時点では、&position は未だ、1のままです。
 tab()は、&position を移動する関数です。
 この場合は 2の位置へ移動します。
 その時の tabの値は、前の位置と新たな位置との間の部分文字列と(すなわちスペ
ース1個)となります。 (この値は使っていませんが。)
                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 ■The■Icon■Programming■Language

 * 最初の &position (= 1)
   * スペース以外を見つけたときの upto(cc)の値 (=2)
   * tab(upto(cc)) により &positionをここに移動。(=2)
 --  tab(upto(cc))の値は、移動した部分の文字列。(スペース)

 次に、tab(upto(cc))が成功しましたので、do 以降が実行されます。

 many(c,s)は、文字列 sを走査対象として、現在の &positionの位置以降の c以外の
文字を探します。 sが省略されていますと対象は &subject となります。
 この場合は line の 2以降で、スペース以外の文字以外の文字(ややこしいですが、
すなわち スペース)を探します。
 5の位置にスペースがありますので、manyは成功して、その値は、5となります。
                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 ■The■Icon■Programming■Language

   *  &positionの位置(=2)
         * many(cc) の値(次のスペースの位置)(=5)

 tabの値は、前の値 2 と 今度の値 5 の間の文字列になります。 すなわち
The となります。 この値を writeで出力している訳です。
                   1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 ■The■Icon■Programming■Language

   *  前の &positionの位置(=2)
         * many(cc) の値(次のスペースの位置)(=5)
         * tab(many(cc)) によりここに &positionを移動(=5)
   ------  tab(many(cc))の値は、移動した部分の文字列。(The)

 これで、do の処理が終わって、また while に戻ります。

 どういう動きとなるかは、プログラムを以下のように書き換えて、&position の位置
を書き出して見ると分かりやすいかも。

-----^ SAMP_09.ICN ( date:96-11-24 time:18:39 ) ------------<cut here
procedure main()
  line := " The Icon Programming Language"
  line ? while tab(write(upto(cc := ~' '))) do (tab(write(many(cc))))
end
-----$ SAMP_09.ICN ( lines:4 words:19 ) --------------------<cut here

 結果はこうなります。
-----^ SAMP_09.RST ( date:96-11-24 time:18:40 ) ------------<cut here
2
5
6
10
11
22
23
31
-----$ SAMP_09.RST ( lines:8 words:8 ) ---------------------<cut here

 文字列走査支援関数のうち、upto,many,tab を説明しました。 この他に
  ・move(n)
    &position を nだけ動かす。 成功すると、動かした位置の間の文字列を
   値とします。

  ・any(c,s)
    使ったことが無いのでよくわかりません。

  ・bal(c1,c2,c3,s)
    これも使ったことが無いのでよくわかりません。 プログラム言語では、
   開き括弧と閉じ括弧の数がふつう一致していないといけませんがそういう
   チェックに使えるみたいです。

 で、awkでは自動的にやってくれる、カラム分解はどうやるかを次に例をあげます。

-----^ SAMP_10.ICN ( date:96-11-24 time:19:08 ) ------------<cut here
procedure main(args)
# 文字列走査(stirngs scanning)のサンプル
# awk風のカラム分解の例

# ブロック1 ファイルオープン手続き
  Usage := "Usage : samp_10 input_file > output_file"   # 使用法メッセージ
  # コマンドライン引数の数が1だったら、ファイルオープン。
  if *args = 1 then dir := open(f_name := args[1]) |
    stop("cannot open ",f_name)    # ファイルオープンできなければエラー表示
  else stop(Usage)                 # 引数が1以外だったら使用法表示
  write(&errout,f_name)            # ファイル名表示

# ブロック2 ファイルを読み込みでスペース・タブで分割しリストに入れて、
# リストの要素を番号つきで出力
  while line := read(dir) do {     # ファイルからの1行読み込みを繰り返す。
    L := split(line)               # 読み込んだ行をスペース・タブで区切り
                                   # リストに変換する。
                                   
    show_sln(L)                    # リストの要素を出力(実際のプログラム
                                   # ではここにいろんな処理を記述する。)
  }
end

# ブロック3 行をリストへ変換
procedure split(line,c)
# 文字列を c(cset)で分割し、リストへ変換するプロセデュア
  /c := ' \t'              # 引数に cが省略されていたら、スペースかタブとみなす
                           # / はnullかどうかのチェック。nullならば...。
  list := []               # 戻り値用リストを生成
  line ? {                 # line を走査対象とする。
    while tab(upto(~c)) do   # c以外の文字が見つかったら走査位置をそこ迄移動
      put(list,tab(many(~c)))  # c以外の文字以外(すなわち c)が見つかる位置迄
  }                            # 移動し、移動した位置の間の文字列をlistへ追加
  return list
end

# ブロック4 結果表示procedure
procedure show_sln(list)
# リストの内容表示(テスト/表示用)
  every i := 1 to *list do writes(" ",i," :",list[i])
  write()
  return
end
-----$ SAMP_10.ICN ( lines:43 words:132 ) ------------------<cut here

 う〜む。今回でスキャンを終わらせるつもりでいましたが、未だ終わりません。
あと、string で走査を行う関数が残っています。 それを次回に。

 では、第7回はここらへんで。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 愛の言霊/サザンオールスターズ
BGD: ジャスミンティー
BGS: Mild Seven Menthol
(icon_07.txt)



■  Icon > Icon入門講座(8)Iconの特徴(6)スキャン 風つかい      目次へ

 byte.com の記事検索は便利ですね。雑誌を購読していても古い雑誌の処分には悩み
ます。 雑誌社の方でああいう仕掛けを持っていてくれると助かります。
 国内の雑誌では無いですよね。 雑誌社と記事の著者との契約の問題だと思うのです
が日本でもやってくれると、古い雑誌が捨てることができて助かるんですが。

 さて、前回でIconの特徴を終わらせるつもりでしたが、stringでのスキャン処理が
あふれてしまいましたので、続きです。

 文字列から文字列を検索するための関数として、findと matchが用意されています。

  ・match は、 awkの matchとほぼ同じです。(少し機能が多いのですが、私は同じ
   使い方しかやっていないもので...)

  ・findは、uptoを string対応にしたものです。
   find(s1,s2)は、文字列 s2を走査し、s1が見つかると成功しs1の開始位置を
   値として持ちます。 簡単なサンプルを次に。

-----^ SAMP_11.ICN ( date:96-11-24 time:21:35 ) ------------<cut here
procedure main()
# find のサンプル
  # サンプルデータ
  # 確か中学の時、英語を勉強しはじめた時に、こんな例があったみたい。
  line := "That that that that man used that place is wrong."

# that の位置をかき出す。
  map(line) ? while tab(write(find(s := "that"))) do move(*s)
end
# 補足 map(s1,s2,s3) は、文字変換関数です。s2:s3が変換テーブルになります。
#       map("hello","el","EL") は、"hELLo"となります。
#       s2,s3の指定がないときは、s2:&ucase,s3:&lcaseとなります。すなわち
#       英文字はすべて小文字に変える関数となります。
-----$ SAMP_11.ICN ( lines:13 words:42 ) -------------------<cut here

 結果はこうなります。
-----^ SAMP_11.RST ( date:96-11-24 time:21:35 ) ------------<cut here
1
6
11
16
30
-----$ SAMP_11.RST ( lines:5 words:5 ) ---------------------<cut here

 日本語での照合を行う時は、コードが2バイトですので findで調べなければいませ
ん。
 Icon自体は英語の国の方が作りましたので、2バイト文字は意識していません。
 2バイト文字も1バイトづつの処理になります。

 で、何か使う上で困ることがあるかということですが、ほぼ、実際上の問題はありま
せん。

 データを扱う上では問題ないのですが、プログラム上に2バイト文字を表記する時に
若干の問題があります。2バイト目が、16進コードの 5C すなわち "\"になるコード
の場合に、"\" がコンパイラにエスケープ文字と解釈されるためです。 その場合は、
その文字の後ろに "\"補ってやる必要があります。

 例えば、MS漢字(シフトJIS)ですと
  write("表示") とすると、表の字が16進コードで 955Cとなりますので化け
 ます。 この場合、 write("表\示") とすると正常に表示されます。

 こういうケースは、プログラムのテストの時点で文字化けが分かりますので、その
時点で手を加えれば良い訳です。

 尚、データファイル中に 表 のような2バイト目が 5Cという文字があっても、
それをファイルから読み込んで string  操作して加工する分には、単なるデータ
扱いですので、問題は起きません。

 というところで、Iconの特徴の項は終わりにします。
 あと色んな関数があるのですが、説明はしきれません。

 Icon の関数サマリーは、Icon教典には勿論載ってますが、下記にも含まれています
ので、ご覧下さい。

   ftp://ftp.cs.arizona.edu/icon/library/bipl.lzh
 このファイルは、グラフィック関係以外のライブラリー集です。

 この中に、ihelp.icn と ihelp.dat というのが入っています。 このプログラムは
Iconのヘルププログラムです。 ihelp.datには関数説明が載っています。


 ところで、Iconには何に使えるのかよくわからない機能があります。
 string に関数を代入できるのです。

-----^ NANJARO.ICN ( date:96-11-22 time:22:04 ) ------------<cut here
procedure main()
  print := write     # 関数 writeをprintに代入
  print("AAA")       # すると、printを writeと同様に使える。
end
-----$ NANJARO.ICN ( lines:4 words:13 ) --------------------<cut here

 関数名がstring だからできるとIcon教典(The Icon Programming Language)には
書いてあります。 ということは、これでも動くわけです。

-----^ NANJARO2.ICN ( date:96-11-23 time:11:27 ) -----------<cut here
procedure main()
  "write"("AAA")
end
-----$ NANJARO2.ICN ( lines:3 words:4 ) --------------------<cut here

面白い機能だけれど、関数名を変えると紛らわしいような気がします。


 やっと Iconの特徴の説明が終ったつもりでいますが、感じをわかっていただけた
でしょうか?

 次回からは、Iconプログラムの実例・・・といっても、私が使っているログ処理プロ
グラムあたりを題材にすることになりますが。

 では、第8回はここらへんで。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: LALALA Love Song/久保田利伸
BGD: ジャスミンティー
BGS: Mild Seven Menthol
(icon_08.txt)



■  Icon > Icon入門講座(9) データ構造 set     風つかい     目次へ

 前回までで、Iconの特徴を awkと比較して説明したつもりだったのですが、読み返し
てみると、データ構造のあたりで、使い方をだいぶ はしょってありますね〜。
 set,list,tableについて補足をしようと思います。
 というところで、第9回、いきま〜す。

 set は、集合ですが、関連の関数の説明を。
  ・set(L)
    集合を生成するのは、set(L)関数を使います。 Lはリストです。 指定した
    リストの要素を持つ集合を生成します。
     S := set() で空の集合ができます。 ということは、()に何も指定しない
    と、デフォルトでは、空のリスト[]が使われるということですね。

  ・insert(S,x)
    集合 Sに、要素 xを追加します。 xが既に Sに含まれるときは、Sは変化しま
    せん。 常に成功して、Sを値とします。

  ・delete(S,x)
    集合 Sから、要素 xを取り去ります。常に成功して、Sを値とします。

  ・member(S,x)
    集合 Sに、 xが含まれるかのチェックです。 成功すれば、xを値とします。

  ・sort(S)
    集合 Sをソートされた順に並んだリストに変換します。

  ・演算
    csetと同じように、和、差、積の演算ができます。
    和 S1 ++ S2
    差 S1 -- S2
    積 S1 ** S2

 set は、私は実用に使ったことがありませんので、良い例は出せないのですが、
Icon Newsletter に載っていた例に、若干手を入れたのがありますので、サンプルに。

【エラトステネスのふるい】というのを覚えておいでですか?
 素数を洗い出す手続きですが、これをそのままプログラムして、ふるいをかける様子
を出力するプログラムです。

-----^ SIEVE.ICN ( date:96-11-26 time:00:32 ) --------------<cut here
procedure main(args)
################################
# エラトステネスのふるいのデモ #
################################

# ふるいの大きさの設定
  limit := args[1] | 100         # コマンドライン引数が無ければ、100。
# ふるいに入れる
  S := set()                     # 
  every insert(S,1 to limit)
# 始めますよ〜
  write("エラトステネスのふるい")
  write("1 から ",limit," までふるいま〜す。")
# ふるいの内容表示
  disp(S)

  limit2 := integer(sqrt(limit))                        # ルートNまでふるう。
# ふるいにかける
  every member(S,i := 2 to limit2) do {                 # せっせ、せっせ。
    every delete(S,i + i to limit by i)
    write("\n","ふるいの目 : ",i," 残り : ",*S)
    disp(S)
  }
# 終わったよ〜
   write("\nふるいおわったよ!")

end

procedure disp(S)
# セットをソートして、内容を出力。(表示/テスト用)
  L := sort(S)
  every writes(right(!L,4))  # right(s1,i,s2) 右寄せ桁合わせ関数、i:桁数
  write("")                  # 余ったところには、s2を詰める。s2デフォルトは" "
end
-----$ SIEVE.ICN ( lines:34 words:90 ) ---------------------<cut here


 では、第9回はここらへんで。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 愛すること/辛島美登里
BGD: さつま白波5:5お湯割り
BGS: Mild Seven Menthol
(icon_09.txt)



■  Icon > Icon入門講座(10)データ構造  list        風つかい      目次へ

  今回は、listです。 awkでは、連想配列に【感動】しましたが、Iconでは、このlist
に【感動】しました。  なんせ便利なんですね〜。  しかし考えてみると、データ構造
が載っている本や雑誌には、必ずでてくるリスト構造が、  プログラム言語で標準的に
サポートされていないなんて、とんでもないですよね〜。 市販の本に載っているよう
なデータ構造とアルゴリズムは言語でサポートして欲しいな〜。
というところで、第10回、いきま〜す。

  list は、 setや table(awkの連想配列)と異なり、要素の間に順番がついています
ので、色んな取り扱いが必要です。  そこで支援関数も沢山あります。

    ・list(x,i)
        リストを生成するには、いきなり
          L := ["AA","BB",12,34,["DD","EE"]]

      という風に書いてしまうか、このlist生成関数を使います。
        この関数は、 xを i個分だけ要素に持つリストを生成します。
        ただし私は使ったことがありません。  というのは、最初に空のリストを作っ
      て、そのリストに順次追加していく使い方をするもので、新規リスト生成は
          L := []  で間に合うためです。

    ・リストへの追加・取り出し関数
        put/get,push/pop,push/pull  のペア関数があります。(pushはだぶって
      いますが。)
        要素の順番が問題になりますので、次の3要素のリストにて説明します。
          L := ["AA","BB","CC"]

        このリストは3要素のリストで、先頭が "AA"、次が "BB"、最後が "CC"と
      という構成です。

    【個別アクセス】
        このリストの要素へは、いきなり、L[1]、L[2]、L[3]と指定して
      アクセスできます。
                    (先頭)                    (末尾)
                         ------       ------       ------
    リスト L            | "AA" | --- | "BB" | --- | "CC" |
                         ------       ------       ------
                           ↑            ↑          ↑
    要素へのアクセス法:  L[1]          L[2]        L[3]

    【末尾へ追加し、先頭から取り出す】(QUE,FIFO方式)
        追加要素は末尾の後ろへ追加し、取り去るときは先頭から取り去る場合は
        put/get のペア関数を使います。
        ・put
          末尾の要素の後ろへ要素を追加します。
          put の値は、要素が追加されたリストなります。
        ・get
          先頭の要素をリストから取り出す(取り去り)ます。
          get の値は、取り出した要素になります。

                    (先頭)                    (末尾)
                         ------       ------       ------
    リスト L            | "AA" | --- | "BB" | --- | "CC" |
                         ------       ------       ------
                           ↓                                ↑
                      get 先頭から取り出し            put 末尾へ追加
                         ------                            ------
                        | "AA" |                          | "DD" |
                         ------                            ------

    【先頭へ追加し、先頭から取り出す】(Stack,LIFO方式)
        追加要素は先頭の前へ追加し、取り去るときも同じく先頭から取り去る場合は
        push/pop のペア関数を使います。
        
        ・push
          先頭の要素の前へ要素を追加します。
          push の値は、要素が追加されたリストなります。
        ・pop
          先頭の要素をリストから取り出す(取り去り)ます。
          pop の値は、取り出した要素になります。
          (pop は getと同じです。)

                    (先頭)                    (末尾)
                         ------       ------       ------
    リスト L            | "AA" | --- | "BB" | --- | "CC" |
                         ------       ------       ------
                 ↑        ↓
       push 先頭へ追加  pop 先頭から取り出し
               ------    ------ 
              | "DD" |  | "AA" |
               ------    ------ 


    【先頭へ追加し、末尾から取り出す】(QUE,FIFO方式)
        追加要素は先頭の前へ追加し、取り去るときは末尾から取り去る場合は
        push/pull のペア関数を使います。 put/getと逆方向の使い方です。
        
        ・push
          先頭の要素の前へ要素を追加します。
          push の値は、要素が追加されたリストなります。
        ・pull
          末尾の要素をリストから取り出す(取り去り)ます。
          pull の値は、取り出した要素になります。

                    (先頭)                    (末尾)
                         ------       ------       ------
    リスト L            | "AA" | --- | "BB" | --- | "CC" |
                         ------       ------       ------
                 ↑                                  ↓
       push 先頭へ追加                      pull 末尾から取り出し
               ------                              ------ 
              | "DD" |                            | "CC" |
               ------                              ------ 

    ・sort(L)
        リスト Lからソートされた順に並んだリストを生成します。

  ・sortf(L,i)
    リスト Lの i番目のフィールドにてソートしたリストを生成します。


  あ、そうそう、基本的なことを忘れていました。リストは演算子で連結ができます。
      L1 ||| L2 で、リストを連結できます。

  また、部分リストは部分文字列と同じように指定できます。
      L := ["AA","BB","CC"]        として
          L[1:3]  は、["AA","BB"]  です。
          L[2:0]  は、["BB","CC"]  です。

 では、以上のサンプルプログラムを。

-----^ SAMP_12.ICN ( date:96-11-27 time:18:25 ) ------------<cut here
procedure main()
# リストの使い方のサンプル
  L  := ["AA","BB","CC"]         # サンプルデータ
  L2 := ["DD","EE"]

write("リストの内容")
  write(" L  := [\"AA\"\,\"BB\"\,\"CC\"]")
  write(" L2 := [\"DD\"\,\"EE\"]")

write("個別位置指定サンプル")
  write(" L[1] : ",L[1],"  L[2] : ",L[2],"  L[3] : ",L[3])
  L[2] := "XX" ;  writes(" L[2] := \"XX\"   L: ") ; show_sl(L)

  write("put/get サンプル")
  write(" put(L,\"FF\")")  ; put(L,"FF")          ; show_sl(L)
  writes(" get(L) : ")     ; write(" ",get(L))    ; show_sl(L)

  write("push/pop サンプル")
  write(" push(L,\"GG\")") ; push(L,"GG")         ; show_sl(L)
  writes(" pop(L) : ")     ; write(" ",pop(L))    ; show_sl(L)

  write("push/pull サンプル")
  write(" push(L,\"HH\")") ; push(L,"HH")         ; show_sl(L)
  writes(" pull(L) : ")    ; write(" ",pull(L))   ; show_sl(L)

  write("sortサンプル")
  show_sl(sort(L))

  write("リスト連結サンプル")
  writes(" L ||| L2 : ")   ; show_sl(L ||| L2)

  write("部分リストサンプル")
  writes(" L[1:3] : ")     ; show_sl(L[1:3])
  writes(" L[2:0] : ")     ; show_sl(L[2:0])

  write("sortfサンプル")
  L3 := [["A1","B2","C3"],["A2","B3","C1"],["A3","B1","C2"]]

  write("原データ")              ; show_wl(L3)
  write("フィールド1でソ\ート") ; show_wl(sortf(L3,1))
  write("フィールド2でソ\ート") ; show_wl(sortf(L3,2))
  write("フィールド3でソ\ート") ; show_wl(sortf(L3,3))

end

procedure show_sl(list)
# リストの内容表示(テスト/表示用)
  every writes(" ",!list)
  write()
  return
end

procedure show_wl(wlist)
# 2重リストの内容表示(テスト/表示用)
  every list := !wlist do {
    every writes(" ",!list)
    write("")
  }
  write("")
  return
end
-----$ SAMP_12.ICN ( lines:61 words:166 ) ------------------<cut here


  では、第10回はここらへんで。
                                                            【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: The Incredible Jazz Guiter of Wes Montgomery
BGD: 茉莉花茶
BGS: Mild Seven Menthol
(icon_10.txt)



■  Icon > Icon入門講座(11)データ構造 table    風つかい      目次へ

 今回は、table です。 table は、 awkの連想配列と同じものです。awkより若干、
支援関数が多くなっています。 さて、第11回を始めます。

 では、table の支援関数の説明を。
  ・table(value)
    table を生成するには、table()関数を使います。
    T := table() で空の tableができます。 ()内には初期値を指定できます。
    生成した後は、いきなり、
     T["TOKYO"]    := "東京"     とか
     T["中山美穂"] := [1970,3,1,"O",158,80,60,84,45,"東京都小金井市"]

    とか  key/value のペア形式でデータを挿入できます。

  ・insert(T,key,value)
    table Tの、key に対する valueを追加します。keyが既に Tに含まれるとき
    は、keyに対する valueが更新されます。 Tを値とします。

  ・delete(T,key)
    table Tから、key を取り去ります。 Tを値とします。

  ・member(T,key)
    table Tに、keyが含まれるかのチェックです。成功すれば、keyを値とします。

  ・key(T)
    table Tの keyを生成します。(ジェネレータ)

  ・sort(T,i)
    table Tをソートされた順に並んだリストに変換します。
    i の値によって、リストの作り方とソートのやり方が違います。

    i = 1                            i = 2
     [[key1,value1],[key2,value2],.....,[key_n,value_n]と連なったリスト
      keyでsort            valueでsort

    i = 3                            i = 4
          [key1,value1,key2,value2,....,key_n,value_n]と連なったリスト
      keyでsort            valueでsort

 では、サンプル、いきます。

-----^ SAMP_13.ICN ( date:96-11-28 time:02:30 ) ------------<cut here
procedure main()
# table の使い方のサンプル
  T1 := table()
  write("直接指定のサンプル")
  T1["TOKYO"]   := "東京"
  T1["YOKOHMA"] := "横浜"
  T1["CHIBA"]   := "千葉"
  show_st(T1)

  write("\nvalue がリストのサンプル")
  T2 := table()
  T2["中山美穂"] := [1970,3,1,"O",158,80,60,84,45,"東京都小金井市"]
  show_wt(T2)

  write("\ninsertのサンプル")
  insert(T1,"SAITAMA","埼玉")
  show_st(T1)

  write("\ndeleteのサンプル")
  delete(T1,"SAITAMA")
  show_st(T1)

  write("\nmemberのサンプル")
  if member(T1,s := "YOKOHAMA") then write(s," 有り") else write(s ," 無し")
  if member(T1,s := "SAITAMA")  then write(s," 有り") else write(s ," 無し")

  write("\nsortのサンプル")
  T3 := table()
  T3["AA"] := "FF"
  T3["CC"] := "EE"
  T3["BB"] := "DD"

  write("オリジナルデータ")
  show_st(T3)

  write("\nkey sort ->[[key1,value1]...]")
  show_wl(sort(T3,1))

  write("value sort ->[[key1,value1]...]")
  show_wl(sort(T3,2))

  write("key sort ->[key1,value1,key2,value2...]")
  show_sl(sort(T3,3))

  write("\nvalue sort ->[key1,value1,key2,value2...]")
  show_sl(sort(T3,4))

end

procedure show_st(T)
# table を key : value ペアで出力
  every s_key := key(T) do write(s_key," ",T[s_key])
  return
end

procedure show_wt(T)
# valueがリストの table を key : value ペアで出力。
  every writes(s_key := key(T)," :") do {
    every writes(" ",!T[s_key])
    write()
  }
  return
end

procedure show_sl(list)
# リストの内容表示(テスト/表示用)
  every writes(" ",!list)
  write()
  return
end

procedure show_wl(wlist)
# 2重リストの内容表示(テスト/表示用)
  every list := !wlist do {
    every writes(" ",!list)
    write()
  }
  write()
  return
end
-----$ SAMP_13.ICN ( lines:80 words:159 ) ------------------<cut here

 では、第11回はここらへんで。 今後の予定は、

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: WINK/At Heel Diamond
BGD: 大関のものも
BGS: Mild Seven Menthol
(icon_11.txt)



■  Icon > Icon入門講座(12)procedure/scope         風つかい       目次へ

 また、やってしまった。table(value)の説明で、T := set なんてやってしまって 
います。(追記 このテキストでは直っています。)
 setと同じ関数名が多いので、setの説明を修正して書いたんですが、修正がもれて
しまいました。  さて、前回までは、データ構造の補足でしたが、 次は
プログラム制御構造の補足です。  さて、第12回いきます。

 今回は、procedure関係の補足です。 和訳すると手続きですが、awkの関数と同じ
ものです。 いずれも、プログラムの構造化を支援するものです。 Iconでは組込み
のものを関数(function)、ユーザが作ったものを手続き(procedure)と呼んでいます。

 Iconではプログラムには、1つ(だけ)main() purocedureが必要です。 その中
には、ユーザ定義のprocedureを含むことができます。 そのユーザ定義のprocedure
の中にもユーザ定義のprocedureを含むことができます。

       ---------------------------------------------
      |procedure main()                             |
      |  ...........                                |
      |  aaa := nantara("AA","BB")                  |
      |  ...........                                |
      |  bbb := kantara("CC","DD","EE")             |
      |  ...........                                |
      |  end                                        |
      |                                             |
      |   ---------------------------------         |
      |  |procedure nantara(s1,s2)         |        |
      |  |  ..........                     |        |
      |  |  return ...                     |        |
      |  |end                              |        |
      |   ---------------------------------         |
      |   ---------------------------------         |
      |  |procedure kantara(s1,s2,s3)      |        |
      |  |  ..........                     |        |
      |  |  aaa := dotara("FF","GG")       |        |
      |  |  ..........                     |        |
      |  |  return ...                     |        |
      |  |end                              |        |
      |   ---------------------------------         |
      |                                             |
      |   ---------------------------------         |
      |  |procedure dotara(s1,s2)          |        |
      |  |  ..........                     |        |
      |  |  return ...                     |        |
      |  |end                              |        |
      |   ---------------------------------         |
       ---------------------------------------------

 1)変数のスコープ

   前の図の例で、aaaという変数を、mainの中でもkantaraの中でも使っていますが
  それぞれの有効範囲(scope)は各々のprocedureの中だけです。
   scope はIconでは2種類設定できます。
    local   そのprocedureの中だけで有効。
        特に指定しなければlocalと見なされます。
    global  全procedureの中で有効。

 2)procedure間のデータ受け渡し

   前の図の例で、mainは、nantaraを使うときに、
          nantara("AA",BB")
    という風に、2つのデータを渡しています。

   nantara側で、このデータを使うときは、
          procedure nantara(s1,s2)
    と書いておくと
       s1 := "AA" ; s2 := "BB" と解釈されます。
  s1,s2という名前はどういう名前を使っても構いません。

     引数の数が一定しない場合や多い場合はリスト渡しをします。
   nantaraを使うときに、
          nantara(List)
    という風に、リスト渡しをして、呼ばれる側で
       procedure nantara(args)
    として
       args[1]から順に使っていくというやり方です。
    argsという名前は、どういう名前を使っても構いません。

  nantaraは通常はmainに値を返さなければなりません。
     return 式
  という格好で返します。 式を書かなかった場合やnantaraが失敗した場合は
  nullが返ります。(というか、返らない場合はnullというのが正しいのかな)


 3)もう1つの返し方
   あるprocedureが呼んだprocedureに値を返すやり方には return 式 というやり
  方の他に
     suspend 式
  という返し方があります。 これは、式がジェネレータの場合に使います。
   例えば、
     suspend (1 | 2 | 3)
  と書くと、このprocedureは、呼ばれる度に順に 1、2、3の値を返します。

  【済みません! 私は、このsuspendは使いこなせません。】

  私はプログラムを構成するときには、そういう場合はすぐリストにして
      return [1,2,3]
  というような返し方にして、呼んだ側で順に処理するような処理をします。

  じゃ〜、どういう場合に使うのかというと、Iconにはバック・トラッキング(ある
  処理をやっていて、結果が失敗になると別の条件で試してみる)というプログラム
  の組み方をサポートしています。 そういう場合に役に立つ受け渡しのやり方らし
  いのですが...
   前の例では、1というデータを呼んだ側が試してみてだめで失敗すると、2のデー
  タを試して、それもだめなら 3のデータで試す というような動きをサポートする
  ためらしいです。

  (この項の話はあまり信用しないで下さい。)

 4)main の引数
   main の引数はコマンドライン引数がセットされます。コマンドライン入力の
  引数は、次のように使います。
     nantara AAA BBB CCC
  とした場合、nantara.icn にて
   procedure main(args)
    と書いておけば
       args[1]  には、"AAA"
          args[2]  には、"BBB"
          args[3]  には、"CCC"

    がセットされます。

 5)引数の省略
   組み込み関数では、引数が省略できて、その時はデフォルト値が使われるものが
  あります。
   引数が3個あるもので、2個しかセットされずにprocedureが呼ばれた場合には
  呼ばれた側では、3番目の引数がセットされていないことになります。すなわち
  nullとなります。
   そこで、実現方法としては、引き数がnullかどうかのチェックをすれば良い訳
  です。

   nullチェックは、第7回の split.icnの中で使っています、
     /c := ' \t'     の所です。 cがnullなら、' \t'をセットするという処理
   となります。
   尚、nullでなければ...というのは、\c := ... という表現になります。

 5)1度だけよ!
   main 以外の procedure でも、最初に呼ばれた時だけ実行したい処理がでてくる
  時があります。 初期設定処理です。 そういう処理は
     initial {
            .......
            .......
          }
    という書き方をすると、最初に呼ばれた時だけ実行するようにできます。

 6)忘れたくない。
   main 以外の procedureでは、initialで指定した以外の部分の処理は呼ばれる度
  に実行されます。 前回呼ばれたときの事は忘れています。
   しかし、でも、ある変数の値は保持しておきたい場合があります。
  global指定をすれば可能ですが、構成が美しくありません。 そういう場合は
  static 指定をすれば、値は保持されます。

 7)分割コンパイル
   共通的に使うprocedureやデータは、ファイルとしても別にしておいて、それを
  引用したいですよね。
   Iconでは、2つのやり方があります。

    ・$include "abcd.def"
      こういう指定をプログラム先頭にて行うと、"abcd.def"ファイルはその
     プログラムのソースファイルの一部として扱われます。

    ・link common
      こういう指定をすると、common.icnは、そのプログラムの一部として
     組込まれます。
      commonを組み込むためには、common.icnを中間言語形式にコンパイルして
     おく必要があります。
      icont -c common.icn
     という風にコンパイル指定を行うと、common.u1 common.u2 というファイル
     ができます。 これが中間言語形式のファイルです。

   icon-projectにより、汎用的に使えそうな procedure や データを集めたものが
  ライブラリーとしてまとめられています。
    ・bipl      グラフィック以外のライブラリー
    ・gipl      グラフィック関係のライブラリー(giplを引用している)

  urlは以下の通りです。
    ftp://ftp.cs.arizona.edu/icon/library/bipl.lzh
    ftp://ftp.cs.arizona.edu/icon/library/gipl.lzh
  各々1M強のファイルサイズです。

 で〜。第12回はこの辺で。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: モモイズム/遊佐未森
BGD: 大関のものも
BGS: Mild Seven Menthol
(icon_12b.txt)



■  Icon > Icon入門講座(13)procedure/scopeサンプル 風つかい      目次へ

 前回の procedure/scopeで書いた内容をサンプルプログラムで動作確認をしてなか
ったので気になってやってみましたら、案の定、私が誤解していたころがありました。
 削除して訂正版をアップしました。 2度読まれた方にお詫びします。
(追記 このテキストでは直っています。)

 さて、今回は前回の講座の補足として、サンプルプログラムをアップします。


-----^ SAMP_14.ICN ( date:96-11-30 time:00:52 ) ------------<cut here
$include "samp_14b.icn"
link disp
procedure main(args)
# procedure の使い方のサンプル
  # コマンドライン引数のテスト
  # samp_14 abc def 123 と起動すると、abc、def、123を出力する。
  write("コマンドライン引数は以下の ",*args," 個です。")
  every write(!args)

# $includeで定義したprocedure
  test_05()
# procedure間のデータの渡し方
  write("リスト渡し:")
  data1 := ["AA","BB"]
  show_sl(data1)
  test_01(data1)

  write("個別渡し:")
  write(s1 := "CC"," ",s2 := "DD")
  test_02(s1,s2)

  write("戻り値:")
  show_sl(test_03())

# suspendのテスト
  write("suspend のサンプル")
  every write(!test_04())

  write("back tracking の非常に簡単なサンプル")
  write("test_04() の値が 3 以外は失敗させた時の動きの例")
  write("同じ数字が2個続けば成功しています。")
  write(write(test_04()) = 3)

end

procedure test_01(args)
  write("リスト受け:")
  show_sl(args)
  return
end

procedure test_02(s1,s2)
  write("個別受け:")
  write(s1," ",s2)
  return
end

procedure test_03()
  return ["EE","FF"]
end

procedure test_04()
  suspend 1 | 2 | 3
end
-----$ SAMP_14.ICN ( lines:54 words:88 ) -------------------<cut here

$include で引用するファイルです。
-----^ SAMP_14B.ICN ( date:96-11-30 time:00:53 ) -----------<cut here
procedure test_05()
  write("$include test")
end
-----$ SAMP_14B.ICN ( lines:3 words:5 ) --------------------<cut here

第11回の samp_13.icn の表示プログラムの部分を別ファイルにしたもの。
icont samp_14.icn を行う前に、icont -c disp.icn で中間言語に変換して
おきます。
-----^ DISP.ICN ( date:96-11-29 time:23:12 ) ---------------<cut here
procedure show_st(T)
# table を key : value ペアで出力
  every s_key := key(T) do write(s_key," ",T[s_key])
  return
end

procedure show_wt(T)
# valueがリストの table を key : value ペアで出力。
  every writes(s_key := key(T)," :") do {
    every writes(" ",!T[s_key])
    write()
  }
  return
end

procedure show_sl(list)
# リストの内容表示(テスト/表示用)
  every writes(" ",!list)
  write()
  return
end

procedure show_wl(wlist)
# 2重リストの内容表示(テスト/表示用)
  every list := !wlist do {
    every writes(" ",!list)
    write()
  }
  write()
  return
end
-----$ DISP.ICN ( lines:31 words:70 ) ----------------------<cut here

 ほんじゃ。第13回はこの辺で。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 愛が止まらない/WINK
BGD: 玄米茶
BGS: Mild Seven Menthol
(icon_13.txt)



■  Icon > Icon入門講座(14)type変換、他            風つかい      目次へ

 Iconの特徴の項で、やり残した説明を補足してきました。一応、今回でそれも終わる
予定です。

 さて、今回はデータのtype変換あたりを補足説明したいと思います。
では、第14回、いきま〜す。

 1)type変換
   Iconでは、データ構造のところで説明しましたような色んなデータタイプがあり
  ます。 このデータタイプは、自動変換される場合と、意識的に変換してやらない
  といけない場合があります。

   ・nullには、どんなデータタイプも代入できます。
    変数は初期値は nullですが、そこには、数字でも stringでもでもlistでも
    代入できます。 ある procedureの中で初めて使うのであれば、 いきなり
       no      := 0
       name    := "辛島美登里"
       WINK    := ["相田翔子","鈴木早智子"]
    とかできるわけです。

   ・違うtype同士のデータの演算はできません。
    上の例に引き続き
       xxx := no + name  とか
       WINK +:= 1        (WINK := WINK +1 の略記)
    をしようとすると、実行時エラーになります。
    また、いきなり、typeの決まっていない変数を使って演算しようとすると
    やはりエラーになります。
    数字のrealとintegerは演算できます。これはできないとね。

   ・組み込み関数の引数では、できる範囲は自動変換されます。
       write(no) とやると、数字の 0は、文字 "0"へ変換されます。
    cset,integer,real,string間ではできる範囲はやってくれるみたいです。

    私は、エラーがでたら、きちんと変換するといういい加減なやり方をして
    います。ハイ。

  以下に type変換関数をあげます。 これもできる範囲しかできないわけですが。
    ・string(x)       文字列へ変換
    ・numeric(x)      10進数へ変換(10進数表記文字列のみ)
    ・cset(x)        文字セットへ変換(文字とは1バイトキャラクタ)
    ・integer(x)      10進整数へ変換(10進数表記文字列のみ)

  Iconでは、ある変数がどういうtypeかチェックする関数があります。その名は
  ずばり、 type(x)です。 これを使うと、引数のデータタイプによって処理を
  分ける procedureが作れます。

 2)照合
   Iconではデータの照合記号がデータによって異なります。
              等号 不等号 比較 比較  比較  比較
     数字では、    =      ~=      <     <=      >      >=
     文字(列)では、 ==     ~==     <<    <<=     >>     >>=
     一般的な値比較は、===    ~===
   です。
   すみません。 ===の使い方はよく理解していません。

   尚、照合式も値を持ちます。 式1 照合記号 式2 が成功しますと、式2の値を
   もちます。
     例えば、 20 > nn は成功すれば、nnの値を持ちます。

   比較記号と 代入記号:= をつなぐと比較結果を、代入できます。
     例えば、 nn >:= 5 は、成功すると、nnに 5が代入されます。

 3)文字発生/文字番号
   Iconでいう文字は、1バイトで表せるものということで、256通りの文字が
  ありえます。256文字全体を含んだ文字セットとして、&csetというキーワード
  があります。(&csetは、どう使うのかわかりません。)
   で、16進コードの 00からFFまでの256文字には、0〜255まで番号が
  つけられていて、この番号指定で文字を指定できます。
    ・char(n)
      n番目の文字を生成します。
    ・ord(c)
      文字 cの番号を生成します。

 4)文字列整形
   以下の関数により文字列の整形ができます。
    ・right(s1,i,s2)
      s1を i桁に右寄せで整形する。余りには、s2が詰められる。
    ・left(s1,i,s2)
      rightの左寄せ版
    ・center(s1,i,s2)
      i文字列として、真ん中寄せ。余りには、s2を使う。
      s2のデフォルトはスペース。
    ・trim(s,c)
      末尾の文字(c)を取り去る。(末尾のスペースを取り去るのによく使う)
      cのデフォルトは、スペース。
    ・entab(s)/detab(s)
      スペースをタブコードにしたり、タブコードをスペースへ変換します。

 5)文字変換
   map(s1,s2,s3)
   s1の中の文字を、s2:s3の変換テーブルで、変換します。 s2,s3のデフォルト
   は、&ucase(英字大文字)、&lcase(英字小文字)です。よってs2,s3を省略す
   ると、英字大文字を小文字へ変換する関数になります。

 それでは、今回のサンプルプログラム、いきます。尚、dispは前回と同じものです。

-----^ SAMP_15.ICN ( date:96-12-01 time:00:03 ) ------------<cut here
link disp
procedure main()
  write("★type変換サンプル")
  write("★nullへのセット")
  write(no   := 0)
  write("My favorite singer :",name := "辛島美登里")
  writes("WINK :")
  show_sl(WINK := ["相田翔子","鈴木早智子"])

  write("★type不一致エラーのサンプル:コメントアウトされています。")
#  xx    := no + name     # エラーがでるのでコメントアウト
#  WINK +:= 1             # エラーがでるのでコメントアウト
#  yy   +:= 1             # エラーがでるのでコメントアウト

  write("★type変換関数の例       ・・・最終的には stringに変換されています。")
  write("string(128) :",string(128))
  write("numeric(\"128\") :",numeric("128"))
  write("cset(128) :",cset(128))
  write("integer(\"128.5\") :",integer("128.5"))
  write("real(\"128.5\") :",real("128.5"))

  write("★関数typeの使用サンプル")
  write("noのタイプは :",type(no))
  write("nameのタイプは :",type(name))
  write("WINKのタイプは :",type(WINK))
  write("WINK[1]のタイプは :",type(WINK[1]))
  write("T := table() のタイプは :",type(T := table()))
  write("S := set() のタイプは :",type(S := set()))
  write("cc := \'abcd1234\' のタイプは :",type(cc := 'abcd1234'))
  write("128.5 のタイプは :",type(128.5))
  write("show_sl のタイプは :",type(show_sl))
  
  write("★比較記号の使用サンプル")
  write("nn := ",nn := 10)
  write("20 > nn の値 :",20 > nn)
  write("nn >:= 5 での nnの値 :",nn >:= 5)

  write("★char/ordの使用サンプル")
  write("ord(\"A\") :",ord("A"))
  write("char(ord(\"A\")) :",char(ord("A")))

  write("★文字列整形関数の使用サンプル")
  write("right(\"ABCD\"\,10\,\"xyz\") :",right("ABCD",10,"xyz"))
  write("left(\"ABCD\"\,10\,\"xyz\") :",left("ABCD",10,"xyz"))
  write("center(\"ABCD\"\,10\,\"xyz\") :",center("ABCD",10,"xyz"))
  write("trim(\"aaabbbxxxdddxxx\"\,\'x\') :",trim("aaabbbxxxdddxxx",'x'))

  write("★entab/detabの使用サンプル")
  write("detab(\"abc\\tdef\\tfgh\") :",detab("abc\tdef\tfgh"))
  write("entab(\"abc     def     fgh\") :",entab("abc     def     fgh"))

  write("★mapの使用サンプル")
  write("map(\"ABCDEF\"\,\"ABC\"\,\"123\") :",map("ABCDEF","ABC","123"))
  write("★mapの使用サンプル/データ入れ替え")
  write("map(\"54321\"\,\"12345\"\,\"ABCDE\") :",map("54321","12345","ABCDE"))
end
-----$ SAMP_15.ICN ( lines:56 words:141 ) ------------------<cut here

 では、第14回はこの辺で。少し説明残りがでましたので、それは次回に。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 空耳の丘/遊佐未森
BGD: 茉莉花茶
BGS: Mild Seven Menthol
(icon_14.txt)



■  Icon > Icon入門講座(15)エスケープ文字、他      風つかい       目次へ

 前回、少し説明残りがでましたので、補足をします。
 では、15回、いきます。

 1)エスケープ文字
   エスケープ文字は次の通りです。

        \b      backspace               \v      vertical tab
        \d      delete(rubout)          \'      single quote
        \e      escape (altmode)        \"      double quote
        \f      formfeed                \\      backslash
        \l      linefeed (newline)      \ddd    octal code
        \n      newline (linefeed)      \xdd    hexadecimal code
        \r      carriage return         \^c     control code
        \t      horizontal tab

 2)キーワード
   私には、どう使うのか分からないのもありますが、次の通りです。

        &allocated : i1,i2,i3,i4    # accumulated bytes allocated
                                    # (total,static,string,block)
        &ascii : c                  # cset of ascii characters
        &clock : s                  # current time of day
        &collections : i1,i2,i3,i4  # collection count
                                    # (total,static,string,block)
        &cset : c                   # cset of all characters
        ¤t : C                # current co-expression
        &date : s                   # current date
        &dateline : s               # current date and time
        &digits : c                 # cset of digits 0-9
        &dump : i                   # if non-zero, causes dump on termination
        &e : r                      # base of natural logarithms, 2.71828...
        &error : i                  # run-time error conversion control
        &errornumber : i            # run-time error number
        &errortext : s              # run-time error message text
        &errorvalue : x             # run-time error offending value
        &errout : f                 # standard error output file
        &fail                       # fails
        &features : s1,s2,...,sn    # implementation features
        &file : s                   # current source code file name
        &host : s                   # string identifying host computer
        &input : f                  # standard input file
        &lcase : c                  # cset of lower case letters a-z
        &letters : c                # cset of all letters A-Za-z
        &level : i                  # level of current procedure call
        &line : i                   # current source code line number
        &main : C                   # main co-expression
        &null : n                   # the null value
        &output : f                 # standard output file
        &phi : r                    # The golden ratio, 1.61803...
        &pi : r                     # The value of pi, 3.14159...
        &pos : i                    # string scanning position
        &progname : s               # file name of the executing program
        &random : i                 # random number seed
        ®ions : i1,i2,i3         # current region size
                                    # (static,string,block)
        &source : C                 # activator of current co-expression
        &storage : i1,i2,i3         # current bytes allocated
                                    # (static,string,block)
        &subject : s                # string scanning subject
        &time : i                   # current run time in milliseconds
        &trace : i                  # procedure tracing control
        &ucase : c                  # cset of upper case letters A-Z
        &version : s                # version of Icon

 3)算術・論理関数
    私はあんまり使う機会がありませんが、次のとおりです。

        abs(N) : N                  # compute absolute value
        acos(r1) : r2               # compute arc cosine
        asin (r1) : r2              # compute arc sine
        atan (r1,r2) : r3           # compute arc tangent
        cos(r1) : r2                # compute cosine
        dtor(r1) : r2               # convert degrees to radians
        iand(i1,i2) : i3            # compute bit-wise and
        icom(i1) : i2               # compute bit-wise complement
        integer(x) : i              # convert to integer(切上げ関数に使える)
        ior(i1,i2) : i3             # compute bit-wise inclusive or
        ishift(i1,i2) : i3          # shift bits
        ixor(i1,i2) : i3            # compute bit-wise exclusive or
        log(r1,r2) : r3             # compute logarithm
        rtod(r1) : r2               # convert radians to degrees
        sin(r1) : r2                # compute sine
        sqrt(r1) : r2               # compute square root
        tan(r1) : r2                # compute tangent


 今回で、私の分かる範囲は、説明を終わりました。
 次回は、私が使っているプログラム例を説明したいと思います。
 それでは、第15回はこの辺で。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 咲き誇れ愛しさよ/WINK
BGD: 茉莉花茶
BGS: Mild Seven Menthol
(icon_15.txt)



■  Icon > Icon入門講座(16)wild.icn                風つかい      目次へ

 前回、タイトルが間違っていましたね〜。(追記 このテキストは直っています。)
 それと前々回に、文字列操作関数を2つ忘れていました。では、16回、いきます。

 まず、忘れた文字列操作関数を
  ・reverse(s1)
    文字列の向きを入れ替えます。
    "ABCD" を、"DCBA"へ変換する関数です。

  ・repl(s1,i)
    文字列 s1を i個分つなぐものです。

 では、本題の wild.icnの話しへ戻ります。  予定では、YAX形式のバインダーの
iyab.icnを説明する予定だったのですが、そこから呼んでいる wild.icnを先にやんな
くちゃ。 ということで、wild.icnの説明を先に。

 Iconは、ファイル読み込みをプログラムに記述して行います。 そこで、ワイルド
カード指定でファイルを複数まとめて処理する時には、そのための procedureを作ら
ないといけません。

 wild.icnは、
  ・引数のファイル指定に従って、MS-DOSへ"DIR"コマンドを発行し、その結果を
   テンポラリーファイルへ出力します。
   例えば、"dir *.icn >> $$$tmp.$$$" です。
  ・Iconは、このテンポラリーファイルを読み込んで解析して、ファイル毎の
    ・フルパス付きファイル名
    ・ファイルサイズ
    ・日付
    ・時刻
   を要素として持つリストのリストを値として持ちます。
  ・該当ファイルが無い場合は失敗します。
  ・先頭に @をつけたファイル名リストによるファイル指定にも対応しています。

 尚、"dir"コマンドの結果は メーカー・バージョンによって異なりますので、お使い
の機種によっては修正が必要かも知れません。

-----^ WILD2.ICN ( date:96-12-01 time:19:52 ) --------------<cut here
link dir2lst2
procedure wild(args)
# wild.icn Ver.1.1 1996/10/26 windy Ver.1.3 1996/12/01 windy
# Usage: wild(file(s) or @file_list)
#      : sortf(wild(file(s) or @file_list),1)    ファイル名でsortする場合
###################
# ファイル指定コマンド行処理
###################
# ワイルドカードファイル指定のファイルの情報を"dir" を発行して調べてリスト
# にして返す。
# レスポンスファイルも指定可。(@file_list)
# value : [i][1] フルパス付きファイル名、[i][2] ファイルサイズ、[i][3] 日付
#       : [i][4] 時刻      i : 1 〜  ファイルの数
# 該当ファイルが無ければ失敗(fail)

  tmp   := "$$$tmp.$$$"                         # テンポラリファイル名設定
  if s := getenv("TMP") then tmp := s || "\\" || tmp    # 環境変数にテンポラリ
                                                # ディレクトリが設定してあれば
                                                # ファイル名の前に追加
  fn_list := []                                 # ファイル名等格納リスト

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

  dir := open(tmp) | stop("cannot open " || tmp)        # ファイルオープン

# "dir" の結果格納ファイルから、ファイル指定部分を抜き出してリストへぶち込む。
  while line := read(dir) do                    # tmpファイルから1行づつ読込。
    put(fn_list,dir2lst(line))                  # ファイル情報を抜き出して、
                                                # リストへ格納
  close(dir)
  remove(tmp)                                   # 証拠隠滅
####################
# コマンド解析終了
####################
  if *fn_list = 0 then fail                     # 該当ファイル無し
  else return fn_list
end
-----$ WILD2.ICN ( lines:56 words:236 ) --------------------<cut here

-----^ DIR2LST2.ICN ( date:96-12-01 time:20:16 ) -----------<cut here
link split2, strings2
####################
# dir2lst.icn Ver.1.1 1996/11/3 Ver.1.2 1996/12/1 windy
# Usage : dir2lst(line)
# "dir" コマンドの結果を1行ずつもらい、ファイル部分ならファイル属性をリストに
# して返す。 ファイル部分で無ければ失敗(fail)
# value : [1] フルパス付きファイル名、[2] ファイルサイズ、[3] 日付、: [4] 時刻
###################
procedure dir2lst(line)
static c_dir                                            # ディレクトリー指定
  line ? {
    if find(" ディレクトリ") then {
      if (c_dir := split(line)[-1])[-1] ~== "\\" then c_dir ||:= "\\"
          # ↑ディレクトリー名末尾に"\\"がついていなければ追加。
      fail
    }
    if {*line = 0} | {line[1] == " "} then fail   # not file
    if find("<DIR>") then fail                    # not file
    if find("あります") then {c_dir := "" ; fail} # c_dir リセット
  }     # end of line ?
    list := split(line)                           # カラム分割
    #
    case *list of {
      3       : put(list,"00:00")       # PC-98 no_EXT and 00:00
                     # ↑00:00は出ないので補う。
      4       : { if charcnt(list[4],&digits ++ '-') = 8  # date test
                     # ↑数字とハイフンだけかとういうチェック
                  then { put(list,"00:00")                # PC-98 00:00
                         push(list,pop(list) || "." || pop(list))
                         # ↑ファイル名と拡張子を取り出して、"."でつなぐ。
                  }
                  else {
                    if charcnt(s := list[4],&digits ++ ':') ~= *s # time test
                    then list[4] := "00:00" # PC-98 00:00
                  }
                }
      default : {
                  if charcnt(list[4],&digits ++ '-') = 8          # date test
                  then {
                    if charcnt(s := list[5],&digits ++ ':') ~= *s # time test
                    then list[5] := "00:00"                       # PC-98 00:00
                  push(list,pop(list) || "." || pop(list))
                  }
                  else {
                    if charcnt(s := list[4],&digits ++ ':') ~= *s # time test
                    then list[4] := "00:00" # PC-98 00:00
                  }
                }
    }
    list[1] := c_dir || list[1]               # ディレクトリーを補う。
    list[2] := deletec(list[2],',')           # "\,"を取り去る。
    list[4] := right(list[4],5,"0")           # 時刻の10時の桁を補う。
    return list[1:5]
end
-----$ DIR2LST2.ICN ( lines:54 words:248 ) -----------------<cut here

-----^ SPLIT2.ICN ( date:96-12-01 time:19:53 ) -------------<cut here
# 文字列を指定文字(セット)で区切りリストに入れる。
procedure split(line,c)
# function : split a strings with c and store a list(exclude c)
  /c := ' \t'                      # 指定が無ければスペースかタブとみなす。
  list := []                       # return用リスト生成
  line ? while tab(upto(~c)) do put(list,tab(many(~c)))
  return list
end
-----$ SPLIT2.ICN ( lines:8 words:37 ) ---------------------<cut here

-----^ STRINGS2.ICN ( date:96-12-01 time:19:51 ) -----------<cut here
############################################################################
# biplの中のstrings.icnから、講座で使うものだけ取り出したものです。
############################################################################
#       charcnt(s, c)      文字列内の特定文字(セット)数をカウント。
#       deletec(s, c)      文字列から特定文字(セット)を取り去る。
############################################################################
procedure charcnt(s, c)                 #: character count
  local count
  count := 0
  s ? while tab(upto(c)) do count +:= *tab(many(c))
  return count
end

procedure deletec(s, c)                 #: delete characters
  local result
  result := ""
  s ? {
    while result ||:= tab(upto(c)) do tab(many(c))
    return result ||:= tab(0)
  }
end
-----$ STRINGS2.ICN ( lines:21 words:61 ) ------------------<cut here

 それでは、第16回はこの辺で。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: なし。
BGD: 茉莉花茶
BGS: Mild Seven Menthol
(icon_16.txt)



■  Icon > Icon入門講座(17)Test Driver for wild    風つかい      目次へ

 前回、wild.icn とその中で使っている procedureだけを示しましたが、実際はテス
ト用のドライバーやテストデータを作ってテストしています。
 それがないと、動きがわかりにくいと思いますので、その部分を参考にアップロード
します。 では、17回、いきます。

 dir2lst のテストドライバーです。 "DIR"コマンドの結果ファイルを読み込んで
dir2lstで処理した結果を書き出すものです。
-----^ DIR2LST~.ICN ( date:96-12-01 time:19:19 ) -----------<cut here
link dir2lst2, disp
# a test driver and a stub for dir2lst.icn
# Usage: dir2lst~ >dir2lst.rst
procedure main()
  write("test for dir2lst.icn\n")
  dat := open(s := "dir2lst.dat") | stop("cannot open ",s)
  while line := read(dat) do {
    write(line)
    writes("->")
    show_sl(dir2lst(line))
  }
end
-----$ DIR2LST~.ICN ( lines:12 words:41 ) ------------------<cut here

 "DIR"コマンドの結果ファイルです。 お使いのマシンの結果でテストして
みて下さい。
-----^ DIR2LST.DAT ( date:96-11-27 time:02:24 ) ------------<cut here
  IBM Aptiva530 Win95のDOS窓 PC-DOS J6.1
 ドライブ D: のボリュームラベルはありません.
 ボリュームシリアル番号は 2727-1AF8
 ディレクトリは D:\ICN

.              <DIR>        96-10-26  20:06 .
..             <DIR>        96-10-26  20:06 ..
AAA      AAA            10  96-10-26  20:06 AAA.AAA
BBB      BBB            10  96-10-26  20:07 BBB.BBB
CCC                      6  96-10-26  20:07 CCC
CCC                      6  96-10-26        CCC
 ↑テスト用に付加したデータ(実際にはこんなデータは無い)
SRC            <DIR>        96-10-26  20:07 SRC
         3 個                  26 バイトのファイルがあります 
         3 ディレクトリ     44,810,240 バイトの空きがあります 

  PC-9801VM21 MS-DOS 3.3D のDOSプロンプト
 ドライブ B: のディスクのボリュームラベルは user       
 ディレクトリは B:\ICN

CCC               729  95-06-16 
AAA      AAA      729  95-06-16 
BBB      AAA     1077  95-06-08   14:47
        3 個のファイルがあります.
  3682304 バイトが使用可能です.
 

 ドライブ I: のディスクのボリュームラベルは RAMDISK1920
 ディレクトリは I:\

RCS          <DIR>     95-06-23    0:50
AAA      AAA      729  95-06-16 
BBB      AAA     1077  95-06-08   14:47
CCC              1077  95-06-08   14:47
        4 個のファイルがあります.
  1949696 バイトが使用可能です.


  IBM Aptiva530 Win3.1 DOS窓 PC-DOS J6.3
 ドライブ C にはボリューム・ラベルがありません
 ボリューム・シリアル番号は 255B-1DDB です
 ディレクトリーは  C:\ICON\MY_PROGS

.            <DIR>       96-05-04   18:03
..           <DIR>       96-05-04   18:03
MAX_LEN  ICN         326 96-02-06    1:01
PAGE     ICN       2,975 96-02-06    1:15
DISP_COL ICN         553 96-05-05   18:26
TRIM     ICN          68 95-06-26   14:29
ADD_NO   ICN         267 96-05-07   22:50
ICON2U   ICN         704 96-05-12    2:09
IYABP    ICN       2,563 96-05-04   16:19
IYABPL   ICN       2,520 96-05-04   16:17
ICON2E   ICN         701 96-05-12    2:08
TEST     ICN          41 96-05-07   23:00
       12 個            10,718 バイトのファイルがあります
                    81,821,696 バイトが使用可能です
-----$ DIR2LST.DAT ( lines:57 words:188 ) ------------------<cut here

 wildのテストドライバーです。 想定したパターンのテストデータを与えて
結果を書き出します。
-----^ WILD2~.ICN ( date:96-12-01 time:20:30 ) -------------<cut here
# a test driver and  stub for wild.icn
# Usage: wild2~ > wild.rst
link wild2, disp
procedure main()
  write("test for wilds.icn\n")

  write((L := ["abc"])[1])
  show_wl(wild(L)) | write(L[1],"は見つからない。\n")

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

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

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

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

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

end
-----$ WILD2~.ICN ( lines:25 words:52 ) --------------------<cut here

 wild~で使うレスポンスファイルです。
-----^ WILD_FL.DAT ( date:96-12-01 time:19:38 ) ------------<cut here
wild_fl.dat
wild2~.icn
-----$ WILD_FL.DAT ( lines:2 words:2 ) ---------------------<cut here

 それでは、第17回はこの辺で。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: なし。
BGD: 大関のものも
BGS: Mild Seven Menthol
(icon_17.txt)



■  Icon > Icon入門講座(18)iyab.icn                風つかい      目次へ

 今回でやっと YAX形式のファイルバインダー iyab.icnの説明にたどり着きました。
 では、18回、いきます。

  YAX形式というのは、次のようなプログラムの前と後ろに識別行を付加した
アップロード用プログラム形式のことです。

-----^ SAMP_16.ICN ( date:96-12-01 time:21:59 ) ------------<cut here
procedure main()
  write("sample")
end
-----$ SAMP_16.ICN ( lines:3 words:4 ) ---------------------<cut here

 この形式は、日経mixのawk会議で、当時議長だったtakun(AWK教典:The AWK
Programming Language の訳者です。)達がまとめられた形式です。

 awkのプログラム(スクリプト)は短いのが多いので、通常の書き込みの中に
書き込んでも問題ないのですが、紛れてしまうので、前後にはじめと終わりの
行をつけようということで、議論があったような気がします。 だいぶ古い話し
ですので、もうよくは覚えていません。

 awkのプログラムとしては、上記形式にする yab.bat と、ログファイルから
スクリプトを抜き出す yax.bat があるのですが、ここで取り上げるのは、
yab.bat (yet another binder)の方です。

 では、iyab.icn のプログラムを次に。 wild.icn関係のプログラムを引用し
ています。

-----^ IYAB2.ICN ( date:96-12-01 time:22:44 ) --------------<cut here
link wild2,top2,split2
procedure main(args)
# iyab2.icn 1.1 1995/06/23 windy  1.10 1996/12/01 windy
  Usage := "Usage : iyab2 input_file(@file_list) >output_file"

###################
# YAX.LZH awkスクリプト掲載標準形式布教パッケージ Version 1.00 July/4/1990
# by takun@日経MIX のYAB.BATをIconに置換したもの。細かい動作は多少異なる。
##################

  if *args = 0 then stop(Usage)                      # ファイル指定無し。
  else fn_list := wild(args)  | stop(Usage)          # コマンド行解析
  # argument : コマンドラインからのファイルリスト。
  #            レスポンスファイル指定可(@file_list)
  # value : リスト  [i][1] フルパス付きファイル名、[i][2] ファイルサイズ
  #         [i][3] 日付、[i][4] 時刻、i : 1〜ファイルの数
  #         ファイルサイズは使用せず。

####################
# バンドル処理設定
####################
  head   := "-----^ "
  trail  := "-----$ "
  # please change the next line as you like it.
  # (お気に召すまま変えてちょうだい。)
  width := 60   # 切取り線の長さ; コメントが要らないときは 0
  # select or change as you like it.       (あなた好みに変えていいのよ。
#  cut_here := ""                          # でも責任も取ってよ。  ギク!)
  cut_here := "<cut here"

###################
# バンドル処理メイン
###################
  every list := !fn_list do {                           #ファイルリストから順に
    dir := open(list[1]) | stop("cannot open ",list[1]) #取り出し。

  ###################
  # ヘッダー出力
  ###################
    write(&errout,list[1]," ( ",list[3]," ",list[4]," )")
    c_fname := top_cut('\\',list[1])                    # ディレクトリー部削除
    str := head || c_fname || " ( date:" || list[3] || " time:" || list[4] ||
           " ) "
    str := left(str,width,"-")          # width = 0 でfailするので↑と分ける。
    write(str || cut_here)

  ###################
  # ファイル本体出力
  ###################
    n_line := 0                                         # 行数/ファイル
    n_word := 0                                         # 単語数/ファイル
    while line := read(dir) do {
      write(line)
      n_line +:= 1
      n_word +:= *split(line,' \t')
    }   # end of while
    close(dir)                                          # 脱がせたら着せる。
                                                        # えっ。あれ〜?

  ###################
  # トレーラー出力
  ###################
    str := trail || c_fname || " ( lines:" || n_line || " words:" ||
           n_word || " ) "
    str := left(str,width,"-")
    write(str || cut_here)

  }     # end of every

  ###################
  # おまけ(終わり表示)
  ###################
  write(&errout,"\t",*fn_list," file(s) bundled.")

end
-----$ IYAB2.ICN ( lines:75 words:264 ) --------------------<cut here

-----^ TOP2.ICN ( date:96-12-01 time:22:30 ) ---------------<cut here
# 文字列の 先頭から特定文字までの部分 を取り去る。最長部分を取り去る。
procedure top_cut(c,s)
  s ? {
    repeat {
      if cp := upto(c,s) then s:= s[cp +1 :0] else return s
    }
  }
end

# 文字列の 先頭から特定文字までの部分 を得る。最短部分を得る。
procedure top_get(c,s)
  s ? {
    if cp := upto(c) then return s[1:cp] else return s
  }
end
-----$ TOP2.ICN ( lines:15 words:47 ) ----------------------<cut here

 wild.icn iyab.icn 関係のファイル名で、後ろに 2という名前がついているのが多い
のですが、これは私が元々使っていたプログラムに説明を付け加えたり、講座に関係の
無い procedureを削ったりしているファイルなもので、オリジナルと区別するため後ろ
に 2を加えたファイル名としているという訳で...

 それでは、第18回はこの辺で。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 瞳水晶/遊佐未森
BGD: 大関のものも
BGS: Mild Seven Menthol
(icon_18.txt)



■  Icon > Icon入門講座(19)vanlog.icn              風つかい      目次へ

 プログラム例の説明も今回で終わりです。 では、19回、いきます。

 このプログラムは、pcvanのログファイルからメッセージを抜き出すものです。
 メッセージを抜き出すだけなら、YOTさんの ygrepでpv.patを使えば高速に抜き
出せます。
 私もずっと ygrepのお世話になっていましたが、pcvanのログで不便な点を解消
しようと、このプログラムを作りました。

 pcvanのタイトル形式では、メッセージタイトルの先頭に識別記号がついていな
いので、メッセージタイトルで検索してタグファイルを作るのが面倒なのです。

 で、メッセージを抜き出すついでに、メッセージタイトルの先頭に記号つけるように
しました。(記号は"■  "としています。)

 これで、ygrep -tg "■  " van1201.lop | irep elis でメッセージタイトルをもとに
簡単にタグジャンプできるようになりました。
 ま、そんなためのプログラムです。

-----^ VANLOG2.ICN ( date:96-12-01 time:23:18 ) ------------<cut here
########################################
# PCVANのログファイルからメッセージを抜き出すフィルター。
# ygrep の PATを使えば速いが、Iconプログラムの勉強のため作成。
# Ver1.1 1996/11/04   Ver.1.2 1996/12/01
########################################
#
# サンプルログ(pcvanのSIG書込みの開始)
##1007/1007 テキストデータ処理
#★タイトル (TRA11936)  96/10/13  14:52  (175)
#■  Icon >月別書き込み数集計 風つかい
#★内容
#
# サンプルログ(インターネットニュースの開始)
#Article 10 (561/561) in comp.lang.icon:
#
# サンプルログ(書込み・ニュースの終わり)
#番号またはコマンド
##################
link van_ln22, strings2, top2, wild2

procedure main(args)
  Usage := "Usage: vanlog2 van????.log"
  if *args = 0 then stop(Usage)                      # ファイル指定無し。
  else fn_list := wild(args)  | stop(Usage)          # コマンド行解析

  every list := !fn_list do {                        # ファイルリストから順に
    f_name := list[1]                                # ファイル名を取り出す。

    if map(top_cut('\.',f_name)) == "log"            # 拡張子"log"チェック
    then f_out := (top_get('\.',f_name) || "\.lop")  # 出力先ファイル名生成
    else stop("file_extention is not <<log>>")       # エラーメッセージ

  # ログファイルオープン
    dir     := open(f_name) | stop("cannot open ",f_name)
  # 出力ファイルオープン
    out_dir := open(f_out,"a") | stop("cannot open ",f_out)

    write(&errout,top_cut('\\',f_name)," -> ",top_cut('\\',f_out)) # モニタ

    # ファイルから1行づつ読み込んで、処理モードに従い処理。
    while line := read(dir) do {
      write(out_dir,van_line(deletec(line,'\^M')))   # 単独CRを削除した行データ
    }                                                # の処理結果を出力
    write(&errout)
    close(dir)                                       # ログファイルクローズ
    close(out_dir)                                   # 出力ファイルクローズ
  }
end
-----$ VANLOG2.ICN ( lines:48 words:146 ) ------------------<cut here

-----^ VAN_LN22.ICN ( date:96-12-01 time:23:19 ) -----------<cut here
##################
# pcvan のログの1行処理
# メッセージブロックを検出して、メッセージ行なら返す。さもなくば失敗。
##################
link match2
procedure van_line(line)
    static mode, st_pat1, st_pat2, end_pat1, sub_pat
    initial {
      # 処理モード初期化
      mode    := 0 # 0: search header
                   # 1: ★タイトル
                   # 2: message title
                   # 3: ★内容
                   # 4: message body
                   #11: news body

      st_pat1  := ["#",&digits,'/',&digits] # 先頭パターン(のリスト)
      st_pat2  := ["Article ",&digits,&digits ++ ' ()/',"in "] #
                                            # 兼末尾パターン
      end_pat1 := ["番号または"]            # 末尾パターン(のリスト)
      sub_pat  := ["Subject:"]
    }
    case mode of {
      0 : { if L := em_match(st_pat1,line) then {
               # サーチパターンと一致
               # em_matchはサーチパターン文字が連続的に
               # 出現すれば成功し、出現ポジションをリス
               #トにして返す。出現しなければ失敗。
              mode   := 1
              writes(&errout,line[1:L[3]]," ")    # 
              return line
            }
            if L := em_match(st_pat2,line) then {
              mode   := 11
              writes(&errout,line[1:L[3]]," ")    #
              return line
            }
            fail
          }
      1 : {  mode   := 2
             return line
          }
      2 : {  mode   := 3
             write(&errout,line)
             # メッセージタイトルを出力、動作モニター用CRT出力
             return if line[1:5] == (ss := "■  ") then line else ss || line
          }
      3 : {  mode   := 4
             return line
          }
      4 : {  if em_match(end_pat1,line) then {
               mode   := 0
               fail
             }
             if L := em_match(st_pat1,line) then {
               writes(&errout,line[1:L[3]]," ")
               mode   := 1
               return line
             }
             return line
          }
     11 : {  if em_match(end_pat1,line) then {
               mode   := 0
               fail
             }
             if L := em_match(st_pat2,line) then {
               writes(&errout,line[1:L[3]]," ")
               return line
             }
             if em_match(sub_pat,line) then write(&errout,line)
             return line
          }
    } # end of case

end
-----$ VAN_LN22.ICN ( lines:75 words:223 ) -----------------<cut here

 match.icnを作りだしてから、やっぱ、biplの正規表現ライブラリーを使えば
よかったと思いました。 正規表現は偉大だ。
-----^ MATCH2.ICN ( date:96-12-01 time:23:04 ) -------------<cut here
# 文字列のパターン照合
procedure em_match(m_list,line)
# exact many type match
# m_list の中の文字・文字列が順に現れたら成功。
#(間があいてはいけない。)
# 一致開始ポジションと最後文字の終了ポジションを返す。
  list := []                  # return用リスト
  /line := &subject           # 指定が無ければ &subject
  pe := 0                     # 先頭検出用
  line ? {
    every i := 1 to *m_list do {        # パターンリストから順次取り出し
      case type(m := m_list[i]) of {    # パターンのタイプを調べる。
        "cset"   : { tab(ps := upto(m)) | fail        # 文字の時は upto関数
                     if pe  = 0 & ps ~= 1  then fail  # 文字列先頭でないと失敗
                     if pe ~= 0 & ps ~= pe then fail  # 続いていないと失敗
                     tab(pe := many(m))
                   }
        "string" : { tab(ps := find(m)) | fail        # 文字列の場合は find関数
                     if pe  = 0 & ps ~= 1  then fail  # 文字列先頭でないと失敗
                     if pe ~= 0 & ps ~= pe then fail  # 続いていないと失敗
                     tab(pe := ps + *m)
                   }
        default  : fail
      } # end of case
      put(list,ps)                      # リストへ文字(列)開始位置を格納
    } # end of every
    put(list,pe)                        # 最後の文字(列)終了位置を格納
  }
  return list
end
-----$ MATCH2.ICN ( lines:30 words:155 ) -------------------<cut here

 それでは、第19回はこの辺で。 次回のむすびでおしまいになります。
                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 瞳水晶/遊佐未森
BGD: 大関のものも
BGS: Mild Seven Menthol
(icon_19.txt)



■  Icon > Icon入門講座(20)むすび                  風つかい      目次へ

 AWKer のための Icon入門講座 と副題をつけるべきだったな〜と思いつつ、私の知識
の範囲でのIconの説明を終わります。

 最初に、テキスト(文章)解析言語といっておきながら、文章解析の話が全然でて
こないぞ。 と、お思いでしょう。

 Icon自体は、その機能を備えているのですが、私が使いこなしていないのもので..
 Icon教典には、文章解析の例がでてくるのですが、よく理解できておりません。

 私が使えない機能が未だ沢山あります。
  ・バックトラッキング関係の機能は、ジェネレータとsuspend 以外にもあるのです
   が、手に負えません。

  ・現時点では、グラフィック関係は Unix版で X-Windowを動かさないと無理みたい
   ですので試していません。
   Linux あたりが、使える環境になりましたら試してみたいのですが。
   でも、グラフィックの説明なんて、テキスト文章の範囲で、できるかしら。

 この講座を読まれて、
  ・Iconを使ってみよう。 とか、
  ・Iconを極めてみよう。 とか、
  ・講座の文章や例が分かりにくいからもっとわかりやすく書き換えてあげよう。
   とか
  ・抜けている分の講座を作ってやろう。 とか

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

  ・アリゾナ大学へ留学してみよう。 とか
  ・今度の海外旅行は、アリゾナへいこう。
 というんでも、ま、いっか。

  ちなみに、アリゾナ大学は、西部劇では割とでてくるツーソンというところにあり
 ます。 http://www.cs.arizona.eduから、アリゾナ大学紹介 →Tucson の紹介へと
 たどれます。

 それではIcon入門講座を終わります。長文におつきあいいただきまして、ありがとう
 ございました。  では、またお会いする日まで。

                              【転載・編集自由】
風つかい
(TRA11936@pcvan.or.jp)

BGM: 瞳水晶/遊佐未森
BGD: 茉莉花茶
BGS: Mild Seven Menthol
(icon_20.txt)