如何实现高亮

平时我们在使用一些代码编辑器或者Markdown时很好奇它的代码高亮是如何实现的。其实原理也挺简单的,就是区分代码内容的不同token并加以颜色标识。我们将以js规则为例来说明这一过程。在对js代码的编译处理中其实只要第一个过程词法法分析即可实现基本的代码高亮,这个过程被称为lexer或者tokenizer。下面介绍一下词法语法结构。

词法结构

如何定义一门语言?想要分析一门语言,必须要从它的结构入手提取出一般化的东西。比如说中文的句式(|是或者的关系):

句子->主语 谓语 宾语

主语->代词|名词|短语

代词->你|我|他

可以通过迭代的方式来描述该语言。计算机语言也是语言,可以同样的方式来描述它,而且比自然语言更加的严格。计算机中定义该结构的式子就叫产生式,产生式是由终结符、非终结符、以及关系组成。终结符是无法往下扩展的符号,比如说代词中的“你”,“我”,“他”无法往下划分,非终结符由终结符、非终结符组成。产生式的写法:由巴克斯-若尔提出来的BNF(backs-Naur Form)产生式写法比较流行。上面的中文结构可以写成:

<中文>::=<句子>|<中文><句子>

<句子>::=<主语><谓语><宾语>|<主语><谓语>

<主语>::=<代词>|<名词>|<名词性短语>

<代词>::="你"|"我"|"他"

还有扩展后的EBNF:

中文::={句子} //{}表示可以重复多次

句子::=主语 谓语 [宾语] //方括号0-1个

主语::=代词 | 名词 | 名词性短语

代词::="你"|"我"|"他"

了解了产生式的写法,再来了解形式化语言的类型。

所有的计算机语言都属于形式化语言,根据其表达能力,划分了乔姆斯基谱系,从0-3规则越来越严格。他们也是从属关系,即3型必从属于2型,以此类推。(下方产生式的?即可指代终结符亦可指代非终结符).0-型文法(无限制文法或短语结构文法)所有的计算机语言都属于此范畴,计算机语 言必须是图灵完备的,也就是说该语言能完整编写出一个图灵机实现所有功能。

产生式?::=?

2.1-型文法(上下文相关文法)自然语言文法

产生式<上文><A><下文>::=<上文><B><下文>

3.2-型文法生成上下文无关语言,为大多数编程语言提供理论基础

产生式<A>::=?

4.3-型正规语言,表达能力等同有限状态自动机

产生式<A>::=<A>?

参考文献:https://262.ecma-international.org/11.0/#sec-lexical-grammar

Javascript的产生式

了解当中的Lexical Grammar部分就能完成token解析了,其它语言也相通。但是需要精简一下,毕竟对于新的es6语法,以及完全还原JavaScript 的解析代码量很大,也要做许多复杂处理,导致主题的思路反而不明确,所以简化下它的Lexical产生式如下:

实例中的xregexp。

需要辨识出注释,运算符,数字,变量,关键字这些即可,运用正则的强大能力对字符串处理。

用文件管理

使用一个文件来管理以及配置要用的正则,通过命名分组方式来分辨不同的token类型。

实例中compileRegExp

然后写个函数处理html过来的字符串以及执行正则。

实例中escapehtml、scan。