4. Lexer and Parser Definition
词法分析器定义文件内容如何分解为令牌。
创建词法分析器的最简单方法是使用JFlex
4.1。
定义词法分析器
使用我们词法分析器的规则定义*/com/simpleplugin/Simple.flex *文件。
package com.simpleplugin;
import com.intellij.lexer.FlexLexer;
import com.intellij.psi.tree.IElementType;
import com.simpleplugin.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; }
4.2。
生成词法分类器
现在我们可以从Simple.flex文件的上下文菜单中通过* JFlex Generator *生成一个词法分析器类。
Grammar-Kit插件使用JFlex lexer生成。
如果您是第一次运行它,它会让您选择一个文件夹来下载JFlex库和骨架。
选择项目根目录。
之后,IDE生成词法分析器:* com.simpleplugin.SimpleLexer *。
4.3。
定义适配器
package com.simpleplugin;
import com.intellij.lexer.FlexAdapter;
import java.io.Reader;
public class SimpleLexerAdapter extends FlexAdapter {
  public SimpleLexerAdapter() {
    super(new SimpleLexer((Reader) null));
  }
}
4.4。
定义根文件
在com.simpleplugin.psi命名空间中创建类。
package com.simpleplugin.psi;
import com.intellij.extapi.psi.PsiFileBase;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.psi.FileViewProvider;
import com.simpleplugin.*;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
public class SimpleFile extends PsiFileBase {
  public SimpleFile(@NotNull FileViewProvider viewProvider) {
    super(viewProvider, SimpleLanguage.INSTANCE);
  }
  @NotNull
  @Override
  public FileType getFileType() {
    return SimpleFileType.INSTANCE;
  }
  @Override
  public String toString() {
    return "Simple File";
  }
  @Override
  public Icon getIcon(int flags) {
    return super.getIcon(flags);
  }
}
4.5。
定义解析器定义
package com.simpleplugin;
import com.intellij.lang.*;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.tree.*;
import com.simpleplugin.parser.SimpleParser;
import com.simpleplugin.psi.*;
import org.jetbrains.annotations.NotNull;
public class SimpleParserDefinition implements ParserDefinition {
  public static final TokenSet WHITE_SPACES = TokenSet.create(TokenType.WHITE_SPACE);
  public static final TokenSet COMMENTS = TokenSet.create(SimpleTypes.COMMENT);
  public static final IFileElementType FILE = new IFileElementType(SimpleLanguage.INSTANCE);
  @NotNull
  @Override
  public Lexer createLexer(Project project) {
    return new SimpleLexerAdapter();
  }
  @NotNull
  public TokenSet getWhitespaceTokens() {
    return WHITE_SPACES;
  }
  @NotNull
  public TokenSet getCommentTokens() {
    return COMMENTS;
  }
  @NotNull
  public TokenSet getStringLiteralElements() {
    return TokenSet.EMPTY;
  }
  @NotNull
  public PsiParser createParser(final Project project) {
    return new SimpleParser();
  }
  @Override
  public IFileElementType getFileNodeType() {
    return FILE;
  }
  public PsiFile createFile(FileViewProvider viewProvider) {
    return new SimpleFile(viewProvider);
  }
  public SpaceRequirements spaceExistenceTypeBetweenTokens(ASTNode left, ASTNode right) {
    return SpaceRequirements.MAY;
  }
  @NotNull
  public PsiElement createElement(ASTNode node) {
    return SimpleTypes.Factory.createElement(node);
  }
}
4.6。
注册解析器定义
<lang.parserDefinition language="Simple" implementationClass="com.simpleplugin.SimpleParserDefinition"/>
4.7。
运行该项目
使用以下内容创建属性文件:
# You are reading the ".properties" entry.
! The exclamation mark can also mark text as comments.
website = http://en.wikipedia.org/
language = English
# The backslash below tells the application to continue reading
# the value onto the next line.
message = Welcome to \
          Wikipedia!
# Add spaces to the key
key\ with\ spaces = This is the value that could be looked up with the key "key with spaces".
# Unicode
tab : \u0009
现在打开* PsiViewer *工具窗口,检查词法分析器如何将文件内容分解为标记,解析器将标记解析为PSI元素。
                        Last modified: 8 May 2019