KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder));
String extension = FileUtilRt.getExtension(psiFile.getName());
if (extension.isEmpty() || extension.equals(KotlinFileType.EXTENSION) || (psiFile instanceof KtFile && ((KtFile) psiFile).isCompiled())) {
ktParsing.parseFile();
} else {
ktParsing.parseScript();
}
return psiBuilder.getTreeBuilt();
}
}
可以看到Kotlin的语法分析是通过KotlinParsing进行的,在parse方法中创建KotlinParsing然后把要分析的文件传递过去,这里的文件也就是我们熟悉的以 .kt结尾的文件。当然也不局限于kt文件。接着我们跟进下ktParsing.parseFile();
public class KotlinParsing extends AbstractKotlinParsing {
void parseFile() {
PsiBuilder.Marker fileMarker = mark();
//分析类的注释、package、import*
parsePreamble();
while (!eof()) {
//分析包、类、方法的声明方法,例如:package、class、function
parseTopLevelDeclaration();
}
checkUnclosedBlockComment();
fileMarker.done(KT_FILE);
}
}
parseFile中做的.
《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 开源分享
kt类中的声明分析,这些声明也就是上一篇提到的KtTokens中定义的关键字和操作符之类的。顺便提一下语法分析大概分为两类:
自顶向下分析:根据形式语法规则,在语法分析树的自顶向下展开中搜索输入符号串可能的最左推导。单词按从左到右的顺序依次使用。
自底向上分析:语法分析器从现有的输入符号串开始,尝试将其根据给定的形式语法规则进行改写,最终改写为语法的起始符号。
可以看到Koltin中是使用的自顶向下分析法,这种分析法也比较适合我们的编码习惯。 到这基本上有了语法分析的大概,但是没有看到我们前面举例的if和括号使用的分析。其实在KotlinParser中会创建KotlinExpressionParsing类,这个类中主要处理的也是一些和表达式相关的分析。
public class KotlinExpressionParsing extends AbstractKotlinParsing {
private boolean parseAtomicExpression() {
boolean ok = true;
if (at(LPAR)) {
parseParenthesizedExpression();
}else if (at(LBRACKET)) {
parseCollectionLiteralExpression();
} else if (at(IF_KEYWORD)) {
parseIf();
}
…
return ok;
}
private void parseIf() {
advance();
parseCondition();
PsiBuilder.Marker thenBranch = mark();
if (!at(ELSE_KEYWORD) && !at(SEMICOLON)) {
parseControlStructureBody();
}
if (at(SEMICOLON) && lookahead(1) == ELSE_KEYWORD) {
advance(); // SEMICOLON
}
thenBranch.done(THEN);
}
private void parseCondition() {
myBuilder.disableNewlines();
if (expect(LPAR, “Expecting a condition in parentheses ‘(…)’”, EXPRESSION_FIRST)) {
PsiBuilder.Marker condition = mark();
parseExpression();
condition.done(CONDITION);
expect(RPAR, “Expecting ')”);
}
myBuilder.restoreNewlinesState();
}
}
parseAtomicExpression方法中根据getTokenType判断当前关键字是this、try、if、when等,然后对单个关键字进行分析,以parseIf为例会先通过parseCondition检验if后有没有LPAR KtSingleValueToken LPAR = new KtSingleValueToken("LPAR", "(");
LPAR也就是我们在Token定义的“(”,如果发现没有括号也就会给我们提示前面我再studio中写if语句中的错误信息Expecting a condition in parentheses '(...)'
然后进行后续的判断,直到满足语法的要求,是一个完整的句子才不会给错误的提示。当然没有错误后会回到KotlinParser中的psiBuilder.getTreeBuilt();并生成AST抽象语法树
抽象语法树
抽象语法树的建立过程如图所示,可以让你更加清晰的理解本篇内容,图中的关键方法和类我们也有提到过。每一步骤的具体介绍和关键方法的作用IntelliJ平台插件SDK都有介绍,我就不做代码的搬运工了,感兴趣的可以了解下
总结
我们知道语法分析器是在词法分析之后,根据词法分析的结果和定义的语法规则判断输入的程序是否有语法错误。知其表也要知其里 综合上面的知识我们就可以得出Kotlin表达式if/When为什么要结合使用?大概分为3步如下:
1、我们拿到词法分析后输出在KtTokens中定义的关键字和运算符等如:if()、for()、final等 (获取Token流)
2、KotlinParsing会根据Token中定义的关键字进行组合判断在结构上是正确,如果在结构组合上不符合规范就抛出异常如:Expecting a condition in parentheses ‘(…)’(KotlinParsing语法分析)
是正确,如果在结构组合上不符合规范就抛出异常如:Expecting a condition in parentheses ‘(…)’(KotlinParsing语法分析)