山田邦博です。

Cafe の version up です。 Version 2.3 となりました。

複素数を手軽に扱える(RPN)関数電卓です。
電気・電子工学の研究開発に携わる研究者、技術者のためのものです。

今回の主な変更は、unary reduction operator を導入した事です。
    ベクトルとベクトルの内積の例ならば
        %+ ($vec1 * $vec2)
    などと書けます。(ここで、$vec1 と $vec2 は同一サイズの一次元配列)

詳細は下記 web ペイジを参照して下さい。
        http://www.tksa.gr.jp/king/Software/Cafe/Cafe.html

-...-

アーカイブ:
----------
Cafe Ver.2.3 の全てのファイルは
        ftp://ftp.tksa.gr.jp/king/Cafe/Cafe_2.3.tgz
にあります。

最新の Cafe (patch 版を含む)については
       http://www.tksa.gr.jp/king/Software/Cafe/
からたどって下さい。

-...-

以下に Ver.2.2 に対する diff を最後に添付します。
文書(doc)は diff だけ、プログラム(bin)は diff+shar です。



=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=


##### (BEGIN) cut here for documents #####
diff -uNr Cafe_2.2/doc/BNF.txt Cafe_2.3/doc/BNF.txt
--- Cafe_2.2/doc/BNF.txt        2004-11-18 22:19:20.000000000 +0900
+++ Cafe_2.3/doc/BNF.txt        2004-12-06 01:03:01.000000000 +0900
@@ -1,4 +1,4 @@
-This is BNF(Bakus-Naur Form) of Cafe Ver.2.2.
+This is BNF(Bakus-Naur Form) of Cafe Ver.2.3.
 ---------------------------------------------
 
 <letter> ::= [a-zA-Z]            # is one of upper or lower case of alphabets
@@ -23,10 +23,11 @@
                | <fixed_number><exponent_mark><exponent_part>
 
 <special_unary_operator> ::= '+' | '-' | '!' | '~'
-<special_binary_operator> ::= '//' | '.*' | '+' | '-' | '*' | '%'
+<special_binary_operator> ::= '//' | '.*' | '+' | '-' | '*'
                           | '/' | '^' | '.' | '&' | '|'
                           | '==' | '>=' | '>' | '<=' | '<' | '!='
-<special_reduction_operator> ::= '/+' | '/*' | '/.*'
+<special_reduction_operator>       ::= '/+' | '/*' | '/.*'
+<special_unary_reduction_operator> ::= '%+' | '%*' | '%.*'
 <stack_inserting_modifier>  ::= '+:' | ':'
 <stack_extracting_modifier> ::= '-:+' | '-:' | '=:'
 
@@ -35,7 +36,10 @@
 <mnemonic_operator> ::= <ID>               # is defined to be an operator.
 <mnemonic_function> ::= <ID>               # is defined to be a function.
 
+<unary_reduction_operator> ::= <special_unary_reduction_operator>
+                          | '%'<binary_operator> | '%'<operator>
 <unary_operator>  ::= <special_unary_operator> | <mnemonic_unary_operator>
+                 | <unary_reduction_operator>
 <binary_operator> ::= <special_binary_operator> | <mnemonic_binary_operator>
 <operator>         ::= <mnemonic_operator>
 <function>         ::= <mnemonic_function>
@@ -153,6 +157,6 @@
 
 
 .-.-.
-18 Nov.2004
+6 Dec.2004
 
 YAMADA Kunihiro <king@tksa.gr.jp>
diff -uNr Cafe_2.2/doc/BUGS.jp.txt Cafe_2.3/doc/BUGS.jp.txt
--- Cafe_2.2/doc/BUGS.jp.txt    2004-11-23 23:14:51.000000000 +0900
+++ Cafe_2.3/doc/BUGS.jp.txt    2005-01-08 23:47:07.000000000 +0900
@@ -1,4 +1,4 @@
-Cafe Version 2.2 におけるこれまでに分かっているバグおよび使用上
+Cafe Version 2.3 におけるこれまでに分かっているバグおよび使用上
 の注意を以下に記しておきます。
 
 -...-
@@ -72,8 +72,12 @@
             @"error" # エラー
             @'error'   # エラー
             @pi        # 正常:スタックに積まれる。
+
+  Unary reduction operator の reference は表現できません。 必要なら関数
+(Unary operator)として再定義してから rererence を表現して下さい。
+
 .-.-.
-23 Nov.2003
+8 Jan.2005
 
 山田邦博
 YAMADA Kunihiro <king@tksa.gr.jp>
diff -uNr Cafe_2.2/doc/MUMBLE.jp.txt Cafe_2.3/doc/MUMBLE.jp.txt
--- Cafe_2.2/doc/MUMBLE.jp.txt  2004-11-23 23:39:25.000000000 +0900
+++ Cafe_2.3/doc/MUMBLE.jp.txt  2004-12-25 16:49:51.000000000 +0900
@@ -112,6 +112,9 @@
 されている。 なんか object oriented の手法を取り入れたかって? いや、
 Cafe にはそんな物は無縁だ。 極自然な発想、手法だ。
 
+Ver.2.2 と Ver.2.3 で配列演算が強化され、従来の cafe とは別物のような
+様相を示して来たのだが、プログラム的には僅かな変更でしかない。
+
 -...-
 
 従来(Ver.2.0 およびそれ以前)、reference の先の実体が undef 等でなくな
@@ -149,9 +152,12 @@
 
 -...-
 
-私が使ったことのない binary operator が一個だけあった。 それは "%" だ。
-"mod" を使うことは良くある。 将来の version で "%" を別の用途に使い出す
-かも知れないな。
+Version 2.2 までで、私が使ったことのない binary operator が一個だけあっ
+た。 それは "%" だ。 ("mod" を使うことは良くある。)
+Version 2.3 で "%" を unary reduction operator の prefix として使用して
+しまった。
+従来の "%" は "residual" と書いてもらうことにした。 長ったらしいが、忘れ
+にくいだろうし、console での対話なら補間が効くから不便ではないはずだ。
 
 -...-
 
@@ -170,8 +176,13 @@
        $real_array1 + j $real_array2
 関数を一発書けば可能だが、この方がスマートでしょう。
 
+Version 2.3 で unary reduction operator を導入したので、vector と
+vector の内積が簡単になった;
+       %+ ($vector1 * $vector2)
+という風に書ける。
+
 .-.-.
-23 Nov.2004
+25 Dec.2004
 
 山田邦博
 YAMADA Kunihiro <king@tksa.gr.jp>
diff -uNr Cafe_2.2/doc/README.jp.txt Cafe_2.3/doc/README.jp.txt
--- Cafe_2.2/doc/README.jp.txt  2004-12-01 18:18:34.000000000 +0900
+++ Cafe_2.3/doc/README.jp.txt  2005-01-09 23:03:27.000000000 +0900
@@ -5,7 +5,7 @@
 
                                山田邦博
                    YAMADA Kunihiro <king@tksa.gr.jp>
-                        1 Dec.2004 (Release 2.2)
+                        9 Jan.2005 (Release 2.3)
                     Copyright policy: GNU GPL Ver.2
 
 
@@ -25,7 +25,7 @@
 
   Scalar 値を取り扱う unary および binary operator に関しては、配列の
 各要素への自動適用が可能です(関数定義で array expandable が宣言されて
-いる場合)。(Ver.2.2 より) 
+いる場合)。
 
   強力なヘルプ機能を付けました。 ユーザ定義の関数はその定義を表示させ
 ることができます。 また、関数や変数の定義に付属したコメントを表示させ
@@ -33,8 +33,8 @@
 エラー発生時にはバックトラックが行われ、その原因と場所が表示されます。
 
 
-Cafe Ver.2.2 の全てのファイルは
-       ftp://ftp.tksa.gr.jp/king/Cafe/Cafe_2.2.tgz
+Cafe Ver.2.3 の全てのファイルは
+       ftp://ftp.tksa.gr.jp/king/Cafe/Cafe_2.3.tgz
 にあります。
 
 最新の Cafe については
@@ -71,6 +71,11 @@
 (MUMBLE.jp.txt を参照)
 
 
+Version 2.3 での主な変更点:
+---------------------------
+・Unary reduction operator を導入した。
+
+
 Version 2.2 での主な変更点:
 ---------------------------
 ・Scalar 値を演算対象とした unary operator および binary operator につ
@@ -396,7 +401,7 @@
 ものが僅かな演算誤差によって虚部が 0 にならないケースが当然考えられま
 す。 これが問題になるなら、積極的に Re 関数を使うべきでしょう。
 整数演算は特にサポートしていないので、必要なら int,round,floor,ceil 等
-の関数を積極的に使ってください。("%" が唯一ありますが)
+の関数を積極的に使ってください。("residual" が唯一ありますが)
 
   Boolean value は複素数の特殊なケースである。 虚部が 0 でかつ実部が 0
 または 1 である。 これ以外の数値は boolean value として不適当であると
@@ -558,32 +563,32 @@
 
        記号   Priority   機能
      -------------------------------------------
-       ^       100     Arithmetic Power
-       " "   110     Blank operator (same as multiply "*" except priority)
-       *       120     Multiply
-       /       120     Divide
-       %       120     Residual
-       +       130     Add
-       -       130     Subtract
-       mod     150     Modulo
-       //      200     Parallel impedance: ($left*$right)/($left+$right)
-       max     250     Maximum (Larger value)
-       min     250     Minimum (Smaller value)
-       .*      300     String multiplication
-       .       310     String concatination
-       ==      500     Arithmetic equality
-       !=      500     Arithmetic inequality
-       >    500     Arithmetic greater than
-       >=   500     Arithmetic greater than or equal to
-       <    500     Arithmetic less than
-       <=   500     Arithmetic less than or equal to
-       eq      500     String equality
-       ne      500     String inequality
-       &   1000    Logical AND
-       and     1000    Logical AND
-       |       1010    Logical OR
-       or      1010    Logical OR
-       xor     1020    Logical EXCLUSIVE OR
+       ^        100    Arithmetic Power
+       " "    110    Blank operator (same as multiply "*" except priority)
+       *        120    Multiply
+       /        120    Divide
+       residual 120    Residual
+       +        130    Add
+       -        130    Subtract
+       mod      150    Modulo
+       //       200    Parallel impedance: ($left*$right)/($left+$right)
+       max      250    Maximum (Larger value)
+       min      250    Minimum (Smaller value)
+       .*       300    String multiplication
+       .        310    String concatination
+       ==       500    Arithmetic equality
+       !=       500    Arithmetic inequality
+       >     500    Arithmetic greater than
+       >=    500    Arithmetic greater than or equal to
+       <     500    Arithmetic less than
+       <=    500    Arithmetic less than or equal to
+       eq       500    String equality
+       ne       500    String inequality
+       &    1000   Logical AND
+       and      1000   Logical AND
+       |        1010   Logical OR
+       or       1010   Logical OR
+       xor      1020   Logical EXCLUSIVE OR
 
   Priority の値が小さい物程演算の優先度が高い。
 
@@ -594,9 +599,11 @@
 関する制限がある。 最終的に 1 個の要素をスタックに乗せなければならない。
 このスタックの長さのチェックは binary operator の実行の度になされる。
 
-  "%" (剰余)と "mod" は似ていますが、少し動作が異なります。 前者は剰余
-の計算前に各オペランドの小数部を切捨てて整数としてから剰余を求めます。
-これは perl の剰余演算そのものです。
+  "residual" (剰余)と "mod" は似ていますが、少し動作が異なります。 前者
+は剰余の計算前に各オペランドの小数部を切捨てて整数としてから剰余を求めま
+す。 これは perl の剰余演算("%")そのものです。
+       注:Ver.2.3 から "%" は unary reduction operator の接頭文字とし
+           て使用されます。
 後者はいずれも整数とはせずに剰余を求めます。 これは例えば radian 角を
 0 から 2pi の値に正規化する時に役立ちます。
     例:
@@ -656,6 +663,24 @@
 が表示されます。
 
 
+Unary reduction operator:
+------------------------
+  後述の reduction 操作("/op") は stack に対して作用するが、この unary
+reduction operator ("%op") は配列に対して作用する。
+Unary reduction operator は合成 operator であるが、unary operator として
+機能する。
+%op における関数 op に対する制限は /op と同じである。(Reduction の節を
+参照)
+
+  Unary reduction operator は配列に作用して、その次元を一つ減ずる。 元の
+配列が一次元であればその結果はスカラー(0次元)に、元の配列が二次元であれ
+ばその結果は一次元の配列となる。
+
+  典型的な使用例としてはベクトルとベクトルの内積がある。
+       %+ ($vec1 * $vec2)
+ここで、$vec1 と $vec2 は同一サイズの一次元配列である。
+
+
 Nullary operator:
 ----------------
   引数が 0 個で、演算結果を stack 上に一個だけ置く関数は通常の変数と同
@@ -667,7 +692,6 @@
        date            Local time
        nstack          Number of depth of the stack
        sysver          System version number
-       untyp           Make untype
        null_array      Make null array
        undefined_value Make undefined value
 
@@ -792,6 +816,10 @@
                        # ら直接的あるいは間接的に print する文字列の
                        # 最後に改行 "\n" がない場合は強制的に改行が挿
                        # 入される。
+       warn            # 引数は文字列。 STDERR に出力する。 スタックに
+                       # は積まれない。 引数が文字列出ない場合は今日静
+                       # 的に文字化される。 文字列の最後に改行 "\n" が
+                       # ない場合は強制的に改行が挿入される。
        ps              # stack 上の要素を表示する。
        pc              # 引数は変数(関数)名。または文字列。
                        # 変数、関数に付けられたコメントを表示する。
@@ -1149,8 +1177,8 @@
 は BNF 上、Cafe の正しい構文であり得ます。 この時 b は変数でも、binary
 operator でも、unary operator でも、更には引数のない nullary operator
 でもあり得るのです。 ID "b" がそれまでにどういう宣言、定義がなされたか
-によって解釈(意味)が変わって来ます。 Blank operator の挿入がされること
-もありますが、それは BNF だけでは決定できません。
+によって解釈(意味)が変わって来ます。 Blank operator が挿入されることも
+ありますが、それは BNF だけでは決定できません。
 そういう semantics を無視した BNF を書く事もできるでしょうが、それは人
 間にとってあまり意味のあるものではないでしょう。 そこで敢えて、冗長で
 (文法的には意味のない)誤りとも思える形で書いてあります。 この方が私の
@@ -1230,4 +1258,4 @@
 ------
   著作権は GNU GPL Version 2 に準じます。(GPL-2 参照)
   無保証です。
-v  バグレポート、意見等は歓迎します。
+  バグレポート、意見等は歓迎します。
diff -uNr Cafe_2.2/doc/TODO.jp.txt Cafe_2.3/doc/TODO.jp.txt
--- Cafe_2.2/doc/TODO.jp.txt    2004-11-19 23:38:38.000000000 +0900
+++ Cafe_2.3/doc/TODO.jp.txt    2004-12-11 23:26:41.000000000 +0900
@@ -8,12 +8,11 @@
        ずなのだが。
        誰か作ってくれると嬉しい。
 
-Array への reduction 適用。
-       現在の reduction は stack に適用される。 Reduction operator を
-       unary operator 扱い出来るように拡張する。
-       /op の "/" を別にする必要があるかな? "%op $array" でどうか? この
-       場合は既にある binary operator "%" を例えば "residual" に変える
-       ことになるが。
+@%op
+       Unary reduction operator(%op) の reference が考えられるが、その
+       必要性があるか?
+       Operator の rererence(@op) も必要性があるか?
+       これらは文字列で関数に渡して、関数側で eval すれば済むはず。
 
 Reference の一般化。
        ようは現在禁止している referenced value の変数への代入を、許す
@@ -25,7 +24,7 @@
        今しばらくは考えない事にする。
 
 .-.-.
-19 Nov.2004
+11 Dec.2004
 
 山田邦博
 YAMADA Kunihiro <king@tksa.gr.jp>
diff -uNr Cafe_2.2/doc/change.log Cafe_2.3/doc/change.log
--- Cafe_2.2/doc/change.log     2004-12-01 18:19:24.000000000 +0900
+++ Cafe_2.3/doc/change.log     2005-01-10 00:57:31.000000000 +0900
@@ -1,3 +1,33 @@
+10 Jan.2005
+       Version 2.3 : released.
+
+8 Jan.2005
+       word.cafe: retuned <<NULLARRAY>> if "" applied.
+
+25 Dec.2004
+       diagnosis.cafe: corrected typo.
+
+13 Dec.2004
+       Cafe.pm: removed system (nulary) function untype().
+       define.cafe: added function make_array.
+
+12 Dec.2004
+       diagnosis.cafe: added checking code for unary reduction operator.
+
+10 Dec.2004
+       Cafe.pm: residual operator : "%" -> "residual".
+               added and modified for unary reduction operator.
+               added "warn" system function.
+
+8 Dec.2004
+       define.cafe: corrected dup() for referenced value.
+       diagnosis.cafe: changed version-check.
+
+6 Dec.2004
+       BNF.txt: removed "%" from binary operators.
+                added <special_unary_reduction_operator> and
+                      <unary_reduction_operator>
+
 1 Dec.2004
        Version 2.2 : released.
 
##### (END) cut here for documents #####

-...-

##### (BEGIN) cut here for binaries #####
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.2.1).
# To extract the files from this archive, save it to some FILE, remove
# everything before the `!/bin/sh' line above, then type `sh FILE'.
#
# Made on 2005-01-10 01:45 JST by <king@owlin>.
# Source directory was `/home/king/tmp'.
#
# Existing files will *not* be overwritten unless `-c' is specified.
#
# This shar contains:
# length mode       name
# ------ ---------- ------------------------------------------
#  13775 -rw-r--r-- Cafe_2.3-bin.diff
#
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=FAILED
locale_dir=FAILED
first_param="$1"
for dir in $PATH
do
  if test "$gettext_dir" = FAILED && test -f $dir/gettext \
     && ($dir/gettext --version >/dev/null 2>&1)
  then
    set `$dir/gettext --version 2>&1`
    if test "$3" = GNU
    then
      gettext_dir=$dir
    fi
  fi
  if test "$locale_dir" = FAILED && test -f $dir/shar \
     && ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
  then
    locale_dir=`$dir/shar --print-text-domain-dir`
  fi
done
IFS="$save_IFS"
if test "$locale_dir" = FAILED || test "$gettext_dir" = FAILED
then
  echo=echo
else
  TEXTDOMAINDIR=$locale_dir
  export TEXTDOMAINDIR
  TEXTDOMAIN=sharutils
  export TEXTDOMAIN
  echo="$gettext_dir/gettext -s"
fi
if touch -am -t 200112312359.59 $$.touch >/dev/null 2>&1 && test ! -f 200112312359.59 -a -f $$.touch; then
  shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am 123123592001.59 $$.touch >/dev/null 2>&1 && test ! -f 123123592001.59 -a ! -f 123123592001.5 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am 1231235901 $$.touch >/dev/null 2>&1 && test ! -f 1231235901 -a -f $$.touch; then
  shar_touch='touch -am $3$4$5$6$2 "$8"'
else
  shar_touch=:
  echo
  $echo 'WARNING: not restoring timestamps.  Consider getting and'
  $echo "installing GNU \`touch', distributed in GNU File Utilities..."
  echo
fi
rm -f 200112312359.59 123123592001.59 123123592001.5 1231235901 $$.touch
#
if mkdir _sh15254; then
  $echo 'x -' 'creating lock directory'
else
  $echo 'failed to create lock directory'
  exit 1
fi
# ============= Cafe_2.3-bin.diff ==============
if test -f 'Cafe_2.3-bin.diff' && test "$first_param" != -c; then
  $echo 'x -' SKIPPING 'Cafe_2.3-bin.diff' '(file already exists)'
else
  $echo 'x -' extracting 'Cafe_2.3-bin.diff' '(text)'
  sed 's/^X//' << 'SHAR_EOF' > 'Cafe_2.3-bin.diff' &&
diff -uNr Cafe_2.2/bin/cafe Cafe_2.3/bin/cafe
--- Cafe_2.2/bin/cafe   2004-12-01 18:16:07.000000000 +0900
+++ Cafe_2.3/bin/cafe   2005-01-10 00:51:19.000000000 +0900
@@ -9,7 +9,7 @@
X 
X # Author:
X #     YAMADA Kunihiro <king@tksa.gr.jp>
-#             (Please see my web page; http://www.tksa.gr.jp/king/)
+#                      <http://www.tksa.gr.jp/king/>
X #
X # Copyright policy:
X #     GNU GPL Ver.2
@@ -29,6 +29,7 @@
X #   15 May 2003   Ver.2.0
X #    3 Jan.2004   Ver.2.1
X #    1 Dec.2004   Ver.2.2
+#   10 Jan.2005   Ver.2.3
X #
X 
X no lib qw(:ALL .);
@@ -69,7 +70,7 @@
X if ($opt_v) {
X   my @n = cafeine("sysver\n");
X   print "\nThis is Cafe version $n[0].\n\n",
-        "Copyright 2000-2004, YAMADA Kunihiro <king\@tksa.gr.jp>\n\n",
+        "Copyright 2000-2005, YAMADA Kunihiro <king\@tksa.gr.jp>\n\n",
X       "You can get the latest version from\n",
X       "\thttp://www.tksa.gr.jp/king/Software/Cafe/\n\n";
X   exit 0;
diff -uNr Cafe_2.2/lib/Cafe.pm Cafe_2.3/lib/Cafe.pm
--- Cafe_2.2/lib/Cafe.pm        2004-12-01 18:21:19.000000000 +0900
+++ Cafe_2.3/lib/Cafe.pm        2005-01-10 00:54:20.000000000 +0900
@@ -5,7 +5,7 @@
X 
X # Author:
X #     YAMADA Kunihiro <king@tksa.gr.jp>
-#             (Please see my web page; http://www.tksa.gr.jp/king/)
+#                      <http://www.tksa.gr.jp/king/>
X #
X # Copyright policy:
X #     GNU GPL Ver.2
@@ -25,6 +25,7 @@
X #   15 May 2003   Ver.2.0
X #    3 Jan.2004   Ver.2.1
X #    1 Dec.2004   Ver.2.2
+#   10 Jan.2005   Ver.2.3
X #
X 
X 
@@ -80,7 +81,7 @@
X ###  Constants  ###
X ###################
X 
-my $VERSION = "2.2";
+my $VERSION = "2.3";
X 
X my $INF = 1e9999999999;
X my $NAN = $INF - $INF;
@@ -94,8 +95,8 @@
X my $PTN_ENDOFEXPRESSION = '$|[;,?:)}\]]|\+:|-:|=:';
X my $PTN_STACKMODIFIER = '\+:|-:\+|-:|=:|:';
X my $PTN_UNARY  = '[+\-!~]';
-my $PTN_BINARY = '\/\/|\.\*|[+\-*%/^.&|]|==|>=|>|<=|<|!=';
-my $PTN_ASSIGN_BINARY = '\/\/|\.\*|[+\-*%/^.&|]|==|!=';
+my $PTN_BINARY = '\/\/|\.\*|[+\-*/^.&|]|==|>=|>|<=|<|!=';
+my $PTN_ASSIGN_BINARY = '\/\/|\.\*|[+\-*/^.&|]|==|!=';
X my $PTN_REDUCTION = '\/[+*]|\/\.\*';
X my $PTN_SPECIAL = "$PTN_BINARY|$PTN_REDUCTION|$PTN_UNARY";
X my $PTN_BRACKET = '\[[^\[\]]*\]\s*';
@@ -271,19 +272,43 @@
X #  print "#",__LINE__,"# execute_function: check_stack=\"$check_stack\"\n" if $DEBUG;
X   my $id;
X   my $op;
+  my $reduction;
X   if (ref $vid) {
X     die "!!BUG!! exec: No name in vid: " unless exists $vid->{name};
X     $id = $vid->{name};
X     $op = $vid;
+  } elsif (not $vid) {
+    die "!!BUG!! exec: No vid specified: ";
+  } elsif ($vid =~ /^%(.*)/) {   # Unary reduction operator
+  print "#",__LINE__,"# execute_function: \$vid=\"$vid\"\n" if $DEBUG;
+    $reduction = 1;
+    $id = $1;
+    $op = getID($id);
X   } else {
-    die "!!BUG!! exec: No vid specified: " unless $vid;
X     $id = $vid;
X     $op = getID($id);
X   }
X #  print "#",__LINE__,"# execute_function: id=\"$id\"\n" if $DEBUG;
X   die "!!BUG!! exec: \"$id\" is not function: "
X     unless $op->{type} eq 'F' or $op->{type} eq 'B';
-  die "!!BUG!! exec: \"$id\" : too less stack: " if nvstack() < $op->{narg};
+  die "!!BUG!! exec: \"$id\" : too less stack: "
+    if ($reduction ? nvstack() < 1 : nvstack() < $op->{narg});
+
+  if ($reduction) {
+    die "!!BUG!! exec: $id->{narg} <= 1: " if $op->{narg} <= 1;
+    my $v = popvstack();
+    DIE("\"%$id \" needs an array for the argument.\n",$v)
+      unless $v->{type} eq 'A';
+    DIE("\"$v->{name}\" is empty array.\n",$v)
+      if @{$v->{value}} <= 0;
+    pushvstack(shift @{$v->{value}});
+    while (@{$v->{value}}) {
+      pushvstack(shift @{$v->{value}});
+      execute_function($op,1);
+    }
+    return;
+  }
+
X   if (defined $op->{arrayex} and $op->{arrayex}) {
X     if ($op->{type} eq 'F' and $op->{narg} == 1) {
X       ### Unary ###
@@ -368,6 +393,7 @@
X       die "!!BUG!! exec: Bad array extension : \"$id\" :"
X     }
X   }
+
X   if (ref($op->{value}) eq 'CODE') {
X     ## System defined function ##
X     my $ref = $op->{ref};
@@ -535,10 +561,10 @@
X       return cmplx($ai/$bi,-$ar/$bi) if $br == 0;
X       return cmplx(($ar*$br + $ai*$bi)/$d,($ai*$br - $ar*$bi)/$d);
X     }
-  } elsif ($opid eq '%') {
-    DIE("\"%\": Right side operand($b->{name}) should be real number.\n",$a,$b)
+  } elsif ($opid eq 'residual') {
+    DIE("\"residual\": Right side operand($b->{name}) should be real number.\n",$a,$b)
X       unless Im($b) == 0;
-    DIE("\"%\"(residual): divided by 0.\n", $a,$b)
+    DIE("residual: divided by 0.\n", $a,$b)
X       if Re($b) == 0;
X     return real(Re($a) % Re($b)) if Im($a)==0;
X     return cmplx(Re($a) % Re($b), Im($a) % Re($b));
@@ -807,7 +833,7 @@
X sub op_sub () { _op_bin_arith('-') }
X sub op_mul () { _op_bin_arith('*') }
X sub op_div () { _op_bin_arith('/') }
-sub op_residual () { _op_bin_arith('%') }
+sub op_residual () { _op_bin_arith('residual') }
X sub op_pwr () { _op_bin_arith('^') }
X sub op_para () { _op_bin_arith('//') }
X sub op_blank () { _op_bin_arith($ID_BLANK_OP) }
@@ -950,7 +976,7 @@
X     'Blank operator (Same as complex multiplication "*" except priority)');
X setsysbin("*",\&op_mul,120,1,'Complex Multiplication');
X setsysbin("/",\&op_div,120,1,'Complex Division');
-setsysbin("%",\&op_residual,120,1,'Complex Residual');
+setsysbin("residual",\&op_residual,120,1,'Complex Residual');
X setsysbin("+",\&op_add,130,1,'Complex Addition');
X setsysbin("-",\&op_sub,130,1,'Complex Subtraction');
X setsysbin("//",\&op_para,200,1,'Parallel impedance');
@@ -1023,12 +1049,12 @@
X   if ($t eq 'U') {
X     die "Stringify: \"$v->{name}\" : undefined type.\n"
X       if $check_error and not $NO_ERROR_STRINGIFY;
-    return '<<UNTYPE>>';
+    return '<<UNDEFINED>>';
X   }
X   unless (defined $v->{value}) {
X     die "Stringify: \"$v->{name}\" : undefined value.\n"
X       if $check_error and not $NO_ERROR_STRINGIFY;
-    return "<<UNDEFVALUE>>";
+    return ($t eq 'A' ? '<<NULLARRAY>>' : '<<UNDEFVALUE>>');
X   }
X   if ($t eq "N") {
X     my ($re,$im) = (Re($v),Im($v));
@@ -1348,12 +1374,6 @@
X   pushvstack(string($VERSION));
X }
X 
-sub op_untype () {
-  my $v = makevar();
-  $v->{name} = 'untype:';
-  pushvstack($v);
-}
-
X sub op_null_array () {
X   my $v = makearray();
X   $v->{name} = 'null_array:';
@@ -1371,7 +1391,6 @@
X setsysfunc("date",\&op_date,0,'"Nullary" Local time.');
X setsysfunc("nstack",\&op_nstack,0,'"Nullary" Number of depth of the stack');
X setsysfunc("sysver",\&op_version,0,'"Nullary" System version number.');
-setsysfunc("untype",\&op_untype,0,'"Nullary" Make untype');
X setsysfunc("null_array",\&op_null_array,0,'"Nullary" Make null array');
X setsysfunc("undefined_value",\&op_undefined_value,0,
X          '"Nullary" Make undefined value');
@@ -1437,6 +1456,13 @@
X   }
X }
X 
+sub op_warn () {
+  my $v = popvstack();
+  my $s = Stringify($v,"check-error");
+  print STDERR $s;
+  print STDERR "\n" unless $s =~ /\n$/s;
+}
+
X sub op_print_flush () {
X   print "\n" unless $last_print_char eq "\n";
X   $last_print_char = "\n";
@@ -2214,6 +2240,7 @@
X setsysfunc("quit",\&op_quit,0,'Quit');
X setsysfunc("exit",\&op_exit,1,'Exit with return code');
X setsysfunc("die",\&op_die,1,'Die. Terminate execution with message.');
+setsysfunc("warn",\&op_warn,1,'Warn. Print message on STDERR.');
X setsysfunc("include",\&op_include,1,'Include file.');
X 
X ###############
@@ -2963,6 +2990,21 @@
X       $un = $ID_UN_MINUS if $un =~ /\-/;
X       push_un [$un,$prepnt,$cmdpnt];
X       next;
+    } elsif (s/^%($PTN_BINARY|$PTN_ID)//o) {
+      my $un = $&;
+      my $id = $1;
+      $cmdpnt += length($&);
+      print "#",__LINE__,"# term: unary reduction operator\n" if $DEBUG;
+      my $op = getID($id);
+      die "term: \"$id\" is not defined.\n" unless ref $op;
+      print "#",__LINE__,"# reduction: type=\"$op->{type}\"\n" if $DEBUG;
+      die "term: \"$id\" is not function.\n"
+       unless $op->{type} eq 'B' or $op->{type} eq 'F'; 
+      die "term: \"$id\" has too less arguments for unary reduction operator.\n"
+       if $op->{narg} < 2;
+      push_un [$un,$prepnt,$cmdpnt];
+      print "#",__LINE__,"### 5\n" if $DEBUG;
+      next;
X     } elsif (s/^($PTN_REF)\s*($PTN_BINARY|$PTN_UNARY)//o) {
X       $cmdpnt += length($&);
X       pushvstack setref(getID($2));
@@ -3753,19 +3795,24 @@
X EOF
X     c_assign();
X     return;
-  } elsif (s/^\/($PTN_ID|$PTN_BINARY)(\s*)($PTN_ENDOFCOMMAND)/$3/o) {
+  } elsif (s/^([\/%])($PTN_ID|$PTN_BINARY)(\s*)($PTN_ENDOFCOMMAND)/$4/o) {
X     ###### Reduction #####
-    $cmdpnt += length "$1$2";
-    my $id = $1;
+    $cmdpnt += length "$1$2$3";
+    my $rd = $1;
+    my $id = $2;
X     my $op = getID($id);
X     die "command: \"$id\" is not declared.\n" unless ref $op;
X     die "command: \"$id\" is not function or binary operator.\n"
X       unless $op->{type} eq 'F' or $op->{type} eq 'B';
X     die "command: Number of parameter of \"$id\" should be >= 2\n"
X       unless $op->{narg} >= 2;
-    while (nvstack() >= $op->{narg}) {
-      my $svnvstack = nvstack();
-      execute_function($op,1);
+    if ($rd eq '%') {
+      execute_function("$rd$id",1);     # unary reduction operator for array
+    } else {
+      while (nvstack() >= $op->{narg}) {
+       my $svnvstack = nvstack();
+       execute_function($op,1);
+      }
X     }
X     die "reduction: Cannot reduce properly. Bad number of stack elements.\n"
X       unless nvstack() <= 1;
@@ -3833,7 +3880,7 @@
X         return;
X       }
X       } elsif (/^($PTN_ENDOFCOMMAND)/o) {   ## Bare function (Id only)
-       die "!! BUG !! command: Bare ID had beeb already checked: ";
+       die "!! BUG !! command: Bare ID had been already checked: ";
X       } else {
X       ### Function term .... ###
X #     print "#",__LINE__,"# Function term ....\n" if $DEBUG;
diff -uNr Cafe_2.2/lib/define.cafe Cafe_2.3/lib/define.cafe
--- Cafe_2.2/lib/define.cafe    2004-12-01 18:22:16.000000000 +0900
+++ Cafe_2.3/lib/define.cafe    2005-01-10 00:54:43.000000000 +0900
@@ -1,9 +1,9 @@
-# define.cafe : Cafe auxiliary system definition file (Ver.2.2)
+# define.cafe : Cafe auxiliary system definition file (Ver.2.3)
X #
X 
X # Author:
X #     YAMADA Kunihiro <king@tksa.gr.jp>
-#                      (http://www.tksa.gr.jp/king/)
+#                      <http://www.tksa.gr.jp/king/>
X #
X # Copyright policy:
X #     GNU GPL Ver.2
@@ -19,13 +19,14 @@
X #   15 May 2003   Ver.2.0
X #    3 Jan.2004   Ver.2.1
X #    1 Dec.2004   Ver.2.2
+#   10 Jan.2005   Ver.2.3
X #
X 
-def DEFVER=="2.2";   # Version number of define.cafe
+def DEFVER=="2.3";   # Version number of define.cafe
X 
X def Version() = {     # Print version                 \
-       print "\tCafe system : Version $(sysver)\n";  \
-       print "\tdefine.cafe : Version $(DEFVER)\n"}
+       print "\tcafe system : version $(sysver)\n";  \
+       print "\tdefine.cafe : version $(DEFVER)\n"}
X 
X # You can change version string to version number as following;
X #     eval DEFVER     # 1.9991 (pre-release) or 2.001 (patched) for example
@@ -63,13 +64,21 @@
X def not($a) ax = {!$a}                # "Unary" Logical negation (same as "!")
X 
X def copy($n) = {$n=:}         # Copy stack[$n]
-def dup($a) = {push $a; $a}    # Duplicate the last element on stack
+def dup()    = {-1=:}          # Duplicate the last element on stack
X def insert($n) = {$x=pop; $n +: $x} \
X                       # Insert last data on stack into n-th data on stack
X def extract($n) = {$n -:+ }   # Extract n-th data on stack
X def swap(@$a) = {stack <=> $a}  # Swap contents of stack and array $a
X def shrink() = {$x<=>stack; clear; $x}  \
X                               # Shrink elements on the stack to an array
+def make_array($n,$initial_value) = {                          \
+               # Make array with initial value                 \
+               #       $n : number of elements of the array    \
+               #       $initial_value : initail_value for all the elements \
+       $a = null_array;                                \
+       for(;$n>=1;--$n){ apush(@$a,$initial_value) };       \
+       $a;                                             \
+}
X def q() = {quit}              # Quit
X 
X ########################
diff -uNr Cafe_2.2/lib/diagnosis.cafe Cafe_2.3/lib/diagnosis.cafe
--- Cafe_2.2/lib/diagnosis.cafe 2004-12-01 18:22:55.000000000 +0900
+++ Cafe_2.3/lib/diagnosis.cafe 2005-01-10 00:55:10.000000000 +0900
@@ -5,7 +5,7 @@
X 
X # Author:
X #     YAMADA Kunihiro <king@tksa.gr.jp>
-#             (Please see my web page; http://www.tksa.gr.jp/king/)
+#                      <http://www.tksa.gr.jp/king/>
X #
X # Copyright policy:
X #     GNU GPL Ver.2
@@ -21,17 +21,19 @@
X #   15 May 2003   Ver.2.0
X #    3 Jan.2004   Ver.2.1
X #    1 Dec.2004   Ver.2.2
+#   10 Jan.2005   Ver.2.3
X #
X 
-$REQUIRED_VERSION = "2.2"
+$REQUIRED_VERSION = "2.3"
X print "\nThis diagnostic script is for cafe version $REQUIRED_VERSION or later.\n"
X Version
X print "\n"
+if (eval sysver != eval DEFVER) { \
+       die "Mismatch version: cafe($(sysver)) and define.cafe($(DEFVER)).\n" }
X if (eval sysver < eval $REQUIRED_VERSION) { \
X       die "Use version $REQUIRED_VERSION or later for cafe.\n" }
-if (eval DEFVER < eval $REQUIRED_VERSION) { \
-       die "Use version $REQUIRED_VERSION or later for define.cafe.\n" }
-
+if (eval sysver > eval $REQUIRED_VERSION) { \
+       warn "Warning: Mismatch version: cafe and diagnosis.cafe.\n\n" }
X 
X ### test if ###
X 
@@ -464,6 +466,11 @@
X if (reduce($cmpx==$reim,@&) != 1) { die "reduce($cmpx==$reim,@&) != 1"; }
X if (reduce($cmpx==$reim,@+) != 5) { die "reduce($cmpx==$reim,@+) != 5"; }
X 
+### Check unary reduction operator ###
+
+$vec1 = ({1;2;3;4;5;shrink})
+$vec2 = ({2;3;4;5;6;shrink})
+if (%+($vec1 $vec2) != 70) {die "%+(\$vec1 \$vec2) != 70"; } 
X 
X #####################
X ### Trigonometric ###
diff -uNr Cafe_2.2/lib/word.cafe Cafe_2.3/lib/word.cafe
--- Cafe_2.2/lib/word.cafe      2004-01-03 14:10:12.000000000 +0900
+++ Cafe_2.3/lib/word.cafe      2005-01-08 23:02:58.000000000 +0900
@@ -2,12 +2,13 @@
X 
X # Author:
X #     YAMADA Kunihiro <king@tksa.gr.jp>
-#                      (http://www.tksa.gr.jp/king/)
+#                      <http://www.tksa.gr.jp/king/>
X #
X # Copyright policy:
X #     GNU GPL Ver.2
X #
X # History:
+#         (Please see other document "change.log" for detail.)
X #  3 Jan.2004 Released with cafe ver.2.1.
X #
X 
@@ -22,6 +23,7 @@
X def word($s)={                # "Unary" split string into array of word     \
X       $a=split $s;            \
X       $w='';                  \
+       $wa=null_array;         \
X       while(narray($a)>0) {        \
X         $c = ashift @$a;      \
X         if($c eq ' ' | $c eq "\t" | $c eq "\n"){  \
SHAR_EOF
  (set 20 05 01 10 01 40 58 'Cafe_2.3-bin.diff'; eval "$shar_touch") &&
  chmod 0644 'Cafe_2.3-bin.diff' ||
  $echo 'restore of' 'Cafe_2.3-bin.diff' 'failed'
  if ( md5sum --help 2>&1 | grep 'sage: md5sum \[' ) >/dev/null 2>&1 \
  && ( md5sum --version 2>&1 | grep -v 'textutils 1.12' ) >/dev/null; then
    md5sum -c << SHAR_EOF >/dev/null 2>&1 \
    || $echo 'Cafe_2.3-bin.diff:' 'MD5 check failed'
f924461736a077db42519f6cebe2b47e  Cafe_2.3-bin.diff
SHAR_EOF
  else
    shar_count="`LC_ALL= LC_CTYPE= LANG= wc -c < 'Cafe_2.3-bin.diff'`"
    test 13775 -eq "$shar_count" ||
    $echo 'Cafe_2.3-bin.diff:' 'original size' '13775,' 'current size' "$shar_count!"
  fi
fi
rm -fr _sh15254
exit 0