独家揭秘:Kotlin编译器前端—解析阶段

news2024/12/23 18:43:19

独家揭秘:Kotlin编译器前端:解析阶段

Kotlin编译器对我来说就像一个黑盒子,虽然有关于Kotlin PSI在IDE插件中有使用的文档,但除了源代码中留下的注释之外,几乎没有其他信息可用。接下来的文章中我们来探索Kotlin编译器前端:解析阶段。

Kotlin编译器的独特之处在于其前端是建立在其之上,这使得前端易于与编译器插件和IDE插件共享。对于Kotlin,前端的目标是解析编写的代码并分析其解释结构,以便生成中间表示(IR)。然后,将此IR和额外生成的信息一起发送到编译器的后端,后端会进一步分析、增强和优化IR,最终将其转化为机器码。
Kotlin编译器的前端部分,Kotlin文件被输入编译器,随后被分析并转换为AST / PSI,这样就可以在解析过程中进一步分析其正确性

这个系列观察了当您通过Kotlin编译器提供代码时发生的情况:这是了解编译器在每个阶段所做的最简单的方式。本文介绍了前端部分的第一阶段,即解析阶段。

解析阶段

源代码编译时,编译器首先必须弄清开发人员实际编写了什么。假设我们通过编译器发送以下文件:

fun main() {
    1 + 2
    1.plus(2)
}

编译器可以通过解析并将人类可读代码翻译成编译器自己可以理解的格式来“理解”开发人员编写的内容。在下面的图片中,Kotlin文件首先被提供给解析阶段。创建了一个词法分析器来解析源文件并生成标记。然后将这些标记通过语法分析进行处理,从而创建了一个PSI结构(在语法分析阶段下面更详细地解释和说明)。
Kotlin文件首先被输入到编译器的解析阶段。词法分析生成KtTokens和Kt。这些令牌随后通过语法分析进行处理,创建一个抽象语法树(AST)。

此时,编译器并不关心代码是否有效,只关心弄清楚文件中写了什么。解析阶段负责创建语法树,以便编译器在解析阶段后能够分析和验证代码。

解析的基础可以看作是以下两个阶段的过程:

  • 词法分析:将文本文件解析为令牌。
  • 语法分析:解析并组织令牌成为语法树。

词法分析

在词法分析期间,Kotlin解析器首先创建一个KotlinLexer。该Lexer扫描Kotlin文件并将文本拆分成一组称为KtTokens的标记。例如,KtTokens表示符号如下:

KtSingleValueToken LPAR = new KtSingleValueToken("LPAR", "(");
KtSingleValueToken RPAR = new KtSingleValueToken("RPAR", ")");

KotlinExpressionParsing将建立一个访问器来将这些记号安排成表达式节点的集合。这些表达式节点随后通过ASTNode附加以构建PSI树。

Programming Structure Interface(PSI)是JetBrains构建的一种抽象。它有点像重量级的通用语法树,可以在他们的IDE中处理文本/代码/语言。这些树是在语法分析期间生成的内存中表示,并且需要编译器生成附加的数据,并以后的阶段递归分析自身以进行代码验证。PSI对于编译器插件和IDEA插件很有用,因为您可以过滤PSI以拦截特定的代码片段。

简而言之,Kotlin解析器创建连接层次关系中的节点的结构。例如,如果KotlinExpressionParsing捕获到throw关键字,则会解析另一个元素,并将其转换为PSI元素添加到树中:

/*
 * : "throw" element
 */
private void parseThrow() {
    assert _at(THROW_KEYWORD)
    PsiBuilder.Marker marker = mark();
    advance(); // THROW_KEYWORD
    parseExpression(); 
    marker.done(THROW);
}

在接下来的部分中,语法分析将创建一个包装记号作为PsiElements的PSI解析器。每个节点都包含一个描述,递归地描述了源代码的语法结构。

语法分析

生成的PSI文件描述了一组PsiElements(称为PSI树),构建了语法和语义代码模型。PSI树更像是抽象语法树(AST)还是具体语法树(CST)?嗯,似乎生成的PSI树具有两者的特点。

Eli Bendersky关于抽象v.具体语法树的博客在更大的细节范围内很好地解释了两者之间的区别。像一个CST树一样,PSI结构包含所写内容的更正式的表示,包括符号。然而,像AST一样,PSI树在每个节点本身中保留了其他有用的信息。

在IntelliJ IDEA中,您可以下载插件PSIViewer来检查您编写的代码的PSI。您还可以突出显示代码的某些部分,以查看PSIViewer在其呈现的树中选择的内容。

下面的图像显示了PSIViewer如何将5.minus(2)解释为一个名为DOT_QUALIFIED_EXPRESSION的节点,其第一个子节点是INTEGER_CONSTANT 表示5,第二个子节点是DOT表示.,第三个子节点是CALL_EXPRESSION 表示minus(2)

PSIViewer可以让您检查PSI节点所持有的属性
这些PSI元素包含标记,并能够保留可能与其持有关系的子元素和父元素的信息。随着编译器从中构建并生成更多的信息,这些PSI结构变得更加复杂。PSI结构具有CST和AST的特征,虽然它们的结构随着时间的推移变得更加类似于AST。为了讨论和方便起见,我们将用AST的术语来指代这些树。

考虑表达式5—2。生成的AST如下图所示,树的较深色节点表示为元素,较浅色节点表示为标记。

工具PSIViewer将类似的树形结构呈现在您的IntelliJ IDE中,其中所有元素都定义为PsiElement类型。为了简单起见,此图像使用较浅的节点表示令牌(表示为“Token. p s i E l e m e n t ”),使用较暗的节点表示元素(表示为“ E l e m e n t . {psiElement}”),使用较暗的节点表示元素(表示为“Element. psiElement),使用较暗的节点表示元素(表示为Element.{psiElement}”)。

表达式5 - 2可以分解为由两个整数常数组成的二元表达式,作为操作数和一个OPERATION_REFERENCE作为运算符。但是,表达式5.minus(2),即使其计算结果与5 - 2相同,其AST结构也完全不同。


与将5-2定义为BINARY_EXPRESSION不同,5.minus(2)中的DOT_QUALIFIED_EXPRESSION包含了一个CALL_EXPRESSION,其REFERENCE_EXPRESSION是“minus”,VALUE_ARGUMENT_LIST是“(2)”。

PSI树告诉我们代码是如何被终端用户编写的,但目前为止并没有太多信息。这意味着在此阶段,编译器只能告诉我们代码是如何被编写的,但它并不知道代码是否能够编译通过。

无论代码是否正确,都可以构建PSI树。请考虑下面IntelliJ IDEA的屏幕截图。面板左侧显示了Utils.kt中的代码。在main函数中,有两个语句,函数的第二行是5.((2)而不是5.minus(2)。我们知道(IDE也知道)像5.((2)这样的语句将无法编译。但要记住,PSI树不需要知道这一点。它会生成元素,尽管可能无法准确解释层次关系。
PSIViewer捕捉LPAR LPAR元素
IDE如何能在屏幕截图的左侧窗格中给出红色波浪线?这正是Resolution阶段负责的,这给了我们下一篇文章的完美过渡。下一篇文章将深入探讨Resolution阶段,该阶段创建了必要的分析,帮助判断代码是否可以编译。请关注!
 Kotlin 编译器前端的“Parsing”与"Resolution"阶段

参考

https://www.youtube.com/watch?v=wUGfuWHCqrc&t=281s&ab_channel=KotlinbyJetBrains
https://github.com/ahinchman1/Kotlin-Compiler-Crash-Course/blob/master/README.md

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/638510.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6. WebGPU 将图像导入纹理

我们在上一篇文章中介绍了有关使用纹理的一些基础知识。在本文中,我们将介绍从图像导入纹理。 在上一篇文章中,通过调用 device.createTexture 创建了一个纹理,然后通过调用 device.queue.writeTexture 将数据放入纹理中。 device.queue 上还…

Axure教程—穿梭框(中继器+动态面板)

本文将教大家如何用AXURE中动态面板和中继器制作穿梭框效果 一、效果 预览地址:https://8k99mh.axshare.com 下载地址:https://download.csdn.net/download/weixin_43516258/87897661?spm1001.2014.3001.5503 二、功能 在待选区域选项中可以选择一个选…

CURL获取与使用

背景:在日常工作中,经常会遇到需要获取CURL构造请求来进行问题定位,那如何获取及使用CURL则成为一个测试人员必备的技能; CURL是什么 CURL是一个命令行工具,开发人员使用它来与服务器进行数据交互。 如何获取完整 C…

Python开源自动化工具Playwright安装及介绍

目录 前言 1、Playwright介绍 2、Playwright安装 3、实操演示 4、小结 总结: 前言 微软开源了一个非常强大的自动化项目叫 playwright-python 它支持主流的浏览器,包含:Chrome、Firefox、Safari、Microsoft Edge 等,同时支…

简单使用Hystrix

使用Hystrix之前&#xff0c;需要先对SpringCloud有所了解&#xff0c;然后才会使用的顺畅&#xff0c;它是我们SpringCould的一种保护机制&#xff0c;非常好用。 下面直接开始 先导入Hystrix所需要的依赖 <!-- 引入openfiegn--> <dependency> <groupId>org…

Java学习笔记(视频:韩顺平老师)3.0

如果你喜欢这篇文章的话&#xff0c;请给作者点赞哟&#xff0c;你的支持是我不断前进的动力。 因为作者能力水平有限&#xff0c;欢迎各位大佬指导。 目录 如果你喜欢这篇文章的话&#xff0c;请给作者点赞哟&#xff0c;你的支持是我不断前进的动力。 算数运算符 号使用…

体验 TDengine 3.0 高性能的第一步,请学会控制建表策略

正如我们之前所言&#xff0c;在 3.0 当中&#xff0c;我们在产品底层做了很大的变化调整&#xff0c;除了架构更加科学高效以外&#xff0c;用户体验也是我们重点优化的方向。以之前一篇文章为例&#xff1a;对于 Update 功能&#xff0c;用户不再需要任何配置 &#xff0c;默…

社交泛娱乐出海如何抓住AIGC?我在融云WICC上看到了答案

大模型掀起的AIGC时代&#xff0c;所有企业的所有业务与产品都值得利用大模型技术重做一遍&#xff0c;接下来也将有越来越多依托AIGC技术的创新应用涌现。关注【融云全球互联网通信云】了解更多 在社交泛娱乐赛道&#xff0c;AI大模型技术也呈现出了加速落地的态势。日前&…

功能测试如何转型自动化测试

在互联网行业&#xff0c;我们是那些被遗忘的技术人。 很多人都觉得&#xff0c;传统开发、运维才是技术含量的一个工作。 但是测试的入门门槛比较低&#xff0c;所做的事情相对有限&#xff0c; 这是我之前跟一些大型互联网软件测试负责人大牛们聊天的时候发现&#xff0c;…

学网络安全常用的10大工具

从事网络安全工作&#xff0c;手上自然离不开一些重要的网络安全工具。今天&#xff0c;分享10大网络安全工具。 一、Kali Linux Kali 是一个基于 Debian 的 Linux 发行版。它的目标就是为了简单&#xff1a;在一个实用的工具包里尽可能多的包含渗透和审计工具。Kali 实现了这…

【JMeter】 二次开发插件开发 Dubbo 接口测试插件浅析

概述 在一些企业中&#xff0c;各类业务系统非常丰富&#xff0c;相互之间或对外提供很多的服务或接口 这些服务或接口中&#xff0c;有很多是需要强契约约束的&#xff0c;服务的提供方、服务的使用方必须遵守相同契约 这类服务最典型的就是RPC&#xff0c;其中应用广泛的有Du…

一文读懂,WAF阻止恶意攻击的8种方法

WAF&#xff08;Web 应用程序防火墙&#xff09;是应用程序和互联网流量之间的第一道防线&#xff0c;它监视和过滤 Internet 流量以阻止不良流量和恶意请求&#xff0c;WAF 是确保 Web 服务的可用性和完整性的重要安全解决方案。 它通过充当保护 Web 应用程序服务器免受恶意客…

属性和方法

类的属性 变量&#xff1a;1&#xff0c;按照数据类型来分基本数据类型&#xff0c;引用数据类型 2&#xff0c;按照变量在类中声明的位置不同&#xff1a;成员变量&#xff08;属性&#xff09;、局部属性&#xff08;方法内&#xff0c;构造器内&#xff0c;代码块内等&…

android 如何分析应用的内存(六)

android 如何分析应用的内存&#xff08;六&#xff09; 接上文&#xff0c;本系列文章&#xff0c;最重要的部分——————对native堆内存的分析&#xff0c;即将上演 分成六大板块&#xff1a; 手动实现&#xff0c;new和delete&#xff0c;以及malloc和freee&#xff0…

LVS+Keepalived负载均衡高可用群集(往事清零,万事顺意)

一、Keepalived高可用详解 1.应用场景 在企业应用中&#xff0c;单台服务器承担应用存在单点故障的危险。单点故障一旦发生&#xff0c;企业服务将发生中断&#xff0c;造成极大的危害。所以需要群集实现高可用性&#xff0c;保证服务稳定。 2.介绍和原理简介 Keepalived是…

【JAVA开发环境配置】 卸载JDK很简单, 一分钟帮你搞定!

&#x1f680; 个人主页 极客小俊 ✍&#x1f3fb; 作者简介&#xff1a;web开发者、设计师、技术分享博主 &#x1f40b; 希望大家多多支持一下, 我们一起进步&#xff01;&#x1f604; &#x1f3c5; 如果文章对你有帮助的话&#xff0c;欢迎评论 &#x1f4ac;点赞&#x1…

中科三方:DNS云解析技术浅析

智能DNS云解析通过其智能解析&#xff0c;健康监测&#xff0c;负载均衡&#xff0c;宕机切换等高可用性的功能特性&#xff0c;给客户带来快捷&#xff0c;安全&#xff0c;流畅的上网体验。传统的DNS因为其解析时间冗长&#xff0c;易被劫持&#xff0c;无法精准调配用户的流…

【jupyter notebook】Anaconda prompt查询版本包(已安装的包列表、可以安装的包列表)

目录 0.环境介绍 1.查询当前已安装的某包信息 2.查询某包的所有版本 3.查看已安装的各个包的版本 0.环境介绍 windows Anaconda 1.查询当前已安装的某包信息 信息包含包名和版本&#xff0c;以包【matplotlib】为例 conda list matplotlib 2.查询某包的所有版本 conda s…

playwright-自动化测试

这里写目录标题 安装运行记录操作执行脚本 安装 &#xff08;1&#xff09;安装Playwright依赖库&#xff08;Playwright支持Async\Await语法&#xff0c;故需要Python3.7&#xff09; pip install playwright &#xff08;2&#xff09;安装Chromium、Firefox、WebKit等浏览…

【Unity Shader】平面投影实现阴影

介绍 球体和立方体挂载下面这个shader&#xff0c;就是多渲染一个阴影投影到y0的平面上 // shader&#xff0c;放在需要显示阴影的对象上 Shader "Custom/PlanarShadow1" {Properties{_Instensity("Shininess", Range(2, 4)) 2.0 //光照强度_Diffuse(&…