GCC/Clang词法分析器和语法分析器

4
我对C/C++中词法分析器(lexer)和语法分析器(parser)是如何协同工作感到好奇。我知道语法分析器通常需要至少一个记号的前瞻。然而,我的问题是,在生产编译器(比如gcc或clang)中:
1)词法分析器是否先运行,对整个文件进行词法分析,然后让语法分析器生成AST。这意味着词法分析器会生成一个记号列表。
还是
2)词法分析器只生成足够语法分析器完成其工作的一小组令牌。这意味着词法分析器和语法分析器轮流运行。
我肯定认为选项1被使用,因为像C++这样的语言有时需要任意的前瞻,因为它的语法不是上下文自由的,但这将需要大量的内存。

2
这里有一些关于clang的信息:http://clang.llvm.org/docs/InternalsManual.html;它更像是你的第二个选项(解析器从词法分析器请求标记),但我并不熟悉到可以真正回答。 - Mat
1
一些事情:虽然C++语言不是上下文无关的(例如,变量需要在使用之前定义),但用于解析该语言的语法是上下文无关的。这是怎么做到的呢?例如,基于LALR(1)语法的解析器将在执行规约时执行语义动作。具体来说,当它识别到变量声明时,它将把变量定义输入符号表中。当它识别到使用变量的表达式时,它可以检查符号表以查看变量是否存在。 - Booboo
1
一般来说,词法分析和语法分析是并行运行的,解析器在需要时调用词法分析器获取“下一个标记”。但这可能涉及到词法分析器的大量读取和处理。考虑包含文件的处理,这些文件可能嵌套多层并包含宏定义。我们知道C/C++编译时开关之一是只预处理输入并输出一个新的源文件而不进行编译。但这不是解析器处理的实际标记流。您仍然需要对此输出进行词法分析。 - Booboo
2
既不是(1)也不是(2)。词法分析器根本没有“运行”:每次解析器需要一个新的标记时,它被作为过程调用。词法分析器一次返回一个标记。C++不需要任意向前看,而文法不是上下文无关的事实与此无关。 - user207421
1个回答

6
传统的答案接近于您的第二种情况,但并非完全如此。请注意,词法分析器和解析器通常都是相对简单的状态机实现。
词法分析状态机可以从以下任一方式驱动: - 获取一个新标记 (显然需要获取输入代码并将其组装成标记),或者 - 这里有一个新的输入字符 (最终导致标记从词法分析器中“掉落”)。
解析器状态机可以从以下任一方向驱动: - 给我一个解析 (然后必须获取标记,直到找到一个完整的句子),或者 - 这里有一个新的标记 (然后必须将标记组合成一个句子)。
如果我们使用的解析器算法是这样驱动的,我们将会用以下方法“编译”文件:
for all input characters:
    feed character to tokenizer

当标记从分词器“掉落”时,它们会驱动解析器。整个过程都是从下向上驱动的协程。

传统上,在由yacc、bison等生成的解析器中,以及为它们服务的词法分析器中,我们更多地运行在“自上而下”的方式,即某人调用一个“给我一个句子”的函数(它可以构建AST,或直接发出代码,或介于两者之间——例如,为一个函数或声明构建一个AST,然后将其转换为中间代码,然后为另一个函数或声明构建另一个AST等)。这驱动着将标记从词法分析器中提取出来的方向,但它仍然相当像协程,因为解析器只询问一个标记。

这种方法也是手工编写递归下降解析器的显而易见的方法:你的顶层函数是“给我一个句子”(或“给我所有句子”或其他),最终导致某个函数调用“给我一个标记”。因此,在这两种情况下,算法的实际表达形式都会使得重复地向词法分析器进行“给我一个标记”的调用。

GCC有一个手工编写的解析器(和手工编写的词法分析器)以这种方式工作。我没有看过clang的内部,但我认为它是一样的。

关于C++,它有一些非常棘手的解析情况;请参见https://en.wikipedia.org/wiki/Most_vexing_parsePavel Minaev's answer,以及Is there a good Python library that can parse C++?。一些编译器使用临时方法来处理这个问题,例如提供一个过度接受的语法并尝试回溯最终的AST,或通过黑客手段“操纵”语法。(我看到过C++编译器在这里崩溃:输入语法上有效但在语义上无意义的标记,黑客手段可能会失效。)另一种方法是使用GLR解析器,这可能是更好的方法;请参见Ira Baxter's answer here

我已经很久没有做与解析理论相关的事情了,在撰写这篇答案时,我发现2011年sjoerd的评论提到了GLL解析器,这非常有趣。


1
非常感谢您的回复!它非常有帮助 :-) ! - Jas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接