PR['registerLangHandler'] 的调用被引用,以便 Closure Compiler 不会重命名该调用,以便可以分别编译/缩小此语言扩展。 prettify.js 中定义的其他符号也以类似方式引用。
调用的结构如下:
```
PR['registerLangHandler'](
PR['createSimpleLexer'](
shortcutPatterns, // 快捷模式数组
fallThroughPatterns), // 后备模式数组
[languageId0, ..., languageIdN]) // 语言ID数组
```
语言 ID
=============
语言 ID 通常是该语言的源文件的扩展名,以便用户可以仅根据扩展名语法突出显示任意文件。 这是启发式的,但在实践中效果很好。
快捷模式
=================
快捷模式是在标记中的第一个字符位于字符串中的情况下在其他模式之前尝试的模式。
这非常有效地让我们可以快速正确地决定常见标记类型。
所有其他模式都是后备模式。
后备模式
========
词法分析器通常实现为一组正则表达式。
`SimpleLexer` 函数采用正则表达式、样式和一些语用信息并生成一个词法分析器。 令牌描述如下所示:
`[STYLE_NAME, /regular-expression/, pragmas]`
最初,简单词法分析器的内部循环如下所示:
```
while sourceCode is not empty:
try each regular expression in order until one matches
remove the matched portion from sourceCode
当源代码不为空时:
按顺序尝试每个正则表达式,直到有一个正则表达式匹配
从 sourceCode 中删除匹配的部分
```
对于大型文件来说,这非常慢,因为某些 JS 解释器会对匹配部分进行缓冲区复制,复杂度是 O(n*n)。
当前循环现在如下所示:
1. 使用 js-modules/combinePrefixPatterns.js 将所有正则表达式组合成一个
2. 使用单个全局正则表达式匹配来提取所有标记
3. 对于每个标记,按顺序尝试正则表达式,直到一个匹配它并使用关联的样式对其进行分类
这提高了很多效率,但这意味着无法跨边界使用前瞻和后顾来对标记进行分类。
有时我们需要前瞻和后顾,有时我们想处理嵌入式语言——HTML 中的 JavaScript 或 CSS,或 C 中的内联汇编。
如果特定模式具有编号组,并且其样式模式以“lang-”开头,如:
`['lang-js', /<script>(.*?)<\/script>/]`
那么标记分类步骤会将标记分解成多部分。
第 1 组括号的内容使用“lang-js”的语言处理程序重新解析,周围部分使用当前语言处理程序重新分类。
此机制为我们提供了前瞻、后顾和语言嵌入。