实现词法分析器
Lexer,或称为
词法分析器,
它定义了如何将文件的内容分解为 token。
词法分析器是自定义语言插件几乎所有特性的基础,从基础语法高亮,到高级代码分析特性。
Lexer 的 API 被定义在
Lexer
接口中。
IDE 在三个主要的上下文中调用 lexer,并且插件可以为这些上下文提供不同的 lexer 实现:
-
语法高亮: Lexer 将从
SyntaxHighlighterFactory
接口的实现中被返回,该接口在com.intellij.lang.syntaxHighlighterFactory
扩展点中被注册。 -
构建文件的语法树:Lexer 预期从
ParserDefinition.createLexer()
, 中返回,并且ParserDefinition
接口在com.intellij.lang.parserDefinition
扩展点中被注册。 -
构建文件中包含的单词的索引: 如果使用了基于 lexer 的单词扫描器的实现,lexer 将被传递到
DefaultWordsScanner
的构造器中。
用于语法高亮的 lexer 可以被增量调用,以仅处理文件中被修改的部分,而在其他情况下的 lexer 总是被调用来处理整个文件,或以不同的语言嵌入到文件的完整语言结构中。
增量地使用 Lexer 可能需要返回它的状态,这意味着上下文对应着文件中的每个位置。
例如,对于顶级上下文,注释上下文与字面字符串上下文,
Java lexer
可以拥有独立的状态。
对于语法高亮 lexer 的一个重要需求是:当词法分析从文件的中间恢复时,它的状态必须通过单个整型数字表示,这个数字从
Lexer.getState()
中被返回。
那个状态将被传递到
Lexer.start()
方法中,以及要处理的片段的起始偏移量。
用于其他上下文的 Lexer 可以总是从 getState()
方法中返回 0
。
最简单的为自定义语言查案件创建 lexer 的方式是使用 JFlex。
类
FlexLexer
与
FlexAdapter
使 JFlex lexer 适配 IntelliJ Platform Lexer API。
我们有一个
JFlex 的修补版本,
可以与在
IntelliJ IDEA Community Edition
源代码中位于 tools/lexer/idea-flex.skeleton 的 lexer skeleton 文件一起使用,以创建与
FlexAdapter
相兼容的 lexer。
JFlex 的修复版本提供了一个新的命令行选项 --charat
,它可以改变 JFlex 生成的代码从而使其与 IntelliJ Platform skeleton 一起工作。
为词法解析启用 --charat
选项传递的数据类型为
CharSequence
而不是一个字符数组。
对于使用 JFlex 开发 lexer,GrammarKit plugin 是很有用的。 它为编译 JFlex 文件提供语法高亮和其他有用的特性。
示例:
用于 lexer 的 token 的类型通过
IElementType
的实例定义。
所有语言通用的许多 token 类型定义在
TokenType
接口中。
自定义语言插件应该在适用的情况下重用这些 token 类型。
对于所有其他 token 类型,插件需要去创建新的
IElementType
实例并与使用 token 类型的语言相关联。
每当 lexer 遇到特定的 token 类型时,都应该返回相同的
IElementType
实例。
示例: 针对 Properties language plugin 的 Token 类型
可以在 lexer 级别中实现的一个重要特性是在文件中混合语言,例如,嵌入 Java 代码片段到某些模板语言中。
如果一个语言支持(动词)将其代码片段嵌入另一种语言,则它需要为可以嵌入的不同类型的片段定义变色龙(译者注:原文为 chameleon) token 类型,并且这些 token 类型需要实现
ILazyParseableElementType
接口。
封闭语言的 lexer 需要把嵌入式语言的整个片段作为单个变色龙 token 返回,类型由嵌入语言定义。
为了解析变色龙 token 的内容,IDE 将会通过调用
ILazyParseableElementType.parseContents()
来调用嵌入式语言的解析器。