Path: sran124!katsu From: katsu@sra.co.jp (WATANABE Katsuhiro) Message-ID: Date: 14 Jun 90 13:17:35 Organization: Software Research Associates, Inc.,Japan In-reply-to: katsu@sra.co.jp's message of 12 Jun 90 08:33:47 GMT Newsgroups: sra.test Subject: Re: Today's Junk article. [Unimaga 1990Jun little language] Distribution: sra References: 「本日のゴミ記事」 この企画の趣旨: 特になし。趣味といえるかもしれない。日記をめざしている。 「趣味のプログラミング」 記事 で katsu@sra.co.jp (WATANABE Katsuhiro) いはく > Unix Magazine 1990年6月号の「Little Language」は、コンマつきの数字を > 扱う企画でした。その中で、bc の関数を使って普通の表記の数をコンマつきの > 数に直すようなことを試みているのですが、数字を表示した後の改行を取り除く > しかし、bc でも「無理に」やろうとすれば、次のようにすることができると > 思います。 : : : : > comma.bc のようなものと共に bc を使えば、uexpr は expr のために > 引数を quote したり、コンマで区切るために sed で力まかせに変換したり > する必要はなくなると思います。ああ、でも、comma.bc がそのぶんの歪みを > 全部かかえこんでますかね。 コンマ付きの数に対して計算をやる uexpr を書くのには、bc でなくとも 式を評価する機構がある command/filter であったら何を使ってもよかった はずです。こういったものの一つとして m4 がありますね。 というわけで、さっそく m4 で uexpr を書いてみました。 ---------------- uexpr.m4 divert(-1) define(COMMA, `^') # real `,' cannot be concatenated define(TRUE, 1) define(FALSE, 0) # get stdin into number define(tf, maketemp(/tmp/m4-XXXXX)) syscmd(`tr -d ,' > tf) define(expression, include(tf)) syscmd(rm -f tf) define(number, eval(expression)) # define output space define(output, `') define(print, ` define(`output',output`$1$2$3$4$5$6$7$8$9') ') # check minus sign ifelse(eval(number < 0), TRUE, ` define(`number', eval(-number)) print(-) ') # divide number into 3 digit numbers and save it in array named `stack'. define(stackLevel, 0) define(stackEach3Digits, ` ifelse(eval((number / 1000) == 0), TRUE, ` print(number) ',` define(`stackLevel', incr(stackLevel)) define(`stack'stackLevel, eval(number % 1000)) define(`number', eval(number / 1000)) stackEach3Digits ') ') stackEach3Digits # output stacked 3 digit numbers. define(zeroPrint, ` print(eval($1 / 100)) print(eval(($1 % 100) / 10)) print(eval($1 % 10)) ') define(printLevel, stackLevel) define(printStackWithComma, ` ifelse(eval(printLevel > 0), TRUE, ` print(COMMA) zeroPrint(`stack'printLevel) define(`printLevel', eval(printLevel - 1)) printStackWithComma ') ') printStackWithComma divert dnl translit(output, COMMA, `,') ---------------- echo "123,456,789 + 987,654,321 * 2" | m4 uexpr.m4 なんてことをやってみてください。(マニュアルによれば、演算は int の 範囲でなければならないようです。) # uexpr.m4 は comma.{bc,dc} と違って、3桁ごとに区切る方法でやってます。 [工夫したところ] 1.標準入力から式を取り込むために maketemp と syscmd と include を 組み合わせてしのいだ。 2.m4 はトークンごとに区切って文字列を書き換えるから、普通に出力 させると数字の間に空白が入るのを避けられない。よって、出力は すべて -1 に divert して捨てることとし、本当に得たい結果は output という symbol にため込んで最後にまとめて出力するようにした。 このため、コメント(# の後ろと自分勝手にきめました)を書くことが 可能になったという画期的な副作用もあった。 3.「,」は m4 の中でメタキャラクタとして使われているので、output に 入れることができない。他の文字(^)で代用して最後に置換した。 [m4 で uexpr を書くことによる利益] なし。 -- ----____----____ 渡邊克宏 環境開発部 今月の歌: 「♪ 僕等の名前を覚えて欲しい 大型機を知らない子供達さ ♪」