我正在尝试更多地了解编译器的构造,所以我一直在玩flexc++和bisonc++;然而,对于这个问题,我将参考flex/bison。
在bison中,可以使用%token声明来定义令牌名称,例如
%token INTEGER
%token VARIABLE以此类推。在语法规范文件上使用bison时,会生成一个头文件y.tab.h,其中包含对每个令牌的一些定义指令:
#define INTEGER 258
#define VARIABLE 259最后,lexer通过为每个令牌返回正确的代码来包含头文件y.tab.h:
%{
#include "y.tab.h"
%}
%%
[a-z] {
// some code
return VARIABLE;
}
[1-9][0-9]* {
// some code
return INTEGER;
}因此,解析器定义了令牌,然后lexer必须使用该信息来知道每个令牌要返回的整数代码。
这不是完全奇怪吗?正常情况下,编译器管道会转到lexer ->解析器->代码生成器。为什么词汇必须包含解析器的信息呢?lexer应该定义令牌,然后flex创建一个包含所有整数代码的头文件。然后,解析器包含该头文件。这些依赖项将反映编译器管道的通常顺序。我遗漏了什么?
发布于 2014-02-07 22:04:55
和很多事情一样,这只是一个历史上的意外。当然,令牌声明可能是由lex生成的(但请参阅下面)。否则,就有可能迫使用户编写自己的声明。
但是,yacc/bison生成令牌编号更方便,因为:
yacc解析,因为它们是语法生成中的显式元素。另一方面,在lex中,它们是未解析操作的一部分,lex可以生成代码,而不需要任何关于令牌值的显式知识;yacc (和bison)生成由终端和非终端编号索引的解析表;表的逻辑要求终端和非终端具有不同的代码。lex无法知道非终端是什么,所以它无法生成适当的代码。第二个参数有点弱,因为在实践中,bison-generated解析器重新编号令牌id,以适应标识编号方案。即便如此,这也只有在bison负责实际数字的情况下才有可能。(重命名的原因是为了使id值连续;由于另一次历史事故,保留代码0到255用于单字符令牌,保留0用于EOF是正常的;然而,大多数扫描器并不实际使用所有8位代码。)
发布于 2014-02-07 20:08:19
在lexer中,标记只存在于返回值中:它们是目标语言的一部分(即。( C++),而莱克斯本身对它们一无所知。
另一方面,在解析器中,标记是定义语言的一部分:您可以在实际的解析器定义中,而不仅仅是在目标语言中编写它们。所以yacc必须知道这些记号。
发布于 2014-02-07 21:03:43
各个阶段的顺序不一定反映在编译器的体系结构中。扫描器是第一阶段,解析器是第二阶段,所以从某种意义上说,数据从扫描仪流向解析器,但在典型的Bison/Flex生成的编译器中,它是控制一切的解析器,当解析过程中需要一个新的令牌作为输入时,解析器作为助手子程序调用lexer。
https://stackoverflow.com/questions/21636038
复制相似问题