Tcl文法編

 シンタックス
 Tclは、ごく簡単なシンタックスしか持っていません。それは、以下のような規則です。

   @空白文字で区切られた文字列の最初のワードコマンド、それ以外はコマンドの引数である。
   Aコマンドとコマンドは、改行または、セミコロン(;)で区切られる。

 たとえば、以下の2つの例は、同じ動作をします。

  set cnt 10;incr cnt;puts "cnt=$cnt"

set cnt 10
incr cnt
puts "cnt=$cnt"

 太字がコマンドで、それ以外はすべて引数です。

 ただし、最後のスクリプトでは、cnt=$cnt が1つの引数としてみなされます。
 Tcl8.0以降バイトコードコンパイラが採用されたため、
 両者には実行速度に違いはないと考えてよいでしょう。
 シンタックスとしては、以上ですべてです。すると当然、「ループや分岐などの制御機構は無いの?」という疑問が出てくると思います。
 結論からいうとTclインタプリタは、そのような制御構造を持っていません。ただ単に上記のようなコマンドを
評価していくだけです。
 それでなんでループが出来るかというと、それらをコマンドが内部的に行っているためです。
 以下の、for コマンドをみてください。
  set sum 0
for {set cnt 1} {$cnt <= 10} {incr cnt} {
  set sum [expr $sum + $cnt]
}
puts "sum=$sum"
 変数 sum に初期値0を設定
 変数 cnt を1から10まで加算しながらループさせます
 変数 sum に 変数 cnt を加算し結果を sum に再設定し
 ます。
 最後に変数 sum の値を表示します。
 これは、ごく普通にループとわかるスクリプトだと思います。しかし、これはインタプリタから見ると3つのコマンドを評価しているだけなのです。
 for コマンドを評価する際、インタプリタは、4つの引数を for コマンドに渡します。それらの内容は、以下の通りです。
  set cnt 1
$cnt <= 10
incr cnt
set sum [expr $sum + $cnt]
 第1引数
 第2引数
 第3引数
 第4引数
 for コマンドがこれらの文字列を引数としてインタプリタから渡されると、その内部では以下のような処理をしていると思われます。
 
  @ 第1引数 ”set cnt 1”をインタプリタに渡して評価させる。
  A 第2引数 ”$cnt <= 10”を続けてインタプリタに評価させる。
     評価結果がfalseの場合、処理を終えてreturnする。
  B第4引数 ”set sum [expr $sum + $cnt]”をインタプリタに評価させる。
  C第3引数 ”incr cnt”をインタプリタに評価させ、Aへ戻る。
 
 このように、コマンドの内部でインタプリタを再度呼び出すことによって、for コマンドを評価したいわば「外側」のインタプリタが知らないうちに、ループ制御が行われています。
 この仕組みは、ちょっと面倒くさいように思えますが、インタプリタに高度な制御機構を備えること無く、自由な実行制御をコマンドを追加するだけで実現できるという大きなメリットがあります。
 たとえば、標準のTclコマンドには、Untilループがありませんが、必要に応じてUntilループを実装することも出来る訳です。コンパイラ言語であるC言語などでは、考えられないような機能だといえるでしょう。
 
 置換とクォート
 Tcl言語のもう一つの重要な機能として、置換とクォートがあります。

置換

 Tclインタプリタは、スクリプトを解析する際にワードごとに以下のような置換を行い、その結果の文字列をコマンドに引数として渡します。

 

  変数置換 ドルマーク($)で始まるワードは、$を除いた部分を変数とみなしてその値で置換します。
例) set val 10
puts "val=$val"
puts コマンドには、文字列 val=10 が渡される。
コマンド置換 ブラケット([])で囲まれた文字列をTclスクリプトとしてみなしてその結果で置換します。
下で記述している「クォート」の一種とみなしてもよいでしょう。
例) set val 10
puts "Ans.=[expr $val * 2]"
expr $val * 2 スクリプトの評価結果 20 で […] を、置換された文字列 Ans.=20 が
1ワードとして
、puts コマンドに渡される。
バックスラッシュ置換  バックスラッシュで始まるワードは、以下のような特別な文字に置換される。
例) \a
\b
\f
\n
\r
\t
\v
\\
\{
\}
\"
\改行
ベル
バックスペース
改頁
改行
復帰
タブ
垂直タブ
バックスラッシュ
左ブレース
右ブレース
ダブルクォート
1つの空白。これは、行が長くなった場合に見やすくするのに便利です。

 

クォート

 Tclインタプリタは、空白文字でスクリプトをワードに分割しますが、以下のようにそれを無視させることができます。
  ダブルクォート 
”…”
ダブルクォートで囲まれている個所の空白文字のみを無視させます。
ただし、入れ子にはできません。
例) set val 10
puts val = $val

puts "val = $val"

 文字列 val = $val の = の両側には空白があるため、
 全部で4ワードからなるスクリプトとみなされる。
 文字列 val = $val がクォートされているため1ワードとみなされ、
 puts コマンドには文字列 val = 10 が渡される。
ブレース
{…}
ブレースで囲まれている個所のすべての置換を無視させます。
また、入れ子が可能です。
例) set cnt 0
set sum 0
while { $cnt < 10 } {
incr sum [incr cnt]
}
puts "sum=$sum"

 while コマンドに渡される文字列は、
 第1引数:$cnt < 10
 第2引数:改行incr sum [incr cnt]改行
 第2引数は、左ブレースで始まっているために、右ブレースまでの2つの改行、
 1つのブラケットを含めてすべてが無視され、1ワードとして認識されます。