09 | Java编译器(一):手写的编译器有什么优势?
该思维导图由 AI 生成,仅供参考
- 深入了解
- 翻译
- 解释
- 总结
本文深入探讨了Java编译器的实际实现机制,旨在帮助读者学习和印证编译原理的基础知识,加深对编译原理的理解。作者首先介绍了Java语言的发展和普及,以及编译器和虚拟机技术的变化。接着,文章初步介绍了Java的编译器,解释了javac命令的使用和Java编译器的自举现象。文章还提到了JavaCompiler的实现和源代码结构,建议读者关注com.sun.source.tree包和com.sun.tools.javac.parser包的源代码,以便更好地理解Java编译器的实现原理。通过对词法分析器和语法分析器的探索,读者可以更好地理解Java编译器的工作原理和实现细节。文章还介绍了Java词法分析器的有限自动机和处理关键字与标识符冲突的技术点。建议读者在IDE中采用调试模式跟踪执行,以更直观地理解Java词法分析的过程和结果。整体而言,本文为读者提供了深入了解Java编译器的概要信息,并指引读者如何深入探索Java编译器的源代码结构和实现原理。 文章还介绍了Java编译器采用的是递归下降算法,通过对解析表达式的调用层次和具体解析过程的分析,展示了Java编译器对优先级和结合性的处理。文章指出Java编译器采用了典型的消除左递归的算法,并通过一个循环处理多种不同优先级的操作符,同时保证了优先级的正确性。此外,文章还详细解释了Java编译器的算法是如何借助一个工作区,自底向上地组装AST,并介绍了这种处理表达式优先级的解析方法,即“运算符优先级解析器(Operator-Precedence Parser)”。这些内容展示了Java编译器在处理复杂表达式时的高效性和灵活性,为读者提供了深入了解Java编译器实现原理的技术细节。
《编译原理实战课》,新⼈⾸单¥59
全部留言(10)
- 最新
- 精选
- ヾ(◍°∇°◍)ノ゙jabel这种让jdk8支持高版本java语法的项目也是用到了编译技术了吧
作者回复: 没错。 这是作者吃透了Java编译器基础上做的很有想象力的一个工作。非常不错。值得玩一下,借此看别人是如何Hack Java的编译器的。
2020-06-245 - minghu6说编译器成熟后就要自举,这绝对是一个槽点太多以至于无处下嘴的迷思,任何脚踏实地的人不应该迷信这种东西. 首先,不管你如何自举,不可能根本摆脱依赖某些原生操作平台上的工具链的支持,当然也不排除有些人通过重新造轮子的方法把这些工具链全部重新实现一遍,但那只是意味着要额外安装一份儿二进制文件. 对于开发团队来讲,他需要额外管理一个boot build的版本机制,对于用户来讲可怕的来了,他需要先安装一份儿预先编译的版本的然后再把它升级,如果不巧没有合适的直接可以用于升级的预编译的版本,那他将不得不做一个人肉递归,从更早的版本甚至自举前的版本开始逐步升级.由于自举造成的麻烦这不知道浪费了多少人的生命在额外的research&&download, 实际上几个激进自举的语言实现比如Go,比如Clozure CL用起来都有些反直觉,让人花费高时间成本,从一个很不舒服的地方开始. 那么好了,自举有实际的好处吗? 并没有,因为对于一个语言关键得是解决某一类领域的问题具有优势, 不管这个优势是开发效率高\性能表现好\还是上手简单招工容易等等. 人们关注得是否有杀手级应用和大公司的背书,而不是它是否完成了自举. 最后, 个人认为自举在国外流行主要是来源于早期部分黑客"非我不用"的这种有宗教狂热色彩的值得商榷的风格的演化,如果一门语言本身就是用系统原生语言比如C或者其他系统级编程语言比如C++/Rust写的,那我不认为有自举的必要.
作者回复: 洋洋洒洒一大篇,但读起来并不拗口。个人感觉你表达能力超强。 是的,大部分情况下没有必要重新造轮子,但少量场景下,还就是非造不可。 像浏览器里的JS引擎,大家一开始为了实现起来快,就拿llvm怼在后端。但腾出手来,还是要换掉,因为JS引擎对编译速度等的要求实在llvm不满足。 前端工具也是如此,基本的需求都行。可有时你就是想字斟句酌地扣性能,比如SQL过滤器,可能你就要手写。 工具链也是。我最近在设计一些几乎在裸设备上运行的场景,工具链不说重写吧,也要做相当的改造。 当然,对这些少量场景,肯定是有资金支持的,也意味着它有特殊的价值。否则就没必要做这个事情了。
2021-06-152 - 易昊老师请教一个问题,最近在看Javac的源码中的词法分析部分,其中Tokens.java中,enum Tag定义有一个是NAMED,我不理解这个NAMED Tag是做什么用的,并且看enum TokenKind的定义,似乎仅有assert, boolean, byte, char, double, enum, float, int, long, short, super, this, void, true, false, null, _ 是对应的NAMED tag,想弄明白为什么会这样设计。
作者回复: 非常高兴你能真正潜入到代码中去探索。 其实你顺着代码多看一下,在代码里搜索一下,就能明白它的用途。 enum Tag是在Tokens.java中定义的,用在Token类中。而Token类有几个子类,其中一个是NamedToken类,实现了Token的name()方法。而NamedToken是在JavaTokenizer.java类中创建的。 接下来,你就看看在代码里什么地方用到了Token.name()方法就好了。 比如,在JavacParser.java中,在生成AST的标识符节点的时候,就会取出Token.name(),作为标识符的名称。 至于boolen、byte这些,我相信也会在类型分析中用到Token.name()的。我只是猜测,这里并没有去看代码,你可以去验证一下。 BTW,我看上述代码时,对Java的Token类的设计也产生了一点小兴趣。它定义了几个方法,比如name()和stringVal(),但自己又不实现,而是放在子类中去实现。这种设计方法可以拿来为自己所用。这也是阅读别人的代码带来的收益吧!
2021-02-072 - wusiration补交作业,没有看下一讲的答案.... odStack opStack 后续运算符 step1: a step2: a,b > * step3: a,b,2 >,* + step4: a,b*2 > + step5: a>b*2,3 + step6: a>b*2+7
作者回复: 做作业的好同学! 然后你可以跟参考答案对照一下,再把思路过一遍!
2020-07-012 - lion_fly老师,我在debugJava编译器的代码: 在源码的注释里面出现了这样的内容 Qualident = Ident { DOT [Annotations] Ident } Java编译器的这种文法是什么文法,感觉不是上下文无关文法
作者回复: 这个是上下文无关的文法。 大家可能会使用不同的写法。比如,有的人用产生式的写法,有的人用EBNF的写法,关键看本质。不同的写法本质上是同构的。
2021-01-211 - Apsarasstep1: a step2: a,b > * step3: a,b,2 >,* + step4: a,b*2 >,+ step5: a,b*2,3 >,+ step6: a,b*2+3 step7: a>b*2+3
作者回复: 我刚给出了参考答案(在下一讲中),你可以对比一下。 略有差异,但看得出你是理解了这个算法的!
2020-06-231 - 冬天里的懒猫原来竟然是这样。。。 用了这么多年的java,从来没有想过编译器是如何实现的。这篇课程非常有用。
作者回复: 如果掌握了这种hack的手法,其实通过编译器可以更快地掌握一门语言的各种特性的实质。
2020-10-28 - chris老师能否介绍一下如何建一个ide工程阅读源码?
作者回复: 我习惯用IDEA。在IDEA中建立任何一个Java工程,都需要指定一个JDK。而JDK里就包含了源代码。在IDEA中的"External Libraries"目录,就可以打开JDK中的各个模块,查看其源代码。这样,我们就可以在调试程序的时候,跟踪到JDK的源代码里面了。 其他IDE也大致差不多。
2020-06-232 - Geek_71d4ac交作业 step1: a step2: a,b > * step3: a,b,2 >,* + step4: a,b*2 > + step5:a, b*2,3 >,+ step6:a, b*2+3 > step7: a >b *2+3
作者回复: 非常好。 看得出你掌握得很扎实。 我刚在下一讲中给出了参考答案。
2020-06-22 - mikewt老师 javacc编译器跟这个有啥关系 为啥java不用javacc编译2023-08-04归属地:上海1