}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.
推荐阅读
- 我TCL6198
- 王者清理游戏数据后果
- 我的 TCL768 一周使用经历
- FreeBSD 数据迁移方法
- MIUI11怎么备份数据
- 内交外换 明基P30数据交换能力初探
- 金融信用信息基础数据库是征信吗
- 10 FreeBSD连载:系统启动脚本
- 安装鸿蒙系统数据会丢失吗
- 关于W219的数据传输
