tree-sitter编写parser,用external scanner实现eof规则

介绍和分析

tree-sitter是一个parser生成工具,用于生成语法树。tree-sitter parser官网英文教程一篇优秀tree-sitter的中文介绍

eof规则表示从当前位置开始,匹配空字符直到文件结尾,中途任何的非空字符都会导致匹配失败。

tree-sitter本身不提供eof规则,以下是使用external scanner功能实现的eof

本文假定你已经会创建tree-sitter项目,能够通过tree-sitter dsl编写一般的规则(否则也不会来看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) {
  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->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]))

已知问题

当你存在extra规则,且出现在文件结尾,下面是一个例子:

(带匹配的内容)

// 这个行注释规则写在extras里面,上下都有换行

eof规则解析就会出现错误,所以能不用eof就不用吧,你也许不需要eof规则

posted @ 2024-12-03 23:48  laditor  阅读(38)  评论(0编辑  收藏  举报