Tcl语言全方位教程:从基础到嵌入式应用

Tcl语言全方位教程:从基础到嵌入式应用

本文还有配套的精品资源,点击获取

简介:Tcl是一种简单、易学的脚本语言,广泛应用于系统管理、网络编程等多个领域。本教程深入探讨了Tcl的核心概念、语法结构、命令控制、数据结构操作、文件I/O、正则表达式、错误处理、图形界面设计、扩展库使用以及嵌入式应用等方面,旨在帮助读者快速掌握Tcl语言并在实际项目中应用。

1. Tcl语言基础语法入门

欢迎阅读本系列文章,我们将一步步深入探索Tcl(Tool Command Language)语言的世界。Tcl是一种动态语言,以其强大的脚本功能和跨平台性,在系统编程、网络应用、测试自动化等领域得到了广泛应用。本章节作为基础入门,将介绍Tcl语言的基本构成和语法基础,为你后续学习打下坚实的基础。

1.1 Tcl语言简介

Tcl语言最初由John Ousterhout设计开发,其核心设计原则是简单易用。Tcl的语法简洁,主要由命令组成,易于编写和维护,非常适合于快速开发原型。

1.2 基本语法元素

Tcl语法的基本元素包括变量、控制流语句、过程和表达式。Tcl支持多种数据类型,包括整数、浮点数、字符串、列表和字典等。

# 定义变量并赋值

set name "Alice"

# 输出变量值

puts "Hello, $name!"

在上述示例中,我们使用 set 命令定义了一个名为 name 的变量,并将字符串”Alice”赋值给它。之后使用 puts 命令输出带有变量引用的字符串。

1.3 脚本结构

Tcl脚本通常包含多个命令,每个命令以换行符或分号结尾。命令可以通过空格或换行符进行分隔。Tcl解释器顺序执行脚本中的命令。

# 命令分隔示例

puts "First command"

puts "Second command"

本章介绍了Tcl语言的基本特点和入门语法。第二章我们将深入学习Tcl的命令执行流程及控制结构,进一步深化对Tcl语言的理解。希望你能够在接下来的学习旅程中,不断探索和实践,充分利用Tcl语言的优势。

2. 命令与控制结构的深入应用

2.1 命令的使用和执行流程

2.1.1 基本命令的书写规则

在Tcl中,命令通常由一个或多个元素组成,以空格分隔,并以换行符或分号结束。每个元素都可以是命令名、变量、字符串、数字或者过程调用。

命令名 :Tcl是区分大小写的语言,所以命令名必须严格按照定义时的大小写来使用。 变量 :以美元符号 $ 开始,后跟变量名。 字符串 :用双引号 " 或花括号 {} 包围的文本,双引号内的内容会进行变量替换和命令替换。 数字 :整数、浮点数等直接书写。 过程调用 :使用 proc 定义的过程名后跟参数列表,参数列表可以是简单参数也可以是包含在花括号或双引号中的复杂参数。

举例说明,假设有一个命令 puts ,它用于输出信息到标准输出:

puts "Hello, Tcl World!"

此处的 puts 是命令名,而 Hello, Tcl World! 是被双引号包围的字符串。

2.1.2 执行命令的环境和上下文

Tcl命令在不同的环境中执行,其行为可能会有所不同。比如,在Tcl shell中执行和在嵌入式系统中的Tcl解释器里执行,得到的结果可能因为环境配置的不同而不同。命令的执行环境包括:

Tcl版本 :不同的Tcl版本可能会有不同的命令支持或命令行为。 环境变量 :如 PATH 变量会影响可执行文件的查找。 编码 :命令输入输出涉及的编码转换,尤其在国际化应用中非常重要。 安全性 :不同的执行环境可能对安全有不同的限制,如在受限环境下运行的Tcl应用可能无法执行某些系统调用。

在编写Tcl脚本时,需要考虑到这些上下文信息,确保脚本可以在目标执行环境中正确运行。例如,下面是一个处理环境变量的简单脚本:

set envVar [info env PATH]

puts "The PATH environment variable is $envVar"

这个脚本首先通过 info env 获取环境变量 PATH 的值,然后输出。这在不同的执行环境中可能会得到不同的结果。

2.2 控制结构的掌握和实践

2.2.1 分支控制结构详解

分支控制结构允许脚本根据条件执行不同的代码分支。Tcl提供了 if 和 switch 命令来实现分支控制。

if : if 命令用于基于一个或多个条件执行代码块。它通常和 else 以及 elseif 子句一起使用。如:

if {$a > $b} {

puts "a is greater than b"

} elseif {$a == $b} {

puts "a is equal to b"

} else {

puts "a is less than b"

}

switch : switch 命令用于比较变量或表达式与一个或多个值。如果匹配,执行对应的代码块。如:

set fruit "apple"

switch -exact -- $fruit {

"apple" { puts "This is an apple." }

"banana" { puts "This is a banana." }

default { puts "Unknown fruit." }

}

2.2.2 循环控制结构应用

Tcl提供了 for 、 while 和 foreach 等循环控制结构。

for :和C语言中的 for 循环类似, for 循环在Tcl中也用于固定次数的迭代。如:

for {set i 0} {$i < 10} {incr i} {

puts "Iteration number $i"

}

while : while 循环在条件为真时持续执行。如:

set i 0

while {$i < 10} {

puts "Current value: $i"

incr i

}

foreach : foreach 循环用于迭代列表中的每个元素。如:

foreach item {a b c d} {

puts "Processing item: $item"

}

2.2.3 过程和方法的定义与调用

在Tcl中,过程是通过 proc 命令来定义的。定义过程后,可以通过其名称来调用。

proc定义 : proc 后跟过程名和参数列表,然后是需要执行的命令块。

proc square {number} {

return [expr {$number * $number}]

}

过程调用 :可以像调用内置命令一样调用过程。过程可以返回值,可以有参数也可以没有参数。

set result [square 5]

puts "The square of 5 is $result"

过程是模块化编程和代码复用的基础,它们使得Tcl脚本更加清晰和可维护。

[接下去将继续探讨列表与字典的数据操作技巧......]

3. 列表与字典的数据操作技巧

Tcl(Tool Command Language)语言在数据操作方面提供了一系列强大而灵活的工具,其中列表(list)和字典(dict)是最为常用的数据结构。本章将深入探讨列表与字典在数据操作中的技巧和应用,并展示如何优化这些数据结构的使用。我们将从列表和字典的基本操作开始,逐步深入到高级操作和对比分析。

3.1 列表数据的创建和管理

3.1.1 列表的基本操作

在Tcl中,列表是有序元素的集合,可以包含任意类型的元素。创建和管理列表的基本操作是Tcl程序员必须掌握的技能。列表可以通过花括号 {} 或者空格分隔的元素来创建,如下所示:

set mylist {a b c d e}

# 或者

set mylist [list a b c d e]

列表的元素可以通过索引来访问,Tcl使用从0开始的索引。可以使用 lindex 命令获取列表中指定位置的元素:

set thirdElement [lindex $mylist 2] # 返回 'c'

添加、删除或替换列表中的元素也很直接。使用 lappend 命令可以向列表末尾添加新元素:

lappend mylist f

# 结果: a b c d e f

而 linsert 命令则可以在列表中指定位置插入元素:

linsert $mylist 1 "x y z"

# 结果: a x y z b c d e f

要删除列表中的元素,可以使用 ldelete 命令,该命令支持正则表达式来匹配需要删除的元素:

ldelete mylist {b c}

# 结果: a x y z d e f

参数说明:

lindex : 获取指定索引位置的元素。 lappend : 向列表末尾添加一个或多个元素。 linsert : 在列表中的指定位置插入一个或多个元素。 ldelete : 删除列表中匹配到的元素。

3.1.2 列表的高级操作和优化

列表除了基本操作之外,还提供了一系列高级操作。例如,可以使用 lsearch 命令搜索列表中是否包含某个元素,或者使用 lsort 命令对列表进行排序:

set index [lsearch $mylist "d"]

# index will be 3

set sortedList [lsort $mylist]

# sortedList will be: a d e f x y z

在处理较大的列表时,性能优化变得尤为重要。为了提升性能,应尽量避免在遍历列表时修改列表本身,因为这会触发列表的复制操作。可以通过列表复制或使用迭代器来优化性能:

set myList [list 1 2 3 4 5]

foreach elem $myList { # 这里不修改原始列表

# ... do something ...

}

此外,理解列表的内部存储机制对优化也有帮助。在Tcl中,列表是通过字符串来存储的,这意味着访问列表元素时需要进行解析,这可能会带来性能负担。因此,在性能敏感的场景中,尽可能减少列表解析的次数是一个很好的优化策略。

3.2 字典数据的使用与优势

3.2.1 字典数据结构特点

字典(dict)是一种关联数组,以键-值对的形式存储数据,提供了快速访问数据的能力。字典在Tcl 8.5版本之后被引入,它可以存储不同类型的键和值,是处理键值对应关系数据的理想选择。字典的创建和使用示例如下:

set mydict [dict create key1 value1 key2 value2]

# 结果: key1 value1 key2 value2

dict set mydict key3 value3

# 结果: key1 value1 key2 value2 key3 value3

dict get $mydict key1

# 结果: value1

参数说明:

dict create : 创建一个新的字典。 dict set : 向字典中添加或修改键值对。 dict get : 获取字典中指定键的值。

3.2.2 字典与列表的对比应用

在处理键值对应关系时,字典与列表相比有其独特的优势。列表可以用来存储顺序数据,但操作起来可能比较繁琐,特别是当需要通过特定的标识符访问数据时。字典则通过键直接访问值,非常直观且效率高。例如,在表示学生记录时:

使用列表:

set studentList [list [list "John" 21] [list "Jane" 19] [list "Bob" 20]]

# 找到名字为 "Jane" 的学生的年龄

set index [lsearch -all -inline -not -exact $studentList "Jane"]

set age [lindex $index 1]

使用字典:

set studentDict [dict create John 21 Jane 19 Bob 20]

# 直接通过键 "Jane" 获取年龄

set age [dict get $studentDict Jane]

字典提供了更快的访问速度和更清晰的数据结构,使得代码更易于维护。然而,字典的内存消耗通常比列表要大,且在某些特定的算法实现中,列表可能更加直观和方便。因此,在实际编程中,应当根据具体需求选择使用列表还是字典。

以上示例展示了如何在Tcl中进行基本的列表和字典操作。下一章将继续深入探索文件I/O操作的原理与实践,为读者提供更多实用的技巧。

4. 文件I/O操作的探索与实践

文件输入/输出(I/O)操作是任何编程语言不可或缺的一部分,Tcl语言也不例外。本章节将深入探索Tcl中的文件操作,从基本的文件读写到复杂的文件系统管理,以及异常处理机制的详细解析。

4.1 文件读写的原理与方法

4.1.1 文件基本操作命令

在Tcl中,处理文件最基本的操作包括打开文件、读取文件内容、写入数据到文件以及关闭文件。

# 打开一个文件用于读取,返回文件句柄

set file_id [open "example.txt" r]

# 读取文件内容

set content [read $file_id]

# 关闭文件句柄

close $file_id

在这段代码中, open 命令用于打开文件,其中 "example.txt" 是文件名, r 参数指定了以只读模式打开文件。文件句柄( $file_id )用于后续的读写操作。使用 read 命令可以读取文件内容,最后使用 close 命令关闭文件,释放系统资源。

4.1.2 文件读写的高级技术

当涉及到大文件的读写时,一次性读取整个文件内容可能会消耗大量内存。此时,可以采用分块读取的方式。

# 打开文件用于读取

set file_id [open "largefile.txt" r]

# 设置块大小

set chunk_size 1024

set content [read $file_id $chunk_size]

# 循环读取,直到文件结束

while {[string length $content] != 0} {

# 处理内容块

process_chunk $content

set content [read $file_id $chunk_size]

}

# 关闭文件句柄

close $file_id

在上述代码示例中,我们设置了1024字节的块大小( $chunk_size ),每次从文件中读取这个大小的内容块,并将其处理。循环会继续直到没有更多内容可读。这样的处理方式可以有效地管理内存使用,并处理任意大小的文件。

4.2 文件系统管理与异常处理

4.2.1 目录和文件的管理技巧

除了基本的文件操作外,Tcl还提供了丰富的文件系统管理命令,如列出目录内容、创建或删除文件和目录等。

# 列出当前目录下所有文件和文件夹

puts [glob -directory . -type f *]

puts [glob -directory . -type d *]

# 创建一个新目录

file mkdir "new_folder"

# 删除一个空目录

file delete "empty_folder"

# 删除一个文件

file delete "example.txt"

glob 命令可以用来获取匹配指定模式的文件列表, file 命令用于进行目录和文件的创建与删除操作。这些命令都是文件系统管理中常用到的技术。

4.2.2 文件I/O异常的捕获与处理

在文件操作过程中,经常会遇到各种异常情况,比如文件不存在、权限不足、磁盘空间不足等。Tcl通过 try 和 catch 命令来处理这些异常情况。

try {

set file_id [open "nonexistent.txt" r]

} trap {POSIX ENOENT} {

puts "文件不存在"

} trap {POSIX EACCES} {

puts "没有权限打开文件"

} on error {msg options} {

puts "发生了一个未知错误: $msg"

} finally {

puts "这是最终执行的代码块"

}

在这段示例代码中,我们尝试打开一个不存在的文件。 try 块中的代码如果执行失败,则会传递给 catch 命令指定的异常处理器。这里,我们针对不同的错误类型(文件不存在或没有权限)使用了不同的异常处理器,并在 finally 块中执行了最终需要执行的代码。这样即便发生异常,也能保证资源的正确释放和其他必要的清理工作。

通过本章内容的深入学习,你已经对Tcl的文件操作有了全面的了解。了解如何高效地进行文件读写操作,如何管理和操作文件系统,以及如何妥善处理文件操作中的异常情况,对于任何需要文件处理的Tcl项目都是至关重要的。在接下来的章节中,我们将继续探索正则表达式、错误处理、Tk图形界面编程等领域,这些高级特性将使你更加深入地掌握Tcl编程。

5. 正则表达式在Tcl中的应用

正则表达式是处理文本和数据的强大工具,它通过使用特定的模式,可以进行复杂的搜索、匹配、提取、替换等操作。Tcl语言对正则表达式有着良好的支持,允许开发者在处理字符串时能够更加灵活和高效。

5.1 正则表达式的基本语法学习

5.1.1 正则表达式的基本构成

正则表达式由一系列的字符组成,这些字符可以分为普通字符和特殊字符。普通字符即文本中的字面字符,而特殊字符,又称为元字符,它们具有特殊的含义,比如“.”表示任意字符,“*”表示前一个字符的零次或多次出现。

# 示例:查找包含"abc"字符串的模式

set pattern "abc"

regexp $pattern "The string contains abc" match

puts "Matched: $match"

在上述示例中,我们定义了一个简单的正则表达式,用于匹配字符串”abc”。 regexp 命令用于执行匹配操作,成功时返回1,并将匹配结果存放在变量 match 中。

5.1.2 模式匹配与替换技巧

除了匹配文本,正则表达式还可以用来替换文本中的特定模式。Tcl中通过 regsub 命令完成替换操作。 regsub 命令的基本结构是 regsub ?switches? exp string subSpec varName ,其中 exp 是正则表达式, string 是待处理的原始字符串, subSpec 是替换用的新字符串, varName 是存放结果的变量名。

# 示例:将字符串中的"abc"替换为"ABC"

set originalText "abc appears here"

regsub {abc} $originalText "ABC" newText

puts "Original: $originalText"

puts "Modified: $newText"

上述代码将字符串中的”abc”替换为了”ABC”,并打印出了替换前后的内容。

5.2 正则表达式的高级应用与优化

5.2.1 高级模式匹配策略

在进行复杂的文本处理时,正则表达式可以使用如分组、回溯引用、先行断言等高级特性来匹配复杂的模式。分组通过括号”()”来实现,它可以帮助提取和引用特定的匹配部分。

# 示例:匹配一个完整的电子邮件地址

set emailPattern {([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})}

regexp $emailPattern "user@example.com" match user domain

puts "Username: $user"

puts "Domain: $domain"

上述代码展示了如何使用分组来匹配电子邮件地址,并分别提取用户名和域名部分。

5.2.2 性能优化和最佳实践

在处理大量文本或者性能敏感的应用时,正则表达式的性能就显得尤为重要。为了避免正则表达式消耗过多的计算资源,开发者应该尽量避免使用过于复杂的表达式,并且应避免使用贪婪模式,除非确实需要。

# 示例:非贪婪匹配

set greedyPattern {<.*>}

set nonGreedyPattern {<.*?>}

# 假设 htmlContent 包含需要处理的HTML代码

regexp $greedyPattern $htmlContent match

puts "Greedy Match: $match"

regexp $nonGreedyPattern $htmlContent match

puts "Non-greedy Match: $match"

在这个示例中,我们比较了贪婪模式和非贪婪模式对性能的影响。非贪婪模式通常可以提升匹配的效率。

正则表达式的使用可以极大地提升文本处理的灵活性和效率,掌握其高级特性对开发者的技能提升至关重要。本章探讨了正则表达式在Tcl中的基本用法和高级技巧,以及在实际应用中需要注意的性能优化问题。通过本章节的介绍,读者应能熟练使用正则表达式进行高效的文本匹配和处理。

6. Tcl语言的错误处理机制全面解析

在任何编程语言中,错误处理都是一个非常关键的部分,它能够帮助开发者更好地管理程序中可能出现的异常情况,从而提高程序的健壮性与可靠性。Tcl语言同样内置了一套完善的错误处理机制,能够有效地协助开发者处理各种错误情况。本章节将对Tcl中的错误处理机制进行深入的探讨,包括基本的错误处理概念、异常的捕获与处理流程,以及错误处理的高级策略和应用。

6.1 错误处理的基本概念和方法

错误处理是任何应用程序中不可或缺的一部分。在Tcl语言中,开发者通过使用异常处理命令来管理程序的运行时错误。错误类型可以大致分为两类:语法错误和运行时错误。语法错误通常在代码执行之前就被检测到,而运行时错误则是在程序运行过程中发生的。

6.1.1 错误类型的识别与分类

在Tcl中,错误类型可以是:

语法错误 :通常发生在脚本的解析阶段,例如当脚本中有语法错误时,Tcl解释器无法识别某些命令或表达式。 运行时错误 :在脚本执行过程中发生的错误,如文件不存在、操作不被允许、算术运算错误等。 逻辑错误 :程序逻辑上的错误导致程序行为与预期不符,虽然不一定会导致程序崩溃,但可能导致程序输出错误的结果。

Tcl通过一系列命令,如 error 、 catch 、 try 等,允许开发者捕捉和处理这些错误。开发者可以根据错误的类型选择不同的处理策略。

6.1.2 异常捕获与处理流程

在Tcl中, catch 命令是用来处理异常的最基础工具之一。 catch 命令可以捕获在脚本执行过程中出现的任何异常,并将异常信息存储到变量中,以便后续进行分析和处理。基本用法如下:

catch {expression} varName ?options?

其中, expression 是可能会产生异常的命令序列, varName 用于接收错误信息, options 提供了额外的处理选项。

下面是一个简单的例子:

catch {set x 1 / 0} errorMessage

puts "Error: $errorMessage"

在上面的例子中,尝试执行除以零的操作会产生一个运行时错误。 catch 命令捕获到错误并将其存储在变量 errorMessage 中,随后我们使用 puts 命令将其输出。

6.2 错误处理的高级策略与应用

在更复杂的应用中,简单的错误捕获可能不足以处理所有潜在的异常情况。在Tcl中, try 和 trap 命令提供了更为强大的异常处理能力,使得错误处理更加灵活和高效。

6.2.1 异常报告和日志记录

为了有效地追踪和分析错误,Tcl允许开发者将错误信息记录到日志中。 try 命令可以用来捕获异常,并将异常信息保存到一个变量中,然后利用标准的日志机制记录下来。示例如下:

try {

# some script

} trap {TCL_ERROR} err {

puts "Error: $err"

# log the error to a file or standard log facility

}

在这个例子中,如果 try 块中的脚本执行失败, trap 子句会捕获 TCL_ERROR 异常,并将其记录到标准错误输出中。在实际应用中,开发者可以将错误信息记录到文件或日志服务器中。

6.2.2 容错设计和恢复机制

错误处理不仅仅是捕捉和记录错误,更应该考虑到如何让系统从错误中恢复并继续运行。容错设计是构建健壮应用程序的关键。在Tcl中,开发者可以使用 try 命令的 finally 子句来实现容错逻辑,确保无论是否发生异常,程序都能执行必要的清理和恢复操作。

下面是一个使用 try 、 trap 和 finally 的例子:

try {

# some script

} trap {TCL_ERROR} err {

# handle specific error

puts "Error: $err"

} finally {

# this code runs regardless of whether an error occurred

puts "Cleanup actions."

}

在这个例子中,无论 try 块中是否发生错误, finally 子句都会被执行。这通常用于释放资源、关闭文件或网络连接等操作,确保系统资源得到妥善处理。

总结

Tcl语言中的错误处理机制为开发者提供了强大的工具来管理和响应运行时错误。从基本的 catch 命令到高级的 try 和 trap 命令,Tcl提供了一系列灵活的方法来处理异常,使得开发者能够构建健壮的程序。通过将异常捕获、日志记录和容错机制结合在一起,开发者可以确保应用程序即使在面对错误时也能优雅地执行和恢复。

7. Tk图形界面编程的实践与创新

7.1 Tk图形界面的基础入门

7.1.1 Tk组件和窗口管理

Tk是一个为Tcl语言设计的图形界面工具包,它提供了丰富的组件来构建窗口应用。窗口(window)是Tk中非常基本的单元,所有的GUI元素都是在窗口的基础上添加的。比如一个标签(label)、按钮(button)、文本框(text)等。

在Tk中,窗口管理涉及窗口的创建、配置和布局。使用 wm 命令可以对窗口的特性进行控制,如窗口标题、大小和位置等。

以下是创建一个基本窗口的代码示例:

#!/usr/bin/tclsh

package require Tk

# 创建窗口实例

wm title . "Tk基础窗口示例"

wm geometry . +100+100

# 添加标签

label .lb -text "这是Tk标签"

# 配置窗口

pack .lb -side left -expand true -fill both

# 运行主事件循环

vwait forever

以上代码将创建一个标题为”Tk基础窗口示例”的窗口,并在左侧放置一个可扩展的标签。

7.1.2 事件驱动编程机制

事件驱动编程是图形用户界面(GUI)编程的一个重要概念。在Tk中,当用户进行操作(比如点击按钮、输入文本等)时,系统会产生事件,程序会根据这些事件执行相应的处理函数。

在Tk中,常用的事件处理函数有:

bind :将一个事件与一个回调函数绑定。 after :在指定的毫秒数后执行某个函数。

例如,以下代码创建了一个按钮,当用户点击它时,会弹出一个消息框:

button .b -text "点击我" -command {tk_messageBox -message "你好,世界!"}

pack .b

7.2 Tk图形界面的高级应用

7.2.1 自定义控件和布局

Tk允许开发者通过继承现有控件来创建自定义控件,以及通过布局管理器(如 grid 、 place 、 pack )来设计复杂的界面布局。

例如,创建一个自定义按钮控件,可以使用继承现有 button 控件的方式:

oo::class create MyButton {

superclass button

constructor args {

my variable text

set text [lindex $args 0]

next [lrange $args 1 end]

}

method display {} {

puts "按钮显示文本为: $text"

}

}

MyButton .mybutton "自定义按钮"

pack .mybutton

7.2.2 动画效果和交互设计

为了使应用程序更加吸引人,Tk提供了各种内置命令来实现动画效果和交互设计。这些动画效果可以通过 after 命令实现,或者使用特定的控件如 canvas (画布)来创建动画。

例如,以下代码段演示如何在画布上创建一个简单的移动的球体:

canvas .c -width 400 -height 400

pack .c

set x1 10

set y1 10

set radius 10

$c create oval $x1 $y1 [expr $x1 + $radius*2] [expr $y1 + $radius*2] -fill red -tag ball

after 100 updateBall

proc updateBall {} {

global x1 y1

.c move ball [expr $x1 % 2] [expr $y1 % 2]

after 100 updateBall

}

以上代码创建了一个画布,并在画布上绘制了一个圆形(球体),然后通过 after 命令周期性地更新球体的位置,实现简单的动画效果。

本文还有配套的精品资源,点击获取

简介:Tcl是一种简单、易学的脚本语言,广泛应用于系统管理、网络编程等多个领域。本教程深入探讨了Tcl的核心概念、语法结构、命令控制、数据结构操作、文件I/O、正则表达式、错误处理、图形界面设计、扩展库使用以及嵌入式应用等方面,旨在帮助读者快速掌握Tcl语言并在实际项目中应用。

本文还有配套的精品资源,点击获取

相关灵感

正规beat365旧版 铭记长征精神,10部长征题材佳片集结电影频道
365bet足球网开户 跑车为什么很少上高速

跑车为什么很少上高速

📅 06-30 👁️ 227
365365094 小视频怎么发朋友圈?手把手教你轻松搞定!
365bet足球网开户 很抱歉,您访问过于频繁,请过一段时间再试
365bet足球网开户 中国银行最新利率:存款8万有多少利息?
正规beat365旧版 刀剑神域ALO:桐人获得断钢圣剑却选择扔掉它,理由竟然是这个!
365365094 基票直播 v1.0 安卓版

基票直播 v1.0 安卓版

📅 08-11 👁️ 9865
正规beat365旧版 废村少女

废村少女

📅 10-19 👁️ 1834
正规beat365旧版 全身麻醉到底是什么感觉?网传:相当于死过一次...