allegro skill
0、打开skill 窗口界面:
输入命令:set telskill
注意,上面这行代码最后要加一个空格,才能弹出skill窗口。
1、apply 函数
apply
函数的作用是将列表中的元素作为参数依次传递给目标函数,并执行该函数。这种方式在处理动态参数列表时非常有用,例如当参数数量不确定或需要从其他数据结构中提取参数时。
; 定义一个简单的函数
procedure(sum(x y)
x + y
)
; 使用 apply 调用 sum 函数
apply('sum, list(1, 2)) ; 结果为 3
如果目标函数需要多个参数,而这些参数已经存储在一个列表中,apply
可以方便地将这些参数传递给函数
2、Skill 函数传递参数 @rest @optional @key 的区别
来源:Skill 函数传递参数 @rest @optional @key 的区别 - 初学入门 - Cadence Skill 论坛 - Powered by Discuz!
询问kimi
在Cadence Skill语言中,`@rest`关键字用于定义函数时接收不确定数量的参数。以下是`@rest`的使用方法和特点:
### 语法
`@rest`关键字必须放在函数参数列表的最后一个参数前,例如:
lisp
procedure(functionName(param1 param2 @rest restParams)
; 函数体
)
其中,`restParams`会将所有多余的参数收集到一个列表中。
### 示例
以下是一个使用`@rest`的函数示例:
lisp
procedure(myAdd(@rest args)
prog((result)
result = 0
foreach(num args
printf("myAdd: %n + %n\n" result num)
result += num
)
return(result)
)
)
调用该函数时,可以传递任意数量的参数:
lisp
myAdd(1 2 3) ; 输出结果为 6
运行过程如下:
myAdd: 0 + 1
myAdd: 1 + 2
myAdd: 3 + 3
=> 6
### 注意事项
- `@rest`只能用于函数参数列表的最后一个参数。
- `@rest`与`@optional`和`@key`不能同时使用,因为它们的功能存在冲突。
- 使用`@rest`时,多余的参数会被收集到一个列表中,可以通过`car`、`cdr`等函数操作该列表。
在 Cadence SKILL 中,`@rest`、`@optional` 和 `@key` 是用于定义函数参数的三种不同方式,它们各有用途和特点,以下是它们的区别:
### 1. **`@rest`**
- **用途**:允许函数接收任意数量的参数,并将这些参数作为一个列表传递给函数。
- **特点**:
- 所有额外的参数都会被收集到一个列表中。
- 可以与普通参数或 `@optional` 参数一起使用,但不能与 `@key` 参数同时使用。
- **示例**:
```lisp
procedure(myAdd(@rest args)
prog((result)
result = 0
foreach(num args
result += num
)
return(result)
)
)
```
调用 `myAdd(1 2 3)` 时,`args` 会是一个列表 `(1 2 3)`。
### 2. **`@optional`**
- **用途**:定义可选参数,这些参数可以有默认值,调用函数时可以选择性地传递这些参数。
- **特点**:
- 必须按顺序传递可选参数。
- 不能与 `@key` 参数同时使用。
- **示例**:
```lisp
procedure(trBuildBBox(height width @optional (xCoord 0) (yCoord 0))
list(xCoord:yCoord, xCoord+width:yCoord+height)
)
```
调用 `trBuildBBox(1 2)` 时,`xCoord` 和 `yCoord` 使用默认值 `0`。
### 3. **`@key`**
- **用途**:定义可选参数,并允许以关键字的形式传递参数,调用时参数的顺序可以任意。
- **特点**:
- 参数必须以关键字形式传递,例如 `?keyName value`。
- 不能与 `@optional` 参数同时使用。
- **示例**:
```lisp
procedure(trBuildBBox(@key (height 0) (width 0) (xCoord 0) (yCoord 0))
list(xCoord:yCoord, xCoord+width:yCoord+height)
)
```
调用 `trBuildBBox(?height 1 ?width 2 ?xCoord 4 ?yCoord 10)` 时,参数顺序可以任意。
### 总结
- **`@rest`**:用于接收任意数量的参数,参数以列表形式传递。
- **`@optional`**:用于定义有默认值的可选参数,参数按顺序传递。
- **`@key`**:用于定义有默认值的可选参数,参数以关键字形式传递,顺序任意。
需要注意的是,`@optional` 和 `@key` 不能同时出现在一个函数的定义中,而 `@rest` 可以与它们中的任何一个结合使用。
3、car函数用法
在Cadence Skill语言中,`car`函数用于获取列表的第一个元素。以下是其用法和特点:
### 语法
lisp
car(list)
- **参数**:`list`是一个列表。
- **返回值**:返回列表的第一个元素。
### 示例
lisp
numbers = '(1 2 3)
car(numbers) ; 返回 1
如果列表为空,`car`函数会返回`nil`。
### 注意事项
- `car`函数只能用于列表类型的数据,不能用于其他类型。
- 如果需要获取列表的其他元素,可以结合`cdr`函数使用。例如,`car(cdr(list))`可以获取列表的第二个元素。
`car`函数是Lisp语言中处理列表的基本函数之一,其名称来源于早期Lisp语言中的机器语言指令,代表“地址寄存器的内容”。
4、单引号 ' 的用法
在Cadence SKILL语言中,单引号 `'` 的作用是引用符号(symbol)或创建一个未求值的列表。以下是其具体用法:
### 引用符号
在SKILL中,单引号 `'` 可以用来引用一个符号,而不是直接调用它。例如:
lisp
'symbol
这会返回符号 `symbol` 本身,而不是尝试对它求值。
### 创建未求值的列表
单引号也可以用来创建一个未求值的列表。例如:
lisp
'(1 2 3)
这会返回一个列表 `(1 2 3)`,而不会对列表中的元素进行求值。
### 示例
lisp
x = 10
'(x 20) ; 返回列表 (x 20),而不是 (10 20)
在这个例子中,`'(x 20)` 创建了一个包含符号 `x` 和数字 `20` 的列表,而不是将 `x` 替换为其值 `10`。
总之,单引号 `'` 在SKILL语言中用于引用符号或创建未求值的列表,这在处理符号和列表时非常有用。
5、cdr函数
在 Cadence SKILL 中,`cdr` 函数用于获取列表中除第一个元素以外的所有其他元素组成的列表。以下是 `cdr` 函数的详细用法:
### 功能
`cdr` 函数返回一个列表,其中包含原列表中第一个元素之后的所有元素。
### 语法
lisp
cdr(list)
- **输入参数**:`list` 是一个列表。
- **返回值**:返回一个列表,包含原列表中第一个元素之后的所有元素。
### 示例
lisp
myList = '(1 2 3 4)
cdr(myList) ; 返回 (2 3 4)
如果列表为空或只有一个元素,`cdr` 的返回值为 `nil`。
### 注意事项
- `cdr` 函数返回的仍然是一个列表,而不是单个元素。
- 如果需要获取列表中的单个元素,可以结合 `car` 函数使用,例如 `car(cdr(myList))` 可以获取列表的第二个元素。
`cdr` 函数是 SKILL 语言中处理列表的基本工具之一,常用于列表的遍历和操作。
6、 list的·增删改查
在 Cadence SKILL 中,对列表(List)的增删改查操作可以通过多种函数实现。以下是一些常用的操作及其对应的函数:
### 1. **创建列表**
- **`list()`**:创建一个空列表或包含指定元素的列表。
lisp
myList = list(1 2 3 4) ; 创建一个包含 1, 2, 3, 4 的列表
### 2. **增加元素**
- **`cons()`**:将一个元素添加到列表的开头。
lisp
myList = cons(0 myList) ; 在 myList 前面添加 0,结果为 (0 1 2 3 4)
- **`append1()`**:将一个元素添加到列表的末尾。
lisp
myList = append1(myList 5) ; 在 myList 末尾添加 5,结果为 (1 2 3 4 5)
### 3. **删除元素**
- **`cdr()`**:删除列表的第一个元素,返回剩余部分。
lisp
myList = cdr(myList) ; 删除第一个元素,结果为 (2 3 4 5)
- **`remove()`**:删除列表中指定的元素。
lisp
myList = remove(3 myList) ; 删除列表中的元素 3,结果为 (1 2 4 5)
### 4. **修改元素**
- **`setcar()`**:修改列表的第一个元素。
lisp
setcar(myList 10) ; 将 myList 的第一个元素修改为 10,结果为 (10 2 3 4)
- **`setnth()`**:修改列表中指定索引位置的元素。
lisp
setnth(myList 2 20) ; 将 myList 的第三个元素(索引为 2)修改为 20,结果为 (10 2 20 4)
### 5. **查找元素**
- **`car()`**:获取列表的第一个元素。
lisp
firstElement = car(myList) ; 获取 myList 的第一个元素,结果为 10
- **`nth()`**:获取列表中指定索引位置的元素。
lisp
thirdElement = nth(2 myList) ; 获取 myList 的第三个元素,结果为 20
- **`member()`**:检查列表中是否存在指定元素,并返回从该元素开始的子列表。
lisp
result = member(20 myList) ; 检查 20 是否在 myList 中,结果为 (20 4)
### 6. **其他操作**
- **`reverse()`**:反转列表。
lisp
myList = reverse(myList) ; 反转 myList,结果为 (4 20 2 10)
- **`length()`**:获取列表的长度。
lisp
listLength = length(myList) ; 获取 myList 的长度,结果为 4
这些函数提供了对 SKILL 中列表的基本操作能力,能够满足大多数编程需求。
7、if when unless
在 Cadence SKILL 语言中,`if`、`when` 和 `unless` 是三种条件语句,用于基于特定条件执行代码块。
### `if` 语句
`if` 语句用于在给定条件为真或假时执行不同的代码块。基本结构如下:
lisp
if( condition
then
statements-if-true
else
statements-if-false
)
`if` 语句会先判断条件 `condition` 是否满足。如果条件为真(non-nil),则执行 `then` 部分的语句;如果条件为假(nil),则执行 `else` 部分的语句。
### `when` 语句
`when` 语句类似于 `if` 语句,但它只执行条件为真时的代码块,没有 `else` 部分。其基本结构如下:
lisp
when( condition
statements-if-true
)
这等同于 `if` 语句中只有 `then` 而没有 `else` 的情况。
### `unless` 语句
`unless` 语句是 `if` 语句的否定形式,即当条件为假时执行代码块。其基本结构如下:
lisp
unless( condition
statements-if-false
)
这等同于 `if` 语句中条件为假时执行的代码块。
这些条件语句在 SKILL 编程中非常有用,可以帮助开发者根据不同的条件执行不同的代码逻辑。
8、Case
在 Cadence SKILL 语言中,`case` 语句是一种多分支选择语句,用于基于不同条件执行不同的代码块。以下是 `case` 语句的基本结构和用法:
### 基本结构
lisp
case( expression
( pattern1
statements1
)
( pattern2
statements2
)
...
( t
statements-default
)
) ; case
其中,`expression` 是要进行匹配的表达式,`pattern1`、`pattern2` 等是匹配模式,`statements1`、`statements2` 等是匹配成功时要执行的语句,`t` 是默认匹配模式,用于处理没有匹配成功的情况。
### 用法示例
以下是 `case` 语句的一个示例,用于根据 `shapeType` 的值执行不同的操作:
lisp
case( shapeType
( "rect"
++rectCount
println( "Shape is a rectangle" )
)
( "line"
++lineCount
println( "Shape is a line" )
)
( "label"
++labelCount
println( "Shape is a label" )
)
( t
++miscCount
println( "Shape is miscellaneous" )
)
) ; case
在这个例子中,`shapeType` 的值会与 `"rect"`、`"line"`、`"label"` 进行比较,当 `shapeType` 的值与 `"rect"`、`"line"`、`"label"` 中的任意一个相同,那么就执行该值下面的所有表达式。如果未找到匹配的值,那么最后一段语句将会执行。
需要注意的是,如果一个分支的值是一个列表,那么只要列表中的任一个值与比较值匹配,该分支下的所有语句将会执行。
9、prog 和return
在 Cadence SKILL 语言中,`prog` 是一种特殊的代码块,它允许你定义局部变量,并且可以在块内使用 `return` 语句来提前退出函数并返回一个值。`prog` 块非常适合在需要多个返回点或者使用 `go` 进行控制跳转的情况。
`return` 语句则用于从 `prog` 代码块中提前退出,并返回一个指定的值。如果没有执行 `return` 语句,`prog` 块的计算结果为 `nil`。如果在 `prog` 中执行 `return`,则 `prog` 会立即返回并返回给 `return` 语句的参数值。
以下是 `prog` 和 `return` 的使用示例:
lisp
procedure( proc2(a)
prog((x y z a) ; 声明局部变量
;;;
return(1)
);prog
);proc2
在这个例子中,`a`, `x`, `y`, `z` 将是局部于过程 `proc2` 的变量,任何同名的全局变量都不会受到影响。而且,`prog` 允许我们使用 `return` 语句,这可以在你的情况下使用。
需要注意的是,`return` 语句仅在 `prog` 语句中使用时才有意义。`go` 和 `return` 都不是纯粹的功能,因为它们以非标准方式转移控制权。也就是说,它们不会返回给调用者。
10、for, foreach, while
在 Cadence SKILL 语言中,`for`、`while` 和 `foreach` 是三种不同的循环结构,用于重复执行代码块。
### `for` 循环
`for` 循环用于当循环次数已知时,或者根据条件结束循环的情况。在 `for` 语句中,循环变量在执行前已经保存,在执行结束时也同时保存最终值。例如,计算从1到5之间的所有整数和:
lisp
sum = 0
for( i 1 5
sum = sum + i
println( sum )
)
每循环一次SKILL将打印一次 `sum` 值,本例运行结果如下:
1
3
6
10
15
注意:`for` 语句返回值始终为 `t`。
### `foreach` 循环
`foreach` 循环与 `for` 循环类似,但其循环变量是一个列表(list),列表中有多少个元素,`foreach` 语句将循环多少次,从第一个元素开始,到最后一个元素结束。例如:
lisp
rectCount = lineCount = polygonCount = 0
shapeTypeList = ‘( “rect” “polygon” “rect” “line” )
foreach( shapeType shapeTypeList
case( shapeType
( “rect” ++rectCount )
( “line” ++lineCount )
( “polygon” ++polygonCount )
( t ++miscCount )
) ;case
) ; foreach
在该例子中,`shapeType` 是一个索引变量,在执行 `foreach` 语句前,SKILL首先保存当前 `shapeType` 的值,当执行一次循环后,`shapeType` 保存 `shapeTypeList` 中的下一个元素值。`foreach` 的返回值是一个list,包含 `shapeTypeList` 中的所有元素。
### `while` 循环
`while` 循环用于在给定条件为真时重复执行代码块。其基本结构如下:
lisp
while( condition
statements
)
`while` 循环会不断检查条件 `condition` 是否满足。如果条件为真(non-nil),则执行循环体内的语句;如果条件为假(nil),则退出循环。在搜索结果中,有一个使用 `while` 循环的例子:
lisp
i=0
while(i<20
println(i)
i=i+2
)
这个例子中,`while` 循环会打印出从0开始,每次增加2,直到小于20的所有整数。
11、文件和文件夹的增删改查
在Cadence SKILL中,对文件和文件夹进行增删改查操作是常见的任务。以下是一些基本的文件操作函数:
### 文件操作
1. **打开文件**
- 使用 `infile` 函数打开一个输入端口准备读取文件。
- 基本结构:`infile(S_fileName)`,其中 `S_fileName` 为读取文件路径,可以为相对路径或绝对路径。
在计算机系统中,文件路径是用于指定文件或目录位置的字符串。路径可以是相对路径或绝对路径:
### 绝对路径(Absolute Path)
- 绝对路径是从根目录开始,一直到目标文件或目录的完整路径。
- 它精确地指向文件系统中的某个位置,不依赖于当前工作目录。
- 在 UNIX/Linux 系统中,绝对路径通常以根目录的正斜杠 `/` 开始。
- 在 Windows 系统中,绝对路径通常以盘符(如 `C:`)开始,后面跟着反斜杠 `\`。
**示例**:
- UNIX/Linux: `/home/user/documents/report.txt`
- Windows: `C:\Users\Username\Documents\report.txt`
### 相对路径(Relative Path)
- 相对路径是相对于当前工作目录的路径。
- 它不从根目录开始,而是从当前位置开始,指向目标文件或目录。
- 相对路径使用 `.` 表示当前目录,`..` 表示上一级目录。
- 相对路径依赖于当前工作目录,因此在不同的工作目录下,相同的相对路径可能指向不同的位置。
**示例**:
- 当前工作目录为 `/home/user/documents` 时:
- `report.txt` 指向 `/home/user/documents/report.txt`
- `../images/photo.jpg` 指向 `/home/user/images/photo.jpg`
- `../parent/sibling/file.txt` 指向 `/home/user/parent/sibling/file.txt`
### 使用场景
- **绝对路径**:当你需要确保无论从哪个位置访问,都能准确找到文件或目录时,使用绝对路径。
- **相对路径**:当你需要在不同目录之间移动,或者在脚本中使用路径时,使用相对路径更为灵活。
### 注意事项
- 在编写脚本或程序时,使用绝对路径可以避免因工作目录变化而导致的路径错误。
- 使用相对路径可以使脚本或程序更具可移植性,因为它们不依赖于特定的文件系统结构。
- 在处理文件路径时,需要注意不同操作系统的路径分隔符差异(UNIX/Linux 使用 `/`,Windows 使用 `\`)。在跨平台应用中,可能需要使用适当的函数或方法来处理这些差异。
2. **读取文件**
- 使用 `gets` 或 `fscanf` 函数读取文件内容。
- 示例:`while(gets(s file)` 用于读取文件中的一行,将读取到的值传递给变量 `s`。
3. **关闭文件**
- 使用 `close` 函数关闭文件端口。
- 示例:`close(file)`,在读取完文件后,需要使用 `close` 函数关闭文件端口。
4. **删除文件**
- 使用 `delete` 函数删除文件。
- 示例:`delete("filename")` 删除指定的文件。
5. **修改文件**
- 可以通过读取文件内容,修改后再写回文件的方式来实现文件的修改。
在 Cadence SKILL 中,修改文件通常涉及以下几个步骤:读取文件内容、修改内容、然后将修改后的内容写回文件。下面是一个简单的示例,展示了如何实现这一过程:
### 步骤 1: 读取文件内容
首先,你需要打开文件并读取其内容。可以使用 `infile` 和 `gets` 函数来实现:
lisp
filename = "example.txt" ; 指定文件名
file = infile(filename) ; 打开文件进行读取
if file = nil then
printf("Failed to open file: %s\n" filename)
else
contents = "" ; 初始化一个空字符串用于存储文件内容
while (gets(line file) do
contents = cat(contents, line, "\n") ; 读取每一行并添加到 contents 字符串中
)
close(file) ; 关闭文件
endif
### 步骤 2: 修改内容
一旦你有了文件的内容,就可以根据需要进行修改。例如,我们可以修改字符串中的某些特定文本:
lisp
modified_contents = subst("new text", "old text", contents) ; 替换文本
### 步骤 3: 写回文件
修改完内容后,你需要将修改后的内容写回文件。可以使用 `outfile` 和 `printf` 函数来实现:
lisp
file = outfile(filename) ; 打开文件进行写入
if file = nil then
printf("Failed to open file for writing: %s\n" filename)
else
printf(file, "%s", modified_contents) ; 将修改后的内容写入文件
close(file) ; 关闭文件
endif
### 完整示例
将上述步骤合并,我们可以得到一个完整的示例:
lisp
procedure(modify_file(filename old_text new_text)
file = infile(filename) ; 打开文件进行读取
if file = nil then
printf("Failed to open file for reading: %s\n" filename)
return
endif
contents = "" ; 初始化一个空字符串用于存储文件内容
while (gets(line file) do
contents = cat(contents, line, "\n") ; 读取每一行并添加到 contents 字符串中
)
close(file) ; 关闭文件
modified_contents = subst(new_text, old_text, contents) ; 替换文本
file = outfile(filename) ; 打开文件进行写入
if file = nil then
printf("Failed to open file for writing: %s\n" filename)
else
printf(file, "%s", modified_contents) ; 将修改后的内容写入文件
close(file) ; 关闭文件
endif
end procedure
### 使用示例
调用 `modify_file` 函数来修改文件:
lisp
modify_file("example.txt" "old text" "new text")
这将把 `example.txt` 文件中所有的 "old text" 替换为 "new text"。
### 注意事项
- 在处理文件时,务必确保文件路径正确,并且程序有足够的权限来读取和写入文件。
- 在修改文件内容时,建议先备份原始文件,以防修改过程中出现错误。
- 在写回文件时,确保文件以写入模式打开(`outfile`),以覆盖原始内容。
6. **查询文件**
- 使用 `isFile` 函数判断文件是否存在。
- 示例:`if(isFile("G:/file.txt")` 判断文件是否存在。
### 文件夹操作
1. **创建文件夹**
- 使用 `mkdir` 函数创建文件夹。
- 示例:`mkdir("foldername")` 创建指定名称的文件夹。
2. **删除文件夹**
- 使用 `rmdir` 函数删除文件夹。
- 示例:`rmdir("foldername")` 删除指定的文件夹。
3. **修改文件夹**
- 文件夹的修改通常涉及到文件的移动或重命名,可以使用 `rename` 函数。
- 示例:`rename("oldname" "newname")` 将文件或文件夹从旧名称改为新名称。
4. **查询文件夹**
- 使用 `isDir` 函数判断文件夹是否存在。
- 示例:`if(isDir("foldername")` 判断文件夹是否存在。
这些操作可以帮助你在SKILL中有效地管理文件和文件夹。
12、cat函数
在Cadence SKILL中,`cat` 函数用于连接字符串。根据搜索结果,`cat` 函数的定义如下:
lisp
cat(S_string1 [S_string2 ...]) => T_result
该函数将输入的字符串(strings)连接起来,组成一个新的字符串。返回值 `T_result` 是一个新的字符串,包含所有输入字符串 `S_string1`, `S_string2`, …,并连接在一起。输出值顺序从左到右与输入参数顺序保持一致。
13、复制文件
在Cadence SKILL中,文件复制可以通过调用`axlOSFileCopy`函数来实现,这是一个Allegro SKILL函数,用于复制文件。根据Cadence Community中的讨论,下面是一个使用`axlOSFileCopy`函数的示例:
lisp
(setq SrcFile (sprintf nil "%s/pcb/%s.%s" (axlGetVariable "CDS_SITE") file_name file_ext))
(setq DestFile (sprintf nil "%s/%s.%s" (axlGetVariable "cwd") file_name file_ext))
(unless (axlOSFileCopy SrcFile DestFile nil) (axlUIConfirm "file copy FAILED"))
在这个示例中,`SrcFile` 是源文件的路径,`DestFile` 是目标文件的路径,`axlOSFileCopy` 函数尝试将源文件复制到目标路径。如果复制失败,`unless` 语句将执行 `axlUIConfirm` 函数来弹出一个错误消息框。
需要注意的是,目标路径应该包含文件名,否则函数可能无法正确执行复制操作。此外,确保路径格式正确,并且SKILL脚本具有足够的权限来访问和修改指定的文件和目录。
逐行分析
这段 SKILL 代码主要用于在 Cadence Allegro 环境中复制一个文件。下面是对这段代码的逐行解释:
### 代码解释
1. **定义源文件路径**
lisp
(setq SrcFile (sprintf nil "%s/pcb/%s.%s" (axlGetVariable "CDS_SITE") file_name file_ext))
- `setq` 是 SKILL 中用来赋值的函数。
- `SrcFile` 是一个变量,用于存储源文件的路径。
- `sprintf` 函数用于格式化字符串,这里它将 `CDS_SITE` 环境变量的值、文件名 `file_name` 和文件扩展名 `file_ext` 组合成一个完整的文件路径。
- `axlGetVariable "CDS_SITE"` 获取环境变量 `CDS_SITE` 的值,这通常是一个指向项目或工作区根目录的路径。
- `file_name` 和 `file_ext` 是变量,分别存储文件的名称和扩展名。
2. **定义目标文件路径**
lisp
(setq DestFile (sprintf nil "%s/%s.%s" (axlGetVariable "cwd") file_name file_ext))
- `DestFile` 是一个变量,用于存储目标文件的路径。
- `axlGetVariable "cwd"` 获取当前工作目录的路径。
- 同样使用 `sprintf` 函数将当前工作目录、文件名和文件扩展名组合成目标文件的完整路径。
3. **执行文件复制并检查结果**
lisp
(unless (axlOSFileCopy SrcFile DestFile nil) (axlUIConfirm "file copy FAILED"))
- `unless` 是一个条件语句,它检查 `axlOSFileCopy` 函数的返回值。
- `axlOSFileCopy` 是一个用于复制文件的函数,它接受三个参数:源文件路径 `SrcFile`、目标文件路径 `DestFile` 和一个标志(这里传入 `nil`,表示默认行为)。
- 如果 `axlOSFileCopy` 返回 `nil`(即复制失败),则执行 `axlUIConfirm` 函数,弹出一个消息框显示 "file copy FAILED"。
### 总结
这段代码的主要功能是将一个位于 `CDS_SITE` 目录下的文件复制到当前工作目录。它首先构建源文件和目标文件的路径,然后尝试复制文件,并在复制失败时显示一个错误消息。这种操作在自动化脚本中非常有用,特别是在需要处理多个文件或在不同目录之间移动文件时。