我正在阅读 自定义语言支持教程 并在第 4 部分的最后一节收到编译错误。
错误是:
cannot find symbol zzAtBOL = true; location: class SimpleLexer
如果我评论这一行,下一个错误是:
cannot find symbol if (!zzEOFDone) { location: class SimpleLexer
注释掉对
zzAtBOL
和zzEOFDone
的引用“解决”了这个问题,我能够runIde
。但显然这不是解决问题的方法。
所以,问题是如何让“Run JFlex Generator”在我的案例中生成有效的源代码?
一些细节:
使用 Intellij Idea Build #IU-223.8836.41,构建于 2023 年 3 月 10 日
使用 Kotlin 代替 Java 实现插件。
com.example.sampleplugin.SimpleLanguage.kt:
package com.example.sampleplugin
// imports
object SimpleLanguage : Language("Simple")
object SimpleFileType : LanguageFileType(SimpleLanguage) {
override fun getName() = "Simple File"
override fun getDescription() = "Simple language file"
override fun getDefaultExtension() = "simple"
override fun getIcon() =
IconLoader.getIcon("/icons/jar-gray.png", SimpleLanguage::class.java)
}
object SimpleLexerAdapter : FlexAdapter(SimpleLexer(null))
class SimpleFile(viewProvider: FileViewProvider) : PsiFileBase(viewProvider, SimpleLanguage) {
override fun getFileType() = SimpleFileType
}
object SimpleTokenSets {
val identifier = TokenSet.create(SimpleTypes.KEY)
val comments = TokenSet.create(SimpleTypes.COMMENT)
}
object SimpleParserDefinition : ParserDefinition {
override fun createLexer(project: Project?) = SimpleLexerAdapter
override fun createParser(project: Project?) = SimpleParser()
override fun getFileNodeType() = IFileElementType(SimpleLanguage)
override fun getCommentTokens() = SimpleTokenSets.comments
override fun getStringLiteralElements(): TokenSet = TokenSet.EMPTY
override fun createElement(node: ASTNode?): PsiElement = SimpleTypes.Factory.createElement(node)
override fun createFile(viewProvider: FileViewProvider) = SimpleFile(viewProvider)
}
com/example/sampleplugin/psi.SimplePsi.kt:
package com.example.sampleplugin.psi
// imports
class SimpleTokenType(debugName: String) : IElementType(debugName, SimpleLanguage)
class SimpleElementType(debugName: String) : IElementType(debugName, SimpleLanguage)
.bnf
和 .flex
文件我从教程中原样复制(仅更改包):
{
parserClass="com.example.sampleplugin.parser.SimpleParser"
extends="com.intellij.extapi.psi.ASTWrapperPsiElement"
psiClassPrefix="Simple"
psiImplClassSuffix="Impl"
psiPackage="com.example.sampleplugin.psi"
psiImplPackage="com.example.sampleplugin.psi.impl"
elementTypeHolderClass="com.example.sampleplugin.psi.SimpleTypes"
elementTypeClass="com.example.sampleplugin.psi.SimpleElementType"
tokenTypeClass="com.example.sampleplugin.psi.SimpleTokenType"
}
simpleFile ::= item_*
private item_ ::= (property|COMMENT|CRLF)
property ::= (KEY? SEPARATOR VALUE?) | KEY
package com.example.sampleplugin;
import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import com.example.sampleplugin.psi.SimpleTypes;
import com.intellij.psi.TokenType;
%%
%class SimpleLexer
%implements FlexLexer
%unicode
%function advance
%type IElementType
%eof{ return;
%eof}
CRLF=\R
WHITE_SPACE=[\ \n\t\f]
FIRST_VALUE_CHARACTER=[^ \n\f\\] | "\\"{CRLF} | "\\".
VALUE_CHARACTER=[^\n\f\\] | "\\"{CRLF} | "\\".
END_OF_LINE_COMMENT=("#"|"!")[^\r\n]*
SEPARATOR=[:=]
KEY_CHARACTER=[^:=\ \n\t\f\\] | "\\ "
%state WAITING_VALUE
%%
<YYINITIAL> {END_OF_LINE_COMMENT} { yybegin(YYINITIAL); return SimpleTypes.COMMENT; }
<YYINITIAL> {KEY_CHARACTER}+ { yybegin(YYINITIAL); return SimpleTypes.KEY; }
<YYINITIAL> {SEPARATOR} { yybegin(WAITING_VALUE); return SimpleTypes.SEPARATOR; }
<WAITING_VALUE> {CRLF}({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
<WAITING_VALUE> {WHITE_SPACE}+ { yybegin(WAITING_VALUE); return TokenType.WHITE_SPACE; }
<WAITING_VALUE> {FIRST_VALUE_CHARACTER}{VALUE_CHARACTER}* { yybegin(YYINITIAL); return SimpleTypes.VALUE; }
({CRLF}|{WHITE_SPACE})+ { yybegin(YYINITIAL); return TokenType.WHITE_SPACE; }
[^] { return TokenType.BAD_CHARACTER; }
检查是否:
/**
* zzAtBOL == true <=> the scanner is currently at the beginning of a line
*/
private boolean zzAtBOL = true;
发生在上面:
/** zzAtEOF == true <=> the scanner is at the EOF */
private boolean zzAtEOF;
在文件 idea-flex.skeleton 中,它应该在您的项目主目录中。
如果这些行不在该文件中,则添加它们,然后再次尝试运行 JFlex Generator。
问题在于 JFlex 和 Grammar-Kit Intellij 插件 使用的 idea-flex.skeleton 之间的版本差异。目前看来,该插件采用较旧的 jflex-1.7.0-2.jar 和较新的 idea-flex.skeleton.
并且在这个更新的idea-flex.skeleton
zzAtBOL
和zzEOFDone
被删除(见IC commit)。
所以,我的解决方案是下载并从 CLI 使用更新的 JFlex:
java -Xmx512m -Dfile.encoding=UTF-8 \
-jar jflex-1.9.1.jar -skel idea-flex.skeleton \
-d src/main/gen/com/example/sampleplugin \
src/main/kotlin/com/example/sampleplugin/Simple.flex