Tcl [1]: 语句、字面量和变量 - xiaq's Blog

Tcl [1]: 语句、字面量和变量

xiaq posted @ 2011年8月23日 13:12 in 技术 with tags tcl , 2255 阅读

传送门之一: Tcl on wikipedia, if you like it :)

传送门之二: Tcl Tutorial 下面会反复引用到,因此简称 TT。

Tcl 的语法非常好玩,让我有很强烈的实现它的冲动。我正在写一个 Tcl 解释器,为了帮助自己理清思路,写这一篇文章。闲言少叙,以下先介绍 Tcl 的基本语法。

puts、命令语句和注释语句

Ref:

[TT1] TT: Simple Text Output

# ================= 华丽的注释 =================
# `puts` 类似其它语言的 `print`。
puts "Hello, Tcl."
puts "Hello-"; puts "Tcl!" ;# 一行两句。再附带注释。

puts "Hi" # 额……我不是注释。这一句会产生语法错误。
puts "Another hi" ; # 貌似必须要有分号。But...

# Nice try. 但上面那句依然不是合法的注释。不过我是。
 # 我也不是合法的注释……

看出注释的规则了吗?首先你应该猜到了,分号 ; 和换行都可以分割语句。注释的 # 必须是语句的第一个字符,此后的的 # 则是普通字符。此外,只有换行可以结束注释,分号不行。例子:

puts #我不是注释
puts Hi ;# 注释啦啦啦; 这里依然是注释

上面的 #我不是注释 没有加引号。它是裸词,下面马上就要讲到。此外,分号不结束注释,只有换行才行。

字面量(literal):"" {} 和裸词(bareword)

Ref:

[TT1] TT: Simple Text Output

[TT2] TT: Grouping Arguments with ""

[TT3] TT: Grouping Arguments with {}

puts "Hello, Tcl." ;# 引号界定的字面量
puts {Hello, Tcl.} ;# 花括号界定的字面量
puts Hello,\ Tcl.  ;# 裸词
puts Hello, Tcl.   ;# 错误:两个裸词。`puts`只接受一个字符串参数。

|| 双引号

双引号界定的字面量内部支持 C 的转义序列,此外还允许内嵌换行:

puts "\n\t\"" ;# 换行符、制表符和双引号
puts "
\t\""         ;# 和上句输出相同

完整的转义序列语法参见 [TT2]。

|| 花括号

略显奇葩的是,花括号没有被设计成语句块界定符;它也只字面量界定符,只是内部不支持转义序列:

puts {\n\t} ;# => \n\t
puts {
int main();
}

但是花括号有一个有趣的性质。左右花括号是配对的,这一点就十分类似 C 的语句块了:

puts {{ } { }} ;# => { } { }
puts {
int main() {
    printf("Hello, world!\n");
}
}

然而花括号中并没有其它的语法结构,例如双引号界定的字面量:

puts {"Quoted?}"} ;# 错误;花括号内部并不识别引号界定的字面量
puts {"Quoted?}   ;# => "Quoted?

继续花括号:

puts {\{}      ;# => \{
puts {\}}      ;# => \}

如上所见,在花括号字面量内用 \{\} 可以防止它们参与花括号匹配,但是它们的值仍然是 \{\} 而不是 {}

后面我们将看到,花括号的这些性质如何被巧妙地用来构建 Tcl 的语句块。

|| 裸词

不以双引号或者左花括号开头的字面量就是裸词(bareword)。裸词使用空白符界定;如果要在裸词内部嵌入空白符,应使用转义序列。

puts }               ;# => }
# 单引号是普通字符,不是字面量界定符。
puts 'I'm\ bare      ;# => 'I'm bare
puts \n\tBare,\ too! ;# => <换行><制表>Bare, too!

你可能已经猜到,反复出现的 puts 命令(command)(等同于一般所说的函数或者过程)其实也是一个裸词。在 Tcl 中上述三种字面量是等价的

 puts   Hello!
"puts" "Hello!"
{puts} {Hello!}

这种语法单元都是 Tcl 的(word)。

|| 语句结构(statement)

既然裸词和另外两种字面量是等价的,Tcl 如何区分把 puts 这类 函数/命令/指令/过程和字符串区分开?类似于 shell 语言,只有每个语句的第一个词是命令,其余的都是简单的字符串。

puts puts #; => puts

语法小结

上下文无关文法(Context-free grammar, CFG)给出本文描述的 Tcl 语法。

下面的 CFG 使用我自创的记法。单引号内表示简单的终止符号(terminal symbol),圆括号内是 UNIX 正则表达式(UNIX regular expression)。:= 左侧给出的是非终止符号(non-terminal symbol),右侧是推导规则(induction rule)。同一个符号的多个规则之间隐含的是逻辑或 |

本文略去了不少细节,所以下面并不是正确的 Tcl 语法。此外下述语法假定 Tcl 源文件以一个换行结尾。

source    := 'eof'
             statement source
statement := comment
             command
comment   := '#' ([^\n]*) '\n'
command   := '\n' | ';'
             word command
word      := bareword | quoted | curlied
quoted    := '"' ([^"]*) '"'

barewordcurlied 的语法我暂时没有找到比较简单的描述方法……


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter
Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee