作者: Koichi Yamamoto
日時: 2003/3/9(21:46)
こんにちは、山本です。

"Kosuke Yamazaki <kyam@...>"さんは書きました:
> Tcl で以下のようにプロシージャ内でコメントアウトしたいのですが、
> コメント行内の「{」を認識してしまうようです。Tcl の仕様として
> コメント行にある「{」や「}」の数もカウントするのでしょうか。
> 
> proc test {} {
> #{
> puts "aaa"
> }

Tcl8.4.1の実装を見てみましたが、open brace(「{」記号のこと)が出現すると
たとえその行の先頭が'<whitespace>#'となっていてもopen braceを数えるよう
になっています。

"藤岡和夫 <kazuf@...>"さんは書きました:
> プロシージャ内のコメント行では、{}をセットで使う必要があるということにな
> りますか。\{、\}とエスケープすればセットで使わなくてもエラーになりません
> 。{}を文法の構成要素として捉えていますね。コメントの性質を考えるとバグな
> んでしょう。

procコマンドやforeachコマンドなど「引数」にスクリプトを指定できるコマンド
だけについて注目していると、コメント行のopen braceが数えられるのはバグでは
ないかと感じます。
しかし、Tclという言語では、brace記号はあくまで「close braceが現れるまで一つ
の単語として括る」というものです。Tclにとってのbrace記号は、ブロックという
よりもむしろPerlのシングルクォーテーションや q// で文字列を括っているような
ものだと考えると解りやすくなると思います。
また、Tclでは、文字列中にbrace記号が現れると、その間に括られている文字列を
リストの一要素として扱うことができるため、backslashでquoteされていない
open braceとclose braceを一対一にしておかないと正常にスクリプトを動作させる
ことができなくなります。

例えば、setコマンドで説明すると:

set hoge "a b {c d} e"   ;# ←OK: hogeに「a b {c d} e」という文字列が設定される
set foo {a b {c d} e}    ;# ←OK: fooに「a b {c d} e」という文字列が設定される
set bar {a b {c d} e     ;# ←NG: 最初のopen braceに対応するclose braceが無い
puts [lindex $foo 2]     ;# 「c d」が表示される

これはよく見かけるsetコマンドの書き方ですが、次のように複数行に渡って
setコマンドを記述することもできます。procコマンドなどもこれと同じように
構文解析されます:

set foo {
  a
  b
  # {
    c
    d
  }
  e
}
# ↑
# OK: fooに「\n  a\n  b\n  # {\n    c\n    d\n  }\n  e\n」という文字列が設定される
puts [lindex $foo 3]     ;# 「\n    c\n    d\n  」が表示される

set bar {
  a
  b
  # {
    c
    d
  }
  e
# ↑
# NG: 最初のopen braceに対応するclose braceが無い

このように、brace記号の間にあるopen braceやclose braceには特別な意味があるため、
注意が必要です。


なお、以下のように#の直後にopen braceがある場合は、本当はこのopen braceを
勘定すべきではないと思います。事実、lindexコマンドでリストの要素を取り出して
みると次のように解釈されています:

#{      ← 「#{」という一つの単語として取り出される
# {     ← まず「#」という単語があり、「{」から次の単語が開始する

つまり、whitespaceがあるかないかで微妙に解釈が違ってきます。
だから、今回の↓はやっぱりバグと言えるのです。

proc test {} {
#{
puts "aaa"
}

なんだかややこしいですね(^^;。

--
Koichi Yamamoto, 
http://homepage3.nifty.com/yamakox/