Intellij Language Plugin Tutorial中“Run JFlex Generator”后如何正确解决“cannot find symbol”?

问题描述 投票:0回答:2

我正在阅读 自定义语言支持教程 并在第 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; }
kotlin intellij-plugin
2个回答
1
投票

检查是否:

/**
  * 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。


0
投票

问题在于 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
© www.soinside.com 2019 - 2024. All rights reserved.