來開發 Visual Studio Code SystemVerilog plugin 吧!開發紀錄(二)

Share on:

本文內容採用創用 CC 姓名標示-非商業性-相同方式分享 3.0 台灣 授權條款授權.

在本篇中,我將會參考 官方文件 ,替 Visual Studio Code 加入 SystemVerilog 的語法上色 (highlight) 功能。

Visual Studio Code 中,highlight 可以用兩種功能達成,一種叫做 declarative language features,另外一種叫做 programmatic language features。兩者個不同是 declarative 只做 regular expression 來決定要 highlight 什麼顏色,programmatic 會根據語意來作更厲害的 highlight,並可以提供非常完整之 IDE 功能。當然 declarative 是相對簡單的作法,一般 plugin 中,也會先用 declarative 很快的處理,讓給 user 看到基本的 highlight,再用 programmatic 慢慢的處理。

本篇文章將會用 declarative,作到最基本的 highlight |

登記 SystemVerilog file

首先,我們要告訴 Visual Studio Code,我們的 plugin 提供了 SystemVerilog 語法的功能。為此,我們要把 package.json"contributes" 加入 "languages""grammars" 兩個項目,告訴 Visual Studio Code 我們的 highlight 要對 ".v"".sv" 起作用,相關的語法定義檔放在 "./syntaxes/systemverilog.tmGrammar.json"

 1{
 2"contributes": {
 3    "commands": [
 4        {
 5            "command": "vscode-systemverilog.helloWorld",
 6            "title": "Hello World"
 7        }
 8    ],
 9    "languages": [
10        {
11            "id": "systemverilog",
12            "extensions": [".sv", ".v"]
13        }
14    ],
15    "grammars": [
16        {
17            "language": "systemverilog",
18            "scopeName": "source.systemverilog",
19            "path": "./syntaxes/systemverilog.tmGrammar.json"
20        }
21    ]
22}
23}

定義語法

前面提及的語法定義檔 "./syntaxes/systemverilog.tmGrammar.json",預設當然是不存在的,所以首先我們要創造這個 JSON 檔案,插入基本的內容。

 1{
 2    "scopeName": "source.systemverilog",
 3    "patterns": [
 4        {
 5            "include": "#keyword"
 6        }
 7    ],
 8    "repository": {
 9        "keyword": {
10            "patterns": [
11                { "include": "#comment-line" },
12                { "include": "#comment-block" },
13                { "include": "#storage-type" },
14                { "include": "#storage-modifier" },
15                { "include": "#keyword-control" },
16                { "include": "#keyword-operator" },
17                { "include": "#keyword-operator-char" },
18                { "include": "#variable-others" },
19                { "include": "#variable" },
20                { "include": "#string" }
21            ]
22        }
23    }
24}

這個 JSON 檔裡面,定義了多種我自己分類的 pattern,其對應如下,之後我們要在同一個 JSON 裡面補上這些 pattern 的語法:

名稱 說明
comment-line // 開頭的註解
comment-block /**/ 包圍的註解
storage-type logic 之類的關鍵字
storage-modifier signed 之類的關鍵字
keyword-control always 之類的關鍵字
keyword-operator posedge, or 之類的關鍵字
keyword-operator-char 加減乘除之類的
variable-others macro 之類的我分到這類
variable 變數
string" "string"

定義文法

定義關鍵字

首先,先來看最簡單的 case,就是一個單字的關鍵字,因為實在太簡單了所以沒有什麼好說明的。反而是 "name" 那邊,需要遵守 naming convention。舉例來說,我們只要把 "name" 設定成 "storage.modifier" 或是 "keyword.control" 等等,Visual Studio Code 就會知道他們屬於不同的類別,會去作對應的著色。

 1{
 2"storage-modifier": {
 3	"match": "\\b(inout|input|output|signed)\\b",
 4	"name": "storage.modifier"
 5},
 6"storage-type": {
 7	"match": "\\b(logic|wire|reg)\\b",
 8	"name": "storage.type"
 9},
10"keyword-control": {
11	"match": "\\b(module|endmodule|if|else|always|always_comb|always_ff|always_latch|begin|end)\\b",
12	"name": "keyword.control"
13}
14}

定義註解

SystemVerilog 跟 C++ 的註解方式是一樣的,只要知道他們的定義是「// 開頭到行尾」以及「/* 開頭到 */ 結束」的區段就可以輕鬆寫出他們的文法了,其中對像我這樣的新手來說最困難的部份反而是不知道要 escape 幾次反斜線。

 1{
 2"comment-line": {
 3	"begin": "//",
 4	"end": "$",
 5	"name": "comment.line"
 6},
 7"comment-block": {
 8	"begin": "/\\*",
 9	"end": "\\*/",
10	"name": "comment.block"
11}
12}

定義字串

因為 Example Grammar 有可以抄的範例,所以就直接拿來用了!

1{
2"string": {
3	"begin": "\"", "end": "\"",
4	"patterns": [{
5		"name": "constant", "match": "\\\\."
6	}],
7	"name": "string"
8}
9}

定義變數以及 Macro

變數跟 macro 基本上都是 \w+ 的語法,這邊要注意的一樣也是只有 escape,注意到因為 \b 是 match 「字的開頭或是結尾」,所以因為 macro 開頭是 backquote,所以不是「字的開頭」,因此要把那個 \b 去掉。

 1{
 2"variable-others": {
 3	"match": "`\\w+\\b",
 4	"name": "keyword.control"
 5},
 6"variable": {
 7	"match": "\\b\\w+\\b",
 8	"name": "variable"
 9}
10}

定義 Operator

嗯,原來加號是要 escape 的……。這邊注意到一個事情是,不同的文法規則是可以有同一個 "name" 的。

 1{
 2"keyword-operator": {
 3	"match": "(<=|>=|\\+\\+|--|&&|``|\\+=|-=)",
 4	"name": "keyword.operator"
 5},
 6"keyword-operator-char": {
 7	"match": "[+-><=*/]",
 8	"name": "keyword.operator"
 9}
10}