通用语法校验器tree-sitter——C++语法校验实践

tree-sitter介绍

以下内容来自于官方文档:tree-sitter.github.io/tree-sitter...

Tree-sitter 是一个解析器生成工具和增量解析库,用于为源代码文件构建具体的语法树,并在源文件编辑时高效更新语法树。它旨在提供一个通用、快速且鲁棒的解决方案,用于解析编程语言,即使在存在语法错误的情况下也能正常工作。

主要特点:

  • 通用性:能够解析任何编程语言。
  • 高效性:足够快,可以在文本编辑器中每按一个键就进行解析。
  • 鲁棒性:即使有语法错误,也能提供有用的结果。
  • 无依赖:运行时库使用纯 C11 编写,可以嵌入到任何应用程序中。

工作原理:

Tree-sitter 生成解析器并维护一个增量解析库,随着源文件的编辑实时更新语法树,从而支持如文本编辑器中的实时解析。

支持的语言:

  • 语言绑定:支持 C# (.NET)、C++、Crystal、D、Delphi、ELisp、Go、Guile、Janet、Java (JDK 8+ 和 11+)、Julia、Lua、OCaml、Odin、Perl、Pharo、PHP、R 和 Ruby 等语言的绑定(部分绑定可能不完整或过时)。

tree-sitter的缺点

Tree-sitter 不是利用编程语言(如 C++、JavaScript 等)的现有或官方解析器来进行解析的。它是一个独立的解析器生成工具,使用自己的框架和语法定义来为各种语言生成专属的解析器。这些解析器基于 GLR(广义 LR)算法构建,并通过 Tree-sitter 的工具包预先编译或运行时生成,而不是依赖语言的内置运行时环境(如 V8 对于 JavaScript)。这种设计允许 Tree-sitter 在编辑器中实现高效的增量解析,但也可能导致与官方解析器在某些边缘情况下的不一致。

因此,如果需要高质量的语法解析,请不要用tree-sitter。 虽然tree-sitter提供了api让开发者编写更精细的解析,但不如考虑其他wasm方案或Language Server Protocol (LSP)

测例

以下c++代码中有4处错误,包括使用了关键字/错误的声明/使用了未定义变量/错误语法(a+++),但只识别到了最后一个。

cpp 复制代码
int main()  
{  
    int int = 1;  
    inb a = 1;  
    int a = 0, b = 1, c = 2, d = 3, e = 4;

    if (x > 1)  
    {  
    }  
    a++ + ;  
    if (a || (b < c && e >= d))  
    { /* ... */  
    }

    return 0;  
}

playground

tree-sitter.github.io/tree-sitter...

在浏览器环境中使用tree-sitter

tree-sitter支持在浏览器环境中使用,方法也很简单。

安装依赖

复制代码
npm install web-tree-sitter

生成wasm

语法校验需要对应语言的wasm,生成步骤如下:

  1. 安装依赖
css 复制代码
npm install --save-dev tree-sitter-cli tree-sitter-cpp

将node_modules中的web-tree-sitter.wasm文件复制到public目录下 2. 执行命令,在当前目录下生成tree-sitter-cpp.wasm

bash 复制代码
npx tree-sitter build --wasm node_modules/tree-sitter-cpp
  1. 将生成的tree-sitter-cpp.wasm放入public目录下

实践demo

代码如下:

js 复制代码
import { code } from "./code";
import { Parser, Language, Query } from "web-tree-sitter";
async function main() {
  await Parser.init({
    locateFile(scriptName: string, scriptDirectory: string) {
      return scriptName;
    },
  });
  const cpp = await Language.load("tree-sitter-cpp.wasm");

  const parser = new Parser();
  parser.setLanguage(cpp);
  const tree = parser.parse(code);
  console.log(tree);
  console.log(tree?.rootNode);
  if (!tree!.rootNode.hasError) {
    console.log("没有错误");
    return;
  } else {
    console.log("存在错误");
  }
  // 异常查询
  const queryString = "(ERROR) @error-node (MISSING) @missing-node"; 

  const language = parser.language;
  const query = new Query(language!, queryString);
  const root = tree!.rootNode;
  // Execute query and get matches
  const matches = query.matches(root!);

  const errorNodes = [];
  for (const match of matches) {
    for (const capture of match.captures) {
      errorNodes.push(capture.node);
    }
  }

  console.log(errorNodes);
  if (errorNodes.length) {
    const { row, column } = errorNodes[0]!.startPosition;
    console.log(`${row + 1}行,${column + 1}列存在错误`);
  }
}
main();

错误节点捕获:

相关推荐
贵州数擎科技有限公司17 分钟前
霓虹沙尘暴的 Three.js 实现
前端·webgl
一只叁木Meow18 分钟前
电商 SKU 选择器:用算法实现优雅的用户交互
前端·javascript·算法
笔优站长20 分钟前
vue-sign-canvas v2 重构复盘:从 Vue 2 签名板到 Vue 3 + TypeScript 组件库
前端·vue.js
Aolith24 分钟前
事件驱动设计:我如何为校园论坛实现消息通知功能
前端·vue.js
yingyima25 分钟前
GitHub Actions 定时任务 schedule 踩坑实录:核心语法与实战技巧
前端
代码煮茶25 分钟前
CSS 单位完全指南:px、em、rem、vw、vh、clamp 详解
前端·css
KaMeidebaby30 分钟前
卡梅德生物技术快报|PROTAC 药物降解蛋白原理及数据库平台开发全流程
前端·数据库·其他·百度·新浪微博
玄米乌龙茶1231 小时前
LLM成长笔记(七): AI 应用框架与编排
前端·人工智能·笔记
芯芯点灯2 小时前
gd32f303烧录提示Flash Timeout. Reset the Target and try it again.;
开发语言·前端·javascript
前端若水2 小时前
自定义消息组件:图片、文件附件与图表
前端·人工智能·react.js·typescript