#

如果你用過Dos或是Unix-like的命令模式,那你可以想像,Tcl的程式就好像是一個從第一行到最後一行都是命令組成的程式,Tcl的命令模型大概就像是這個樣子。這一篇文章會先由Tcl的命令模型切入討論,然後再介紹代換的觀念。學會了這些觀念,就幾乎等於學會了Tcl最困難的部份。

4.1 命令模型

Tcl是屬於直譯式的程式語言,它的程式碼是由許許多多的「命令」及「參數」所組成。其中「命令」可以看成是Tcl提供的功能,例如,puts命令提供輸出的功能,button命令提供畫按鈕的功能,if命令提供條件判斷的功能,每個命令都有自己專屬的功能。而「參數」指的是跟隨在命令之後的項目,它們可以用來調整命令執行的行為,給予不一樣的參數,其執行結果就會有所分別。如下是Tcl的命令模型:

命令 ?參數 1? ?參數 2? ?參數 3? ?參數 N?

這個模型非常的簡單,開頭是一個命令後面跟著不定數量的參數,命令及參數或參數及參數間使用空白隔開。雙問號夾起來的參數表示可以選擇性添加,至於要不要添加或到底要加多少,則需要看最前面的命令及寫程式的人來決定,原則上不同的命令可以添加的參數量是不一定的,給予不同數量的參數,命令執行的行為通常也是不一樣的。例如,之前使用過的set命令,事實上它可以接受一或兩個參數,加上2個參數表示要設定變數,如果只有加上一個參數,set會把其後的參數當成是變數,並且取出它的值,例如:



又例如,pwd命令可用來取得目前程式的工作目錄,它是一個不用加任何參數的命令,像這樣:



另外,先前的文章中使用button 命令建立視窗的按鈕。它最少需要1個參數來指定按鈕獨一無二的ID,此外還可以加上其它button特有的參數,像下面的4行程式添加了不一樣的參數量。附帶一點,大部份用來建立視窗元件的命令,都是採用類似的語法,除了識別參數一定要放在第一個位置之外,其它的-text、-command或-borderwidth....等。是可以不用按順序出現的。



§ 引數還是參數?

其實在大部份的書裡,它們會把上面說的「參數」叫做「引數」,而真正的「參數」是指程序裡用來接收傳入值的變數。但我總覺得引數念起來就有點不太順口,所以大家只要知道上面說的參數,在其它語言裡叫引數這樣就行了。

§ 什麼是直譯語言?

程式碼需要透過直譯器翻譯執行的語言,稱為直譯語言。直譯語言的程式在執行前,通常不需先把程式轉換為其它格式的檔案,例如 .exe或是.class。Tcl的直譯器分別是tclsh及wish兩個程式,它們的不同點在於,tclsh預設不包含建立視窗小元件(widget)的功能,而wish預設會把建立視窗小元件的功能引入。

4.2 代換機制

代換機制是一個非常重要的觀念,它的意義是Tcl直譯器在處理一條命令之前,會先找出命令及其參數中有特殊意義的符號,然後嘗式去解釋它們,而解釋後的結果將用來取代原來的符號。以下面的例子來看,當程式執行到第2行的時候,Tcl的直譯器會先找到「$」號開頭的字串num,並嘗試把它當成變數,然後以變數的值取代原先的$num。



對於上面的第2行程式,可以想像Tcl直譯器做了以下的動作:

  1. 直譯器讀入 puts $num 這條命令
  2. 檢查是否有$號開頭的地方,結果找到了$num
  3. 檢查num變數存不存在,如果不存在就產生錯誤停止程式,否則繼續下一步
  4. 直譯器找出變數num值是3,然後把原來puts $num中$num的部份代換成3 → 想像命令看起來變成 「puts 3」
  5. 然後執行 puts 3 把3輸出到螢幕上

在Tcl裡以「變數代換」來說明上這種行為的發生。除了變數代換之外,Tcl還有「命令代換」及「反斜線代換」兩種代換的機制。

4.2.1 命令代換

在Tcl的程式裡中括號有特殊的意義和用法,凡是夾在中括號裡的內容,Tcl的直譯器會把它們當成是一條「子命令」,例如下面的程式碼[expr 1+2]即是一個子命令。如果一條命令中包含有子命令,Tcl的直譯器一定會先將所有的子命令由內層到外層全都先執行完,並且逐一取代所屬的中括號。這個行為就叫做「命令代換」。



對於上面的程式,可以想像Tcl直譯器做了以下的動作:

  1. 直譯器讀入 puts [expr 1+2] 這行命命
  2. 檢查是否有中括號夾起來的子命令,結果找到了[expr 1+2]
  3. 先執行子命令 "expr 1+2",執行結果回傳 3
  4. 直譯器把原來命令中[expr 1+2]的位置代換成 3→想像命令現在看起來l變成 「puts 3」
  5. 然後執行 puts 3 把3輸出到螢幕上

§ expr 命令

expr是Tcl專門用來做數學運算的命令,它可以接受大部份合理的數學式,並計算出結果。

4.2.2 反斜線代換

「$」及「中括號」都會被Tcl當成特殊的符號而且執行對應的代換功能,但如果真的要輸出「$」或「中括號」而不是變數內容或命令的執行結果該怎麼辦? 「反斜線代換」可以取消其它的代換的動作,例如puts \$val會輸出$val,而不是變數val的內容,又例如puts "\[expr 1+3\]" 會輸出字串[expr 1+3]而不是計算的結果。反斜線代換除了可以取消其它代換外,還可以用來代換出特殊的字元,以下是常見的反斜線代換。

  1. \a : 代換成畢一聲,(bell , Ascii 0x07).
  2. \b : 代換成倒退字元(讓console上的游標往前一格),(Backspace , Ascii 0x8).
  3. \n : 代換成斷行字元 ,(Newline , Ascii 0xa).
  4. \r : 代換成Return字元,(Carriage-return , Ascii 0xd).
  5. \t : 代換成Tab (Tab , Ascii 0x9).
  6. \\ : 就是\字元 (Backslash).

§ 代換的位置

代換會發生在命令模型裡的「命令」及「參數」欄位。

4.2.3 雙引號及大括號的差別

雙引號及大括號都可以用來包夾含有空白字元的字串,例如,以下的兩行都是合法的。



雖然雙引號及大括號都可以用來包夾含有空白字元的字串,但它們有意義上的差別:「夾在雙引號間的內容會執行代換的功能,夾在大括號間的內容則不會」。如下的例子:第2行的輸出是「My name is Dai」,而第3行的輸出是「My name is $name」。



4.2.4 巢狀代換

Tcl允許你將上述的的3種代換規則混在一起使用,甚至是巢狀的使用也可以。例如下面的例子,Tcl直譯器在看到第2行及第3行的命令時,會從最內層開始逐一向外執行代換的動作。



本章回顧

Tcl是屬於直譯式的程式語言,它的程式碼是由許許多多的「命令」及「參數」所組成。Tcl的命令模型如下:

命令 ?參數 1? ?參數 2? ?參數 3? ?參數 N?

命令及每個參數間要用空白隔開。每個命令都有專門的功能,參數用來調整命令的行為。

Tcl的直譯器在處理一條命令之前,會先找出命令及其參數中有特殊意義的符號,然後嘗式去解釋它們,而解釋後的結果將用來取代原來的符號,這種行為稱之為代換。Tcl有3種代換的行為,如下是變數代換的例子:



「$」號加上變數名稱,稱之為變數代換,其功能是代換出變數的值。

Tcl的直譯器會把夾在中括號裡的內容當成「子命令」,由內層到外層逐一執行,並取代原來的中括號。這種行為稱之為命令代換。如下是命令代換的例子:



中括號裡的expr會優先執行,執行的結果會取代整個中括號。

反斜線代換可以取消其它的代換的動作,或是代換特殊的字元,如下是取消變數代換的例子:



所有的代換行為都是巢狀的,最內層的代換會優先執行,然後逐一向外代換。

雙引號及大括號都可以用來包夾含有空白字元的字串,但是夾在雙引號間的內容會執行代換的功能,夾在大括號間的內容則不會。

2 個意見

chunlin | 2012年9月9日 下午4:55

Dai你好
我是個剛開始學習TCL的新手
感謝你提供這個很棒的教學網站
4.2.3的
範例一
是不是不應該加str1?
範例二第一行多了一個"

dai | 2012年9月9日 下午5:25

好的!! 謝謝 ~

留下您的意見

Theme Design by devolux.org. Converted by Wordpress To Blogger for WP Blogger Themes. Sponsored by iBlogtoBlog
This template is brought to you by : allblogtools.com | Blogger Templates