介紹和分析
tree-sitter
是一個parser生成工具,用於生成語法樹。tree-sitter parser官網英文教程、一篇優秀tree-sitter的中文介紹
eof
規則表示從當前位置開始,匹配空字元直到檔案結尾,中途任何的非空字元都會導致匹配失敗。
tree-sitter
本身不提供eof
規則,以下是使用external scanner功能實現的eof
。
程式碼實現
.代表專案根目錄
記得將程式碼中的your_language
替換成你的語言名稱
./binding.gyp 檔案中
{
"targets": [
{
...
"sources": [
"bindings/node/binding.cc",
"src/parser.c",
"src/scanner.c", // 新增這一行
],
...
}
]
}
scanner.c 檔案需要手動建立
external scanner的具體規則用法參考 tree-sitter external scanner
./src/scanner.c
#include "tree_sitter/alloc.h"
#include "tree_sitter/array.h"
#include "tree_sitter/parser.h"
static bool scan_eof(TSLexer *lexer);
enum TokenType { Eof };
void *tree_sitter_your_language_external_scanner_create(void) { return NULL; }
void tree_sitter_your_language_external_scanner_destroy(void *payload) {}
unsigned tree_sitter_your_language_external_scanner_serialize(void *payload,char *buffer) {
return 0;
}
void tree_sitter_your_language_external_scanner_deserialize(void *payload,const char *buffer,unsigned length) {}
bool tree_sitter_your_language_external_scanner_scan(void *payload, TSLexer *lexer,const bool *valid_symbols) {
if (valid_symbols[Eof]) {
return scan_eof(lexer);
}
return false; // 匹配失敗
}
bool scan_eof(TSLexer *lexer) {
// 標記匹配開始位置
lexer->mark_end(lexer);
while (!lexer->eof(lexer)) {
// 檢查是否有非空字元,具體忽略哪些空字元可以在這裡指定
if (lexer->lookahead != ' ' && lexer->lookahead != '\n' &&
lexer->lookahead != '\r' && lexer->lookahead != '\t' &&
lexer->lookahead != '\f' && lexer->lookahead != '\v') {
return false; // 匹配失敗
}
lexer->advance(lexer, true); // 消耗字元
lexer->mark_end(lexer); // 動態更新結束位置
}
// 到達檔案末尾,匹配成功
lexer->result_symbol = Eof;
return true;
}
最後在external中宣告新增的規則,就可以使用這個規則了
./grammer.js
module.exports = grammar({
name: "your_language",
externals: $ => [
$.eof,
],
rules: {
source_file: $ => seq(
"world",
$.eof
), // 一個簡單的示例
}
執行
建立一個簡單的文字檔案example.txt
,結尾可以加上任意數量的空字元
world
控制檯執行命令
tree-sitter generate
tree-sitter parse ./example.txt
得到以下輸出,說明eof
規則執行成功
(source_file [0, 0] - [6, 0]
(world [0, 0] - [0, 5])
(eof [6, 0] - [6, 0]))