[ Skill ] Cadence Skill 語言入門

YEUNGCHIE 發表於 2021-09-14

https://www.cnblogs.com/yeungchie/

寫個大筆記,低速更新中 ...

Cadence Skill

Cadence 提供二次開發的 SKILL 語言,它是一種基於通用人工智慧語言— Lisp 的互動式高階程式語言 (1)。

SKILL 語言支援一套類似 C 語言的語法,大大降低了初學者學習的難度,同時高水平的程式設計者可以選擇使用類似 Lisp 語言的全部功能。所以 SKILL 語言既可以用作最簡單的工具語言,也可以作為開發任何應用的、強大的程式語言。

SKILL 可以與底層系統互動,也提供了訪問 Cadence 各個工具的豐富介面。使用者可以通過 Skill 語言來訪問,並且可以開發自己的基於 Cadence 平臺的工具。

LISP 即 List Processing-表處理,是最早和最重要的符號處理程式語言之一,它於1958年由美國的 J. McCarthy 提出,LISP 在人工智慧AI方面獲得廣泛應用。

我的環境是 Virtuoso IC618 平臺,可能存在某些特性不適用於舊版本。

如何檢視官方資料

cdsFinder

  • 用於模糊查詢 Skill 函式,及檢視簡單介紹。
which cdsFinder
# $CDSHOME/tools/bin/cdsFinder

cdnshelp

  • 用於檢視更加詳細的內容,以軟體的使用手冊。
which cdnshelp
# $CDSHOME/tools/bin/cdnshelp

程式碼風格

語法風格

由於 Skill 語言是基於 Lisp ,因此它支援 函式表示法字首表示法 來書寫程式碼。

  • 函式表示法

    func( arg1 arg2 )
    
  • 字首表示法

    ( func arg1 arg2 )
    

以上的兩種表示法可以同時存在,因此在編寫程式碼時候最好注意格式的統一。

推薦統一使用 函式表示法,並需要注意函式名和括號之間不能有空格。

錯誤寫法 : func ( arg1 arg2 )

func 後面多了一個空格,這會將 arg1 作為函式名

命名風格

其次函式和變數的命名風格,Skill 中一般是使用 駝峰命名法 ( Camel-Case ),函式名中的每一個邏輯斷點(單詞)首字母大寫,開頭第一個單詞全部小寫,一般代表 函式/變數 的類別、作者,像我寫的函式和全域性變數一般都習慣用 yc 開頭。

這也是現在更為流行的一種命名方式,相對於傳統的 下劃線命名法,不會使較長的命名顯得更長,且更加能提高可讀性,當程式碼量上來的時候,滿屏的下劃線看起來會非常蛋疼。

下面是一個對比

  • 駝峰命名法

    geGetEditCellView()
    dbOpenCellViewByType(libName cellName viewName nil mode)
    
  • 下劃線命名法 ( 不推薦 )

    ge_get_edit_cell_view()
    db_open_cell_view_by_type(lib_name cell_name view_name nil mode)
    

最後再注意命名不能過於簡化,例如 abc。命名的目標是至少讓人能一眼看出來這個變數是做什麼用的 ( 一眼不行看兩眼 ),例如上面的 libNamecellNameviewName

下面介紹語法部分我會使用的一些非常簡化變數命名,因為只是用於演示,命名就會比較隨意了。

基礎語法

hello world

舉例三種 print 寫 hello world,後面會具體講幾種 print 函式的區別。

print( "hello world" )
println( "hello world" )
printf( "%s\n" "hello world" )

註釋

單行註釋

; 這是單行註釋

多行註釋

/*
  這是多行註釋
*/

資料型別

可以用函式 type 檢視一個資料的型別標識。

type( 'YEUNGCHIE )        ; symbol
type( "YEUNGCHIE" )       ; string
type( list( "YEUNGCHIE" ))  ; list

println 列印一個資料的內容,同時也能夠從列印結果觀察到資料型別。

println( 'YEUNGCHIE )          ; YEUNGCHIE
println( "YEUNGCHIE" )         ; "YEUNGCHIE"
println( list( "YEUNGCHIE" ))  ; ( YEUNGCHIE )

資料型別標識

官方的教程中一般會用來表明函式需要的輸入資料是什麼型別的( 標在字首 )。也用於限制子函式輸入資料的型別。

字首 內部命名 資料型別
d dbobject id , Cadence 資料物件
x integer 整數
f flonum 浮點數
n number 整數 或者 浮點數
g general 通用的 , 任何資料型別
l list 連結串列
p port I / O 控制程式碼
t string 字串
s symbol " 符號 "
S stringSymbol " 符號 " 或者 字串
u function 函式物件 , 函式名 或者 lambda物件

標量

字串

定義方式

字串用雙引號括起來。

"YEUNGCHIE"
; "YEUNGCHIE"
字串連線

strcat

a = "YEUNG"
b = "CHIE"
c = strcat( a b )
println( c )
; "YEUNGCHIE"
字串長度

strlen

下面的 c 沿用上面的變數 c,為了教程不寫得過於繁雜、重複。

println(strlen( c ))
; 9

數字

數字分為 整數 和 浮點數。

整數
18

也可以直接編寫成 二進位制 ( 0b 字首 )、八進位制 ( 0 字首 )、十六進位制 ( 0x 字首 ),但預設會輸出成 十進位制

0b10010    ; 18
024        ; 20
0xFE       ; 254
浮點數
3.14

浮點數也可以使用 科學計數法 和 單位字尾 來表示

1e-06    ; 0.000001
1u       ; 0.000001

symbol

id

連結串列 list

定義方式

  • list( arg1 arg2 list( arg3 arg4 ) ... )

    listA = list( 1 2 )
    ; ( 1 2 )
    
  • '( "value1" sym1 (1 2) ... )

    這種表達方式需要注意,它不適用於變數元素,例如上面 sym1 並不會帶入變數值,而是 symbol 型別 'sym1

    listB = '( 3 4 )
    ; ( 3 4 )
    
  • arg1 : arg2

    僅在只有兩個元素時使用,通常用來表達一個座標點

    point = 1 : 2
    ; ( 1 2 )
    

連線兩個 list

  • append

    listC = append( listA listB )
    println( listC )
    ; ( 1 2 3 4 )
    

往 list 追加元素

  • append1

    往末尾追加

    listD = append1( listC 5 )
    println( listD )
    ; ( 1 2 3 4 5 )
    
  • cons

    往開頭追加

    listE = cons( 0 listD )
    println( listE )
    ; ( 0 1 2 3 4 5 )
    

翻轉一個 list

  • reverse

    listF = reverse( listE )
    println( listF )
    ; ( 5 4 3 2 1 0 )
    

獲取一個 list 元素個數

  • length

    length( listF )
    ; 6
    

提取 list 中的元素

  • car 提取第一個元素

    car( listF )
    ; 5
    
  • cdr 提取除了第一個元素之後的 list

    cdr( listF )
    ; ( 4 3 2 1 0 )
    
  • cadr 及其更多組合

    cadr( listF ) 其實就是 car(cdr( listF )) 的簡寫

    cadr( listF )  ; 4
    caddr( listF ) ; 3
    
  • nth 根據索引提取

    nth( 0 listF )               ; 5
    nth( 1 listF )               ; 4
    nth( length(listF)-1 listF ) ; 0
    

陣列 / 向量

陣列 和 向量 不常用,瞭解一下長什麼樣就行。

陣列

  • 定義

    declare

    declare( ARRAY[10] )
    
  • 賦值

    ARRAY[2] = 4
    ARRAY[3] = 5
    
  • 引用

    println( ARRAY[2] * ARRAY[3] )
    ; 20
    println( ARRAY[0] )
    ; unbound
    println( ARRAY[11] )
    ; *Error* arrayref: array index out of bounds - ARRAY[11]
    

向量

  • 定義

    makeVector

    VECTOR = makeVector( 10 )
    
  • 賦值

    VECTOR[2] = 4
    VECTOR[3] = 5
    
  • 引用

    println( VECTOR[2] * VECTOR[3] )
    ; 20
    println( VECTOR[0] )
    ; unbound
    println( VECTOR[11] )
    ; *Error* arrayref: array index out of bounds - VECTOR[11]
    

對照表 / 雜湊

某些情況下可能需要用到雜湊來優化程式碼邏輯和速度等等。

定義

makeTable

HASH = makeTable( 'HASH )

賦值

HASH[1] = "ONE"
HASH["2"] = 2
HASH[cvId] = "cellName"

引用

  • 檢視一個雜湊的所有 key / value

    HASH~>?
    ; ( "2" 1 db:0x21cfda1a )
    HASH~>??
    ; ( "2" 2 1 "ONE" db:0x21cfda1a "cellName" )
    
  • 遍歷一個雜湊

    foreach( key HASH
      printf( "key: %A  ,  value: %A\n" key HASH[key] )
    )
    ; key: db:0x21cfda1a  ,  value: "cellName"
    ; key: 1  ,  value: "ONE"
    ; key: "2"  ,  value: 2
    

運算

賦值運算

算數運算

比較運算

邏輯運算