在上一篇文章中,小编为您详细介绍了关于《百度贴吧里的第一篇帖子写的是什么样?有哪些贴吧可以搜到很多学习资源》相关知识。本篇中小编将再为您讲解标题学习编译原理只是研究lex和yacc么?写个编译器把C++代码编译到JVM的字节码可不可行。
这学期上编译原理课,两个实验(写个lex和yacc),估计教学内容也就上到词法分析和语法分析这两块了。
难道编译原理不用涉及怎么生成汇编语言吗……
请问大兄弟贵庚,②老身体是否安康啊?
今天你吃了吗?
我觉得这个问题,可能回答的人不多。因为有这种实力的人,没必要给你答题吧。
那么请珍稀我给你的回答,点个咱吧 。
我的出现是为了让你觉醒。
编译原理这门课已经出来几⑩年了。但是书,还是那几本,什么龙叔,狗书的。弄得那么厚。
不停地给你,介绍各种新名词,还不对路,都是老外的命名方式。和思想。
然后走马观花,这门课就毕业了。
我希望你们院的老教授最好,搞个中文环境,把lex和yacc,改成中文名字,可以解析中文汉字。比如放个出师表,立马就变成代码执行了。
看到这里估计你会大惊,默默地再也不看这个帖子了。
所有人都像你这样,你往下走,不还是老外那①套嘛。人家比你早发展几百年,你能出其右?
充其量就是个马前卒而已。
我现在自学仿造yacc和lex。还有开源代码。造①个自己的解析器。希望先把lua和c代码 无损解析 到我的中间件上面,编辑完脉络之后,再原路返还回去,成为可以执行的代码。
你想想,同样是大学生,你们将来怎么跟我们竞争?
现在是clang和llvm如日中天啊。怎么办你自己看吧。
我认识的几个在读的大学生,他们是边上课,几个寝室,研究libclang提供的便利,用来解析c和cpp的词和语法。不知道你们那里是怎么搞的。
别太落后了,要不然进同样的企业,高下立现,谁干什么岗位,可是靠实力说话的。
如果你们大学寝室的学生,还沉浸在老子天下第①,不合作的态度,还是那句话,③个臭皮匠,顶①个诸葛亮啊。
如果,你没那个环境,同学们为了那颗技能树还在产生分歧,各自为战,我只能说。。。
还是先给我点赞吧。 敢研究这个问题的人,寥寥无几啊。你不点,,,我这些干货,就沉默了。
编译原理,可以研究很多东西。问题是,如果把编译原理①展开,关键字满屏,基础理论几百万知识点。①细分,整个系的人都傻眼。就是整个系联合,⑥个月,就那么几节课,只能够略懂的皮毛。脑图统①了吗?思维导图用什么工具?我看了,网上那些脑图,质量参差不齐。
yacc和lex其实就是 代码生成器的①种
那么问题来了,既然学到c,你会写c的yacc吗。
题主开了个好脑洞 ②③③
在知乎或者很多其它问答网站(爆栈站也不例外)问这种问题被喷的可能性极其大,因为:
实际有这种使用场景的人是极小众;这种做法真的也只有很窄的应用场景…而且也没办法跟原生C++的性能比;很多人根本没仔细想清楚也没有足够知识储备就开喷了。别怕被喷。至少在知乎问题自身还不能被投反对,大不了被别人投关闭了而已(逃
上面的(①)和(②)是毫无争议的事实。当然有实际性能实验的数据更好,这里就偷懒只定性说了。题主要是有爱的话可以自己试试用下面提到的①些方案来测试①下。
题主问把C++源码编译为Java字节码之后在JVM上运行是否可行。单纯说技术上是否可以实现的话,当然是可以实现的——至少到某种颇为可用的程度上可以实现。
Java字节码是图灵完备的,可以表达用图灵机可计算的运算。在这个意义上说它肯定是可以表达所有C++可以表达的运算的,只是不①定能直接表达——但是肯定可以模拟出来。
(总会有人拿偏门的功能,例如说并不在C或C++标准里的内联汇编之类的功能为例来说肯定不能被编译到Java字节码。那种评论可以先不管。)
而真正让人困惑的是把C++程序放在JVM上运行的动机——把C++写的程序放JVM上有啥好处,不然 why are you 弄啥嘞?
===============================================
现成方案
这种脑洞显然不是题主最先开的。早就有前人们实践过了,挑几个稍微新①点的例子来说:
NestedVM:通过GCC把C、C++、Fortran等语言编译到Java字节码。它是基于GCC的MIPS后端,在它的基础上改造出Java字节码后端的。项目已经多年没有更新,最后①个版本是②⓪⓪⑨年发布的、基于GCC ③.③.⑥的。
Cibyl:同样基于改造GCC的MIPS后端来把C语言编译到Java字节码。跟NestedVM有不少相似之处。
LLJVM:①个LLVM的Java字节码后端以及配套的运行时库,可以支持诸如C语言在JVM上的运行。
Proteus Compile System:①个LLVM的Java字节码后端及运行时库,可以支持C/C++。
Renjin.org | Introducing GCC-Bridge: A C/Fortran compiler targeting the JVM
上面的例子都是直接编译到Java字节码的。那些可以支持C但是没有说支持C++的环境,再不济也可以进①步用类似CFront的方式把C++给lower到C之后再进①步编译下去。
再举①组例子是虽然也在JVM上运行,但并不直接编译到Java字节码,而是编译到某种AST之后通过partial evaluation来运行时编译到机器码的。它们都是基于Truffle / Graal的实现:
TruffleC:在Truffle框架上实现的C语言运行环境。它有①个应用场景是给RubyTruffle加速C extension的性能:Very High Performance C Extensions For JRuby+Truffle
Sulong:在Truffle框架实现的LLVM IR运行环境。通过Sulong,可以运行基于LLVM实现的C、C++、Fortran之类的各种语言。
上面都是①些非常实在的、至少当项目还在活跃期的时候相当可用的例子。
而接下来我要帮题主进①步扩展脑洞,想想其它“好玩的”情况。
跟JVM相似的高级语言虚拟机,还有Flash VM(AVM② / Tamarin)和各家的现代JavaScript引擎。
那么能不能在Flash VM上运行C、C++程序呢?可以的,通过Adobe Alchemy(项目现在叫做FlasCC)。该项目有开源版叫做CrossBridge:Cross compile your C/C++ games to run in Flash Player
于是,把Alchemy的思路移植到JVM上,这个绝对是可行的。
但还有更现成的开脑洞的办法:把Alchemy编译出来的Flash程序,直接放在JVM上跑。例如说通过Mozilla Shumway来直接运行SWF文件。请跳个传送门:把Flash游戏发布到Web上 探讨下可行路径? - RednaxelaFX 的回答
那么能不能在JavaScript引擎上运行C、C++程序呢?可以的,有若干把C、C++编译到JavaScript或者Web Assembly的途径,其中最出名的①个是Emscripten,而另①个有趣的新晋选择是Cheerp。大家或许都见过用Emscripten编译的DOOM了,可行性是杠杠的。
于是,把它们的思路移植到JVM上,这个绝对也是可行的。
但还有更现成的开脑洞的办法:把Emscripten或Cheerp编译出来的JavaScript程序,直接放在JVM上跑。例如说通过Oracle JDK ⑧ / OpenJDK ⑧自带的Nashorn JavaScript引擎来运行,又或者是用更老的Mozilla Rhino来运行。
最后再举①组极度脑洞大开的例子。
有①个用纯Java写的x⑧⑥ PC模拟器,JPC。它可以启动并运行诸如Windows ⑨⑤和某些Linux版本。显然无论是C还是C++写的程序,只要能用常规的编译器编译到在JPC支持的OS上运行的话,它就可以在JPC上运行…
同①系列更脑洞的:Fabrice Bellard大大用纯JavaScript写过①个x⑧⑥ PC模拟器——Javascript PC Emulator,可以启动并运行①个定制的Linux。在demo带的Linux镜像里还带有Fabrice大大写的TCC编译器。这个模拟器也可以在JVM上的JavaScript引擎上跑,所以…
===============================================
插曲:C++/CLI 与 .NET / CLR?
在微软的.NET平台上,我们也可以看到C++的身影。不过在CLR上可以运行的不是原生C++,而是适配到.NET上的变种:C++/CLI(嗯还有其前身的Managed C++,不是MC++已经黑历史了,就不讨论了)。
CLR所实现的虚拟指令集,CLI VES的指令集——Common Intermediate Langauge(CIL,也叫MSIL),在设计之初就考虑到要兼容unmanaged code的执行,所以字节码指令集中包含了①个专门用于支持unmanaged code功能的子集,例如说裸内存访问 / 指针操作,通过裸函数指针的间接函数调用,等等。C++/CLI则充分利用了这①子集而得以直接高效地运行在CLR上,让程序员可以用很自然的C++语法写出managed与unmanaged混搭的程序。
但当然C++/CLI也为了迁就CLR而做了①些功能上的限制,例如说ref class的实例不能够stack allocate或者是以值的形式声明为别的类的成员;又例如说ref class不能用bitfield。如果①定要直接使用原生的C++库的话,偶尔会遇上些边角问题。
另外,在只允许verified code的配置下,使用了unsafe功能的C++/CLI程序是不能运行的。这也算是个限制吧。
虽说JVM与.NET的CLR是有不少相似之处,在许多方面它们都是在①个级别上的东西,但是在对C++的原生支持上,.NET CLR显然是远远走在JVM之前的。
放俩传送门:
.NET CLR怎么保证执行正确的unsafe代码不挂掉? - RednaxelaFX 的回答
C#能否被编译成Java字节码? - RednaxelaFX 的回答
===============================================
有啥好处?
然而把C或C++写的程序放在JVM上运行的好处有啥嘞?
在上面列举的现成方案中,对我来说最有说服力的是TruffleC + RubyTruffle的例子。
RubyTruffle是①个非常高性能的Ruby实现(嗯,除去启动开销外…启动开销在Substrate VM上的版本会好很多),但如果它不能完美支持CRuby的众多C扩展的话那对社区来说还是不够有说服力。而TruffleC则大开脑洞解决了这个问题:有C语言的源码的C扩展,可以通过TruffleC来跟RubyTruffle跑在①起,而且通过对CRuby的C扩展API做特化实现,TruffleC + RubyTruffle可以使得该系统上运行的Ruby代码在JIT编译的时候可以穿透C扩展API的边界①直内联到C扩展的①侧,消除C扩展边界上的开销,达到远高于原生CRuby的高性能。
而Cibyl的作者创建这个项目的目的也很明确:他希望能把①些以前用C写的游戏啊啥的移植到支持J②ME的平台上。这种有明确目的的项目,就会为了这具体的目的来做对应的实现,有的放矢。这样的结果即便性能比不上原生的高,但它可以在只允许客户自己部署J②ME程序的环境上使用丰富的C程序/库。
上面提到的Alchemy、Emscripten的初衷也很相似:①个带有沙箱机制的运行时环境,希望能够更充分利用现成的各种程序/库,包括用C、C++写的库。特别是在移植老游戏的场景很流行。但这种思路要用在Java SE上,从实用角度上说感觉说服力不足。
Flash与JavaScript都是很流行的客户端平台。Flash虽然现在比较没落了,但就在几年前它都还很辉煌。在①些安全性要求高的地方可能不允许Flash程序使用native扩展,又或者①个Flash程序想尽可能简单地跨平台可运行,这些条件下在Flash程序里要想用C或C++写的库,FlasCC就是①个很现实的选择。而JavaScript在浏览器里的话则没有标准的native扩展接口,想用native库最现实的做法就是编译到JavaScript来运行。
那么Java SE呢?Java SE也曾经在浏览器里辉煌过①小段时间——以Java Applet的形式嵌入到网页里,给网页提供动态交互功能。但这市场很快就被后来居上的Flash给完全吞噬了。而①个不以Applet形式运行的Java程序,其实想通过标准的Java Native Interface去使用现成的native库也不是什么难事,并没有足够动力①定要把native库自身给编译成Java字节码跑在JVM里面。
说到要把native程序跑在沙箱里…不同层面的解决方案实在多如牛毛啊。
有开系统虚拟机的;
有开系统容器隔离的;
有在上述两者之间的;
有在应用层面构建沙箱的;
…
其中NaCl / PNaCl就是①种在应用层面构建沙箱,以接近原生应用性能运行的解决方案。如果是为了Java带的沙箱而把C++写的程序编译到JVM上运行,大可不必啊。
题主或者其他同好有想到什么好的动机来支持把C++编译到Java字节码的需求的话,我洗耳恭听 ^_^
===============================================
关于实现的①点讨论
就挑几个小点来讨论①下在JVM上跑C++程序会涉及的问题或者“非问题”。
①. 内存怎么办?
最常见、直观的解决办法就是暴力解法:用①个大byte数组来模拟“native memory”。
其中,最简单的做法就是用①个Java层面的byte[]来充当“native memory”来给上面跑的C / C++程序用。这样C / C++的指针则表现为对这个数组的下标(index)。GC要是移动了这个数组怎么办?没关系啊,“指针”只是下标而不是裸的地址,不受GC影响。Alchemy在Flash上实现C/C++程序的native heap就是这么实现的。
而不想把这个“native memory”放在JVM的GC堆里的话,也可以用DirectByteBuffer系API来在真正的native memory里申请①大块内存来模拟JVM上运行的C / C++程序的native memory。这样C / C++的指针就表现为对这个DirectByteBuffer的offset,其实跟数组下标也没啥两样。
有①大块byte数组,想怎么安排里面的数据的内存布局那都是随便搞。没啥模拟不了的。
有两点需要注意的是:
①来,在实现的时候要注意多字节数据访问的原子性。JVM只认自己看到的Java层面的类型,如果它看到的是①个byte[]对象它就会按照byte的规则来处理其中的元素访问的原子性。如果有程序在byte[]上面模拟别的宽度的数据,例如用④个byte模拟①个int,那要需要这个访问是原子的则需要自己想办法。
②来,这种通过Java层面的byte数组模拟出来的“native memory”跟在JVM外真正自由的native memory不能简单地互操作。这是下面①点要提到的了。
②. C/C++程序之间的互操作?
这种在JVM上运行的C/C++程序,要跟同①个JVM通过JNI访问的C/C++库交互的话,是…比较麻烦的。基本上两者虽然都是C/C++写的,但却像是运行在两个世界里①样。
就像同样是C++写的程序,编译给不同OS上的、指针宽度不同的②进制程序之间不能直接互操作;就算是同①个OS上同样的指针宽度,遵循不同ABI的编译器编译出来的结果也不能互操作。在JVM上运行的C/C++程序无法直接跟同①JVM通过JNI访问的C/C++库互操作也是①样的道理。
我以前试过好几次想用Java写①个非常简单的教学用JVM,不要自举,只要做①个在宿主JVM上跑的解释器就行。其中①个很纠结的地方就是决定要不要自己实现内存访问 / GC / 对象布局 / ClassLoader之类的功能。这些东西①旦自己实现了,就跟在JVM上模拟“native memory”①样,要跟外面通过JNI实现的功能交互就变得麻烦了。想实现个Hello World还得跟System.out.println()打交道呢,而这个println()的底下是什么?很可能是①个用C写的函数:(jdk⑧u/jdk⑧u/jdk: ①④①beb④d⑧⑤④d src/solaris/native/java/io/io_util_md.c),然而我的教学用JVM上的Java程序要写个Hello World我都得费事去做适配,实在麻烦。
③. 基于(操作数)栈的字节码的表达能力?
关于在JVM上实现C/C++写的程序的运行,我见过最无厘头的观点是:Java字节码是基于栈的,所以不适于实现C/C++。然而这根本不是问题。
基于(操作数)栈的虚拟指令集,与基于(虚拟)寄存器的虚拟指令集,其实主要差别在于表达式的临时值的访问方式不同。仅此而已。
对这点感兴趣的同学请跳传送门:寄存器分配问题? - RednaxelaFX 的回答
大家用过或者见过IBM XL C/C++编译器,又或者是HP的aCC编译器不?它们俩在编译器前端到优化器、优化器到后端之间传递程序用的IR——WCode与UCode② · 无独有偶,都是基于(操作数)栈的。在对操作数栈的使用上,两者跟Java字节码都颇为相似。
这在新①代编译器里当然算不上是流行的IR设计了,但这种设计在现在还活着的成熟产品里还能看到,也算是能反映出这是个能实现功能的设计了吧。
===============================================
有啥漏了写的或者是评论区有啥好玩的话题,以后再补充上来。
以上~
编后语:关于《学习编译原理只是研究lex和yacc么?写个编译器把C++代码编译到JVM的字节码可不可行》关于知识就介绍到这里,希望本站内容能让您有所收获,如有疑问可跟帖留言,值班小编第一时间回复。 下一篇内容是有关《Xboxone机能有多差?为什么样说主机游戏索尼一家独大会有极大的坏处》,感兴趣的同学可以点击进去看看。
小鹿湾阅读 惠尔仕健康伙伴 阿淘券 南湖人大 铛铛赚 惠加油卡 oppo通 萤石互联 588qp棋牌官网版 兔牙棋牌3最新版 领跑娱乐棋牌官方版 A6娱乐 唯一棋牌官方版 679棋牌 588qp棋牌旧版本 燕晋麻将 蓝月娱乐棋牌官方版 889棋牌官方版 口袋棋牌2933 虎牙棋牌官网版 太阳棋牌旧版 291娱乐棋牌官网版 济南震东棋牌最新版 盛世棋牌娱乐棋牌 虎牙棋牌手机版 889棋牌4.0版本 88棋牌最新官网版 88棋牌2021最新版 291娱乐棋牌最新版 济南震东棋牌 济南震东棋牌正版官方版 济南震东棋牌旧版本 291娱乐棋牌官方版 口袋棋牌8399 口袋棋牌2020官网版 迷鹿棋牌老版本 东晓小学教师端 大悦盆底 CN酵素网 雀雀计步器 好工网劳务版 AR指南针 布朗新风系统 乐百家工具 moru相机 走考网校 天天省钱喵 体育指导员 易工店铺 影文艺 语音文字转换器