作者回复: java语句当然是由java的编译器来识别了。
不过你提了一个重要的事情。
在编译领域,有一个事情,叫做自举(bootstraping),也就是这门语言的编译器可以用自己这门语言编写。这是语言迈向成熟的标志。一般前面的版本,是要借助别的语言编写编译器,但后面就应该用自己的语言来编译了。
著名的语言都实现了自举。比如,go语言的编译器是用go编写的(早期版本不是。能实现自举,还是go发展历程上的一个历程碑),jdk里面自带了java语言的编译器,本身也是用java写的。
作者回复: 对。如果正则表达式的内部实现是基于NFA的,就会有这个问题。
NFA和DFA这个知识点不适合在前期讲,会把初学者搞晕。我准备在后面找个机会放入这个知识点。
作者回复: 看你用C语言做了很多实践,非常好!
针对你的问题,也跟你探讨一下:
1.每门语言都有它的优势。很多编译器都是用C/C++编写的,比如可以更灵活的对内存管理,就是优势呀。JVM的实现,也没法用Java,还是要用比较底层的语言。
2.错误处理这个问题比较复杂。最好的情况,是我们知道哪一个小范围是有错的,对这个部分报错,但其他部分继续处理。比如,你调用一个函数时,监测出参数的数量错了,但其他部分仍然可以继续去解析和处理。如果碰到一个错误,就完全停下,那也不行。这样做IDE的时候,就不够友好和智能。
作者回复: 加油!
作者回复: 看到你的github空间里有好几个项目,学习力很强!
另外,能否把你的项目整个cmake文件,便于我编译运行?:)
作者回复: 棒!TypeScript版本的!
作者回复: 看了,非常不错!点赞!
连README.md都写得很清晰。
你学习的效率很高呀!
而且看来你有C语言的基础,所以到时学后端技术你也会毫不费力呀!
作者回复: 你用的这个在线工具很酷。可以提供一个运行环境直接跑!很棒!
我玩了好一会 :-D
作者回复: 你提了一个好问题。
其实,人工智能的发展史经历了两个不同的路径。 早期,更多的是演绎逻辑。就是人为制定规则,比如自然语言翻译的规则,并不断执行这些规则。
第二条路径,是最近复兴的机器学习的方法。它更多的是归纳逻辑。机器学习是通过数据的训练,把规则归纳出来。这些归纳出来的规则目前还是比较黑盒的,人比较难以解读,但却很有用,更加准确。
你的需求场景用这两种方法应该都能解决,只不过落地时还要考虑很多细节和限制因素。
作者回复: 语义的部分后面专门有好几讲来深入展开,比如类型检查等。这讲先让代码简单地运行起来。
作者回复: 负数有两种处理办法:
1.在词法分析阶段,就把它作为一个字面量提取出来。这有一定的难度。比如,a - 3和 a - -3要能准确地把减号和负号区分开。但也不是不能做到。
2.把减号作为一元运算符处理。
示例用的语法规则,是按照第二种方式处理的。
作者回复: 首先,赋值在C和Java里都是表达式,跟加法表达式没啥区别,它也是有值的。
第二,确实可以通过语法规则的设计来避免冲突,包括避免回溯。
作者回复: 这个“感觉”很重要。保持好。遇到挫折也不要在意!
作者回复: 感谢分享!
一起加油!
作者回复: 谢谢你的建议!
好的,我会在迭代版本中改进!
作者回复: 点赞!
作者回复: 谢谢肯定!
编译原理这门课,是学原理可能学不懂。但真正动手,其实都能写出来。早期写编译器的先驱并没有编译原理课。
并且,很多具体实现过程,是可以偏离死搬教条的原理的。比如,理想情况下要设计无二义性文法。实际应用中,只要针对某个具体算法是无二义的就行了。能实际有用才是硬道理。
作者回复: 可以参考成熟的语法规则文件,去琢磨。
大致来说,你从字面意思来理解它就好了。比如语句、表达式、二元表达式。
本课程都是倾向于采用这种有意义的单词,而不是像教科书那样只写一个字母,太抽象。
而在实际工程中,我们总是让自己的语法单元更具可读性,这样更实用。
作者回复: 为你的动脑思考点赞!
泛型语法,嗯嗯有可能。
深度优先算法的回溯,时间复杂性(大O)不是指数的。广度优先的才是指数的。这个在15讲会再总结一遍。
深度优先算法,实际浪费不多,所以是有实用价值的一个算法。再加上预测功能就完美了。讲LL算法的时候会再回过来说这个事情。
作者回复: 是的。
很多时候,做某件事情真正的阻力是畏惧,是根本不去做...