Tcl [1]: 语句、字面量和变量 - xiaq's Blog
Tcl [1]: 语句、字面量和变量
传送门之一: 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 := '"' ([^"]*) '"'
bareword
和 curlied
的语法我暂时没有找到比较简单的描述方法……