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