词汇分析器和解析器上的大多数资源都说明了使用流在它们之间进行通信(或者我理解)。
解释了解析器要求下一个令牌,比如通过调用函数getNextToken()
,并且词法分析器通过返回下一个令牌来响应它。我们是否应该将它们视为在同一程序中交互的两个对象或通过流交互的两个不同程序?
另外,我无法理解为什么没有选择串行方法,即词法分析器一直运行到提供的源的末尾,然后解析器才使用词法分析器的输出进行解析。确切地说,如果词法分析器仅在解析器请求下一个令牌时读取下一个词法,那么如何处理错误?特别是如果在文件末尾发生错误,解析器完成的所有计算都可能由于错误而浪费(假设一个非常基本的解析器没有任何错误处理功能)。最近的输出是否已缓存?
答案 0 :(得分:7)
我的回答仅参考Flex-Bison(或Lex-Yacc)编译模型。我对其他模型知之甚少。
我认为词法分析器/解析器组合是同一程序中的两个协作模块。
当您使用Flex with Bison时,您会看到后者调用前者提供的函数yylex()
(yylex()
等同于您问题中的getNextToken()
函数)。因此,将它们视为单个程序中的协作单元而不是两个不同的程序更有意义。此外,如果词法分析器和解析器是 2个不同的程序,则必须处理进程间通信,共享内存和相关问题,这进一步使手头的任务变得复杂。
回答你的第二个问题:
我可以想到一个重要的问题可能是解析器在词法分析器读完所有输入后开始行动即使是中等大小的程序,内存使用也是巨大的,因为你必须存储内存中的每个令牌的数据结构(想想像,
和=
这样的令牌占用内存中的多个字节,你很快就会明白为什么它不可扩展了。
对于错误处理:如果词法分析器不能匹配任何正则表达式的输入,那么yylex()
应该使用flex规则向解析器返回-1,如下所示:
. { return -1; }
(注意第一列中几乎看不见的句号,它匹配除\n
以外的任何输入符号)
(注意:此规则应该是 last 规则,以显示在您的Flex文件中,因为规则的顺序决定了优先级:Flex使用令牌匹配flex文件中第一个可能的规则。)
词法分析器的返回值-1表示标记化错误,Bison解析器通过调用yyerror(char *)
(理想情况下由您定义)自动处理它;否则,如果输入遇到解析错误,解析器再次调用yyerror(char *)
。
此外,如果您想在遇到错误时显示错误的代码段,您必须有一种方法来访问给定有缺陷令牌的相关源代码,这意味着完全按照读取输入的方法通过解析根本不起作用,除非你在标记化时将相关的源代码与每个标记一起存储,实质上是使编译器成为一个内存巨头。
答案 1 :(得分:0)
词法分析器和解析器上的大多数资源都说明了使用方法 流之间的沟通(或者我理解)。
我见过的那些人都不这样做。它们依赖于词法分析器,它是解析器调用的单个方法。