日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

tcl把文本产生html,TCL脚本数据文件格式(译文)

發布時間:2025/3/21 编程问答 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tcl把文本产生html,TCL脚本数据文件格式(译文) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

TCL腳本數據文件格式

簡介

一個典型的tcl腳本把它的內部數據保存在列表和數組(tcl中兩種主要的數據結構)中.比如,假定你想寫一個能將數據先保存在磁盤上,然后再讀取的tcl應用程序, 這將使你的用戶可以先把一個項目保存下來,以后再重新裝入.你需要一個辦法,把數據從其內部存儲處(列表與數組)寫入到一個文件中,同樣,也要有一個辦法把數據從文件中讀出裝入到正在運行的腳本中去.

你可以選擇把數據保存為二進制格式或文本格式.本文討論的僅限文本格式,我們將考慮幾種可能的數據格式及如何用tcl來進行分析.我們會特別介紹一些簡單的技巧,使文本文件分析更容易.

本文假定你對tcl語言很熟悉,至少已經用tcl語言寫過幾個腳本.

▲一個簡單的例子

假定你有一個簡單的繪圖工具,能把文本和長方形放到畫布上.為了保存畫好的圖,你需要一個必須容易讀取的文本格式的文件,最先想到而且最容易的文件是這樣的:

example1/datafile.dat

rectangle 10 10 150 50 2 blue

rectangle 7 7 153 53 2 blue

text 80 30 "Simple Drawing Tool" c red

The first two lines of this file represent the data for two blue, horizontally stretched rectangles with a line thickness of 3. The final line places a piece of red text, anchored at the center (hence the "c"), in the middle of the two rectangles.

文件的前兩行代表兩個藍色的水平展開的長方形,線條寬度是2(原文此處為3,可能是筆誤,譯者注).最后一行放了一段紅色的文字,定位在中心(由"c"來指定)----在兩個長方形的中間.

用文本文件保存你的數據使程序的調試更容易,因為你可以檢查程序輸出來保證一切都正常。同時也允許用戶手工修改保存的數據(這樣做可能好,也可能不好,取決于你的意圖).

當你讀取這種格式的文件時,或許得先對文件進行分析然后據此創建數據結構.分析文件時,你要一行一行地嘗試,使用象regexp這類的工具來分析文本不同的部分.下面是一個可能的過程:

example1/parser.tcl

canvas .c

pack .c

set fid [open "datafile.dat" r]

while { ![eof $fid] } {

# Read a line from the file and analyse it.

gets $fid line

if { [regexp

{^rectangle +([0-9]+) +([0-9]+) +([0-9]+) +([0-9]+) +([0-9]+) +(.*)$}

$line dummy x1 y1 x2 y2 thickness color] } {

.c create rectangle $x1 $y1 $x2 $y2 -width $thickness -outline $color

} elseif { [regexp

{^text +([0-9]+) +([0-9]+) +("[^"]*") +([^ ]+) +(.*)$}

$line dummy x y txt anchor color] } {

.c create text $x $y -text $txt -anchor $anchor -fill $color

} elseif { [regexp {^ *$} $line] } {

# Ignore blank lines

} else {

puts "error: unknown keyword."

}

}

close $fid

我們一次讀取一行數據,使用正則表達式查找該行代表的是某種數據類型.通過檢查第一個詞,我們可以區分代表長方形的數據和代表文本的數據,所以第一個詞是一個關鍵字,它明確地告訴我們正在處理的是什么類型的數據.同樣我們分析每個項目的坐標,顏色和其他屬性.括號中正則表達式的分組部分使我們找到變量'x1','x2'等的分析后的結果.

假如你知道正則表達式如何工作,這看上去是一個很簡單的實現.但我覺得它有點難以維護,正則表達式也使其難以理解.

還有一個更簡捷的解決方法,叫做“active file(主動文件)”.原本由Nat Pryce在設計樣本時想到的。這種方法基于一個非常簡單的提議:與其用TCL自己來寫語法分析器(用regexp或其他途徑),干嘛不讓TCL的語法分析器為你做這些工作呢?

▲主動文件設計樣本

為解釋這種設計樣本,我們繼續使用上節中那個簡單的繪圖工具。首先我們用TCL語言寫兩個過程,一個畫矩形,一個寫文本。

example2/parser.tcl

canvas .c

pack .c

proc d_rect {x1 y1 x2 y2 thickness color} {

.c create rectangle $x1 $y1 $x2 $y2 -width $thickness -outline $color

}

proc d_text {x y text anchor color} {

.c create text $x $y -text $text -anchor $anchor -fill $color

}

現在要在畫布上繪圖,我們調用這兩個過程就行了,每次調用其中的一項。比如要畫如前所述的圖形,需要下面三個調用。

example2/datafile.dat

d_rect 10 10 150 50 2 blue

d_rect 7 7 153 53 2 blue

d_text 80 30 "Simple Drawing Tool" c red

看上去眼熟嗎?調用過程的代碼看上去與先前我們分析的代碼幾乎完全一樣。唯一的不同之處是關鍵詞由"rectangle"和"text"變成了"d_rect"和"d_text".

現在我們看到了寫樣本的技巧:為分析數據文件,我們要把它當作一個TCL腳本來對待。我們只把對我們寫好的過程的調用放到一個文件中,并用此文件作為數據文件.設計樣本的核心是數據文件實際上包含著對TCL過程的調用.

分析數據文件現在太容易了:

source "datafile.dat"

內建的TCL命令source讀取文件,分析并執行文件中的命令.因為我們已經完成了d_rect和d_text過程,source命令將自動以正確的參數調用這兩個過程.我們將d_rect和d_text稱為分析過程.

我們無需再做任何分析,不用正則表達式,不用一行一行地循環,不用打開/關閉文件.只需調用source命令就完成了所有的工作。

數據文件已經成了可以執行的TCL腳本.因為它包含的是可執行命令,而不僅僅是被動的數據,所以稱之為主動文件.主動文件在大多數腳本語言環境中均可正常運行,在Nat Pryce的主頁上對其有詳細的描述.

▲使用主動文件樣本的優點:

無需再寫一個分析程序,source調用TCL分析程序即可完成.

容易讀取數據文件格式.

使用主動文件樣本的缺點:

如果數據文件包含有危險命令,象l -a exec rm *,它們執行后會帶來嚴重的后果.解決這個問題的辦法是在安全模式下執行主動文件,防止危險命令。具體信息可參看TCL手冊中"安全解釋器"部分.

▲主動文件樣本的局限

此樣本不是對所有可能的數據格式都有效.數據格式必須是以行為基礎的,每一行必須以一個關鍵字開頭.用關鍵字開頭寫TCL過程,就把被動的關鍵字變成了主動的命令。這也意味著你不能使用象if或while之類的關鍵字,因為TCL不允許你用這樣的名字來寫過程.事實上,上面的例子中我把關鍵字改為d_text,就是因為開發工具包已經有了保留字text,該命令用來創建文本工具.

▲英語言過程

至此我們已經可以寫一個簡單的文件格式了:

d_rect 10 10 150 50 2 blue

d_rect 7 7 153 53 2 blue

d_text 80 30 "Simple Drawing Tool" c red

我們還有一個很簡單的分析程序,就是兩個分析過程和source命令.現在,我們看一下如何來進一步改進.

當你觀察大量此類數據時,極易被數據搞糊涂.第一行包含10 10 110 50 3,你得有些這方面的經驗才能很快明白前兩個代表一個坐標,后兩個是另一個坐標,最后一個是線寬.我們能用在數據中引入附加文本的方法來使一個程序員在閱讀時較為容易.

example3/datafile.dat

d_rect from 10 10 to 150 50 thick 2 clr blue

d_rect from 7 7 to 153 53 thick 2 clr blue

d_text at 80 30 "Simple Drawing Tool" anchor c clr red

介詞to和from,參數名thick和color使數據看上去更象英語句子了,為適應這些介詞,我們的分析過程需要其他的附加參數:

example3/parser.tcl

proc d_rect {from x1 y1 to x2 y2 thick thickness clr color} {

.c create rectangle $x1 $y1 $x2 $y2 -width $thickness -outline $color

}

正如你所看到的,執行過程并未改變.新參數在過程體中并未使用;其目的僅僅是為了使用數據可讀性更強.

▲選項/數值對

Tk工具包提供了一個創建圖形界面部件的集合.這些部件以選項和他們的值來加以配置,配置的語法很簡單(一個橫線,后跟選項名,再后面是其值)而且標準化(許多其他的TCL擴展集使用相同的語法來配置其部件).

使用選項/數值對后,數據文件看上去象這樣:

example4/datafile.dat

d_rect -x1 10 -y1 10 -x2 150 -y2 50 -thickness 2

d_rect -thickness 2 -x1 7 -y1 7 -x2 153 -y2 53

d_text -x 80 -y 30 -text "Simple Drawing Tool" -anchor c -color red

為分析數據,我們需要在分析過程d_rect和d_text中引入選項/數值對,我們首先試一下使用與英語過程相似的啞變量.

proc d_rect {opt1 x1 opt2 y1 opt3 x2 opt4 y2 opt5 thickness opt6 color} {

.c create rectangle $x1 $y1 $x2 $y2 -width $thickness -outline $color

}

我們再一次看到,實現的過程并未改變.盡管這個解決方案只對最簡單的數據格式有效,但它很清晰明了.它的優點有兩個:選項在參數列表中的位置是固定的.比如,你不能把color(顏色屬性)放在thickness(線寬屬性)前面.對一個純數據文件格式來說這個方法還不錯(因為數值往往按相同的順序存儲),但當你想將其用于腳本中的手工輸入數據時,這個方法則成了一個障礙.

選項沒有默認值:你必須提供所有選項的值,而不能遺漏其中任何一個.

下面是一個可解決所有問題的實現過程.

example4/parser.tcl

proc d_rect {args} {

# First, specify some defaults

set a(-thickness) 1

set a(-color) blue

# Then, 'parse' the user-supplied options and values

array set a $args

# Create the rectangle

.c create rectangle $a(-x1) $a(-y1) $a(-x2) $a(-y2)

-width $a(-thickness) -outline $a(-color)

}

與使用一個長長的參數表不同,分析過程現在僅有一個名為args的參數,由它來收集調用過程時所有的實際參數.參數x1,y1等消失了.他們現在由一個局部的數組來處理,稍后我們將圓心解釋.

代碼的第一部分為選項設定默認值,第二部分分析args中的選項/數值對.TCL內建的數組處理模塊對此做得非常得心映手.它先在數組a中創建新的入口,使用選項名(包括前導橫線"-")作為索引,選項值作為數組值.

如果用戶在調用中不指定-color選項,a(-color)的入口默認值保持不變. 除用數組入口代替過程參數外,過程體中的最后一行與前面的實現一樣.

如果用戶調用時忘記指定選項-x1,則-x1的數組入口不會被設置(沒有其默認值),創建矩形的調用就會引發一個錯誤.此例說明你可以給其中一些選項指定默認值,使其可隨意選擇,而另一些則不指定默認值,強制其必須由用戶指定.

▲最好的格式通常是各種方法的結合

現在我們已經明白了TCL數據文件的常見方法(主動文件,英語言過程,選項/數值對),我們可以將其各自的優點組合進一個單獨的數據格式中去.對強制性選項,我們使用固定位置參數時,多半與啞介詞相結合增強可讀性(見英語言過程).而所有的可隨意選擇的選項,宜用選項/數值對機制來進行處理,好讓用戶可以空著選項或在調用時改變其位置.最后,數據文件可能會是這樣的:

d_rect from 10 10 to 150 50 -thickness 2

d_rect from 7 7 to 153 53 -thickness 2

d_text at 60 30 "Simple Drawing Tool" -anchor c -color red

假定所有項目的color屬性的默認值都是"blue".

作為一個個人習慣,我通常會寫這樣的命令:

d_rect

from 10 10

to 150 50

-thickness 2

d_rect

from 7 7

to 153 53

-thickness 2

d_text

at 80 30 "Simple Drawing Tool"

-anchor c

-color red

I find it slightly more readable, but that's all a matter of personal taste (or in my case lack of taste :-).

我覺得可讀性要好一些,但這僅是一個個人偏好的問題.(or in my case lack of taste)(這句話是作者在調侃自己,但我不知如何把它譯出來,請哪位大俠幫忙指點一下,譯者注)

--------------------------------------------------------------------------------

▲更多復雜的數據

至今為止,我們已經對一個非常簡單的包含矩形與文本的例子進行了研究.這種數據格式用主動文件設計樣本非常容易讀取并加以分析.

現在我們來看一個更為復雜的數據格式,來解釋一下使用主動文件的更加"高級"的技巧.這將使你在使用TCL數據文件格式方面成為一個專家.

▲數據倉庫工具

我過去經常收集設計樣本,組成了一個樣本庫,每個都有一個簡短的說明和一些屬性.我還把在其中找到樣本的書的名字,作者和ISBN號記下來,作為以后查找時的參考.為了記錄所有這些信息,我用TCL寫了一個數據倉庫工具.其主要功能是把樣本按照類別和級別進行分類,指出全書中每一個樣本和講述它的頁碼.

此工具的輸入是與此相似的一個文件:

#首先,我介紹一些你從中可以找到好的設計樣本的書和設計程序時的習慣寫法.每一本書,

#每一個網址,或是其他的樣本資源都用關鍵字"source"指定,后跟一個唯一的標簽及其他附

#加信息

Source GOF {

Design patterns

Elements of reusable object-oriented software

Gamm, Helm, Johnson, Vlissides

Addison-Wesley, 1995

0 201 63361 2

}

Source SYST {

A system of patterns

Pattern-oriented software architecture

Buschmann, Meunier, Rohnert, Sommerlad, Stal

Wiley, 1996

0 471 95869 7

}

#下一步,我介紹一些類別,為了更容易找到樣本,我想把樣本進行分組.每個類別都

#有一個名稱(如"存取控制")和一個簡短的說明.

Category "Access control" {

How to let one object control the access to one or more

other objects.

}

Category "Distributed systems" {

Distributing computation over multiple processes, managing

communication between them.

}

Category "Resource handling" {

Preventing memory leaks, managing resources.

}

Category "Structural decomposition" {

To break monoliths down into indpendent components.

}

#最后,我介紹了樣本本身,每一個都有一個名字,屬于一個或多個類別,出現在上述樣

#本資源列表的一處或多處.每個樣本都有級別,可能是"arch"(對于結構型樣本),

#"design"代表較小規模的設計樣本,"idiom"代表語言指定型樣本.

Pattern "Broker" {

Categories {"Distributed systems"}

Level arch

Sources {SYST:99}?? ; # 這表示此樣本在標記為"SYST"的書中

# 第99頁加以講述.

Info {

Remote service invocations.

}

}

Pattern "Proxy" {

# This pattern fits in two categories:

Categories {"Access control" "Structural decomposition::object"}

Level design

# Both these books talk about the Proxy pattern:

Sources {SYST:263 GOF:207}

Info {

Communicate with a representative rather than with the

actual object.

}

}

Pattern "Facade" {

Categories {"Access control" "Structural decomposition::object"}

Sources {GOF:185}

Level design

Info {

Group sub-interfaces into a single interface.

}

}

Pattern "Counted Pointer" {

Categories {"Resource handling"}

Level idiom

Sources {SYST:353}

Info {

Reference counting prevents memory leaks.

}

}

這僅是我最初編寫的輸入文件的一部分,但它還是包含了足夠的數據來作為一個較好的例子.樣本的說明很短,還有些笨拙,但對這個例子來說已經夠了.

正如你看到的,這個數據文件幾個新的特點:

▲數據被包含在一些結構中,用大括號{}加以分組.每個結構都由一個關鍵字開頭.

這些結構可以嵌套,如:結構"Pattern"可以包含一個"Info"結構.

▲結構中的元素可以采用很多形式。它們中的一些是標志符或字符串(比如元素"Level"),其他的看上去象是特殊的代碼(如SYST:353),還有一些甚至是自由格式的文本(如在結構Category和Info中的那樣).

▲每個結構中的元素的排列順序是任意的.觀察一下最后兩個樣本就會發現Level和Sources兩個元素的順序可以互換.所有元素實際上都可以按你想要的順序排列.

▲數據文件包含有TCL注釋語句,他們不僅可以在結構之間出現,甚至可以出現在結構內部.注釋語句能讓你的數據更易理解.

你可能會想這種格式比前面的例子復雜太多了,用TCL語言為其寫一個分析器幾乎是不可能的.可能看上去不太明了,我們還可以用主動文件樣本來使此工作更加簡單.分析(解析)過程比前面的更細而已,但肯定不是"復雜".

下面是我的分析如上數據文件的工具:

#我們把數據保存在以下三個列表內:

set l_patterns [list]

set l_sources [list]

set l_categories [list]

#我們還需要一個變量跟蹤我們當前所在的Pattern結構

set curPattern ""

# 下面是關鍵字"Source"的分析過程.

# 正如你所看到的,關鍵字后面跟有一個id號(是source的唯一標志符),

#還有source的說明文本.

proc Source {id info} {

# Remember that we saw this source.

global l_sources

lappend l_sources $curSource

# Remember the info of this source in a global array.

global a_sources

set a_sources($curSource,info) $info

}

# The parsing proc for the 'Category' keyword is similar.

proc Category {id info} {

global l_categories

lappend l_categories $curCategory

global a_categories

set a_categories($curCategory,info) $info

}

# This is the parsing proc for the 'Pattern' keyword.

# Since a 'Pattern' structure can contain sub-structures,

# we use 'uplevel' to recursively handle those.

proc Pattern {name args} {

global curPattern

set curPattern $name?? ; # This will be used in the sub-structures

# which are parsed next

global l_patterns

lappend l_patterns $curPattern

# We treat the final argument as a piece of TCL code.

# We execute that code in the caller's scope, to parse the elements

# of the structure.

# 'uplevel' will call 'Categories', 'Level' and other commands that

# handle the sub-structures.

# This is similar to how we use the 'source' command to parse the entire

# data file.

uplevel 1 [lindex $args end]

set curPattern ""

}

# The parsing proc for one of the sub-structures.? It is called

# by 'uplevel' when the 'Pattern' keyword is handled.

proc Categories {categoryList} {

global curPattern?? ; # We access the global variable 'curPattern'

# to find out inside which structure we are.

global a_patterns

set a_patterns($curPattern,categories) $categoryList

}

# The following parsing procs are for the other sub-structures

# of the Pattern structure.

proc Level {level} {

global curPattern

global a_patterns

set a_patterns($curPattern,level) $level

}

proc Sources {sourceList} {

global curPattern

global a_patterns

# We store the codes such as 'SYST:99' in a global array.

# My implementation uses regular expressions to extract the source tag

# and the page number from such a code (not shown here).

set a_patterns($curPattern,sources) $sourceList

}

proc Info {info} {

global curPattern

global a_patterns

set a_patterns($curPattern,info) $info

}

猛一看,這個程序比我們在相對簡單的繪圖例子所做的要多很多.但考慮到這個方法的功能,只用幾個分析過程并靈活運用命令"uplevel",我們同樣可以分析包含有復雜結構,注釋,嵌套子結構和自由格式文本數據的數據文件.設想一下如果我們從頭寫這樣一個分析器會有多難.

數據由Source,Pattern或Info等過程進行解析.解析后的數據在內部存儲在三個列表和三個數組中.數據的嵌套由調用uplevel來進行處理,用變量curPattern來記住我們當前所在的位置.

要注意的是這種方法需要你的數據能夠理解TCL語法.這意味著大括號應該放在一行的最后,而不是下一行的開頭.

▲遞歸結構

在倉庫的樣例中,Pattern類型的結構包含有其他類型的子結構如Info和Sources.那么當一個結構包含有相同類型的子結構時會如何呢?換句話說,我們如何處理遞歸結構?

例如,你要描述一個面向對象系統的設計,該設計由遞歸子系統實現.

example6/datafile.dat

# Description of an object-oriented video game

System VideoGame {

System Maze {

System Walls {

Object WallGenerator

Object TextureMapper

}

System Monsters {

Object FightingEngine

Object MonsterManipulator

}

}

System Scores {

Object ScoreKeeper

}

}

為跟蹤我們當前處于哪一個System系統結構中,看上去我們需要不只一個全局變量currPattern.在分析的任何時刻,我們都可能處在很多嵌套的System結構中,因此我們需要兩個以上的變量.我們可能需要某種堆棧,在遇到System過程時壓入一個值,在過程的結束時再彈出來.我們用一個TCL列表可以構造這樣一個棧.

但若你不想維護一個棧的話,也可以不用它.這種方法也是基于一個非常簡單的建議:當你需要使用一個棧時,看一下能否使用函數調用棧.處理遞歸數據時,我通常就用這個方法來實現我的分析過程的.

example6/parser.tcl

set currSystem ""

proc System {name args} {

# Instead of pushing the new system on the 'stack' of current systems,

# we remember it in a local variable, which ends up on TCL's

# function call stack.

global currSystem

set tmpSystem $currSystem

set currSystem $name?? ; # Thanks to this, all sub-structures called by

# 'uplevel' will know what the name of their

# immediate parent System is

# Store the system in an internal data structure

# (details not shown here)

puts "Storing system $currSystem"

# Execute the parsing procedures for the sub-systems

uplevel 1 [lindex $args end]

# Pop the system off the 'stack' again.

set currSystem $tmpSystem

}

proc Object {name} {

global currSystem

# Store the object in the internal data structure of the current

# system (details not shown here)

puts "System $currSystem contains object $name"

}

source "datafile.dat"

與把嵌套的系統名存儲在一個棧中(該棧由TCL的列表或數組來模擬)不同,我們只把對象名存儲在一個名為tmpSystem的局部變量中.由于解析過程會由TCL依據棧中的順序自動調用,我們無需再去顯式地壓入/彈出任何數據了.

▲其他例子

由Don Libes 寫的CGI庫使用主動文件樣本來表達HTML文檔.這個想法是寫一個TCL腳本作為HTML文檔并為你生成純正的HTML文件.該文檔包含有核心列表,格式化文本和其他的HTML元素.分析過程調用uplevel處理遞歸子結構.

下面是Don的代碼的一部分,告訴你他是如何應用本文所講述的技巧的.

# Output preformatted text.? This text must be surrounded by '' tags.

# Since it can recursively contain other tags such as '' or hyperlinks,

# the procedure uses 'uplevel' on its final argument.

proc cgi_preformatted {args} {

cgi_put "????? cgi_close_proc_push "cgi_puts"

if {[llength $args]} {

cgi_put "[cgi_lrange $args 0 [expr [llength $args]-2]]"

}

cgi_puts ">"

uplevel 1 [lindex $args end]

cgi_close_proc

}

# Output a single list bullet.

proc cgi_li {args} {

cgi_put

if {[llength $args] > 1} {

cgi_put "[cgi_lrange $args 0 [expr [llength $args]-2]]"

}

cgi_puts ">[lindex $args end]"

}

# Output a bullet list.? It contains list bullets, represented

# by calls to 'cgi_li' above.? Those calls are executed thanks

# to 'uplevel'.

proc cgi_bullet_list {args} {

cgi_put "????? cgi_close_proc_push "cgi_puts "

if {[llength $args] > 1} {

cgi_put "[cgi_lrange $args 0 [expr [llength $args]-2]]"

}

cgi_puts ">"

uplevel 1 [lindex $args end]

cgi_close_proc

}

我不想對這個龐大的庫的細節進行詳細的解釋,你可以自己從Don的主頁上下載后看一下.

--------------------------------------------------------------------------------

作為另一個例子,我的TODL工具使用類和方法等解析過程對面向對象的設計加以分析.下面是我的工具中一個輸入文件的例子:

# Todl schema for module 'shapes'.? It describes classes for some

# geometrical shapes such as rectangles and squares.

odl_module shapes {

#######

# Classes

# Base class for all shapes.

class shape {} {

attr id 0?? ; # Attribute 'id' is inherited by all shapes

# and has default value 0.

}

# Rectangle with a width and height.

# Inherits from 'shape'.

class rect {shape} {

attr w 10

attr h 10

# Some methods to calculate properties for the shape,

# and to draw it on the screen.

method "" perimeter {}

method "" area {}

method "" draw { x {y 0} }

}

class square {shape} {

... (details similar to 'rect')

}

#######

# Module parameters

# All classes automatically get a 'print' method.

param all { print }

# Name of the 'delete' proc.

param delete_name delete

# We want debugging output:

param debug 1

}

查看本文件后,你能指出全部分析過程的列表嗎?

--------------------------------------------------------------------------------

我曾經為C++的類實現寫過一個(非常)簡單的解析器.因為太懶,所以我用TCL語言來寫.事實證明它過于復雜以致沒有一點用處,但它說明了主動文件樣本的強大功能.下面看一下這個包含有復雜的C++的數據文件:

class myListElt: public CListElt, private FString {

This is a documentation string for the class 'myListElt'.

You can see multiple inheritance here.

} {

public:

method int GetLength(void) {

This is a documentation string

Returns the total length of the FString.

} {

// This is the final argument of the 'method' parsing proc.

// It contains freeform text, so this is where I can write

// pure C++ code, including the comment you are now reading.

return myLength;

}

method char* GetString(void) {

Returns the complete FString.

} {

append(0);

return (char*)data;

}

private:

method virtual void privateMethod(short int p1, short int p2) {

Note that just saying "short" is not enough:

you have to say "short int".

} {

printf("Boo!? p1=%d, p2=%d

", p1, p2);

}

}

data short int b {This is just a counter}

data void* somePointer {to store the end-of-list or something like that}

method void error(short int errNo, char* message) {

This is a global library procedure, which

reports an error message.

} {

cout << "Hey, there was an error (" << errNo << ") " << message << endl;

}

cpp_report

這個例子可能有些牽強,但它顯示了主動文件樣本的強大功能.你看到的是TCL代碼,但它看上去象是C++代碼,它能自動產生文檔,類圖,編程參考,當然還有可編譯的C++代碼.

解析過程如方法和類把C++實現存儲在內部的TCL數據結構中,最后,調用cpp_report產生最終的C++代碼.

下面的來自分析器的程序片段說明你可以使TCL分析器去讀取與C++語法類似的文件.

# Parsing proc for 'class' keyword.

# Arguments:

# - class name

# - list of inheritance specifications, optional

# - comment block

# - body block

proc class {args} {

global _cpp

# split names from signs like : , *

set cargs [expand [lrange $args 0 [expr [llength $args] - 3]]]

# -3 to avoid the comment block and the class body.

# First process the name

set className [lindex $cargs 0]

if { $_cpp(CL) == "" } {

set _cpp(CL) $className?? ; # This is like 'currPattern' in the

# pattern repository example

} else {

error "Class definition for $className: we are already inside class $_cpp(CL)"

}

# Then process the inheritance arguments.

# Obvisouly, this is already a lot more complicated than in the

# previous examples.

set inhr [list]

set mode beforeColon

set restArgs [lrange $cargs 1 end]

foreach arg $restArgs {

if { $arg == ":" } {

if { $mode != "beforeColon" } {

error "Misplaced ":" in declaration "class $className $restArgs""

}

set mode afterColon

} elseif { $arg == "public" || $arg == "private" } {

if { $mode != "afterColon" } {

error "Misplaced "$arg" in declaration "class $className $restArgs""

}

set mode $arg

} elseif { $arg == "," } {

if { $mode != "afterInherit" } {

error "Misplaced "," in declaration "class $className $restArgs""

}

set mode afterColon

} else {

if { $mode != "public" &&? $mode != "private" } {

error "Misplaced "$arg" in declaration "class $className $restArgs""

}

if { ![IsID $arg] } {

warning "$arg is not a valid C++ identifier..."

}

lappend inhr [list $mode $arg]

set mode afterInherit

}

}

if { $mode != "afterInherit"? &&? $mode != "beforeColon" } {

error "Missing something at end of declaration "class $className $restArgs""

}

set _cpp(CLih) $inhr

set _cpp(CLac) "private"

# First execute the comment block

uplevel 1 [list syn_cpp_docClass [lindex $args [expr [llength $args] - 2]]]

# Then execute the body

uplevel 1 [list syn_cpp_bodyClass [lindex $args end]]

set _cpp(CL) ""

set _cpp(CLac) ""

set _cpp(CLih) ""

}

--------------------------------------------------------------------------------

關于懶惰

按Larry Wall的話,一個好的程序員的最重要的潛質就是懶惰.也就是說,有創造性的懶惰.本文提到了兩個建議,他們能夠歸于一件事:懶惰.

當你需要一個解析器時,使用一個現成的解析器,修改你的文件格式去造就分析器的要求(當然,需要你已經達到了能夠自由選擇文件格式的境界)

當你需要使用堆棧時,你可以使用現成的函數調用堆棧,忘掉壓入,彈出和其他的操作.

"重用"并不僅表示封裝和信息的隱藏.有些時候它只不過表示懶惰罷了.

--------------------------------------------------------------------------------

總結

以上是生活随笔為你收集整理的tcl把文本产生html,TCL脚本数据文件格式(译文)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。