作者回复: 你理解得没错。 状态1 + 输入a ->状态2 状态1 + 输入a ->状态3 等价于: 状态1 + 输入a -> 中间状态 中间状态 + ε -> 状态2 中间状态 + ε -> 状态3 就像你说的,多个选择的可能性由ε做了表达。
作者回复: 对于某些特殊的词法规则,有时也需要预读多个字符,在实际的编译器里就有这种情况。 在实践中,通常是把这词法分析和语法分析两个处理过程串起来,用语法分析程序来驱动。当需要token的时候,才调用词法分析器来获得一个Token,而不是一次把Token全部生成完毕。
作者回复: 你看看“吃鱼”同学的理解和我的回复,看看有没有帮助?
作者回复: 这个事情要这么理解:如果词法分析都要基于比较复杂的规则,那实际上是不便于人类阅读的。所以,词法规则应该尽量简单。比如,两个+号连载一起的话,那就识别成一个Token。 补充一下: 你的问题让我想起了一种情况,对于有的语言来说,仅仅用上下文无关文法解决不了一些有二义性的语法。 举个例子。c语言有一种奇怪的声明变量的方式,比如: “int(a);” 跟 “int a;” 的含义是一样的,都是声明一个整型变量a。但如果有一个句子是“bar(a)”,那你不知道bar是个类型还是一个函数。类似奇怪的语法还有别的一些。 在这种情况下,即使是做语法分析,也要依赖上下文信息,要搞清楚bar到底是个函数,还是一个自定义的类型。所以,C和C++语言在语法分析阶段就需要用到符号表。
作者回复: 还真不是。 词法分析器因为比较简单,所以手写的可以又快又好。因而,成熟语言的编译器里,词法分析器大多是手写的。 当然,如果你是为了快速完成一个用到编译技术的项目,那么我鼓励你用词法分析器生成工具,这样容易更快见到成果。
作者回复: 点赞!
作者回复: 很多正则表达式引擎都是基于NFA实现的,减少了生成DFA的步骤,从而减少了相应的损耗(时间和内存)。 但NFA有回溯的问题,所以就存在优化空间。这件事情可以这么理解:正则表达式或NFA其实就代表了一个比较简单的程序,而程序是可以被优化的。 编译器的中后端都是运行各种优化算法。对NFA的优化算法,基本上就是这些优化算法的低配版。 你学完编译器的各种优化算法以后,再看看讲正则表达式引擎的书,看看是不是这样。 甚至运行正则表达式,跟运行一个全功能的程序也有类似的地方,都可以基于虚拟机,都有自己的指令。你其实也可以把正则表达式编译成机器指令。 本课程没有专门在正则表达式引擎的实现上做深入。但是,如果掌握了完整的编译器的实现,再去实现一个针对正则表达式的小型的编译器和虚拟机,其实是比较容易的。