構文解析のおおまかな順序

  1. 環境変数の展開、引数の展開、if/for/( ) 等の構造を持った文の構文解析、およびリダイレクトの判断等が同順序
  2. for 制御変数の展開
  3. 環境変数遅延展開の展開
  4. コマンド名、リダイレクトファイル名の確定とリダイレクト・パイプのオープン
  5. (コマンドの探索と実行)

ただし、パイプ構文の場合は、for 制御変数の展開や、環境変数遅延展開の後でも & && | || < > >> 等の文の構文解析、% による環境変数展開が再度行われるようである。

構文解析

以下の解析が同時になされる。

行末の ^ による継続行処理

行末がクォートされていない ^ である場合は次の行とつなげて、構文解析を続ける。

文の区切りの認識

1行に複数の文を書く場合がある。クォートされていない & && || | を区切りと 見なしてその前後で、それぞれ構文解析を行う。

括弧による複合文の認識

改行や上記文区切り記号で区切られた複数の文を、クォートされていない括弧で 囲んで一つの文として扱う。プログラミング言語でよくある { } や begin/end do/end などと同じ。
括弧を開いたまま閉じる括弧がなくバッチスクリプトのファイルが終わった場合は、 開く括弧以降が構文解析できないため全て捨てられる。

if/for という構造を持った構文の解析

文頭が if か for ならそれぞれの構文に従って解析を進める。

リダイレクトの処理

クォートされていない < > >> があればその次のトークンをファイル名と見なして リダイレクト指定であるというマーキングを行う。実際のファイルオープンは まだ先で環境変数遅延展開の後、コマンド実行の前である。
全般/ファイルディスクリプタとリダイレクトも参照。

2個連続した % の1個の % への置換

バッチスクリプトであれば連続した % は1つにして、環境変数展開には使わない。

% による環境変数の展開

単独の % がありその後に % が出てくれば、環境変数展開と見なす。 :~ が途中にあれば部分文字列の修飾で、: = がこの順に途中にあれば文字列置換の 修飾である。

単独の % の削除

対応する % が行内に無い単独の % を削除する。

空白文字の無視

構文解析時にいくつかの箇所で、クォートされていない = ; , は空白と同じ 扱いを受ける。
行頭、リダイレクト記号とファイル名の間、if 構文の比較の == 以外の場所、 for 構文。

^ による特殊文字のクォート

^ の次の特殊文字 ^ " < > & | ( ) = ; ,の特殊な意味を失わせる。 また、リダイレクト記号の直前の1桁の数字も ^ によってクォートされると ファイルディスクリプタ番号としての意味を失う。 これら以外の文字が続く場合は ^ が削除される。 ! はこの時点では特殊文字ではないので、^! と書いても遅延展開の意味を失わない。

" による文字列のクォートと1トークン化

クォートされていない " が出てきたらそこから次の " または行末までの % 以外の全ての特殊文字が特殊な意味を失う。 途中に空白や、構文解析上空白と見なされる場合のある = ; , があっても トークンの区切りとはみなさず複合した1つのトークンとみなす。
複合したトークンとして扱われて意味があるのは、リダイレクト記号の次、 if 構文の比較対象、for 構文の in ( ) の括弧の中。

文頭の @ の認識

クォートされていない @ が文頭にあれば、実行時に echo off しなくても その文が表示されないという印をつける。 実際に表示するのは、for 制御変数の展開を行ってから、環境変数遅延展開の前。

for 制御変数の展開

for 文の制御変数の展開は、前項の構文解析が終わってからなので、 展開後に < > & | ( ) @ の特殊記号が出てきても、 前項の構文解析の結果は変更されない。
for 文や if 文のトークンやオプションにも for 制御変数は使えない。

展開後に echo on で文頭に @ がなければ文が表示される。 この時、for 文や if 文の /オプション や if 文の比較演算子の英小文字は 英大文字として表示される。

環境変数遅延展開の展開

遅延展開が有効でかつ ! が行内にあるとき、以下の処理が行われる。 ! が無い行については何もなされない。 コマンド別/setの「set /a 特殊記号の演算子」も参照。

^ による ^ ! のクォート

% と違って文字として ! を残したい場合 !! と書くのは駄目で両方消える。 ! を環境変数展開に使わず普通の文字として扱いたい場合は ^ でクォートする。 ただし、^ は構文解析時の特殊文字でもあるので、この時点で単独の ^ が必要なら 最初に ^^ と書いておくと構文解析時に1つの ^ になる。
つまり単独の ! 文字が必要なら、^^! と書き、単独の ^ が必要なら ^^^^ と書く。

! による環境変数の展開

単独の ! がありその後に ! が出てくれば、環境変数展開と見なす。 :~ が途中にあれば部分文字列の修飾で、: = がこの順に途中にあれば文字列置換の 修飾である。

クォートされなかった ! の削除

クォートされていない残った ! を削除する。

コマンド実行時の特殊記号の扱い

コマンド実行時には、構文解析時の各特殊記号にどのような意味を与えるのかは 各コマンドの解釈次第である。

例: dir や ren、del、call 等といった比較的単純な多くのビルトインコマンドでは、 クォートされていない = ; , は空白と同じ扱いを受ける。
しかし、echo や set、cd 等ではいずれも特別扱いはされないし、 start 等では扱いが複雑なようだ。

例: ファイル A から " を含む行を検索し、ファイル B に入れることを意図して、次のように書いたとする。

findstr """ A >B

構文解析時には、3つ目の " から行末までは文字をクォートしているので、>B はりダイレクトでなくそのままの文字列として扱われる。
findstr コマンドは """ を1つの " として検索文字として扱い、 A と >B を検索対象のファイル名として扱う。
つまり、A と >B は構文解析時は引用符の中、コマンド実行時は引用符の外である。
その結果として、ファイルA中で " を含んだ行があればそれを表示した後、

FINDSTR: 開くことができません (>B)

というエラーになる。
意図どおりの結果を得るには、リダイレクトが " " の中に入らなければ良いので、

findstr >B """ A
findstr < A > B """

等と書けばよい。



トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2005-06-06 (月) 22:16:27 (7107d)