來源:eetop bbs 作者:天牛不唱歌
注:skill相關(guān)的一些腳本已經(jīng)整理在腳本區(qū):
http://bbs.eetop.cn/viewthread.php?tid=590022
首先要感謝各位對于之前”LNA學(xué)習(xí)歷程“的頂貼,不過話說回來,轉(zhuǎn)眼回頭看之前自己寫的歷程感覺還是不成熟的很,還望各位大大不要笑話呵呵。~~~~~~~ ~~~下面很大部分來自于壇子,有小部分總結(jié)呵呵,直接貼出來了,算是偷工減料的總結(jié)吧。。。
也是剛學(xué)習(xí)不久,為了先騰出點(diǎn)地方自己以后接著寫,所以先占下了2~5樓的位置,大家勿怪呀!??!
SKILL語言有點(diǎn)類似于C語言,是Cadence公司的程序接口語言,也就是說我們平時(shí)用的Virtuoso,Spectre,Assura,Calibre,工藝庫等等都是用skill寫的。Skill可以大,當(dāng)然可以小,譬如一條簡單的skill語句就可以實(shí)現(xiàn)一個(gè)快捷鍵。這就是說,暫且不提skill那些高大上的功能,就憑可以幫助我們快速完成一些批量小任務(wù)來講,skill也是值得我們學(xué)習(xí)一下的。 對于Skill,cadence公司并沒有放出來太多的demon或者說example,對于俺們這樣的小白來說,學(xué)習(xí)要略顯困難一些,還好cadence對于skill給出來許多 user guide 和manual。這些manual里面給出了各個(gè)函數(shù)的參數(shù)和返回值。對于這些manual,論壇里和google都可以搜到。 壇子里也有一些關(guān)于skill使用的教程,尤其推薦一下純粹版圖網(wǎng),里面nfmao大大總是會(huì)放出一些有用的skill代碼,非常實(shí)用O(∩_∩)O~。這些manual不必親力親為的都看一遍,話說實(shí)在太多了。。。
雖然壇子里也是高手如云,不過放出來的代碼還是顯得吝嗇了點(diǎn),呵呵。
SKILL腳本一般是用.il和.ile結(jié)尾的文件,其中 .ile結(jié)尾的文件是加密的,調(diào)用時(shí)候需要密碼。
SKILL代碼的使用有兩種方式:1.在家目錄里的 .cdsinit 文件里寫入 load "***.il" 2.在CIW窗口輸入 load "***.il" 。
凡是實(shí)踐為準(zhǔn)!
/////////example 1////////
ZOOM.zip (235 Bytes)
把上面的附件解壓是把鼠標(biāo)滾輪設(shè)置為放大縮小的快捷鍵的skill——“ZOOM.il"
打開icfb &后,在CIW窗口輸入 load ”路徑/ZOOM.il" 后在原理圖和版圖中我們就可以實(shí)現(xiàn)縮放了。
如果我們將load "路徑/ZOOM.il" 這句放到家目錄的.cdsinit文件下,那每次我們啟動(dòng)icfb,都可以實(shí)現(xiàn)鼠標(biāo)滾輪進(jìn)行縮放了!
上面只是個(gè)簡單的例子,只是為了有個(gè)朦朧的認(rèn)識,真正學(xué)習(xí)一門語言先看看這個(gè)語言基本變量、函數(shù)、操作符是怎么定義怎么使用還是很有必要的,所以強(qiáng)烈推薦先看一下Skill 基本語法的user guide
Skill Language User Guide.pdf (2.27 MB)
之前學(xué)過C語言也就對skill的語法木有多大陌生感了,對于變量,函數(shù),操作符的運(yùn)算有些二者是一樣的,下面主要說說二者不同的地方,些許記憶就好了:
1. skill 使用t 和nil 兩個(gè)單詞表示 真假。
2.skill里的字串或者集合用list表示,字串的定義用list來聲明或者用一個(gè)符號 ' 來聲明,二者部分情況下是通用的,但是有時(shí)候還是不同的,這個(gè)大家就要看語法了。對于list字串或者集合來說,有很多現(xiàn)成的函數(shù),譬如計(jì)算這個(gè)字串包含元素的個(gè)數(shù),合并字串,找到第n個(gè)元素。
3.注意使用基本的關(guān)系運(yùn)算符和邏輯運(yùn)算符
4.注意 if,when,unless,case,cond,for,foreach幾個(gè)經(jīng)常用的函數(shù)的使用方法
5.注意print,println,printf幾個(gè)函數(shù)的使用方法,尤其是格式化輸出printf,對于只學(xué)習(xí)了C++而沒有學(xué)習(xí)c的朋友可能要費(fèi)點(diǎn)心看一下了。
6.注意怎樣用fprint和gets,fscanf寫入和讀取文件內(nèi)容
7.用procedure定義函數(shù)的方法,其中 @reset ,@optional, @key幾種決定參數(shù)傳遞的方式有什么不同。
8.用let和prog定義局部變量的方式以及二者的不同
9.知道一些常用的函數(shù)如abs,round,sqrt,random,zerop是什么含義,返回值是什么類型。
結(jié)合上面9個(gè)問題看skill的語法 user guide 那是真正學(xué)習(xí)skill 的第一步。一定要好好看一下。估計(jì)要用上兩天以上的時(shí)間吧??偸且冻鳇c(diǎn)努力的 你說對吧?。?br style="word-wrap: break-word;">正如蓋一座房子需要一個(gè)根基,skill language user guide就是這個(gè)根基,但是正如偉大的c語言一樣,它可以用在桌面編程,也可以用在嵌入式編程,還可以用來做操作系統(tǒng),那它是否就需要包含n多函數(shù),n多接口呢?
答案顯然是否定的,我們學(xué)習(xí)的c語言只是basic c ,就是c語言的基本語法而已,對于一些特殊接口,俺們是要再根據(jù)具體應(yīng)用而特殊擴(kuò)展的,哈哈,同樣我們學(xué)習(xí)的skill language user guide只是skill語言的基本語法框架而已。根據(jù)在仿真應(yīng)用,原理圖應(yīng)用,版圖應(yīng)用,工藝庫應(yīng)用,cadence都擴(kuò)展制作了很多接口函數(shù)。這些接口函數(shù)使skill可以在cadence框架里發(fā)揮更大的作用。這些擴(kuò)展的函數(shù)也是一些user guide
tiger_lein老兄已經(jīng)上傳了這方面的userguide:
http://bbs.eetop.cn/thread-280627-1-1.html這里也傳這個(gè)附件吧:
skill manual大合集.zip (9.16 MB)
話說這些user guide不是一般的多呀,大家看的時(shí)候開始粗略看一下就好。。。花太多的精力反而沒有太多必要。
一、簡介
1.1 Skill語言起源
Skill語言是Cadence公司開發(fā)的,但是Skill語言的前身可以追溯到LISP語言,在延續(xù)了LISP語言的特性的同時(shí),Skill語言也融合了先進(jìn)C語言的優(yōu)點(diǎn)。所以Skill語言的語法結(jié)合了這二者的有點(diǎn),同時(shí)有的語法也產(chǎn)生了兩種書寫風(fēng)格。譬如(注:這兩個(gè)程序先不用去理解,注意代碼風(fēng)格即可):
程序一:
procedure(fibonacci(n)
if( (n == 1 || n == 2) then
1
else fibonacci(n-1) + fibonacci(n-2)
)
)
程序二:
(defun fibonacci(n)
(cond
((or (equal n 1) (equal n 2)) 1)
(t (plus (fibonacci (difference n 1))
(fibonacci (difference n 2))))
)
)
第一種是代數(shù)表示法,這種方法的形式如 func( arg1 arg2 ...),該表示方法在大多語言里都被采用。另外一種是前綴表示法,類似于LISP語言,即 (func arg1 arg2 ...)這樣的表述形式。這里可以看到類似Lisp語言的表示法后面有很多右括號,而且函數(shù)和參數(shù)容易混淆,所以一般推薦還是用常用的類C語言代數(shù)表示法
1.2 Skill語言的作用
Cadence提供給用戶豐富的Skill語言接口,用戶可以使用Skill來控制Cadence軟件實(shí)現(xiàn)各種功能,譬如定制自己的cadence軟件設(shè)置,進(jìn)行Cadence批量操作,甚至根據(jù)自己需要開發(fā)Cadence相關(guān)插件或者工具軟件(譬如:我們經(jīng)常用的Calibre,Assura等軟件就有大量Skill腳本與Cadence軟件來通信)。
Skill可以大,當(dāng)然可以小(譬如書寫一條簡單的Skill語句就可以實(shí)現(xiàn)設(shè)置某個(gè)快捷鍵的目的)。Skill功能的強(qiáng)大有時(shí)候超出我們的想象,但Skill的入門又非常的簡單,學(xué)習(xí)Skill對于一般工程師來講,經(jīng)常用到的就是用它來幫助我們快速完成一些批量小任務(wù),這極大提高了我們工作的效率。僅此一點(diǎn)Skill也是值得我們學(xué)習(xí)一下的,更不要說通過進(jìn)一步的學(xué)習(xí)我們還能完成那么多高大上的功能。
1.3 Skill腳本的簡單使用
Cadence對于skill語言的支持是無所不在的,我們可以從菜單欄,快捷鍵,程序函數(shù),表格,以及CIW窗口等不同的渠道來觸發(fā)執(zhí)行已加載的Skill腳本程序。
一般加載自己的SKILL代碼文件一般有兩種方式:
① 在家目錄里的 .cdsinit
文件里寫入 load "***.il"
這樣,Cadence在啟動(dòng)后就會(huì)自動(dòng)加載該Skill代碼了。
② 在CIW窗口輸入 load "***.il"。
這種手動(dòng)的加載,一般只對當(dāng)前起作用,會(huì)在下一次啟動(dòng)Cadence就失效了。當(dāng)然我們也可以把 ***.il內(nèi)的內(nèi)容直接復(fù)制到CIW窗口并回車,效果是一樣的。
注:雙引號內(nèi)的文件路徑要設(shè)置正確才能load成功。
譬如下面的幾行skill腳本,我們新建zoom.il文件,并把下面四行代碼復(fù)制到該文件,然后在Cadence的CIW里按照漆面說的第二種方法load該文件,我們就在原理圖和版圖里實(shí)現(xiàn)了用鼠標(biāo)中鍵控制視圖縮放的功能。這樣我們就算有了自己的第一個(gè)非常實(shí)用的Skill腳本,并且我們知道如何使用它了。
hiSetBindKey("Layout""<Btn4Down>" "hiZoomInAtMouse()");
hiSetBindKey("Layout""<Btn5Down>" "hiZoomOutAtMouse()");
hiSetBindKey("Schematics""<Btn4Down>" "hiZoomInAtMouse()");
hiSetBindKey("Schematics""<Btn5Down>" "hiZoomOutAtMouse()");
1.4 Skill腳本的加密
對于某些工程師而言,希望把自己的Skill腳本提供他人使用的同時(shí),也希望保護(hù)自己的Skill腳本,不被別人亂改或者把源碼傳播,那就需要對腳本加密。
Skill腳本一般是用.il和.ile結(jié)尾的文件其中.il是普通文本文件,用文本編輯器可以直接打開,.ile結(jié)尾的文件是加密的,用文本編輯器是打不開的。
當(dāng)我們寫好自己的Skill腳本后,可以在CIW窗口用encrypt()函數(shù)來加密譬如
encrypt(“zoom.il” “zoom.ile” “abc123”)
這樣就會(huì)把zoom.il 加密成zoom.ile文件了,并且密碼是abc123.加密后的文件使用密碼也是不能看到源代碼的。而且在加載使用zoom.ile的時(shí)候是需要提供密碼的。譬如:(注:一般最好用文件的絕對路徑進(jìn)行操作,否則可能會(huì)找不到文件)
load "zoom.ile" “abc123”
注:盡管Linux系統(tǒng)中文件的擴(kuò)展名一般不影響文件的使用,但是為了區(qū)分我們還是在文件命令的時(shí)候遵從一定的規(guī)則讓未加密的文件后綴是.il,讓加密的文件以.ile結(jié)尾。
對于用encrypt加密的文件,但是如果沒有密碼的話,是可以用lineread函數(shù)配合pprint函數(shù)來獲得源代碼的。load下面函數(shù)后使用NlDecrypt(“123.ile”) 就可以恢復(fù)出來源碼了,這個(gè)方法可以用來學(xué)習(xí)別人的源碼。
procedure( NlDecrypt( inputFile @optionaloutputFile "tt")
prog( (inp out line)
if( inputFile then
unless( outputFile
outputFile = sprintf(nil"%s.dec" inputFile)
)
when( isFile( outputFile )
print( "You must specify a file thatdoesn't exist!!!\n" )
hiGetAttention( )
return()
)
unless( inp = infile(inputFile)
printf("Unable to open input file:%s\n" inputFile)
return()
)
unless( out = outfile(outputFile"w")
printf("Unable to open output file:%s\n" outputFile)
return()
)
while( line = lineread(inp)
when( line != t
pprint(line out)
)
)
close(inp)
close(out)
else
printf("You must at least specify aninput file!\n")
return()
) ; ** if inputFile **
return(t)
) ; ** let **
) ; ** procedure **
1.5 關(guān)于.cdsinit和.cdsenv文件
前面說到可以把加載Skill腳本的語句放到.cdsinit文件里,這樣每次啟動(dòng)Cadence就能自動(dòng)加載該腳本了。這里我們要說一下icfb或virtuoso 啟動(dòng)有兩個(gè)重要文件就是 .cdsinit和.cdsenv文件(文件名以點(diǎn)開始的在Linux下認(rèn)為是隱藏文件)。我們每次啟動(dòng)Cadence軟件,都會(huì)加載這兩個(gè)文件,它們一般負(fù)責(zé)cadence的初始設(shè)置和一些用戶自定義設(shè)置,其中
.cdsinit主要負(fù)責(zé)一些加載項(xiàng)的設(shè)置,
.cdsenv主要負(fù)責(zé)一些環(huán)境變量或者參數(shù)的設(shè)置,
兩者功能有一些交叉,在有的時(shí)候都能完成某個(gè)設(shè)置。譬如:我們點(diǎn)擊CIW的退出后,會(huì)彈出來是否要真的退出,如果我們不想讓軟件彈出來這個(gè)詢問的窗口我們可以在.cdsenv里這樣設(shè)置,
ddserv.ciw promptOnExit boolean nil
同樣我們在.cdsinit里也可以進(jìn)行設(shè)置來完成這個(gè)功能,如下用.cdsinit的設(shè)置和上面用.cdsenv的設(shè)置功能是等效的。
envSetVal ("ddserv.ciw" "promptOnExit" 'boolean nil)
注:Skill有個(gè)專門設(shè)置變量的函數(shù)envSetVal()。
關(guān)于.cdsenv的設(shè)置我們可以在CIW窗口->option->save default里導(dǎo)出當(dāng)前的cdsenv然后進(jìn)行分析學(xué)習(xí)等。(注:在cdsenv我們一般會(huì)對字體,格點(diǎn),加載工藝庫,數(shù)字的有效位數(shù)等進(jìn)行一些個(gè)性化的設(shè)置。且cdsenv每行一般分成四部分:大項(xiàng),小項(xiàng),類型,值)。
這里我們就不過多說明.cdsenv文件了。把重點(diǎn)放在.cdsinit文件,因?yàn)?/span>.cdsinit文件里的設(shè)置,除了可以完成cdsenv的功能外,還可以完成很多其它功能。另外補(bǔ)充一點(diǎn),Cadence啟動(dòng)一般會(huì)最先在啟動(dòng)目錄尋找.cdsinit文件,如果找到就加載,如果沒有找到會(huì)到用戶的家目錄去尋找,如果還沒有找到,應(yīng)該會(huì)軟件安裝的某個(gè)目錄下去尋找。
注:如果當(dāng)前啟動(dòng)目錄能找到.cdsinit文件,軟件就不會(huì)自動(dòng)去加載家目錄下的.cdsinit文件了。
1.6 Skill語言的學(xué)習(xí)方法
Skill語言分為兩部分,一部分是skill標(biāo)準(zhǔn)語法,另一部分是Cadence內(nèi)置的關(guān)鍵字和接口函數(shù)。
對于Skill語言,Cadence公司并沒有放出來太多的Demon或者Example,對于俺們這樣的小白來說,學(xué)習(xí)要略顯困難一些,還好Cadence對于Skill語言給出來許多 User Guide 和manual等幫助文檔。的manual里面給出了可以被Skill調(diào)用的Cadence的各個(gè)接口函數(shù)的定義和返回值。對于這些Manual,eetop論壇里和Google都可以搜到。eetop論壇里也有一些關(guān)于skill使用的教程,在早前我會(huì)尤其推薦一下純粹版圖網(wǎng),里面nfmao大大總是會(huì)放出一些有用的skill代碼,非常實(shí)用,但目前該網(wǎng)站應(yīng)該是關(guān)閉了。
對于一般學(xué)習(xí)者,Skill標(biāo)準(zhǔn)語法的manual是必須先要學(xué)習(xí)的,然后再去熟悉一下cadence紛繁重雜的接口函數(shù),本書也秉承這樣的學(xué)習(xí)順序進(jìn)行講解。另外對于cadence的函數(shù)實(shí)在太多,一般我們沒有必要全部去看一遍,只需要對于這些函數(shù)的分類要有了解,對于關(guān)鍵的經(jīng)常用的函數(shù)要記憶一下即可,假如我們遇到一些接口函數(shù)不太了解它的定義和使用方法的時(shí)候,我們可以有三種方式查看該函數(shù)的定義和使用方法:
①最簡單的方法,看~/CDS.log文件或者CIW的輸出區(qū)域。首先我們要把Options->LogFilter都選上,這樣我們進(jìn)行任何操作,在CIW窗口或者log文件下都會(huì)顯示當(dāng)前操作所用到的函數(shù),譬如添加器件刪除器件等操作使用的接口函數(shù),我們一目了然。
②在CIW里輸入命令startFinder,或者在Terminal上輸入cdsFinder& . 我們就打開了函數(shù)搜索器,如果我們想知道某個(gè)函數(shù)的大概作用和使用方法,我們可以在這里進(jìn)行查詢,或者我們只知道函數(shù)的部分名字,也可以通過匹配搜索,找到包含該字串的函數(shù)。
③上面我們查到的關(guān)于函數(shù)用法的介紹很簡單,如何知道其詳細(xì)介紹呢。當(dāng)然如果你知道函數(shù)在那個(gè)文檔里,直接打開就行了,如果不知道,就需要打開help的search功能,這里可以查到詳細(xì)的功能用法。運(yùn)行cdsdoc&, 點(diǎn)擊Search打開Cadence help的搜索功能。高的版本已經(jīng)改為cdnshelp& 命令了,但是原理都是一樣的。另外有可能端口或者/etc/hosts的設(shè)置導(dǎo)致連不上help?;蛘吣承┓峭暾娴腃adence軟件,有可能為了縮小軟件尺寸會(huì)將doc的內(nèi)容刪除了,所以運(yùn)行cdsdoc命令也會(huì)出錯(cuò)。建議安裝cadence官方版。另外我們也可以將所有skill的manual下載后,用pdf軟件進(jìn)行查看搜索我們所需的接口函數(shù)。
從簡入繁,不斷用小實(shí)例小的成功激勵(lì)自己,這是快速穩(wěn)固學(xué)習(xí)的不二法門,本書也會(huì)按照這樣的結(jié)構(gòu)和宗旨去書寫,所以本書非常適合Skill學(xué)習(xí)愛好者通讀,精讀,也是最好的Skill入門教程,沒有之一。
二、Skill基本語法
Skill語言的很多地方和C語言差不多,如變量,函數(shù),控制結(jié)構(gòu),輸入輸出等,但二者的某些內(nèi)置函數(shù),操作符等也會(huì)有一些區(qū)別,學(xué)習(xí)的時(shí)候可以有意識的記憶一下二者的不一樣的部分。對于Skill這里只作簡單介紹。詳情可以參考SKILL Language UserGuide。
2.1 Skill的變量
Skill的變量最大的特點(diǎn)是不需要事先聲明,Skill第一次用到是會(huì)自動(dòng)生成變量。變量可以由字符、數(shù)字、“_” 和 “?” 組成,注意第一個(gè)字符不能是數(shù)字和”?”。由于Cadence所開發(fā)的Skill中的變量、函數(shù)都是第一個(gè)字母小寫,以_為開頭的是Cadence的專用函數(shù),為了避免沖突,所以建議大家函數(shù)和變量命名都以大寫字母開頭。
2.2 Skill的函數(shù)的調(diào)用
Skill的函數(shù)的調(diào)用方式有三種,以Skill內(nèi)置的字串連接函數(shù)strcat為例:
strcat("Hello" "," " everyone" "!" ) ;常見的類C格式
(strcat "Hello" "," " everyone" "!" ) ;類Lisp語言的格式
strcat"Hello" "," " everyone" "!" ;上面的括號可以省略
上面三種方式的返回的結(jié)果都是=> "Hello, everyone!"
推薦使用第一種方式,需要注意的是函數(shù)和第一個(gè)括號之間沒有空格,否則會(huì)報(bào)錯(cuò)
如: strcat ("Hello" "," " everyone" "!" );會(huì)產(chǎn)生如下錯(cuò)誤!
=>*Error* eval: not a function - "Hello"
2.3 list數(shù)據(jù)格式
list是Skill繼承Lisp(list Processing)而來,它是Skill編程中經(jīng)常用到的。對于list,它有點(diǎn)類似于C語言中的數(shù)組,數(shù)據(jù)內(nèi)容是有序的,但是它并不是數(shù)組(要知道Skill本身是有數(shù)組的類似定義和使用方法和C也是基本一樣的),而更像是一個(gè)集合,它的數(shù)據(jù)對象可以是Skill中各種數(shù)據(jù)格式,所以我們經(jīng)常給list定義就是“skill數(shù)據(jù)對象的一個(gè)有序集合”。skill數(shù)據(jù)甚至程序本身都可以看作是一個(gè)list,這是C語言中所沒有的概念。下面是skill list形式的幾個(gè)簡單例子,對于list的操作我們之后再講。
(1 2 3) ;這是一個(gè)list 包含1 2 3 三個(gè)元素
(1) ;這個(gè)list只包含一個(gè)元素1
( ) ;一個(gè)空的list等同于nil
(1 (2 3) 4) ;這個(gè)list的第二個(gè)元素也是一個(gè)list。
2.3.1 創(chuàng)建list的方法
創(chuàng)建list有以下幾種基本的方法,譬如:用操作符'
或者用list()函數(shù)。另外我們可以用cons函數(shù)把指定元素添加到list中或者用append來合并兩個(gè)list。下面舉例說明,并說明他們的區(qū)別。
1).用 ' 和 list 定義一個(gè)list,注意兩者的差別,即list函數(shù)會(huì)把變量的值以實(shí)際的內(nèi)容代替。
a = 1 => 1
b = 2 => 2
'( a b 3 ) => ( a b 3 )
list( a b 3 ) => ( 1 2 3 )
2).用cons命令添加一個(gè)元素到一個(gè)list的頭部
result = '( 2 3 ) => ( 2 3 )
result = cons( 1 result ) => ( 1 2 3 )
3).用append命令合并兩個(gè)list
lista = '( 4 5 6 ) => ( 4 5 6 )
listb = '( 1 2 3 ) => ( 1 2 3 )
listc = append( lista listb) => ( 4 5 6 1 2 3 )
2.3.2 訪問list或list中元素的方法
對于list中元素的訪問是,list的基本操作,Skill提供了很多內(nèi)置的list操作的函數(shù)。使用這些函數(shù),不僅讓代碼簡潔,也增加了程序的可讀性。
car()函數(shù)用于訪問list的第一個(gè)元素。
numbers = '( 1 2 3 ) => ( 1 2 3 )
car( numbers ) => 1
cdr()函數(shù)訪問list除了第一個(gè)元素外的其他元素,注意返回仍然是個(gè)list 。
numbers = '( 1 2 3 ) => ( 1 2 3 )
cdr( numbers ) => ( 2 3 )
nth()函數(shù)用索引訪問list的某個(gè)元素,注意索引從0開始。
numbers = '( 1 2 3 ) => ( 1 2 3 )
nth( 1 numbers ) => 2
member()函數(shù)檢查指定的元素是否在指定的list中,它只檢查頂層元素的元素,返回值是從搜到值開始到結(jié)尾的list 。
numbers = '( 1 2 3 ) => ( 1 2 3 )
member( 4 numbers ) => nil
member( 2 numbers ) => ( 2 3 )
length()函數(shù)計(jì)算list所包含元素的個(gè)數(shù)。
numbers = '( 1 2 3 ) => ( 1 2 3 )
length( numbers ) => 3
2.3.3 關(guān)于x、y坐標(biāo)或者bBox邊界list的訪問
在原理圖和版圖設(shè)計(jì)中,由于是一個(gè)二維的笛卡爾坐標(biāo)系,所以對于坐標(biāo)list操作經(jīng)常用到的,它是一組2維的list,常見的表示方法有:
用 :表示一個(gè)坐標(biāo)的list,其結(jié)果和list命令一樣,用xCoord和yCoord命令可以分別訪問x和y坐標(biāo)。
xValue = 300
yValue = 400
aCoordinate = xValue:yValue => ( 300 400 )
xCoord( aCoordinate ) => 300
yCoord( aCoordinate ) => 400
用list命令或者符號 ' 來表示一個(gè)bBox,注意之前講過二者區(qū)別:list命令先計(jì)算變量或者表達(dá)式,然后賦給list,而操作符' 表示的list和字面的一樣,不會(huì)計(jì)算變量或者表達(dá)式的值。
bBox = list( 300:400 500:450 ) ;含有 : 的bBox
如果把兩個(gè)點(diǎn)的坐標(biāo)組合起來做bBox的話:
含有變量時(shí)要用list()函數(shù):
lowerLeft = 300:400
upperRight = 500:450
bBox = list( lowerLeft upperRight )
' 表示的list嚴(yán)格按字面意思,適合不含有變量的情況
bBox = '(( 300 400 ) ( 500 450 ))
對于已有的bBox,我們可以用car和cdr函數(shù)配合使用來得到bBox內(nèi)的每個(gè)元素。而且有相關(guān)的簡化函數(shù),如下表:
list的相關(guān)操作還有很多,這里就不詳細(xì)介紹了,可以參考User Guide里的Advanced list Operations。
2.4 Skill的輸入輸出
Skill可以把輸出寫入到屏幕也就是CIW窗口,同時(shí)Skill還能對文件進(jìn)行讀入和寫入,下面分別說明
2.4.1 輸出顯示數(shù)據(jù):
print() 和println() 函數(shù)都可以用來顯示單個(gè)數(shù)據(jù),println可以在顯示的數(shù)據(jù)后多加一個(gè)回車。
for(i 1 3 print( "hello" )) ;prints hello three times.
"hello""hello""hello"
for(i 1 3 println( "hello" )) ;prints hello three times.
"hello"
"hello"
"hello"
printf ()函數(shù)是格式化的輸出(對于格式化輸出后面會(huì)講),下面的例子是一定格式輸出圖形層的統(tǒng)計(jì)。
printf("\n%-15s %-15s %-10d %-10d %-10d %-10d"
layerNamepurpose rectCount labelCount lineCount miscCount
)
對應(yīng)參數(shù)的意義如下,printf需要注意輸出類型的對應(yīng),一般格式如下:
%[-][width][.precision]conversion_code
-表示左對齊,width表示位數(shù),.precision表示精度 ,conversion_code部分一般是變量。
對于精度
d表示整數(shù),f表示浮點(diǎn)數(shù),s表示string或者symbol,c表示字符,n表示數(shù)字,L表示list,P表示point list,B表示Bounding box。更多請參考下表:
2.4.2 輸出數(shù)據(jù)到一個(gè)文件
想輸出內(nèi)容到一個(gè)文件,首先用outfile來定義輸出接口文件,然后用print println fprintf輸出到接口文件, 最后close關(guān)閉打開的接口,具體見下面的例子。
例子一:
myPort= outfile( "/tmp/myFile1" )
for(i 1 3
println( list( "Number:" i) myPort )
)
close(myPort )
輸出到文件/tmp/myFile1.
("Number:"1)
("Number:"2)
("Number:"3)
例子二:
myPort= outfile( "/tmp/myFile2" )
for(i 1 3
fprintf( myPort "Number: %d\n" i ) ;注意printf函數(shù)不能輸出到port
)
close(myPort )
輸出到文件/tmp/myFile2.
Number:1
Number:2
Number:3
上面兩個(gè)例子一個(gè)是用的println一個(gè)使用fprintf,注意二者的區(qū)別,并且注意printf函數(shù)不能輸出到port。
2.4.3 從文件讀取數(shù)據(jù)
如果想讀入文件的內(nèi)容,首先用intfile定義輸入接口文件,然后用gets一次從接口文件讀取一行字符串,或者用fscanf根據(jù)指定的格式從接口文件讀取,最后用close關(guān)閉打開的接口。
下面例子實(shí)現(xiàn)的功能是:打開~/.cshrc,輸出文件的每一行到CIW窗口的目的:
inPort= infile( "~/.cshrc" )
when(inPort
while( gets( nextLine inPort )
println( nextLine )
)
close(inPort )
)
下面例子實(shí)現(xiàn)的功能是:打開~/.cshrc,輸出文件中的每一個(gè)字符串到CIW窗口:
inPort = infile( "~/.cshrc" )
when( inPort
while( fscanf( inPort"%s" word )
println( word )
)
close( inPort )
)
2.5 Skill的控制結(jié)構(gòu)
2.5.1 關(guān)系操作符,
關(guān)系操作符和C語言基本差不多主要是用于判斷,但是要注意Skill的關(guān)系操作符返回值是t或者nil。具體參考下表:
2.5.2 邏輯操作符
邏輯操作符主要是用于完成“與”和“或”運(yùn)算,注意返回值可以使數(shù)值、或者t或者nil。具體參考下表:
注:SKILL中只有nil 是假(FALSE),其余的任何值都是真(TRUE)。
另外要特別注意,與/或邏輯操作只有在需要計(jì)算第二個(gè)表達(dá)式時(shí),才計(jì)算第二個(gè)表表達(dá)式,比如&&操作,當(dāng)?shù)谝粋€(gè)表達(dá)時(shí)為假時(shí),就不會(huì)再計(jì)算第二個(gè)表達(dá)式,|| 操作,當(dāng)?shù)谝粋€(gè)表達(dá)時(shí)為假時(shí),才會(huì)再計(jì)算第二個(gè)表達(dá)式。返回的結(jié)果是最后一個(gè)計(jì)算的表達(dá)式,因此與/或邏輯操作可以代替繁瑣的if / when等控制語句。
例如:C語言中的操作符, a>b ? c=a : c=b; 即c取a b中較大的一個(gè)Skill中沒有類似的操作符,可以用下面語句來完成此操作:
if( a>b then
c=a
else
c=b
)
也可以用邏輯操作符: c= (a>b)&&a || (a<b)&&b
當(dāng)然Skill還提供的有max(a b …)的函數(shù),舉這個(gè)例子是為了說明&& || 可以代替if then else之類的控制語句。所以關(guān)系操作符在某種意義上簡化了代碼。
2.5.3 預(yù)定義的函數(shù)
Skill還定義了不少預(yù)定義的函數(shù),包括基本運(yùn)算函數(shù),三角函數(shù)以及隨機(jī)產(chǎn)生函數(shù),直接調(diào)用它們,不僅方便,而且運(yùn)算的效率更高,下面是一些預(yù)定義函數(shù)的列表:
除此之外類型還有很多數(shù)據(jù)判斷和數(shù)據(jù)類型判斷函數(shù),這也是經(jīng)常用到的,采用這些函數(shù)有時(shí)候極大的簡化了代碼,同樣避免使用過多的關(guān)系運(yùn)算符和if語句。具體看下表:
2.5.4 控制語句
同c語言類似,Skill語言同樣有各種判斷和循環(huán)控制語句,下面分別舉例說明一下。
if語句用于判斷,有時(shí)候配合else使用,需要注意的是:
if…then…else的then是不能省略的(除了只有一個(gè)if,沒有else的情況)例子如下:
when語句舉例:
unless語句舉例:
case語句:case語句的判斷可以是數(shù)字和字符串,也可以是它們組成的list,但不支持變量和表達(dá)式把最可能出現(xiàn)的情況放在最前面,如果出現(xiàn)的幾率都一樣,把計(jì)算量最大的放在最后面,這樣可以有效的提高代碼效率。
cond語句:如果有很多判斷語句,用cond代替if…then…else組合,代碼比較清晰而且執(zhí)行效率比較高,下面的兩種代碼是等效的。
上面的cond語句如果用if else表示可以表示成:
舉例子說明cond的用法:
while語句用于循環(huán),舉例如下:
for語句用于指定次數(shù)的循環(huán),和C語言基本相同,舉例如下:
foreach語句是skill經(jīng)常用到的,foreach經(jīng)常用于對list的每個(gè)元素作循環(huán)操作,每個(gè)循環(huán)依次把各個(gè)元素的值賦給一個(gè)變量舉例如下:
上面提到的if(…then…else….),when,unless,case,cond,循環(huán)語句for,forecah等,控制語句和C語言類似,都是先判斷某個(gè)變量或者表達(dá)式是否為真,然后執(zhí)行下面的操作。
2.6 Skill的自定義函數(shù)
Skill中,函數(shù)大部分都是用procedure定義的,我們可以定義具有函數(shù)名的函數(shù)如下面例子一,或者用lambda用來定義一個(gè)沒有函數(shù)名的函數(shù),它在一些很小的函數(shù)里很方便,如下面例子二。
例子一:
procedure(trAdd( x y )
printf( "Adding %d and %d ... %d \n" x y x+y )
x+y
)=> trAdd 定義函數(shù)trAdd
trAdd(6 7 ) => 13 調(diào)用函數(shù)trAdd
例子二:
signallist= '(
( nil strength 1.5 )
( nil strength 0.4 )
( nil strength 2.5 )
)
sort(signallist
'lambda( ( a b ) a->strength <=b->strength )
;定義一個(gè)用來按signallist的strength屬性排序的內(nèi)置函數(shù),它沒有具體的函數(shù)名
)
函數(shù)定義還包括函數(shù)的參數(shù),這些會(huì)在調(diào)用函數(shù)實(shí)例的時(shí)候傳遞給函數(shù),除了基本的參數(shù)傳遞功能外,Skill還允許我們使用@option的方法控制參數(shù)的傳遞,譬如用@rest,調(diào)用函數(shù)時(shí)允許任意多個(gè)參數(shù)傳遞給函數(shù),使用@optional, 可以傳遞一個(gè)可選參數(shù),否則會(huì)用默認(rèn)值,@key,可以指定參數(shù)是如何傳遞的,應(yīng)此調(diào)用是參數(shù)的順序不固定。下面分別用例子說明:
例子一:@rest,調(diào)用函數(shù)時(shí)允許任意多個(gè)參數(shù)傳遞給函數(shù),
procedure( trTrace( fun @rest args )
let( ( result )
printf("\nCalling %s passing %L" fun args )
result = apply(fun args )
printf("\nReturning from %s with %L\n" fun result )
result
) ; let
); procedure
調(diào)用函數(shù)及返回結(jié)果:
trTrace('plus 1 2 3 ) => 6 ;返回值
=>Calling plus passing (1 2 3)
Returning from plus with 6
例子二:@optional, 可以傳遞一個(gè)可選參數(shù),否則會(huì)用默認(rèn)值,
procedure(trBuildBBox( height width @optional
(xCoord 0 ) ( yCoord 0 ) )
list(
xCoord:yCoord ;;; lower left
xCoord+width:yCoord+height ) ;;; upperright
); procedure
調(diào)用函數(shù)及返回結(jié)果:
trBuildBBox(1 2 ) => ((0 0) (2 1))
trBuildBBox(1 2 4 ) => ((4 0) (6 1))
trBuildBBox(1 2 4 10) => ((4 10) (6 11))
例子三:@key,可以指定參數(shù)是如何傳遞的,應(yīng)此調(diào)用是參數(shù)的順序不固定
procedure(trBuildBBox(
@key ( height 0 ) ( width 0 ) ( xCoord 0 ) (yCoord 0 ) )
list(
xCoord:yCoord ;;; lower left
xCoord+width:yCoord+height ) ;;; upper right
); procedure
調(diào)用函數(shù)及返回結(jié)果:
trBuildBBox()=> ((0 0) (0 0))
trBuildBBox(?height 10 ) => ((0 0) (0 10))
trBuildBBox(?width 5 ?xCoord 10 ) => ((10 0) (15 0))
注:其中@key和@optional不能同時(shí)出現(xiàn)在一個(gè)函數(shù)的定義中,另外的情況可以組合在一起譬如:
例子一:@optional和@reset共用
procedure(functionname([var1var2 ...]
[@optional opt1 opt2 ...]
[@rest r])
..
)
例子二:@key和@reset共用
procedure(functionname([var1var2 ...]
[@key key1 key2 ...]
[@rest r])
..
)
涉及到函數(shù),另一個(gè)不得不提的就是變量的作用范圍,在c語言中經(jīng)常用到,譬如在C語言當(dāng)中會(huì)有只當(dāng)前文件作用的變量,只在某個(gè)函數(shù)或者子函數(shù)內(nèi)部作用的變量,或者全局變量等等的區(qū)分。
在Skill中的變量默認(rèn)都是全局變量,這可能會(huì)導(dǎo)致同時(shí)調(diào)用多個(gè)skill的時(shí)候,不同人編寫的Skill命名可能有相同的,那就會(huì)導(dǎo)致沖突,所以要盡量減少全局變量的使用,而采用局部變量。
Skill可以用let和prog定義局部變量,如下面的例子:
procedure(trGetBBoxHeight( bBox )
let( ( ( ll car( bBox ) ) ( ur cadr( bBox ) ) lly ury )
lly = cadr( ll )
ury = cadr( ur )
ury - lly
) ; let
); procedure
局部變量默認(rèn)初始化為nil,當(dāng)然也可以初始化為別的值或表達(dá)式,表達(dá)式中不能有別的局部變量,prog和let的區(qū)別在于,prog支持函數(shù)go和return,可以顯示的循環(huán)和返回多個(gè)值,而let返回值是最后一個(gè)表達(dá)式的值,譬如上面例子的返回值是ury – lly. 除了有必要用prog,一般用let,更加簡潔快速。
2.7 Skill代碼書寫風(fēng)格
為了提高代碼的可讀性,我們一般會(huì)加一些注釋,和c語言類似,段代碼注釋我們要/*和*/ 來注釋,單行代碼用; 來注釋。
2.8 Skill 代碼Debug
代碼中由于我們的疏忽和不嚴(yán)謹(jǐn),編寫的程序難免會(huì)存在問題,一般根據(jù)在CIW窗口給出錯(cuò)的錯(cuò)誤提示,我們就可以找到問題的所在。
例子一: 調(diào)用函數(shù)名和括號之間有空格
如: strcat ( "Hello" "," " everyone""!" );會(huì)產(chǎn)生如下錯(cuò)誤!
=>*Error* eval: not a function - "Hello"
該問題使我們經(jīng)常會(huì)遇到的,書寫時(shí)候一定要注意:
例子二:軟件沒響應(yīng),比如在CIW中輸入段代碼,軟件沒有反映,什么結(jié)果也沒有。一般是因?yàn)?/span>( )或者” “不成對造成的,一般可以通過鍵入 ] 來解決,它表示補(bǔ)充完不對稱的括號(可以代替任意多個(gè)右括號),如果還沒有響應(yīng),鍵入 “] 這時(shí)大部分情況下,系統(tǒng)會(huì)有響應(yīng)。
例子三:數(shù)據(jù)類型不匹配,如:
strcat("Mary had a" 5 );會(huì)出現(xiàn)如下錯(cuò)誤!
=>*Error*strcat: argument #2 should be either a string
ora symbol (type template = "S") – 5
例子四:函數(shù)不合法,一般是我們輸入沒有的函數(shù)會(huì)出現(xiàn)illegal function錯(cuò)誤,我們要檢查是否函數(shù)被加載了,或者函數(shù)名字寫錯(cuò)了。
=>illegalfunction
例子五:無約束變量錯(cuò)誤,一般是調(diào)用一個(gè)變量,而這個(gè)變量沒有被賦值,或者調(diào)用該變量的時(shí)候變量名字寫錯(cuò)了
=>unboundvariable
聯(lián)系客服