首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
287 阅读
2
从零开始配置 vim(15)——状态栏配置
169 阅读
3
nvim番外之将配置的插件管理器更新为lazy
159 阅读
4
2018总结与2019规划
145 阅读
5
PDF标准详解(五)——图形状态
121 阅读
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
登录
Search
标签搜索
c++
c
学习笔记
emacs
windows
elisp
文本操作术
编辑器
NeoVim
Vim
win32
读书笔记
VimScript
linux
文本编辑器
投资理财
Java
反汇编
OLEDB
数据库编程
Masimaro
累计撰写
442
篇文章
累计收到
32
条评论
首页
栏目
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
页面
归档
友情链接
关于
搜索到
1
篇与
的结果
2026-09-22
《elisp 每日一练》——管理 syntax-table
在前面介绍buffer 的时候,简单的介绍了 syntax-table的概念。它是一个存储了 ASCII/Unicode 字符与其语法类 (Syntax Class) 对应关心的表格。在前面的文章中,我只是介绍了如何使用它,例如我们介绍了 scan-sexps 函数,利用表中数据在语法单元间移动。而如果我们要创建自定义的 Major Mode,核心工作之一就是维护自己的 syntax-table。背景知识syntax class前面提到:它存储的是字符到语法类的对应关心。我们先来介绍一下常用的语法单元 (Syntax Class)。常用的有:语法类名称字符代码含义与示例空白符' ' 或 '-'空白字符(空格、Tab、换行符)单词组成字符'w'构成普通单词的字符(字母、数字)。例如按 M-f 会穿过连续的 w符号组成字符'_'构成标识符/符号的字符(如 _ 或 -)。foo_bar 中 _ 设为 _ 时,它是一个完整 Symbol标点'.'标点符号(如 .、 ,、 ;)括号'(' / ')'成对出现的开/闭括号(如 ()、[]、{})字符串引号" '"字符串分界符(如 "" 或 ''转义字符'\'转义字符(如 \)注释起始符< >界定注释的起始和结束位置维护syntax-table 的一般操作syntax-table 与一般的数据一样,对它的操作无外乎增删改查。我们还是按照这个思路来介绍。首先我们可以使用 make-syntax-table 来创建一个空表。根据我们前面在分析 define-derived-mode 中看到的,它一般被定义为全局变量。但是在实际开发中,一般不会从0开始,而是继承自某个父类,以此为基础进行个性化改造。对于编程语言,可以从 prog-mode-syntax-table 继承,而普通文本可以从 standard-syntax-table 。在继承之后,针对一些不合适的项目,我们可以使用 modify-syntax-entry 设置字符的语法类。它的函数原形是:(modify-syntax-entry CHAR NEWENTRY &optional SYNTAX-TABLE)CHAR 是一个字符常量,也可以是一个 (MIN . MAX) 的范围,表示该范围内的字符都是这个Syntax ClassNEWENTRY 是语法描述符,是一个字符串,它每个字符都有明确的含义。第一个字符是前面介绍的Syntax Class 符号;第二个参数是匹配字符,仅当第一个字符是 ( 或者 ) 才有意义;第三个及之后的字符是语法标志,它是一组数字,用于描述多字符注释、可嵌套注释等高级行为。标志的顺序无关紧要。SYNTAX-TABLE 要修改的语法表,如果不填默认修改当前buffer中的syntax-tableNEWENTRY 详解NEWENTRY 是一个相对复杂的数据,我们来通过简单的例子来说明一个字符的情况(modify-syntax-entry ?# "<" my-table)上面的代码,我们设置 # 字符为 shell 的注释。这段代码中,NEWENTRY 只有一个字符,表示 Syntax Class括号的处理(modify-syntax-entry ?\( "()" my-table) (modify-syntax-entry ?\) ")(" my-table)这段代码,我们设置了一个括号区域,它的 NEWENTRY 域有两个字符,第一个字符 ( 表示这是一个左括号,而第二个表示与它匹配的右括号是 ),所以如果我们要添加一个描述中括号的规则可以这么写(modify-syntax-entry ?\[ "(]" my-table) (modify-syntax-entry ?\] ")[" my-table)注释C 语言有两种注释符号,我们看看该如何在 syntax-table 中定义它们。首先我们来看看 /**/(modify-syntax-entry ?/ ". 14" my-table) (modify-syntax-entry ?* ". 23" my-table)既然 /* 是注释,为什么不用代表注释的 < 来设置呢,主要是因为 / 在C 语言中主要的含义是除法运算符,只有和 * 在一起的时候才作为注释。所以Emacs的做法是将它作为运算符处理。作为注释的作用则通过语法标记来完成。Emacs中用于语法标志的数字含义为:1:该字符是双字符注释起始符的第一个字符。2:该字符是双字符注释起始符的第二个字符。3:该字符是双字符注释结束符的第一个字符。4:该字符是双字符注释结束符的第二个字符。对于 /**/ 这样的注释来看,/ 它位于注释区域的第一个字符作为开始,注释的结束位置它是第4个字符。而 * 则对应于注释区域的第2和第三个字符。那么根据这个标准,我们可以定义xml的注释 <!---->, 理论上我们可以依葫芦画瓢写成如下模式:在xml中,注释是 <!----> 是否可以写为 (modify-syntax-entry ?< ". 1" my-table) (modify-syntax-entry ?! ". 2" my-table) (modify-syntax-entry ?- ".3456" my-table) (modify-syntax-entry ?> ".7" my-table)但是遗憾的是,上述方案并不能正常工作。因为Emacs中对于syntax class ,它只支持两个字符,也就是语法标志只支持从1到4。对于这种复杂的类型,可以使用 syntax-propertize-function 函数,通过正则表达式来支持。说完了 /**/,我们再来说另一种注释 //, 根据前面我们的描述,/ 本身是运算符,所以作为注释也是使用数字标识,那么它的写法如下:(modify-syntax-entry ?/ ". 12" my-table)有的读者看到这里是不是认为上述写法没问题呢?// 作为注释它出现在第一和第二位置。如果你这么想,你可能只对了一半,作为 // 类型的注释,它确实出现在 1 4 两个位置,但是别忘了,/ 还可以以 /**/ 的形式出现。所以正确的写法应该是结合我们前面介绍的 /**/ 类型处理方式:(modify-syntax-entry ?/ ". 124" my-table)字符串常量的处理对于字符串常量来说,一般以 "" 进行分隔,它即作为字符串的开始也作为结束的标志,所以我们不需要像前面的括号那样专门制定一个闭合的字符。一般来讲,可以写下如下的代码来处理(modify-syntax-entry ?\" "\"" my-table)这样就够了吗?字符串还有很多复杂的变种,例如对于C++ 11以后的标准,它允许使用 R("") 来表示一个字符串。有的字符串里面采用 \" 表示字符串内部有" 这个字符。复杂的今天我们就不讨论了,我今天只处理 \ 作为转义字符的情况,可以写下如下代码处理:(modify-syntax-entry ?\\ "\\" my-table)小结本节的内容就结束了, 本节我们主要介绍了 modify-syntax-entry 函数,并且通过几个例子演示了它的使用方法。其实可以归纳为3类:单字符就是一个 syntax class 的,直接使用单字符字符串指定对于需要不同字符表示一个区间的,可以使用两个字符的字符串指定,第一个字符是 syntax class 类型,第二个字符表示闭合字符对于4个字符组成的注释区间,可以使用数字 1 2 3 4 指明作为注释符号时它可以出现的位置
2026年09月22日
0 阅读
0 评论
0 点赞