第一章SKILL 语言基础
1.1 SKILL 语言简介
SKILL 是用于Cadence 软件二次开发的语言。我们关于SKILL 的介绍基于SKILL 语言参考档和Allegro
SKILL的应用。
1.1.1 语法格式
SKILL语法支持lisp 格式的语法,但是我们不推荐,推荐类C 的语法格式。
Lisp示例:
(max 5 3) => 5
C 示例:
max(5 3) => 5
Max是求最大值的函数,lisp 格式的不便阅读。
1.1.2 简单的SKILL 运行环境
Allegro 的SKILL 运行环境:在Allegro 的命令窗口输入set telskill
窗口就可以用来运行就可以打开一个新的窗口,这个SKILL 命令。窗口的大小可以手动调节。
1.1.3 Load Skill
可以直接在SKILL development里面运行SKILL,可以把写好的代码放load命令一次性装载。 在说明load
之前,先说一下getSkillPath和setSkillPath 这2 个函数。因为load 要找到SKILL
来装载,通常我们都不喜欢通过绝对路径来装载一个文件,因为那样包含的字符太多了。文件getSkillPath()
将得到当前Allegro 设置的SKILL 加载路径,而setSkillPath
用来指定加载路径。目前先不用考虑这个setSkillPath。
我的Allegro当前默认的SKILL 路径是Allegro
的工作路径和C:\home\pcbenv\skill这样我先把hello.il文件放在C:\home\pcbenv\skill\函数。下面,下一步来加载这个文件,然后运行定义的函数
Hello.il的源代码:
procedure( hello()
let( ()
println("Hello World!")
)
); end procedure
1.1.4 注释
SKILL支持2种注释方式 a. 用于注释多行,像C一样 b. ; 用于注释单行,类似
C 的//
1.1.5 基本的数据类型
integer 5
float 5.0
string "abc defg"
list '(1 2 3 "a")
boolen t/nil
1.1.6 变量
SKILL的变量定义比较随便,不需要指定其类型,赋什么类型的值就是什么类型。
示例:变量名可以包含字母、数字、下划线以及问号,数字和问号不可以作为变量的第一个字符。不过为了规范编程和方便阅读,对于不同类型的数据的变量都使用简写的方式来代表,比如定义一个浮点数的变量,那么推荐使用f
作为前缀。如fPrice,lCoordinate,sMessage,iAge/nAge,bCheck...
f作为前缀。如fPrice,lCoordinate,sMessage,iAge/nAge,bCheck...
1.1.7 操作符
数学运算 +, -, *, /, ++, **
比较运算 >, =,
<=, ==
逻辑运算 ||, &&, !
赋值 =
1.1.8 输出数据
示例: %d --- integer,%f --- float,%s --- string,%L---多种数据格式
1.1.9 错误信息
像调试其它程序一样,调试SKILL 也需要仔细看清楚出错时的错误提示信息。 比如:
这个错误是说load命令没有定义,这个是新手长会碰到的一个问题,就是在Allegro
的cmd 接调试窗口直SKILL 函数,而实际上这是不行的,SKILL命令需要运行在SKILL
环境下,简单点就是在cmd口下输入窗skill回车,然后再load,如下所示:
这个错误是说类型不匹配,查阅SKILL Language Reference(sklangref.pdf)
会发现函数strcat 用操作字符串类型的数据。只适用操作字符串类型的数据。
1.1.10 总结
到目前为止,你应该对SKILL有一点基本的认识了。那么你会:
打开Allegro的SKILL调试窗口了吗?
知道有几种基本的数据类型吗?
知道怎么输出各种类型的数据吗?
知道怎么定义变量吗?你的变量容易被人阅读/识别吗?
找几个SKILL Language Reference里面的函数在调试窗口里面运行吗?
函数执行出现错误,知道问题出在哪里并会解决吗?
1.2 List数据类型
List是Cadence
SKILL中常用的数据类型。可以把List可以有多种类型的常量组成的列表。理解为一个数据结构表,它可以是空的,也可以有多种类型的常量组成的列表例如:
'( 1 2 a b c "PCB" )
在上面这个List中包含的数据有整数、字符、字符串。在List中也可以包含List类型的数据。 例如:
'( 1 ( 2 a a ) b )
1.2.1 创建List 数据
创建新的List数据可以用单引号 ' 或者函数list来新建一个List数据类型的变量。例如:
aList = '( 1 2 a b c) => (1 2 a b c)
bList = list( 1 2 'a 'b 'd) => (1 2 a b d)
cList = '( 1 ( 2 a a ) b ) => (1 (2 a a) b)
注意:当有字符出现的时候,用list 函数创建必须在字符前加单引号。
1.2.2 List 在内存中的储存方式
我们可以把List看做是一个List单元,其中一个List单元占用两个内存位置。这样便于理解。
第一个位置保存List的首个数据元素,第二个位置保存后面的List单元(除第一个元素之外的所有元素组成的表),它可以为空数据。
用car函数可以得到保存在第一个位置的List元素:car( aList) => 2
用cdr函数可以得到保存在第二个位置的List单元: cdr( aList) => (3 4)
List
中可以包含有子List,例如: bList = '( 1 ( 2 3 4 ) 5 ) => (1
(2 3 4) 5)
bList在内存中的储存方式如下图所示:
List中可以同时包含List 和字符,例如: bList = '( 1 ( 2 a a ) b )
=> (1 (2 a a) b)
bList在内存中的储存方式如下图所示:
1.2.3 读取List 元素
1) 读取List 中的第一个元素 使用car函数可以读取List中的第一个元素。例:
car( '(a b c) ) => a
z = '(1 2 3) => (1 2 3)
y = car(z) => 1
y => 1
z => (1 2 3)
car(nil) => nil
2) 读取List 中后面的List 单元 使用cdr函数可以读取List中后面的List
单元。 例:
cdr( '(a b c) ) => (b c)
z = '(1 2 3)
cdr(z) => (2 3)
3) 对List重复混合使用car 或者cdr 函数读取 car 和cdr 函数混合使用,组合的格式为:ca|d[ a|d ][
a|d ][ a|d ]r,以c 开头,r 中间可以由多个结尾, a 或d 组成函数。例如:caadr功能等同于car( car(
cdr( l_list))),caadr 对函数List的操作顺序为:
1. 先执行一次cdr,读取后面的List单元。
2. 对第1步读取的值,执行car,读取其第一元素。
3. 对第2步读取的值,执行car,读取其第一元素。
实例: caaar('(((1 2 3)(4 5 6))(7 8 9))) => 1
等同于car( car( car( l_list)))
caadr('(((1 2 3)(4 5 6))(7 8 9))) => 7 等同于car(
car( cdr( l_list)))
caar('(((1 2 3)(4 5 6))(7 8 9))) => (1 2 3)
等同于car( car( l_list))
cadr('(1 2 3)) => 2 等同于car( cdr( l_list))
4) 按元素序号读取List 中的元素 用nthelem
并输入所有读取的元素序号,即可读取该编号位置的元素。如nthelem(1 l_list)同于等car(l_list)。实例:
nthelem( 1 '( a b c ) ) => a
z = '( 1 2 3 )
nthelem( 2 z ) => 2
类似的函数还有nthcdr。实例: nthcdr( 3 '( a b c d )) =>
(d)
z = '( 1 2 3 )
nthcdr( 2 z ) => ( 3 )
5) 读取List 中最后一个List 单元 用last函数可以读取List
中最后一个元素单元,其数据类型也是一个List。实例:
last( '(a b c) ) => (c)
z = '( 1 2 3 )
last( z ) => (3)
1.2.4 修改List 单元
1) rplaca 函数 用rplaca函数可以替换List中的第一个元素。
aList = '( 1 2 3) => ( 1 2 3 )
bList = rplaca( aList 4 ) => ( 4 2 3 )
aList => ( 4 2 3 )
eq( aList bList ) => t
2) rplacd函数用rplacd函数可以替换List中后面的List单元。
aList = '( 1 2 3 ) => ( 1 2 3 )
bList = rplacd( aList '( 4 5 ) ) => ( 1 4 5 )
aList => ( 1 4 5 )
eq( aList bList ) => t
1.2.5 添加List 元素和合并List
1) 在List 前添加元素(cons,xcons) 用cons函数可以添加元素到List前。
aList = '( 2 3 4 )
aList = cons( 1 aList ) => (1 2 3 4 )
xcons 函数和cons 函数的功能一样,但格式有所区别,前面的变量为List素。,后面的变量为添加的元 xcons( '(
b c ) 'a ) => ( a b c )
2)在List 后添加元素(append1) 用append1函数可以添加元素到List后。
append1('(1 2 3) 4) => (1 2 3 4)
3) 合并List(ncons,append)
cList = '( 1 2 )
dList = '( 3 4 5 )
eList = '( 6 7 )
append( cList dList ) => ( 1 2 3 4 5 )
cList => ( 1 2 )
dList => ( 3 4 5 )
append函数只能合并两个List,并且不改变所合并List变量的值。
nconc( cList dList eList ) => ( 1 2 3 4 5 6 7
)
cList => ( 1 2 3 4 5 6 7 )
dList => ( 3 4 5 6 7 )
eList => ( 6 7 )
nconc函数可以合并多个List,但会改变所合并List 变量的值。
1.2.6 List元素排序
1) 倒序排列(reverse)
aList = '( 1 2 3 )
aList = reverse( aList ) => ( 3 2 1 )
anotherList = '( 1 2 ( 3 4 5 ) 6 )
reverse( anotherList ) => ( 6 ( 3 4 5 ) 2 1 )
anotherList => ( 1 2 ( 3 4 5 ) 6 )
2) 按条件排序(sort)
sort的书写格式为:sort(l_data
u_comparefn),其中第一个变量l_data为List量变量,第二个变u_comparefn为对比函数。对比函数也可以是自定义函数。
sort( '(4 3 2 1) 'lessp ) => (1 2 3 4)
sort( '(d b c a) 'alphalessp) => (a b c d)
sort('("U5" "U10" "U1" "U5" "U2") 'axlStrcmpAlpNum)
=> ("U1" "U2" "U5" "U5" "U10")
当List元素都是由List组成的时候,还可以使用sortcar函数对比子List的第一个元素排序。
sortcar( '((4 four) (3 three) (2 two)) 'lessp )
=> ((2 two) (3 three) (4 four)
sortcar( '((d 4) (b 2) (c 3) (a 1)) nil )
=> ((a 1) (b 2) (c 3) (d 4))
1.2.7 查找List 元素
1) member 函数
member 函数从List 到返回第一个元素查找到最后,如果找到返回找到的元素开始直到最后的元素,找不返回nil。
member( 3 '( 2 3 4 3 5 )) => (3 4 3 5)
member( 6 '( 2 3 4 3 5 )) => nil
2) assoc 函数
assoc函数的书写格式为:assoc(g_key
l_alist),g_key变量为所查找的关键值,l_alist是为一个由多个List组成的List,格式为:((key1
value1) (key2 value2) (key3 alue3) ...)。
assco返回查找到的子List。
aList = '(( 1 "one" )( 2 "two" )( 3 "three" ))
assoc( 2 aList ) => ( 2 "two" )
assoc( 5 aList ) => nil
1.2.8 过滤List 元素
1) 按条件过滤List 元素(setof) setof函数的书写格式为:setof( s_formalVar
l_valueList g_predicateExpression )其中, s_formalVar 变量为局部变量,作用于
g_predicateExpression 表达式中;l_valueList
变量为要过滤的List变量;g_predicateExpression变量为自定义表达式。setof函数会把l_valueList历赋值给变量中的所有元素,遍s_formalVar局部变量,带入到g_predicateExpression表达式中,如果表达式返回的值为nil输出的新,在List中会将其元素过滤。
setof( x '(1 2 3 4) (x > 2) ) =>
(3 4)
setof( x '(1 2 3 4) (x < 3) ) =>
(1 2)
setof( x '( 1 2 3 4 5 6 ) oddp(x)) => ( 1 3 5
)
2) exists 函数
exists 函数和setof 函数区别在于exists 函数查找List
余元素组成的新中满足条件的第一个元素,并返回其元素和其List。
exists( x '(1 2 3 4) (x > 2) ) =>
(3 4)
exists( x '(4 3 4 5) (x < 4) ) =>
(3 4 5)
exists( x '(1 2 3 4) (x > 4) ) =>
nil
3) forall 函数
forall函数判断List中所有的元素是否全部满足表达式,全部满足返回
t,不是就返回nil。
forall( x '(1 2 3 4) (x > 0) )=>
t
forall( x '(1 2 3 4) (x < 4) )=>
nil
forall( x '( 2 4 6 8 ) evenp( x ) ) => t
forall( x '( 2 4 7 8 ) evenp( x ) ) => nil
1.2.9 移除List 元素
1) remove 函数
remove函数可以移除List 中所指定的元素,如果List 中没有所指定的元素,那么返回原
List。remove 函数不会改变原List变量的值。
aList = '( 1 2 3 4 5 )
remove( 3 aList ) => ( 1 2 4 5 )
aList => ( 1 2 3 4 5 )
remove( '( 1 2 ) '( 1 ( 1 2 ) 3 )) => ( 1 3 )
1.2.10 遍历List 元素
1) foreach 函数
foreach( x '(1 2 3 4) println(x))
1
2
3
4
=> (1 2 3 4)
foreach( (x y) '(1 2 3) '(4 5 6) (println x+y))
5
7
9
=> (1 2 3)
2) mapc函数
mapc( 'list '(1 2 3) '(9 8 7) ) => (1 2 3)
mapc( '(lambda (x y) (print (list x y))) '(1 2 3) '(9 8 7) )
(1 9) (2 8) (3 7)
=> (1 2 3)
3) map 函数
map( 'list '(1 2 3) '(9 8 7) )
=> (1 2 3)
map( '(lambda (x y) (print (append x y))) '(1 2 3) '(9 8 7)
)
(1 2 3 9 8 7) (2 3 8 7) (3 7)
=> (1 2 3)
4) mapcar 函数
mapcar( 'plus '(1 2 3) '(9 8 7) )
=> (10 10 10)
mapcar( 'list '(a b c) '(1 2 3) '(x y z) )
=> ((a 1 x) (b 2 y) (c 3 z))
mapcar( 'lambda( (x) plus( x 1 )) '(2 4 6) )
=> (3 5 7)
5) maplist 函数
maplist( 'length '(1 2 3) )
=> (3 2 1)
maplist( 'list '(a b c) '(1 2 3) )
=> (((a b c)(1 2 3))((b c)(2 3))((c)(3)))
6) mapcan 函数
mapcan( 'list '(1 2 3) '(a b c) )
=> (1 a 2 b 3 c)
mapcan( (lambda (n) (and (plusp n) (list n))) '(1 -2 3 -4
5))
=> (1 3 5)
1.2.11 遍历List 元素实例
1) 得到List 中字符串的长度
假设,有一个由字符串元素组成的List变量stringList:
下面写一段代码,它的功能是输出stringList中每个字符串元素的字符长度:
如果在没有熟悉mapcar函数的情况下,可能会使用以下代码:
使用mapcar函数的代码:其实mapcar函数就已经包含遍历List的功能,可以简化代码如下:
2) 将List 中的所有元素(包括子List 中的元素)重新组合成新List
假设,有一个由List组成的List变量x:
下面写一个函数flatten,它的功能是将List中的所有元素重新组合成新List,如下:
下面用mapcan函数,代码如下:
但上面的代码有一个问题,它改变了x变量的值,运行flatten( x )后,x的值如下:
可以使用copy函数复制List副本来避免改变原list值,代码:
上面的代码运行结果如下:
3)将List中的所有元素(多重List)重新组合成新List
假设,有一个由List和多重List组成的List变量x:下面写一个函数flatten,它的功能是将List中的所有元素重新组合成新List,如下:可以重复调用自身函数来解决多重List读取的难题,代码如下:
1.3流程控制
注:下面的一些示例包含多行语句,但是allegro的skill调试窗口不支持多行的调试,所以多于多行的情况,要么把所有的代码重新编辑为一行,或者将代码放到一个文件里面,采用第一章里面说的load
的办法来调试。
1.3.1 逻辑值(t, nil)
在第一节说到关系操作和逻辑操作,结合这些操作和条件选择及循环控制命令可以选择程序运行。关系操作和逻辑操作的结果是真值或假值,前面说到
skill 的 boolean 型数据有 2 种,一种是 t
表示真值,一种是nil表示假值,其实skill中把一切非nil的结果都当作真值,而不是仅仅局限于t。
1.3.2 分支控制
1.3.2.1 单分支命令(when, unless)
when( bCondition ; bCondition 为逻辑表达式,nil或其它(真值)
expressions ; bCondition 为真的时候执行when 里面的命令
)
示例 nCount = 5
when ( nCount>=5
println(“nCount is no less than 5”)
)
=>“nCount is no less than 5”
unless( bCondition
expressions ; bCondition为假(nil)的时候执行unless里面的命令
)
示例 nCount=5
unless( nCount<5
println(“nCount is no less than 5”)
)
注意到when和unless的2个示例的区别了吗?其实when==(!unless),也就是说when在condition
为
真的时候执行内部的表达式,而unless是在condition 为假的时候执行表达式。unless算是when的一
个补充,判断nil的情况比用wehn要简洁。
1.3.2.2 双分支命令(if)
if( bCondition then
exp1 ;bCondition 为真的时候执行
else
if( bCondition then exp1 ;bCondition为真的时候执行 else
exp2 ;bCondition 为假的时候执行
)
示例 nAge=17
if( nAge<18 then
print(“E- not 18 years old, can not watch this movie!\n”)
else
print(“I- enjoy the movie!\n”)
)
=>“E- not 18 years old, can not watch this
movie!”
如果用when来写的话,就要写2个when 语句。
when(nAge<18
print(“E- not 18 years old, can not watch this movie!\n”)
)
when( nAge>=18
print(“I- enjoy the movie!\n”)
1.3.2.3 多分支命令(cond,case)
sSymbol = “test”
cond( ( !sSymbol println(“it is nil”))
( numberp(sSymbol) println(“it is a number”))
( stringp(sSymbol) println(“it is a number”))
( t println(“I do not care the type”)
); end cond
=> it is a string。
cond
命令里面有多个程序块,程序会逐个判断里面各个块里面的程序,然后退出块的条件,直到找到一个逻辑为真的块,执行cond。cond就像是
if then else的多次叠加。 case(type(sSymbol)
( “fixnum”
println(“it is a number”)
)
(“floatnum”
println(“it is a float num”)
)
(“string”
println(“it is a string”)
)
);end case
=> it is a string
case 命令里面也有多个程序块,程序会判断case 条件的程序块。后面的那个表达式满足其中的哪个条件,只执行满足
case和cond的区别在于cond中的判断表达式可以不唯一,而
case只判断一个表达式。比如:
cond( ( numberp(“a”) println(“a number”))
( 5>=3 println( “it is true”))
( t println(“nothing”))
); end cond
=> “it is true”
这里有3个条件表达式,第一个是
numberp(“a”),如果是真值就执行后面的println命令;第二个5>=3
如果是真值就执行后面的, println命令;第三个是t,如果之前的表达式没有真值的,就会执行这部分的println语句。
1.3.3 循环控制(while,for,foreach)
while( bCondition
expressions ; bCondition
非nil的时候一直重复执行while里面的命令行 ) 示例:
nCount=10
while( nCount>0
printf( “it is %d now\n” nCount )
nCount--
)
=>it is 10 now
…
It is 1 now
while命令和C 语言的很相似。
for( nStep 1 10
printf( “it is %d now\n” nStep )
)
=> it is 1 now
…
It is 10 now
For命令的索引只可以递增,不可以像C语言中那样支持递减。 foreach( item alist ; alist
是个list expr ; alist里面有多少个元素,就执行多少遍 )
foreach( item ‘(“a” “b” “c”)
println(item)
)
=>“a”
“b”
“c”
1.3.4返回命令(return)
用prog和return命令组合可以实现从prog程序块中跳出。
prog(
(local variable)
expressions…
)
prog
的一个作用是定义局部变量,还有一个函数有同样的定义局部变量的功能let,语法格式也一样。不同的是prog支持return
直接跳出,而let不支持。单单使用局部变量的功能,那么let的效率比prog
高。比如说从一个for循环里面跳出,采用下面的方法是不行的,skill不支持。
for(nNum 1 20
when( nNum > 10
return( nNum )
) )
必须要在for之前加上一个prog,如下:
prog( ()
for(nNum 1 20
when( nNum > 10
return( nNum )
) ) )
=>11
如果要获得这个返回值,可以将上面这段代码赋值给一个变量,比如:
nCount = prog( ()
…
)
nCount=>11
1.3.5 总结
本章主要介绍了流程控制的命令,学习了以后请尝试使用每一个流程控制命令各写一段代码。
when,unless,if,case,cond,while,for,foreach,prog,return。
1.4 函数
1.4.1 程序块
把多行skill语句放到一个{}中形成一个程序块,这样的一个程序块就像单行skill程序一样,可以赋值。这个功能和前一节说的prog,let类似。比如:求一个线段的长度,线段两头有2个坐标(x,
y) lStardEnd = list(0:0 50:50) fLength = { lStartPoint = car(
lStartEnd ) ; list 操作,得到(0 0) lEndPoint = cadr( lStartEnd )
;得到原
list的第二个坐标(50 50)
sqrt((xCoord(lStartPoint)-xCoord(lEndPoint))**2+(yCoord(lStartPoint)-yCoord(lEndPoint))**2)
; xCoord, yCoord
分别得到坐标的x,y; ; ** 是幂运算 ; sqrt是求平方根 } 这个用let来写就是这样:
lStardEnd = list(0:0 50:50)
fLength = let( ( lStartPoint lEndPoint ) ;
定义为局部变量
lStartPoint = car( lStartEnd )
lEndPoint = cadr( lStartEnd )
sqrt((xCoord(lStartPoint)-xCoord(lEndPoint))**2+(yCoord(lStartPoint)-yCoord(lEndPoint))**2)
)
在{}和let里面的都叫做程序块,但是更推荐用let的方式,使用局部变量。用不用{}方式来写,是个人的习惯,有个{}可能模块看起来更明显,便于阅读。不用{}的写法:
lStardEnd = list(0:0 50:50) lStartPoint = car( lStartEnd )
lEndPoint = cadr( lStartEnd )
fLength
=sqrt((xCoord(lStartPoint)-xCoord(lEndPoint))**2+(yCoord(lStartPoint)-yCoord(lEndPoint))**2)
1.4.2 函数定义
定义函数的最常用的关键字是procedure(不推荐defun),一般的函数格式为: procedure(
func_name(input_para) let( (local variable)
;如果需要支持多种返回值的情况,也就是需要return命令,请使用prog。
skill expressions
); end let
)
上面的那个计算线段程度的程序块加上一个procedure语句结构就可以成为一个函数了,比如 procedure(
CalcLength( lStartEnd ) ; 定义函数名为CalcLength,输入参数为StartEnd
let( ( lStartPoint lEndPoint ) ; 定义2个局部变量
lStartPoint = car( lStartEnd )
lEndPoint = cadr( lStartEnd )
sqrt((xCoord(lStartPoint)-xCoord(lEndPoint))**2+(yCoord(lStartPoint)-yCoord(lEndPoint))**2)
; let程序块的返回值为程序块最后一行执行的结果
); end let
); end procedure CalcLength
lBox = list(0:0 50:50) ; 定义一个能被CalcLength使用的变量
fLength = CalcLength(lBox) ;
调用函数CalcLength,输入参数是lBox,返回结果赋值给fLength
1.4.3 局部变量和全局变量
每种编程语言都会说到这2种变量类型,简单点来说,局部程外好相面序执反的行,程的所序过有是程的不知中程道就序有会都产这可生样以错的使误变用。量这所存个以在变最的量安,,全如所果的以做不不法同会是的有尽程变量序量变重使定量名用义只导局了在相致部其同程变定名序量义,出字的尽但错函量是的数少功问或用能题程不;全序而同局块全的变里局全量面。变局起量变作则量用,正前面提到了prog和let函数结构本身包含了定义局部变量的部分。另外for,foreach是局部变量,作用域在里面用到的自变量也for和foreach
范围之内。 foreach( item ‘( 1 2 3) ; 这里的item是局部变量, … ) ; ;
item在这个括号之前有效 println(item) ; 会提示变量不存在的错误。
1.4.4 函数调用与返回值
根据函数定义的格式来调用函数,比如函数strcat,它的函数格式为 strcat( S_string1 [ S_string2
... ] ) => t_result
输入参数是字符串类型,需要至少一个字符串作为输入,所以调用这个函数就strcat(“ab” “cde”)
=>”abcde”。获取返回值其实就是把返回值赋值给新的变量,比如上面的例子,可以把strcat
赋值给另一个变量。函数返回的新的字符串sNew = strcat(“ab” “cde”);
sNew=>”abcde”。
1.4.5 总结
定义一个找出字符串list中最长的字符串并返回该字符串及字符串的长度的函数
1.5 文件操作
1.5.1文件操作
Skill 的文件操作支持对简单文件的写入和读出,基本步骤为打开一个文件 I/O
端口,然后用相应的命令读数据或写数据。infile命令用于产生读取文件的端口,然后用gets或者fscanf操作读取;outfile命令用于创建打开文件写入的端口,然后用fprintf输出数据到该端口。数据操作完毕,最后一步就是关闭打开的I/O
端口。
1.5.2读文件(infile, gets, fscanf)
pFileIn = infile(filename)
=> port:filename
这里的 pFileIn 就是个读文件的端口(port), gets(sLine pFileIn)
=> 从 pFileIn端口读入一行,也就是从 filename
文件里面读一行,包括换行符,读到的值存储在 sLine 里面。如果读到了文件的末尾,没有数据了,那么返回值为
nil。读取完毕以后要关闭这个打开的端口,close(pFileIn)。 从文件端口读数据的命令除了 gets 还有
fscanf,区别在于 gets 整行读取,读入的数据被当作字符串处理,而fscanf
则需要根据文件本身的格式来读取,读入的数据可以有数字,字符串等等。 fscanf( pFileIn “%s” sWord ) 从
pFileIn端口读入一个字符串,如果一行中数据为 abc def ght,那么 sWord=”abc”。
1.5.3写入文件(outfile, fprintf)
pFileOut = outfile(filename) =>创建一个输出文件的端口;
fprintf( pFileOut “%d %s\n” 15 “abc” ) => 输出数据到文件
filename;
close(pFileOut) => 关闭该文件端口
现在打开文件的话,就会看到文件中有一行数据 15 abc。
其它 print 命令也支持输出数据到文件,但是为了程序的清晰起见,还是只推荐使用 fprintf命令输出数据到文件。
1.5.4总结
Allegro
用户的report命令可以产生很多种的log文件,请挑一种尝试读取文件里面的信息,然后处理这些信息,并将处理后的信息输出到另一个文件中。