[ 英語 | 日本語 ]
Dl は、Dレコードを操作するための言語である。 C、C++、Javaのような汎用のプログラミング言語ではない。 機能的にはawkが最も似ている。 ただしawkが行形式のテキストファイルを扱うのに対し、 Dlは、Dレコードを扱う。 たとえば、入力ファイル中の特定のレコードに新しいフィールドを 加えたり、値を変えたり、フィールドを削除したりすることができる。
Dlはプログラミング言語としての一通りの機能は備えているが、 大きなプログラムを処理するものとして作られてはいない。 DedはDlのインタプリタで、コンパイラのように高速な処理はできない。 複雑な処理を行いたい場合にはperlやCなどでプログラムを書く方をすすめる。 Dlの典型的な使用法として想定されているのは、たとえば次のようなものである:
Ded IF txtlang == jpn OR txtlang == kor OR txtlang == chi THEN area = ea FI input-file.d
このコマンドは、"txtlang"フィールドの値が"jpn"、"kor"または"chi" のレコードについて、"area"フィールドの値を"ea"とする(追加または置き換え)。
Dコマンドのいくつかは、Dlで書くこともできる。たとえば:
Dtie -t ":" a,b c
は次のように書いても同じ結果となる。
Ded FIELD c = FIELD a . CONST ":" . FIELD b ";" FIELD a = FIELD b = "{" "}"
この二つの方法の本質的な違いは、DコマンドがDファイルの基本ファイル演算 を提供するのに対し、Dlは汎用のDレコード操作機能を提供する、 という点にある。 もっと実際的な違いとしてはスピードがある。Dコマンドは特定のファイル演算 を高速化するための専用コードを書いてある。 これに対し、DedはDlを1ステップごとに解釈実行していくわけで 当然遅くなる。 適当なDコマンドが提供されている演算に対してはそのDコマンドを使用すること を推奨する。
Dlプログラムはふつうコマンド引数の並びとして書かれる。 これはUNIXのsedと似ているが、-eオプションは使わず、 プログラムを直接コマンド引数として書いていく。 このほかに、Dlプログラムをテキストファイルに作って引き渡す方法もある。 詳細は下記記法の節参照。
Dlは、非常に単純化された文法を持っている。 多くのコンピュータ言語と異なり、Dlには「文」がなく、 「式」のみである。制御構造の"if"や"while"も Dlの「演算子」である。 さらに";"でさえ、C言語の","に似た演算子である。 式は「評価」される。これはDlのその式の部分を「実行」する と同義語である。
また、Dlはサブルーチンやマクロ機能を持たない。 このため、大規模で複雑なプログラムを書くのに適していない。
Dレコードではどんなフィールドもリピーティングフィールドとなりうる。 したがって、Dlのどの定数も変数も配列である。 Dlではどんな演算子もそれぞれの方法で配列に対して定義されている。 たとえば"+"(加算)はオペランドの要素の数によって異なる演算を行う。 Perl言語はスカラーと配列との2つのコンテキストで演算子の意味を変えているが、 Dlは配列コンテキストのみしかない。
Dlのインタプリタには2つのコマンドがある。 DedはDlのフル処理系であるのに対し、 Dselectは演算子に制限があり、出力レコードに変更を加えるような操作はできない。
Dedでは与えられたDlプログラムが、各入力Dレコードに対して 評価(実行)され、その後のカレントレコードが (フィールド数がゼロ:すなわちレコードが削除されたのでない限り) 標準出力に書き出される。 なお、outputによって途中で明示的にカレントレコードを出力することもできる。 ただしこの場合でも、Dedはプログラムの評価後書き出しを行なう。 書き出し後、Dedは次のレコードを読み込んで新しいサイクルに入り、 入力ファイルの終わりまでこれを繰り返す。
Dselectでは、 与えられたDlプログラムが各入力Dレコードに対して評価され、 結果の値が真であれば(ブール値評価参照) 入力レコードが標準出力に書き出され、そうでなければ書き出されない。 フィールドに対する代入や、強制出力はDselectコマンドでは許されない。 したがって、入力レコードが変更されたり増えたりすることはない。
Dlのプログラムはコマンド引数あるいは-fオプションで指定した ソースファイルから入力される。 Dlプログラムはワードからなる。 Dl演算子、定数、フィールド名、変数名およびその他のDl予約語は すべてワードとして記される。 Dlでは括弧もワードとして記される。 ワードは任意の長さの文字の列である。 入力をどのようにワードとして認識するかはコマンド引数からのプログラムと、 ソースファイルからのプログラムで若干の違いがある。
コマンド引数からプログラムを入力する場合、各コマンド引数がDlのワードとなる。 ソースファイルから入力する場合、 空白文字(SPACE、TAB、IDEOGRAPHIC SPACE=全角スペース、など)でワードを分ける。 空白文字以外では、REVERSE SOLIDUS(\)、QUOTATION MARK(") およびAPOSTROPHE(')は、特殊な意味を持つ。 次に記すクォーティング方法はUNIXのshの仕様に基づくものである。
REVERSE SOLIDUS(\)を行の終わりにおくと行継続マークとなる。 行継続マークとそれに続く改行はワードから取り除かれる。 ただし、APOSTROPHE(')中ではこの限りでない。 上記以外のREVERSE SOLIDUS はAPOSROPHEやQUOTATION MARKの中におかない限り エスケープ文字となり、エスケープ文字自身はワードから取り除かれるが、 続く1文字が強制的にワードの一部となる。 エスケープ文字は通常、空白文字やQUOTATION MARK、APOSTROPHEまたは REVERSE SOLIDUSをワードの中に入れるために使われる。
QUOTATION MARK(")も特殊文字をDlのワードに含めるために 使われるいまひとつの方法である。 DlのパーザがQUOTATION MARKにであうと、その文字はワードに含まれないが、 対応するQUOTATION MARKの前までの文字がワードに取り込まれる。 QUOTATION MARKの中では上記の例外が2つある。 REVERSE SOLIDUS、QUOTATION MARKの組(\")は1文字の QUOTATION MARKとなる。これはQUOTATION MARKの中でQUOTATION MARKを使うためにある。 もう一つの例外は、改行前のREVERSE SOLIDUSで行継続マークとなる。 REVERSE SOLIDUSも改行もワードには取り込まれない。 QUOTATION MARK中のほかのREVERSE SOLIDUSは通常の文字としてワードの一部となる。
APOSTROPHE(')もクォーティングを行う。 これはQUOTATION MARKより強く、DlパーザがAPOSTROPHEにであうと、 次のAPOSTROPHEの前までの文字がワードに取り込まれる。 これには例外がなくREVERSE SOLIDUSも、改行文字も通常の文字としてワードに取り込まれる。 APOSTROPHEをワードの中で使うには前述のREVERSE SOLIDUSによるエスケープか、 QUOTATION MARKによるクォーティングをしなければならない。
Dlソースファイルでのクォーティングされたワード例
one\ word | one word |
"one word" | one word |
'one word' | one word |
one" "word | one word |
o\ n" "e' '' '"w o ""r d" | o n e w o r d |
\o\n\e\ \w\o\r\d | one word |
one\ word |
oneword |
\\\"\' | \"' |
"\"\\'\"" | "\'" |
"one\ word" |
oneword |
'"\"' | "\" |
'one word' |
one word |
次のワードはDlの中で予約語である。
! != !~ $& $' $. $? $` % && ( ) * ** + , - -- . .. / ; < <= <> = == =~ > >= @_ [ ] { || ABS AND ATAN AVG BY CAPS CAT CONST COS COUNT CURREC DIVIDEDBY DO DONE ELIF ELSE EPILOGUE EQ EXISTS EXIT EXP FI FIELD FIELDS FILENAME FNR FOR GE GT IF IN INCL INT LE LENGTH LIKE LOCALE LOG LOG10 LT MATCH MAX MIN MINUS MOD NE NOT NR NUM OR OUTPUT PLUS POSTMATCH POWER PREMATCH QX REC# S SG SIN SQRT STATIC STATUS STR SUBST SUBSTG SUM TAN THEN TIMES TOUPPER UNLIKE VAR WHILE
次の語は、限られた条件の下で予約語となる:
Dlのワードはすべて大小文字の区別がある。 ("IF"は予約語であるが、"if"や"If"は予約語ではない)。
コメントはワード/*で始まり、ワード*/で終わる。 C言語のコメントと違い、/*も*/も空白文字で 区切らなければならない。 /*COMMENT*/はコメントにならない (予約語ではない1語となる)が、 /* COMMENT */はコメントとなる。
Dlのトークンには、フィールド名、, 定数、変数、静的変数、 特殊変数、演算子、括弧 またはエンドトークンがある。 各トークンは1ワードまたは予約語で始まる2つ以上のワードからなる。
次にDlの文法(簡略化したもの)を示す。
フィールド名 |
定数 |
変数と静的変数 |
特殊変数 |
括弧 |
エンドトークン |
予約語FIELDに続く1語がフィールド名トークンである。 たとえば:
FIELD a
は、フィールド名"a"のトークンである。 同様に、
FIELD FIELD
はフィールド名"FIELD"のトークンである。 この場合、2番目のワードFIELDは予約語ではなくフィールド名であり、 最初のワードFIELDが予約語である。
特殊な場合として、プログラムの先頭あるいは次のトークンの次に ある1ワードで、予約語でないものは、フィールド名トークンと解釈する。
(
; , && || !
IF THEN ELIF ELSE WHILE DO
ABS AND ATAN AVG CAPS CAT COS COUNT EXISTS EXP INT LENGTH LOG LOG10 MAX MIN NOT OR SIN SQRT SUM TAN TOUPPER
次の例で、2番目のワード"a"は、トークンEXISTSの次にあるため フィールド名トークンと解釈される。
EXISTS a
フィールド名トークンを評価すると、 カレントレコードでそのフィールド名を持つフィールドの値となる。 同じフィールド名のフィールドが2つ以上あると、値は配列となる。 カレントレコードにその名前のフィールドがないと値は空値となる。
フィールド名トークンの値は文字列である。 しかし、たとえば比較演算をする場合数値として扱いたい場合も あるだろう。数値限定子をつけることにより フィールド名トークンを評価した結果を数値として取り出せる。 フィールド名の後ろにCOLON(:)と文字"n"をつけると 数値限定子となる。 たとえば:
FIELD seq
は文字列として評価されるので"10"は"9"より小さくなる。 しかし、
FIELD seq:n
は数値として評価されるため、"10"は"9"より大きくなる。
定数の形式には2通りある。 1つは予約語CONSTを使用する。 予約語CONSTに続く1語が定数トークンとなる。 配列値を表すには、最初の定数に続いてCONST と値とを繰り返す。
CONST a
CONST a CONST b
もう一つの方法は文字BRACEを使う。 LEFT BRACE({)1文字のワードの後ろで RIGHT BRACE(})1文字のワードの前にあるワードは 全体で定数トークンをなす。 このBRACEの中ではDlの予約語は、 その意味を失って、定数値となる。
{ a }
{ a b }
このBRACEの中ではLEFT BRACEも単に定数となる。 次の例:
{ { } }
は、4番目の語でシンタクスエラーとなる。 3番目の語で定数トークンが終わっているためである。
BRACEによる定数記法では、RIGHT BRACEの1文字だけからなる 定数を表記することはできない。 次のようにCONSTによる記法を使用すること。
CONST }
空値を表記するには、次のように書く。
{ }
CONSTによる記法では空値を表記する方法はない。
特殊な場合として、次のトークンに続く1ワードで、予約語でないものは 定数トークンとして解釈する。
!= !~ % * ** + - . .. /
< <= <> = == =~ > >= [
BY DIVEDBY EQ GE GT IN INCL
LE LIKE LT MINUS MOD NE PLUS POWER
QX S SG SUBST SUBSTG TIMES UNLIKE
たとえば、
FIELD 1 == 1
この例では、2番目のワード"1"はフィールド名で4番目のワードは 定数である。
定数は、そのままで文字列値となる。 たとえば演算子"+"の前後のように数値が必要な場合、 Dlインタプリタはオペランドを自動的に変換する。 定数を直接数値として評価する方法はない。 ただし、NUM演算子により変換することができる。
変数トークンは予約語VARとそれに続く1ワードからなる。 同様に、静的変数トークンは予約語STATICとそれに続く1ワードからなる。 FORトークンの直後に限り予約語VARを省略することができる。 予約語STATICを省略することはできない。
変数および静的変数は、値を保持することができる。 この2つの異なりは、その寿命にある。 変数の寿命は、プログラムの1実行サイクルで、 新しいレコードが入力ファイルから読み込まれて、 プログラムを実行する前に変数はすべて初期化される。 これに対し静的変数は、Dコマンドの実行期間である。 この意味で静的変数が、一般的な「変数」に近く、 変数は、ループのインデクスなどのローカルなものである。 (FOR演算子は、変数をインデクスとして使う。)
変数および静的変数のスコープは常にプログラム全体である。
変数または静的変数を評価すると、 そこに最後に代入された値となる。 値を1度も代入していない変数または静的変数 を評価すると空値(要素数0の配列)となる。
構文的には特殊変数は予約語1語からなる。 意味的には、いくつかはperlの予約変数のようであり、 いくつかはプログラミング言語の文に対応する。
特殊変数を評価すると、プログラムの実行環境に関する 値を返したり、プログラムのある機能を実行したりする。 この意味で「特殊変数」という名は誤解を生みやすいものもある。 しかし、構文上の単純さを確保するためこれらはすべて 特殊変数トークンのもとにまとめられている。
これらの変数は、FIELDSをのぞけば値を代入できない。 FIELDSは、カレントレコード全体を表し、 代入演算によって 値を変えることもできる。
個別の特殊変数に関しては、 演算子および関連特殊変数の節に記述する。
LEFT PARENTHESIS (()およびRIGHT PARENTHESIS ()) は、通常のプログラミング言語と同様に、 演算の順序を変えるために用いる。
ちなみに、CURLEY BRACKETS ({ })は、 定数を示して、式のグルーピングには関係しない。 また、SQUARE BRACKETS ([ ])は、 添え字演算である。
ワード"--"は、明示的にプログラムの終わりを示すのに使われる。 通常、このトークンを使う必要はない。 Dlのパーザは、トークンとして認識できないワード が出てくると自動的にエンドトークンを挿入するためである。 エンドトークンを必要とするのは、 入力ファイル名(の最初のもの)がDlの予約語と 一致する場合だけである。 たとえば:
COUNT a LT 2 -- LT
この例で、3番目の引数LTは、Dlの 予約語で、比較演算子"less than"である。 これに対し6番目の引数LTは、入力ファイル名である。 この場合、エンドトークンが必須となる。 これがないと、ファイル名が演算子と解釈されてシンタクスエラーをおこす。 (もし入力ファイル名が小文字の"lt"であれば エンドトークンは必要ない。)
Dlのプログラムには文がなく式のみであるため、 プログラムは常に「評価」される。これは「実行される」と同義である。 この点ではLISPに似ているともいえよう。
各構文要素(フィールド名、変数等)の評価については、 構文要素 の各節に記述されている。 また、演算子を含む式が評価されるとき、 演算子および関連特殊変数 の各節に記述される演算が実行される。
Dlの演算結果は、文字列値または数値の配列となる。 これをブール値として評価する場合の規則は次の通り。
この規則では奇妙なことも起こりうる。 たとえば、数値{ 0 }は、FALSEであるが、 文字列値{ 0 }は、TRUEとなる(規則1)。 しかしながら、多くの場合この規則は実用的に働く。
このブール値評価規則は、演算子がブール値を必要とする場合一般に 適用される。 たとえば、論理AND演算子はその左辺をブール値として評価する必要があり、 左辺にこの規則を適用する。
制御演算子 |
比較演算子 |
パターンマッチ・置換演算子 |
論理演算子 |
算術演算子 |
数学演算子 |
文字列演算子 |
変換演算子 |
配列演算子 |
添え字演算子 |
代入演算子 |
入出力関連特殊変数 |
システム関連演算子と特殊変数 |
演算子の優先順位 |
単項演算子は、右辺にオペランドとする。 2項演算子は、右辺および左辺をオペランドとする。 3項演算子はは、2ワードを使い、最初のワードの左、2ワードの中間、 後ろのワードの右の3つをオペランドとする。
これらのほかの演算子、たとえば添え字演算子やIF演算子は、 おのおの独自の構文を持つ。
いくつかの演算子や特殊変数は別形を持つ。 たとえば、"!="、"<>"と"NE"は、同じ演算子である。 これは、部分的には、">"のようなシェルの特殊文字を さけるためであり、 また、awkやperlのようなポピュラーなプログラムで 使われている形を使えるようにするためでもある。
制御演算子はUNIXのshと同様の構文としてある。 ただし、現在のDlには、caseやbreak、C言語の continueなどはない。(将来実現する可能性はある。) Dlのの演算子として制御演算子も値をもつ。
次の例は推奨できないが、IFも式をなすので、 正しいプログラムである。
IF IF v >= 0 THEN v ELSE - FIELD v FI > 3 THEN q = large FI
制御演算子表
; | 逐次実行演算子 |
IF THEN ELIF THEN ELSE FI | 条件演算子 |
WHILE DO DONE | whileループ演算子 |
FOR IN DO DONE | forループ演算子 |
EXIT | プログラム終了 |
EPILOGUE | エピローグモードフラグ |
式1 ; 式2 |
この演算子はC言語のコンマ演算子と同様である。 最初に式1を評価し、次いで式2を評価し、 式2の値をとる。 なお、C言語の;ふうの使い方を許すため 式2のない形も許される。 逐次実行演算子の演算優先順位は最低である。
IF 式1 THEN 式2 [ELIF 式3 THEN 式4]... [ELSE 式N] FI |
機能的にはC言語の"?:"演算子に当たる。 最初に式1を評価してその値のブール値評価がTRUEであれば、 式2を評価して、それを結果の値とする。 式1がFALSEでELIFのあるとき、 式3を評価してそれがTRUEなら式4を評価して、それを結果の値とする。 すべてのIFとELIFの条件がFALSEで、ELSEのあるとき、 式Nを評価して、それを結果の値とする。 この場合で、ELSEのないとき、最後のIFまたはELIFの条件式の値 (したがってFALSEである)が結果の値となる。
WHILE 式1 DO 式2 DONE |
式1を評価してその値のブール値評価がTRUEであれば、 式2を評価する。再び、 式1を評価するというループが 式1 がFALSEになるまで続く。 WHILEループ演算の結果は最後の式2の値である。 最初から式1の値がFALSEであれば、 from the first, WHILEループ演算の結果は式1の値となる。
FOR 変数 IN 式1 DO 式2 DONE |
式1を評価してから、変数を式1の各要素の値に順次セットして、 式2を評価する。 FORループ演算の結果は最後の式2の値である。 ただし、式1が空値の場合、結果も空値とする。
EXIT |
このワードが評価されると、プログラムは直ちに終了する。 この特殊変数は値を返さない。
EPILOGUE |
この特殊変数は、エピローグモードで実行している場合、 単純数値1を返す。それ以外の場合は単純数値0を返す。 エピローグモードについてはDedを参照。
比較演算子は、左辺と右辺を比較する2項演算子である。 結果は単純数値で1または0となる。おのおのTRUEとFALSEに対応する。
== | EQ | 等値 | |
!= | NE | <> | 非等値 |
> | GT | より大 | |
>= | GE | 以上 | |
< | LT | より小 | |
<= | LE | 以下 | |
INCL | 含む |
比較演算子は、両義性を持つ。 すなわち、オペランドの型によって、数値あるいは文字列としての比較を行う。 左辺または右辺のオペランドのいずれか一方でも数値の場合、 数値比較を行う。 左辺と右辺の両方が文字列だった場合、文字列比較を行う。 たとえば:
CONST 9 '<' CONST 10
は、結果が0(FALSE)となってしまう。 定数は、文字列型となるからである。
NUM CONST 9 '<' CONST 10
とすれば、数値として比較される。 次の例は、比較演算でよく間違える例である:
seq '<' 10
この場合も、文字列比較されてしまい、通常予期する結果にはならない。 数値比較にするには、数値限定子またはNUM演算子を使うこと。
seq:n '<' 10
seq '<' NUM CONST 10
比較についての詳細は、Dintroマニュアルの 値の比較 参照。
式1 INCL 式2 |
インクルード演算子は、オペランドを要素の順序なし集合として扱う。 式2が式1の部分集合となっていればTRUE(数値1)、 そうでなければFALSE(数値0)となる。 これは、式2のどの要素も、式1のいずれかの要素に等しければ TRUEということと同じである。
たとえば、フィールド"keywords"にいくつかの語が入っているとする、
Dselect keywords INCL database
Dselect keywords INCL { data base }
によって、それぞれ"database"という語を含んでいるか、 "data"と"base"をともに含んでいるか、という条件をテストできる。
=~ | LIKE | 正規表現マッチ |
!~ | UNLIKE | 正規表現案マッチ |
SUBST BY | 置換 | |
SUBSTG BY | 全置換 | |
$& | MATCH | マッチした文字列 |
$` | PREMATCH | マッチした部分の前の文字列 |
$' | POSTMATCH | マッチした部分の後の文字列 |
パターンマッチ演算子および置換演算子は、正規表現マッチに関連する。 Dの正規表現はUNIXのegrep仕様に基づく。 詳細は、Dintroマニュアルの 正規表現の節参照。
式1 =~ 式2 |
式1 LIKE 式2 |
式1 !~ 式2 |
式1 UNLIKE 式2 |
LIKEは=~の、UNLIKEは!~の別形である。
パターンマッチ演算子は、正規表現マッチングをテストする。 式1および式2は、文字列として評価され、 式1がテストされる文字列、式2が正規表現である。 結果は単純数値1または0となる。
式1および式2は、どちらも配列であってよい。 パターンマッチテストは、式1の要素と、式2の要素の すべての組み合わせについて行われる。 =~(LIKE)演算では、 少なくとも1つの式2の要素が、式1のいずれかの要素に マッチしたとき、結果が1、そうでなければ0となる。 !~(UNLIKE)演算では、 少なくとも1つの式2の要素が、 式1のいずれかの要素にマッチしなかったとき、 結果が1、そうでなければ0となる。
オペランドがすべて単純値でない限り、 !~演算はNOT =~演算とは異なるので 注意すること。 たとえば、
NOT a !~ '^[0-9]+$'
は、フィールド"a"が整数かどうかテストする。 フィールド"a"がリピーティングフィールドのときは、 すべての要素が整数かどうかテストすることになる。 これに対して
a =~ '^[0-9]+$'
は、フィールド"a"に整数が1つでもあるかどうかをテストする。
上記例ではUNIXシェルのAPOSTROPHE(')クォーティングを使っている。 WindowsのシェルではAPOSTROPHEのかわりにQUOTATION MARK(")を 使うこと。
パターンマッチ演算子のの優先順位は比較演算子と同じで、 結合順序は左からである。
式1 SUBST 式2BY 式3 |
式1 SUBSTG 式2 BY 式3 |
置換演算子は、perlやsedの (したがってUNIXのedやexの) s/xx/yy/およびs/xxx/yy/gにあたる機能をもつ。 式1、式2、式3はすべて文字列として評価する。 式1はベース文字列、式2は正規表現パターン、 式3が置換え文字列である。 パターンはベース文字列とマッチングを行い、マッチしたとき、 ベースストリングのマッチした部分を置換え文字列で置き換えたものが 結果の文字列となる。 SUBST演算では、ベース文字列の最初のマッチ部分のみ置き換える。 SUBSTG演算では、マッチしたすべての部分を置き換える。 マッチしなかった場合、ベース文字列が結果となる。 マッチしてもしなくても、結果は新しい文字列として作成され、 ベース文字列自体は変化しない。 このため、つぎのような使い方でs/xx/yy/にあたることを行う。
FIELD a = FIELD a SUBST xx BY yy
置換え文字列中で、いくつかの文字は特別な意味を持つ。
& | マッチした文字列 |
\1 | マッチした文字列のうちパターンの1番目の括弧に対応する部分 |
... | ... |
\9 | マッチした文字列のうちパターンの9番目の括弧に対応する部分 |
\& | & |
\\ | \ |
オペランドはいずれも配列であり得る。 この場合、ベース文字列の各要素について、 パターンの各要素を順にマッチングし、 マッチしたとき、置換え文字列のマッチしたパターンに対応する要素を 使って置き換えを行う。 結果は、式1と同じ要素数を持つ。 対応する置換え文字列の要素がない (式3の要素数が式2の要素数より少ない)場合、 置換え文字列としてNULL文字列を使う。
例:次の式は常にTRUEである。
{ CBI NACSIS NII } SUBST { CBI NACSIS } BY { NACSIS NII }
== { NII NII NII }
CONST 2002/12/24 SUBST ([0-9]+)/([0-9]+)/([0-9]+) BY \2/\3/\1
== 12/24/2002
置換演算子の優先順位は、2項演算子より高く、単項演算子のすぐ下である。 結合順序は左からである。
これらの特殊変数は、perlの$&、$`および$' と、わずかな差異をのぞいて同じである。 これらの特殊変数を評価すると、カレントレコードサイクルの 最後の成功したパターンマッチに対応したベース文字列の部分列を値として返す。
MATCH、別形$&は、ベース文字列のマッチした部分列である。
PREMATCH、別形$`は、ベース文字列のうち、先頭から マッチした部分の1文字前までの文字列である。
POSTMATCH、別形$'は、ベース文字列のうちマッチした 部分の1文字後ろから最後までの文字列である。
結果の値は常に単純文字列である。 パターンマッチ演算が配列で行われた場合でも、 最後にマッチしたパターンとベース文字列の組み合わせが使われる。 パターンマッチ演算や置換演算における、パターンマッチの順序は ベース文字列優先、すなわち、式1の最初の要素に 式2の各要素を順にマッチし、その後に式1の2番目の 要素という順である。
カレントサイクル中一度も成功したマッチングがなかった場合、 これらの値はNULL文字列となる。 以前の入力レコードにおけるマッチング結果が使われることはない。
SUBSTG演算におけるPREMATCH特殊変数にはやや問題がある。 パターンマッチが同じベース文字列の中で繰り返し行われ、マッチする文字列 も複数個あり得るためである。SUBSTG演算の後では、複数ある マッチした文字列のうち最後のものが記憶され、PREMATCHは、 それまでの置換えの行われたものを参照する。 これは、perlの$`とは異なるが、Dlの現在の 実装ではそうなっている。
! | NOT | 論理否定(単項) |
&& | AND | 論理積 |
|| | OR | 論理和 |
論理演算子の優先順位は他の演算子より弱いが、 ;および =より強い。 この中で、ORがもっとも弱く、次がAND、さらにNOT と強くなる。結合順序は右から左である。
! 式 |
NOT 式 |
NOTは単項演算子で式をブール値評価して 結果がTRUEであれば単純数値0、 FALSEであれば単純数値1となる。
式1 && 式2 |
式1 AND 式2 |
式1 || 式2 |
式1 OR 式2 |
AND(&&)およびOR(||)は 2項演算子である。 perlのこれらの演算子のように、 値は単純数値0や1ではなく、 式1または式2の値となる。
AND(&&)は式1をブール値評価して TRUEであれば、式2を評価してその値をとる。 FALSEであれば、式2は評価されず、 値は式1となる。
OR(||)はまず式1をブール値として評価し、 結果がTRUEであれば式2は評価せずに式1を値とする。 FALSEであれば、式2を評価してその値をとる。
+ | 加算 | |
- | 減算、単項マイナス | |
* | 乗算 | |
/ | 除算 | |
% | MOD | 剰余 |
** | べき乗 |
算術演算子は単項マイナスをのぞき2項演算である。 構文は次のとおり。
式1 演算子 式2 |
- 式 |
ここに、演算子は、上の表の演算子の一つ。
式1および式2 (または単項マイナスの場合式)は数値として評価する。 %の場合、さらに整数に変換する。
オペランドが両方単純数値の場合、 通常の計算が行われる。 左辺または右辺が配列の場合、 Dlは特別な扱いをする。
単項マイナス演算子:
- foo
は、次の式と同じである。
CONST 0 - foo
次の例は上記の規則を例示したもので、 すべてTRUEとなる。
CONST 1 + CONST 1 == CONST 2
{ 1 2 3 } + { 3 2 1 } == { 4 4 4 }
{ 1 2 3 } * { 4 } == { 4 8 12 }
{ 1 2 3 } * { 4 5 } == { 4 10 }
{ 6 } / { 6 3 2 } == { 1 2 3 }
{ 6 5 } % { 4 3 2 } == { 2 2 }
{ } + { 1 2 3 } == { }
CONST 1 + { } == { }
演算優先順位は通常通りで、
- (unary)
**
* / %
+ -
すべて比較演算子および配列演算子より高く、 2項算術演算子は文字列連結演算子、数学演算子および単項配列演算子 より低い。 単項マイナス演算子の優先順位は数学演算子と同じである。
ABS | 絶対値 |
SQRT | 平方根 |
EXP | 指数関数 |
LOG | 自然対数 |
LOG10 | 常用対数 |
SIN | 正弦 |
COS | 余弦 |
TAN | 正接 |
ATAN | 逆正接 |
数学演算子は単項演算子でその構文は次の通り。
演算子 式 |
ここに、演算子は上掲の表のひとつ。
ほとんどのプログラミング言語で、これらのものは「関数」で、 LOG(x)のような構文を持つ。 しかし、Dlでは演算子で括弧はいらない。たとえば:
SQRT a
しかし、括弧を使っても害はない。
SQRT ( a )
式は数値として評価する。 式が配列の場合、結果も同じサイズの配列で、 そのi番目の要素は式のi番目の要素にその演算を 行ったものとする。 次の例を見よ。
ABS { -1 0 1 } == { 1 0 1 }
ABS { } == { }
これらの演算子の優先順位は算術演算子より高い。
. | 文字列連結 | |
LENGTH | 文字数 | |
TOUPPER | CAPS | 大文字化 |
式1 . 式2 |
連結演算子は2項演算子である。 式1と式2は文字列として評価する。 式1の後ろに式2を連結したものが結果の値となる。 (オペランド自体は変化しない。) オペランドが配列の場合、 算術2項演算と同じ規則が適用される。 つぎの例を参照:
CONST 0x . { abc def } == { 0xabc 0xddef }
{ "¥" "$" } . { 120.5 1.00 } == { "¥120.5" "$1.00" }
連結演算子の優先順位は算術演算子(**)より高く、 数学単項演算子より低い。
LENGTH expression> |
LENGTHは単項演算子である。 オペランドは文字列として評価する。 結果は数値で、オペランドの文字数を値とする。 オペランドが配列の場合、結果も配列で オペランドのi番目の要素の文字数が、結果の配列の i番目の要素となる。 次の例を参照:
LENGTH { abc def } == { 3 3 }
LENGTH演算子の優先順位は数学単項演算子と同じである。
TOUPPER(別形CAPS)演算子は、 オペランドと同じ長さで、オペランド中の 小文字が対応する大文字になっていることをのぞけば、同じ内容の 文字列を値とする。オペランド自体は変化しない。 オペランドが配列の場合の扱いは、 LENGTHや 数学単項演算子 と同じである。 次の例参照。
TOUPPER { Dselect Dgrep Dextract } == { DSELECT DGREP DEXTRACT }
TOUPPER演算子の優先順位は数学単項演算子と同じである
NUM | 数値変換 |
STR | 文字列変換 |
INT | 整数変換 |
NUM 式 |
NUM演算子は式を数値に変換する。 オペランド自体は変更されない。 変換方法の詳細は Dintro マニュアル参照。 オペランドが配列の場合の扱いは、 数学単項演算子 と同じである。 優先順位は数学単項演算子と同じである
STR 式 |
STR演算子は式を文字列に変換する。 オペランド自体は変更されない。 変換方法の詳細は Dintro マニュアル参照。 オペランドが配列の場合の扱いは、 数学単項演算子 と同じである。 優先順位は数学単項演算子と同じである
INT 式 |
INT演算子は式を文字列に変換する。 オペランド自体は変更されない。 オペランドが配列の場合の扱いは、 数学単項演算子 と同じである。 優先順位は数学単項演算子と同じである
, | 配列連結 |
COUNT | 要素数 |
EXISTS | 存在テスト |
MIN | 最小値 |
MAX | 最大値 |
SUM | 合計 |
AVG | 平均値 |
CAT | 要素連結 |
.. | 一連数値の配列 |
式1 , 式2 |
配列連結演算子は、2項演算子である。 式1の後ろに式2の要素を並べたものが、結果の値となる。 (式1がフィールドや変数でもそれ自体は変わらない)。 結果のよう素数は、オペランド双方の要素数の和となる。 次の各例はTRUEとなる。
{ 1 2 3 } , { 4 5 6 } == { 1 2 3 4 5 6 }
式1と式2の型が異なるときは、式2を式1 の型に変換する。 たとえば:
NUM { 1 2 3 } , STR { a b c } == NUM { 1 2 3 0 0 0 }
{ a b c }を数値に変換すると{ 0 0 0 }となることに注意。 (Dintroのマニュアル参照。)
配列連結演算子の優先順位は算術演算子より低く、 比較演算子より高い。
COUNT 式 |
EXISTS 式 |
COUNTは式の要素の個数を示す 単純数値を結果の値とする。
EXISTSは、式の要素数が1以上のとき 単純数値1を 、要素を持たないとき0を値とする。
優先順位は数学単項演算子と同じである
MIN 式 |
MAX 式 |
SUM 式 |
AVG 式 |
これらは単項演算子である。 式の配列に対する統計値を与える。 式の全要素は数値として評価する。 MIN、MAXは最小、最大値、 SUMは全要素の合計値、 AVGはSUM/COUNTを値とする。 次の例を参照:
COUNT { 1 2 3 4 5 6 } == CONST 6
COUNT { } == CONST 0
MIN { 1 2 3 4 5 6 } == CONST 1
MAX { 1 2 3 4 5 6 } == CONST 6
AVG { 1 2 3 4 5 6 } == CONST 10.5
優先順位は数学単項演算子と同じである
CAT 式 |
CATは単項演算子である。 式の全要素を文字列として評価し、 この全要素を要素順に文字列連結したものを値とする。 次の例を参照:
CAT { 1 2 3 4 5 6 } == CONST 123456
優先順位は数学単項演算子と同じである
式1 .. 式2 |
範囲演算子はperlのスカラー環境での範囲演算子に 似ている。 次の例が典型的な使い方を示す。
FOR i IN 0 .. COUNT a - 1 DO
IF a [ VAR i ] =~ [0-9]+ THEN num = FIELD num , a [ VAR i ] FI
DONE
式1と式2の双方を数値として評価する。 さらに、式1の最後の要素と式2の最初の要素とを 整数に変換する。 その後、式1の最後以外の要素を、結果の配列にコピーする。 次に式1の最後の要素(整数にしたもの)から始まって、 式2の最初の要素(整数)までの整数値をその後ろに埋める。 最後に式2の2番目以降の要素をその後に追加する。 整数値を埋めるときの間隔は式1の最後の要素と 式2の最初の要素のどちらが大きいかにしたがって、 1または-1とする。 次の例を参照:
{ 0.5 1.5 } .. { -1.5 -0.5 }
== { 0.5 1 0 -1 -0.5 }
(なぜ0.5と-0.5とが整数に変換されないのか疑問を持つかもしれない。 特に理由はない。ただ、この方が実装上やや楽ではあった。)
範囲演算子の優先順位は配列連結演算子より高く、算術演算子より低い。 結合順序は、左からである。
式1 [ 式2 ] |
式2は添え字で、数値として評価し整数に変換する。 添え字演算の結果は、式1の要素で式2番目 のもの(添え字が式2のもの)である。 要素は先頭をゼロ番目として添え字づけられている。 添え字が式1の範囲を超えていた場合、 結果は空値となる。 添え字が配列の場合、結果もまた配列で、 そのi番目の要素は式1の 「式2のi番目の要素番目」の要素とする。
次の例はすべてTRUEとなる。
{ 1 2 3 } [ 0 ] == { 1 }
{ a b c } [ 1.5 ] == { b }
{ 1 2 3 } [ -1 ] == { }
{ a b c } [ 3 ] == { }
{ 1 2 3 } [ { 0 1 } ] == { 1 2 }
{ a b c } [ { 2 1 0 } ] == { c b a }
{ a b c } [ { 1 2 3 } ] == { b c }
foo [ 1 ] [ 0 ]は構文的には正しい式である。 しかし、これはfoo [ 1 ]と同じで、 2次元配列となるわけではないことに注意せよ。 C言語等と異なり、Dlには1次元配列しかない。
LHE = 式2 |
LHE [ 式1 ] = 式2 |
代入演算子は、式2を評価してその値を 左辺式(LHE)にいれ、また結果の値としてその値をとる。
式2の型がLHEと異なるときは、式2をLHE の型に変換する。たとえばVARの最初の使用時などLHEに型のないときは、 式2の型がLHEの型となる。 なお、フィールド名とカレントレコード特殊変数は常に文字列型である。
LHEは、 フィールド名、 変数、 静的変数、 カレントレコード特殊変数 のいずれかに限られる。 LHEに添え字のついたとき、 式1は添え字(整数)として評価し、 代入対象はLHEの添え字づけられた要素に限定する。
LHEがフィールド名の場合、 カレントレコード中のフィールド順は可能な限り保持される。 たとえば、カレントレコードが、
a:A
b:B
で、プログラムが、
FIELD a = CONST foo
のばあい、結果は、
a:foo
b:B
となる。フィールド"a"は動かない。
ターゲットフィールドも代入値も配列であってよい。 これらの配列の要素数が等しい場合、 対応する要素をフィールド位置を保持しながら代入する。 ターゲットフィールドの方が代入値より多くの要素を持つ場合、 超過分のフィールドはカレントレコードから消去される。 ターゲットフィールドの要素の方が少ない場合、 超過したフィールドは、ターゲットフィールドの最後の ものの直後に追加される。
たとえば、カレントレコードが
a:A
b:AA
a:B
b:BB
で、プログラムが
FIELD a = { 0 1 2 3 }
のとき、結果は次のようになる。
a:0
b:AA
a:1
a:2
a:3
b:BB
ターゲットフィールドがカレントレコード中にない新しいものであるとき フィールドはレコードの最後に追加される。
添え字のついた場合、式1は数値として評価され、整数に変換される。 代入対象は、添え字で指定した要素に限定される。
たとえば、カレントレコード(変数や静的変数でも同じであるが) が次のようだったとする。
a:AA
a:BB
a:CC
プログラムが、
a [ 1 ] = { 1 }
とすると結果は次のようになる。
a:AA
a:1
a:CC
代入する値が次のような配列の場合、
a [ 1 ] = { 1 2 }
対象となる要素が配列で置き換えられて次のようになる。
a:AA
a:1
a:2
a:CC
値が空値の場合、
a [ 1 ] = { }
要素の削除を意味し、結果は次のようになる。
a:AA
a:CC
添え字がターゲットの現在持っている要素数を超えている場合、 代入した値は消えてなくなる。 (perlのように、配列の拡張が行われるわけではないので注意。)
LHEに対する添え字式1が配列だった場合、 規則は「原則1対1、過不足は最後の要素に」というものである。
たとえば、ある変数が次の値を持っていたとする。
{ AA BB CC DD }
プログラムが次のようであると、
VAR a [ { 0 2 } ] = { 0 2 }
結果は{ 0 BB 2 DD }となる。
値の方が要素数が多い場合は、
VAR a [ { 0 2 } ] = { 0 2 4 6 }
結果は、{ 0 BB 2 4 6 DD }となる。
値の方が要素数が少ない場合は、
VAR a [ { 0 2 } ] = { 0 }
変数"a"の要素が削除されて{ 0 BB DD }となる。
OUTPUT | カレントレコードの出力 |
FILENAME | 入力ファイル名 |
FNR REC# | カレントレコード番号(入力ファイル内) |
NR $. | カレントレコード番号(全入力ファイル通算) |
@_ CURREC FIELDS | カレントレコード自体 |
特殊変数にはオペランドはない。
この特殊変数を評価すると、Dl処理系は、 カレントレコードを標準出力に書き出す。 カレントレコード自体は変化しない。 結果の値は、常に単純数値1を返す。
この特殊変数は、カレント入力ファイル名を値とする。 入力ファイルが標準入力の場合、値はNULL文字列となる。
この特殊変数は、カレント入力ファイルの中での カレントレコードのレコード番号(1から始まる) を値とする。 歴史的事情でこの特殊変数は2つの名前を持っている。 REC#はDprのヘッダ行に現れる。 FNRはawkで使われている名称である。
この特殊変数は、全入力ファイルを通算したカレントレコード番号 を値とする。 入力ファイルが1つであれば、FNRと等しい。 NRはawkコンパティブルな名称、 $.はperlコンパティブルな名称である。
この特殊変数は、なまのカレントレコードである。 カレントレコードの各フィールドが、 Dファイル上のフィールド名、COLON、値という形のまま の文字列として、この変数の要素となる。
この特殊変数への代入は、当然、カレントレコードの変更となる。 各要素の値が、Dファイルのフィールド規約を守った ものとするのはユーザの責任で行う。
この特殊変数に空値を代入すると、
CURREC = { }
カレントレコードの削除となる。 (ただし、その後で値を代入しないかぎり。)
この特殊変数はCURREC、FIELDSおよび @_という3つの名前を持っている。 @_は、perl風の名称で、perl と同じ意味ではないが、 perlユーザには覚えやすいだろう。 CURRECは当然"current record"の略であるが、 COUNT CURRECのような場合、意味的にやや不自然な 印象となり、COUNT FIELDSの方が自然である。 このためこれらの別形が用意されている。 どれを使うかは自由である。
QX | システムコマンドの実行 |
$? STATUS | QXのリターンコード |
LOCALE | カレントロケールの値 |
QX 式 |
QXは単項演算子である。 Unixシェルのバックティック(`コマンド`)にあたる。 式は、必要ならば文字列に変換され、 シェルでコマンドとして実行される。 実行結果の標準出力の文字列が演算結果となる。
標準出力が複数行になるとき、結果は各行を要素とした配列となる。 (したがって、改行文字が結果に含まれることはない)。 また、式が配列の場合、 各要素の間に改行文字をはさんで一つの文字列とし、 これをシェルにわたす。 ただし、シェルが2行目以下をしかるべく処理してくれるかどうかは、 オペレーティングシステムによる。 (Windowsのシェルcmd.exeは、 2行以上のコマンドは正しく処理しない)。
QX演算子の優先順位は数学単項演算子と同じである。 QXの名称はperlのqx/command/演算子に由来する。
この特殊変数は、最後に行われたQXでのコマンド実行結果 のリターンコードを保持する。 最初のQXが実行されるまで、この値は0である。
$?はUnixのsh風の名前、 STATUSはUnixのcsh風の名前である。
この特殊変数はカレントロケールの値を保持する。 UNIXではsetlocale(LC_ALL, "")の戻り値、 Windowsではsetlocale(LC_CTYPE, "")の戻り値である。
演算子 | 結合順序 |
[ ] | 左→右 |
- ABS ATAN AVG CAT CAPS COS COUNT EXISTS EXP INT LENGTH LOG LOG10 MAX MIN NUM QX SIN SQRT STR SUM TAN TOUPPER |
右→左 |
SUBST SUBSTG BY | 左→右 |
. | 左→右 |
** | 左→右 |
* / % | 左→右 |
+ - | 左→右 |
.. | 左→右 |
, | 左→右 |
== != > < <= >= INCL =~ !~ | 左→右 |
! | 右→左 |
&& | 右→左 |
|| | 右→左 |
= | 右→左 |
; | 右→左 |
以下の例では、FIELD、CONST、VAR は可能な場合、省略している。 これは、Dlパーザの機能を示すためにそうしているだけで、 そのような使用を推奨しているわけではない。 予約語の省略は、しばしば気がつきにくいエラーのもととなるため、 むしろなるべく、省略に頼らない書き方が勧められる。
フィールド"lang"の値が"jpn"か?
lang == jpn
フィールド"yr"の値が数値2003より小か?
yr:n LT 2003
各入力Dレコードは1つだけのフィールド"l"を持っていて、 その値はあるテキストファイルの1行となっている。 このテキストファイルで、パラグラフは空白行で区切られている。 次の例は、この各レコードにパラグラフの1連番号をフィールド"P" として追加する。
IF NR == 1 THEN STATIC P = 1 FI ;
IF l =~ " *" THEN STATIC P = STATIC P + 1 FI ;
FIELD P = STATIC P
Dtie -t / y,m,d ymdと同じことをDedで行う。 (ただし、フィールド"y"、"m"、"d"は同数の要素を持っていること。)
ymd = FIELD y . CONST / . FIELD m . CONST / . FIELD d ;
y = FIELD m = FIELD d = { }
Dproj fooと同じことをDedで行う。
FOR i IN 0 .. COUNT FIELDS - 1 DO
IF FIELDS [ VAR i ] =~ ^foo: THEN
VAR f = VAR f , VAR i
FI
DONE ;
FIELDS = FIELDS [ VAR f ]
MIYAZAWA Akira