tree-sitter 的 grammar.js 编写方法


要掌握 tree-sittergrammar.js 编写方法,首先我们要理解 tree-sitter 的核心概念,它是一个 基于GLR算法的增量解析器生成工具,常用于语法高亮、代码分析等任务。

一、grammar.js 的作用是什么?

这是 tree-sitter 语法的定义文件,描述了一个语言的 词法规则(Lexing)语法规则(Parsing)


二、基本结构

grammar.js 是一个 CommonJS 模块,通常长这样:

module.exports = grammar({
  name: 'my_language', // 语言名称

  // 词法规则
  extras: $ => [/\s/, $.comment], // 忽略的内容,如空格、注释

  // 定义词法(token)
  rules: {
    source_file: $ => repeat($.statement),

    statement: $ => choice(
      $.variable_declaration,
      $.function_call
    ),

    variable_declaration: $ => seq(
      'let',
      $.identifier,
      '=',
      $.expression,
      ';'
    ),

    function_call: $ => seq(
      $.identifier,
      '(',
      optional($.expression),
      ')',
      ';'
    ),

    expression: $ => choice(
      $.number,
      $.string,
      $.identifier
    ),

    identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
    number: $ => /\d+/,
    string: $ => /"[^"]*"/,
    comment: $ => /\/\/.*/
  }
});

三、关键词解释

  • seq(...): 顺序匹配(sequence),表示一段连续的符号。
  • choice(...): 匹配多个可能之一(like OR)。
  • repeat(...): 重复0次或多次。
  • repeat1(...): 重复至少1次。
  • optional(...): 可选项。
  • token(...): 表示这是一个词法单元(token),不会再细分。
  • prec(n, rule): 设置优先级(n 越大,优先级越高)。

四、编写小技巧

1. 起点是 source_file

tree-sitter 会从你定义的 rules.source_file 开始解析整个文件。

2. 所有规则名(如 identifier, number)都是 $ => ...

这个 $ 是构造语法树时的“工具”,让你可以引用别的规则。

3. 正则表达式用于定义词法规则(终结符),例如:

identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/,
number: $ => /\d+/,

五、🍀 $的简单解释:$ 是规则的“引用工具”

grammar.js 中,你写的每一个语法规则都是一个函数,比如这样:

identifier: $ => /[a-zA-Z_][a-zA-Z0-9_]*/

这里的 $ => 就是给 tree-sitter 传递一个函数,这个函数的参数 $ 是个“语法引用器”。

❓ 那 $ 到底能干嘛?

它能让你“引用其他规则”。

🧠 举个例子来说明

比如你想定义这样一个语句:

let x = 42;

你在写规则时会写成:

variable_declaration: $ => seq(
  'let',
  $.identifier,
  '=',
  $.expression,
  ';'
)

这里的 $.identifier$.expression 就是**“引用”之前定义的两个规则**。注意:

  • $.identifier -> 指向你之前写的 identifier: $ => ...
  • $.expression -> 指向你之前写的 expression: $ => ...

这样 tree-sitter 就能在 variable_declaration 这个规则里,使用别的规则了。


🔧 类比一下:

你可以把 rules 想象成一个对象:

rules = {
  identifier: ...,
  expression: ...,
  variable_declaration: ...
}

$.identifier 就相当于 rules.identifier

所以这个 $ 就是代表你整个 rules 对象本身。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洪小帅

靓仔靓女看过来~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值