首页
归档
友情链接
关于
Search
1
在wsl2中安装archlinux
302 阅读
2
从零开始配置 vim(15)——状态栏配置
176 阅读
3
nvim番外之将配置的插件管理器更新为lazy
165 阅读
4
2018总结与2019规划
154 阅读
5
wsl 启动报错:Wsl/0x80080005
132 阅读
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
登录
Search
标签搜索
c++
c
emacs
elisp
学习笔记
windows
文本操作术
编辑器
NeoVim
Vim
win32
读书笔记
VimScript
linux
文本编辑器
投资理财
Java
反汇编
OLEDB
数据库编程
Masimaro
累计撰写
471
篇文章
累计收到
33
条评论
首页
栏目
软件与环境配置
读书笔记
编程
Thinking
FIRE
菜谱
翻译
页面
归档
友情链接
关于
搜索到
4
篇与
的结果
2026-10-10
《elisp 每日一练》—— syntax table 与 font lock
在前面一节的练习,我们做了一个简单的c 语言语法着色的效果。我们再回看一下代码发现,在设置关联的时候我们实际上没有设置 syntax-table,纯粹靠着正则表达式匹配特定字符和文本结构就完成了着色。这么做也有一个问题,就是它会遇到关键字、就着色,不管它出现的位置。读者可以使用下面的代码来测试一下// this is a line comment with keyword: return、this /*this is a block comment with type int、float*/ int main() { int x = 10; char* str = "this is a string with return and int"; return 0; }本篇我们的目的就是要搞清楚syntax-table 在语法着色的作用,以及我们如何利用syntax-table 来解决这一问题背景知识实际上font lock 着色主要依赖与下面三个类型:font-lock-keywords 里面的正则匹配,也就是我们前面定义的那个映射关系手动填充的 syntax-table 表,以及syntax-propertize-function 函数中将文本赋予的 syntax-table 属性font-lock-syntactic-face-function 函数决定的注释和字符串用什么类型的face我们说第一个是显性的,依赖完整正则匹配。后面两类却是依赖 syntax-table 的词法分析来完成工作。也就是说即使我们不使用 font lock 显式的通过正则表达式这种方式指定,只要我们正确的将对应的文本设置了syntax-table 属性,也可以完成语法着色的工作。正常情况下,我们首先根据编程语言的语法规则,为各个字符设置语法标签,填入到 syntax-table 中,例如将 /**/ 设置为注释,将 " 设置为字符串。接着在利用 font lock 进行语法高亮时调用 syntax-ppss 进行逐段的扫描(这个函数我们前面介绍过,它会按照语法表 syntax-table 自动跳转到下一个语法元素位置)。如果发现当前在字符串或者注释中就会使用 font-lock-comment-face / font-lock-string-face 给这段文本上色。这部分的工作都是通过 syntax-table 完成的对于块注释包含多行的情况下,Emacs 实际上还通过 syntax-propertize-function 利用文本属性中的 syntax-table 属性完成着色和 syntax-ppss 的跳转工作。最后因为 syntax-table 中只规定了那么几种词法样式,并没有规定类型、变量、函数、常量这种高级的语法特性,所以语法着色层面还是需要依赖我们前面定义的正则表达式匹配规则。最后我们再来看看我们之前设置的 font-lock-defaults 它到底接收什么样的值。(KEYWORDS [KEYWORDS-ONLY [CASE-FOLD [SYNTAX-ALIST ...]]])其中各个参数的含义如下:KEYWORDS: 就是我们前面一直在定义使用的规则,它可以是正则表达式和face 符号组成的cons cell,可以是正则表达式、捕获组和face符号组成的列表,也可以一个正则表达式带上多个捕获组和faceKEYWORDS-ONLY: 我们前面一直穿的是nil,nil表示即执行我们使用正则表达式在语法层面的着色,也执行 syntax-table 词法层面的着色,为 t 的话则只进行语法层面的着色CASE-FOLD 正则匹配时是否忽略大小写,为nil 时表示不忽略,t为忽略,此时像 int、Int、INT 这类的关键都会着色SYNTAX-ALIST 表示着色时使用的语法表,我们可以额外提供一个新的syntax-table 替换当前着色时使用的 syntax-table,默认使用的是当前buffer中的 syntax-table练习现在我们应该知道如何解决上面提到的,只要是 return、int 等关键字都会进行着色的问题了。我们实际上只需要添加关于注释和字符串的 syntax-table 项就可以解决这个问题(defvar my-simplec-mode-syntax-table (let ((st (make-syntax-table))) (modify-syntax-entry ?\" "\"" st) ;; 字符串 (modify-syntax-entry ?/ ". 124" st) ;; 注释 (modify-syntax-entry ?* ". 23" st) ;; 块注释 (modify-syntax-entry ?\n "> b" st) ;; 注释结束符 st)) (defvar my-simplec-font-lock-keywords `( ("\\<\\(if\\|else\\|while\\|for\\|return\\)\\>" . font-lock-keyword-face) ("\\<\\(int\\|float\\|double\\|char\\|void\\|bool\\)\\>" . font-lock-type-face) ("\\<\\(true\\|false\\|null\\|NULL\\)\\>" . font-lock-constant-face) ;; 函数定义 ("\\<\\([a-zA-Z0-9_]+\\)\\s-+\\([a-zA-Z0-9_]+\\)\\s-*(" (1 font-lock-type-face) (2 font-lock-function-name-face)) ;; 变量定义 ("\\<\\(int\\|float\\|double\\|char)\\s-+\\([a-zA-Z0-9_]+\\)" (1 font-lock-keyword-face) (2 font-lock-variable-name-face)) ) "MySimpleC 的 Font Lock 正则匹配与 Face 绑定规则。") (define-derived-mode my-simplec-mode text-mode "MySimpleC" ;; 这里为了避免 prog-mode 的干扰改成了 text-mode "配置简单的 Font Lock 关键字代码高亮" (setq-local font-lock-defaults '(my-simplec-font-lock-keywords nil nil)))这里我们添加了关于注释和字符串的 syntax-table 项,它们的着色就放到扫描时解决,因此就删除了正则表达式中关于注释着色的内容。总结到这里我们梳理了 syntax-table 在 font lock 中的作用。syntax-table 是我们在编辑时使用 forward-word 、syntax-ppss 等函数的基础。在此基础上,在启动 font lock 的时候会自动的利用syntab-table 进行词法层面的跳转,例如跳过注释。并且如果我们在 font-lock-defaults 参数中 KEYWORDS-ONLY 位置设置的是 nil 也会利用 syntax-table 中设置的字符串、注释等属性对这些元素进行着色。最后利用我们设置的正则表达式区分关键字、类型、变量、常量、函数名等语法单元进行语法层面的高亮。
2026年10月10日
5 阅读
0 评论
0 点赞
2026-09-24
《elisp 每日一练》—— define-derived-mode 管理 syntax-table
在前面的文章中,我们了解了,实际在通过 define-derived-mode 定义自己的Major Mode 的时候,在处理 syntax-table 时主要通过继承的方式继承父类中内容,然后通过 modify-syntax-entry 修改不符合当前语境下的项目。或者使用 syntax-propertize-function 通过正则表达式处理一些复杂的情况。今天我们深入探讨 define-derived-mode 宏是如何管理 syntax-table 以及如何通过继承机制获得父类的 syntax-table背景知识syntax-table 关键字与 abbrev-table 类似,define-derived-mode 支持通过 :syntax-table 自定义syntax-table。我们通过一个简单的示例看看宏展开的代码:(define-derived-mode my/code-mode prog-mode "mycode" "my code 测试mode" :syntax-table (let ((my-code-syntax-table (make-syntax-table)))))我们展开之后发现,与 syntax-table 相关的代码只有(set-syntax-table (let ((my-code-syntax-table (make-syntax-table)))))也就是说它仅仅将我们通过 :syntax-table 关键字传进来的 内容设置为当前buffer中的 syntax-table。此时继承相关的内容由我们自己管理。因此这里得出的结论也是与 abbrev-table 类似:应该在外部定义一个与宏里面 syntax-table 命名相同的 syntax-table 变量,我们在外部只关心具体的定义,而其余细节交给宏来处理。set-char-table-parent我们观察在继承机制下,对于 syntax-table 的处理发现,继承机制实际上是通过 set-char-table-parent 函数来完成。(set-char-table-parent CHAR-TABLE PARENT)这个代码是底层通过 c 实现的,我们可以简单的看看在Emacs中它是如何实现的。在我找到的一些源码资料中显示,这个函数的C语言实现如下:DEFUN ("set-char-table-parent", Fset_char_table_parent, Sset_char_table_parent, 2, 2, 0, doc: /* Set the parent char-table of CHAR-TABLE to PARENT. Return PARENT. PARENT must be either nil or another char-table. */) (Lisp_Object char_table, Lisp_Object parent) { Lisp_Object temp; CHECK_CHAR_TABLE (char_table); if (!NILP (parent)) { CHECK_CHAR_TABLE (parent); for (temp = parent; !NILP (temp); temp = XCHAR_TABLE (temp)->parent) if (EQ (temp, char_table)) error ("Attempt to make a chartable be its own parent"); } set_char_table_parent (char_table, parent); return parent; } static void set_char_table_parent (Lisp_Object table, Lisp_Object val) { XCHAR_TABLE (table)->parent = val; }从这里我们可以看到,函数内部主要的工作实际上是将表中的 parent 指针指向真实的父类。所以说它的继承结构实际上构成了一个链表。按照我们写程序的一般规律来讲,如果是一个链表结构,可以合理的推测它的查找流程应该是这样的:先在当前buffer 中记录的 syntax-table 表中查找如果未找到,则根据 parent 指针找到它的父表,在父表中查找根据记录的 parent 指针一级级的往后找,直到找到或者 parent 指针是空我们可以在Emacs的源码中找到查表相关的代码:Lisp_Object char_table_ref (Lisp_Object table, int c) { struct Lisp_Char_Table *tbl = XCHAR_TABLE (table); Lisp_Object val; if (ASCII_CHAR_P (c)) { val = tbl->ascii; if (SUB_CHAR_TABLE_P (val)) val = XSUB_CHAR_TABLE (val)->contents[c]; } else { val = tbl->contents[CHARTAB_IDX (c, 0, 0)]; if (SUB_CHAR_TABLE_P (val)) val = sub_char_table_ref (val, c, UNIPROP_TABLE_P (table)); } if (NILP (val)) { val = tbl->defalt; if (NILP (val) && CHAR_TABLE_P (tbl->parent)) val = char_table_ref (tbl->parent, c); } return val; }别的先不用太纠结,我们看到它分了三种情况:如果是普通的 ASCII 字符,直接查找表中的 contents 数据如果是非 ASCII 字符,调用 sub_char_table_ref 查找最后如果当前表中未找到,它会通过 parent 指针找到父表,再递归调用一次上面的代码中,我们看不到 syntax-table 的相关名称,转而退化为了 char-table。实际上 char-table 是Emacs专门为了快速查找 key 类型为 unicode 字符,而value 类型为对应数据这种映射关系而设计的数据结构。syntax-table 只是它里面的一种。如果深入了解Emacs之后会发现很多类似的结构。总结最后我们来总结一下关于 syntax-table 的相关内容。默认情况下,define-derived-mode 会根据传入的 parent 参数来执行继承操作。实现继承的主要方式就是调用 set-char-table-parent 将多个表组成一个链表,实际查找时按链表顺序进行查找。我们可以使用 :syntax-table 关键字指定 syntax-table,但是这个时候需要我们自己处理关于表的一切,define-derived-mode 只负责设置当前buffer 的 syntax-table 为我们指定的内容。
2026年09月24日
7 阅读
0 评论
0 点赞
2026-09-23
《elisp 每日一练》—— 处理复杂与多字符注释
在上一节,我们提到使用 modify-syntax-entry 定义各种符号范围。对于注释来说,它支持通过简单的1到4 这样的数字标识符来表达注释范围,但是对于像xml中的 <!----> 和 <CDATA[]> 这样的结构就无能无力了。今天我们来看看如何处理这种复杂的情况。背景知识syntax-propertize-function 的基本使用对于xml中的注释,或者像python中支持的 """ 注释我们需要使用 syntax-propertize-function 函数来处理。昨天我们提到 syntax-propertize-function 时说它是一个函数实际上是不准确的,实际上它是 Emacs 语法解析的“动态补丁”机制。当 syntax-table 静态规则不够用的时候,它允许你根据缓冲区中的实际上下文为特定的临时打上 syntax-table 文本属性,从而覆盖原有的语法定义。我们打一个不那么恰当的例子,每个人的角色是多变的,他可以是一个父亲,一个丈夫,一名企业职工,也可以是一个儿子。同样的一个字符在不同位置表现出来的含义可能不同。前面我们说到 / 可以是除法运算符,或者作为注释开始的字符。而 # 在c语言中同样有不同的含义,在一段代码的开始位置可能是预处理指令,而在宏定义的中间,用来将参数转换为一个字符串字面量。所以说我们只会通过 modify-syntax-entry 设置字符的静态类型是不够的。syntax-propertize-function 实际是一个变量。变量应该被设置成一个函数,Emacs 在需要解析语法时会自动调用这个函数。如果从C/C++ 语言的角度来说,它是一个需要用户自己实现的接口。函数接收两个参数 start 和 end, 表示需要处理的缓冲区范围。函数内部需要扫描这个区域,给区域内对应的字符设置 syntax class 标识。与 syntax-table 相似的,我们可以定义一个以 mode 名称加 -syntax-propertize 命名的函数,然后通过 setq-local 设置当前buffer 的 syntax-propertize-function 为我们定义的函数。我们看一个具体的示例,C++ 11 新增了一种 R"()" 表达的字符串,它里面可以包含,""、\ ,这些都被视为字符串的一部分,再也不用频繁的使用 \ 对特殊字符进行转义了。针对这种情况,我们无法再简单的将 "" 中包裹的内容统一视为字符串了。我们需要判断"" 是否出现在 R"()" 中。我们可以写下如下代码:(defun my-raw-string-propertize (start end) "把 R\"(...)\" 标记为字符串。" (goto-char start) ;; 搜索开启符 R"( (while (re-search-forward "R\"(" end t) (let ((open-pos (match-beginning 0))) ; R"( 的起点 ;; 如果已经在字符串/注释里,跳过 (unless (nth 3 (syntax-ppss open-pos)) (save-excursion ;; 向后找结束符 )" (when (search-forward ")\"" nil t) (let ((close-pos (match-end 0))) ; )" 的终点 ;; 第一步:整段标成字符串 (put-text-property open-pos close-pos 'syntax-table (string-to-syntax "|")) ;; 第二步:把内容里的 " 覆盖成标点 (save-excursion (goto-char open-pos) (search-forward "(" nil t) ; 跳过 R"( (while (search-forward "\"" close-pos t) (put-text-property (1- (point)) (point) 'syntax-table (string-to-syntax ".")))))))))))上面的内容非常简单,我们先匹配 R"( 然后从这个位置往后匹配它的结束位置 )",将中间的部分标记为字符串。另外我们还取消了字符串中之前对于某些字符的定义。syntax-propertize-extend-region-functions hook 基本简介但是读者应该注意到,这段代码是有问题的。它基于一个假设,Emacs扫描时传入的 start 和 end 正好包含了完整的 R"()" 字符串表达。如果字符串比较长,而Emacs一次没有完全扫描完,可能出现这次无法找到结束标记,而下一次无法找到开始标记的问题。所以读者不用拿这段代码进行测试,我们只需要理解这个基本的思路即可。我们虽然可以通过 (point-min) 和 (point-max) 函数主动的扩大扫描的范围,但是要考虑到最终的性能。而且我们改了之后,Emacs并不知道,下一次问题仍然存在,在函数内部就又要执行一次,最终拖累整体性能。所以最好的办法就是我们在当前基础之上逐步向外寻找R"()" 的开始和结束标志,处理之后通知Emacs,更新范围。Emacs提供了 syntax-propertize-extend-region-functions 类型的hook函数,它在 syntax-propertize-function 被调用之前调用,这个hook函数返回一个新范围 (new-start . new-end) ,Emacs 下一次会按照这个范围再调用 syntax-propertize-function。所以整体的流程应该是:Emacs 调用 syntax-propertize-function 之前先调用 syntax-propertize-extend-region-functions。传入一个范围,假设范围是 start = 100 end = 300在函数 syntax-propertize-extend-region-functions 发现 R"()" 的范围可能跟想象中不一样,假设是 start = 50 end = 240,此时 syntax-propertize-extend-region-functions 会返回这个范围此时Emacs使用hook 函数返回的实际位置范围调用 syntax-propertize-functionsyntax-propertize-rules 宏实际上在 syntax-propertize-function 函数中的操作非常固定:使用正则表达式匹配一个范围,将范围内文本 syntax-table 属性进行修改。那么这种固定的工作可以抽象为一个函数或者宏,Emacs中提供了 syntax-propertize-rules 宏来完成这类工作。(syntax-propertize-rules &rest RULES)RULES 是一组规则,每组规则都由两个部分组成:正则表达和语法类型。例如对于xml 的注释来说,我们可以写下如下的匹配规则(setq-local syntax-propertize-function (syntax-propertize-rules ;; 当正则匹配到 <!-- 时,将最后一个 '-' 动态标记为“注释开始”('<') ("<!--" (0 "<")) ;; 当正则匹配到 --> 时,将第一个 '-' 动态标记为“注释结束”('>') ("-->" (0 ">"))))后面的 (0 "<") 表示正则表达式的捕获组。syntax-table 属性前面我们介绍了 modify-syntax-entry 它修改了语法表 syntax-table, emacs 利用它来实现快速跳转到下一个语法单元、高亮语法单元等等操作,可以说是文本进行词法分析的产物。但是文中给出的 syntax-propertize-function 函数操作,实际在修改文本的 syntax-table 属性,它们二者有什么共同点和不同呢?实际上buffer 的 syntax-table 和 文本属性的 syntax-table 是两套并存、但优先级不同的机制。它们最终都影响 Emacs 对“某个字符是什么语法类”的判断,但作用方式不同。Emacs在确定字符最终的语法属性时,优先查看字符上面是否带了 syntax-table 属性,如果有则采用属性记录的语法类型。如果没有则查找buffer 中的 syntax-table 。实际上我们已经可以意识到,和人的属性一样,一个字符在不同的位置有不同的语法属性,不可能永远是一种角色。单单依靠 syntax-table 语法表是无法处理复杂的情况的。所以Emacs在其基础上打了一个补丁。总结今天我们学习了通过 syntax-propertize-function 处理复杂的情况。该函数由Emacs调用,Emacs每次对一个区域进行扫描都会调用该函数。在函数中我们可以通过正则表达式或者其他方式设置文本的 syntax-table 属性,确定文本的语法类型。如果一次扫描无法覆盖整个语法区域,可以实现 hook 函数 syntax-propertize-extend-region-functions 调整扫描范围。而对于正则表达式匹配为文本赋值 syntax-table 属性,这种重复的工作可以交给 syntax-propertize-function 完成。
2026年09月23日
7 阅读
0 评论
0 点赞
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日
11 阅读
0 评论
0 点赞