GNU dc

言語

リンク

man

man dc は用意されてるけど, 全部のコマンドが載ってないようなのでソースコード読みながらまとめる. 読むのは "bc-1.07.tar.gz" です.

レジスタ

dc_ibase

入力の基底(進数). 2 以上 16 以下整数. 初期値は 10.

dc_obase

出力の基底. 2 以上. 初期値は 10.

dc_scale

計算の精度. 初期値は 0.

ASCII registers

0 から 255 までの ASCII 文字に対応するレジスタが用意されている. その文字でレジスタに名前がついており, いくつかのコマンドはこの名前で指定する.

例えば 61 に対応するのは a という文字だから, 61 番目のレジスタには a という名前がついている. 後述する s コマンドはこの後ろにレジスタ名を続けて指定するので saa レジスタへの操作を宣言する.

各レジスタは次の3つの用途がある.

  1. 一個の値(数値または文字列)
  2. スタック
  3. 配列

実際にはこの 1 つ目は長さ(深さ) 1 のスタックで表現されており 2 つ芽とデータを共有している. 一方で 2 つ目と 3 つ目はたまたま同じ名前が与えられているだけで, 全く別のデータとして確保されている (内部データとしては, どちらも linked list で持ってる).

コマンド

数値 [_.0-9A-F]*

数値として解釈してスタック. マイナス単符号は _.

四則演算 +-*/

2つ値をポップして順に y, x とするとき, x op y を計算してプッシュする.

例えば 3 2 -1 をプッシュする.

剰余 %, ~

% は単に剰余を取る.

~ は商と余りを両方取る. スタックのトップが余りで二番目に商を置く.

べき乗 ^, |

^ は単にべき乗を計算する.

| は剰余を取りながらべき乗計算をする. これはスタックの頭から3つをポップして, 頭から順に mod, exp, base だとし, baseexp 乗の mod 剰余を計算してスタックする.

平方根 v

値一個をポップして平方根を計算する.

条件分岐 <, = >, !

スタックの頭から2つをポップして順に a, b だとするとき, <, =, > はそれぞれ a < b, a = b, a > b のとき, 続いて指定するレジスタに入ってる文字列をコマンドとして解釈して実行する. さもなくば何もしない.

! をこの前につけることで条件を否定できる.

入力 ?

一行文字列を読み込んでコマンドとして解釈し実行.

文字列 [ ]

[ から対応する ] を一つの文字列データとしてスタックに積む.

コメント #

# から行末まではコメント

文字への変換 a

ポップしてきた数値データを ASCII コードで文字に変換してプッシュ.

eval x

ポップしてきた値を dc のコマンドとして解釈して実行.

dc_ibase の設定 i, I

i でポップした値を dc_ibase にセット. I で dc_ibase の値をプッシュ.

dc_obase の設定 o, O

同様

dc_scale の設定 k, K, X

k でポップしてセット. K でプッシュ.

X は現在の dc_scale の値でスタックのトップを上書きする.

Store s, S

レジスタ一文字を続けて指定して使う. ポップした値をそこにセットする.

s はレジスタを一個の値で上書きする. これは一度レジスタを空にしてからプッシュする. S はレジスタにプッシュする.

Load l, L

続いてレジスタ名を一文字で指定して使う. レジスタから値を読み出してプッシュ. l はレジスタを単に一個の値として読んでプッシュ. L はレジスタをスタックだとし, スタックからポップした値をプッシュする.

n は 値をポップして出力する. 数値データは数値として出力される. このとき, 改行は出力されない.

p は値をピークして(ポップせず覗き見るだけ)出力する. 数値データは数値として出力される. このとき改行も出力される.

P は値をポップして出力する. 数値データは ASCII として解釈して文字で出力する (a). このとき, 改行は出力されない.

Quit q, Q

q で実行から抜け出す. dc の一部のコマンドは再帰的に dc のコマンドを呼び出すため, 実行環境は入れ子構造をしているが, q は二段階までしか抜け出さない.

Q はポップしてきた値で何段階抜け出すかを指定する.

Stack Clear c

c で現在のスタックを空にする.

Duplicate d

d でトップの値をプッシュする. (ポップしてその値を2回プッシュする.)

Stack PrintAll f

スタックの中身を全て表示する:

$ echo 1 2 3 f | dc
3
2
1

Rotate (Swap) r, R

r はスタックの頭2つを入れ替える.

R はまず値をポップし, 数値データ \(n\) を得る. この値は 1 以上の整数か -1 以下の整数でなければならない. \(n\) が 1 以上の場合, この時点でスタックの頭から \(n\) 番目のものをスタックのトップに持ってくる. \(n\) が -1 以下の場合, この時点でスタックの頭にある値を, 頭から \(-n\) 番目にあるように持っていく.

以下に例を示す:

$ echo 1 0 0 3R f | dc
1
0
0

$ echo 0 0 0 1 _3R f | dc
0
0
1
0

スタック長 z

現在のスタックの長さ(深さ)をプッシュする.

データ長 Z

ポップしてきた値のデータ長をプッシュする. データ長の定義は数値ならマイナス符号と小数点を除いた桁数. 文字列ならその長さ.

配列への代入 :

レジスタ名を続く一文字 (a-z) で指定する. : は値を 2 つポップする. 順に index, value とし, レジスタの配列の index に紐づく値に value をセットする.

配列からの取得 ;

レジスタ名一文字を続けて指定する. 2つ値をポップして index, value として紐づく値をプッシュする.