flex和bison彼此需要什么?

flex和bison彼此需要什么?,bison,flex-lexer,Bison,Flex Lexer,当flex和bison一起使用时 为什么flex文件需要包含bison创建的C头文件 编译需要bison和flex创建的C源文件。bison和flex创建的C源文件相互需要什么 bison生成的报头中最重要的是enum值,用于标识令牌类型,这些令牌类型是通过词法操作返回给解析器的值 标头还声明了YYSTYPE语义类型,以及具有该类型的变量yylval,用于将每个标记的语义值传递给解析器。至少,对于具有语义值的标记。类似地,如果解析器使用位置信息,则标头定义YYLTYPE位置类型以及该类型的变量y

当flex和bison一起使用时

为什么flex文件需要包含bison创建的C头文件

编译需要bison和flex创建的C源文件。bison和flex创建的C源文件相互需要什么


bison生成的报头中最重要的是enum值,用于标识令牌类型,这些令牌类型是通过词法操作返回给解析器的值

标头还声明了YYSTYPE语义类型,以及具有该类型的变量yylval,用于将每个标记的语义值传递给解析器。至少,对于具有语义值的标记。类似地,如果解析器使用位置信息,则标头定义YYLTYPE位置类型以及该类型的变量yylloc

由于标头依赖项不能是循环的,因此解析器在扫描程序上没有任何标头依赖项。正是由于这个原因,bison输入文件必须包含yylex声明

对于解析器和扫描器之间的经典接口来说,这很好,它使用全局变量进行通信。它也或多或少地与可重入的纯解析器一起工作,在这种解析器中,语义值和位置(如果使用的话)通过参数传递给yylex,尽管yylex的声明不是自动的这一事实更令人恼火

当扫描仪再次进入时,它开始出现故障。在这种情况下,解析器必须使用yyscan\u t类型的不透明扫描程序上下文对象调用扫描程序。yyscan_t属于扫描仪,因此只能在扫描仪的标题中定义。但如上所述,这将导致循环依赖链。这揭示了传统模型中的弱点:解析器是扫描器的客户机,因此扫描器依赖于解析器来定义基本数据结构的事实是依赖关系倒置

这是一个非常现实的问题,因为可重入扫描程序的公共接口包括其原型需要特定于解析器的数据类型YYSTYPE和YYLTYPE的函数,而解析器原型几乎肯定需要接受扫描程序上下文对象作为参数,因此,在没有特定于扫描仪的数据类型yyscan_t的情况下无法声明它

这个问题的通常解决方案是通过注意yyscan_t只是一个void*来打破封装,因此它可以在解析器中声明为void*,从而避免解析器需要包括scanner头,只要它不需要访问在该头中声明的任何其他公共方法

在我看来,一个不那么丑陋的解决方案是完全避免这种特殊的配置。Bison允许您请求一个可重入推式解析器,该解析器可以与可重入扫描器一起使用,而不会出现上述任何复杂情况

在推式解析器模型中,scanner是用来解析文件的顶级函数,scanner每次识别令牌时都会调用解析器。头依赖项不再是循环的,因为解析器不需要知道任何关于扫描器上下文对象的信息,也不需要知道任何关于yylex原型的信息。扫描器现在是解析器的客户机,因此对解析器具有自然的头依赖性,因此解析器定义令牌枚举以及语义和位置数据类型的事实不再是例外


除了简化两个组件之间的头依赖关系外,推式解析器通常还简化了扫描仪内部的控制流。在许多用例中,单个扫描器模式将导致识别多个令牌。在传统模型中,扫描器必须保留一个令牌队列,在解析器调用时一次释放一个令牌。但是在推送模型中,扫描器操作可以简单地调用解析器几次,每个标识一次。该模型由sqlite3的Lemon解析器生成器部分推广,随后由其他解析器生成器(包括bison)实现。

bison生成的头中最重要的是枚举值,用于标识令牌类型,这些令牌类型是通过词法操作返回给解析器的值

标头还声明了YYSTYPE语义类型,以及具有该类型的变量yylval,用于将每个标记的语义值传递给解析器。至少,对于具有语义值的标记。类似地,如果解析器使用位置信息,则标头定义YYLTYPE位置类型以及该类型的变量yylloc

由于标头依赖项不能是循环的,因此解析器在扫描程序上没有任何标头依赖项。正是由于这个原因,bison输入文件必须包含yylex声明

对于解析器和扫描器之间的经典接口来说,这很好,它使用全局变量进行通信。在w 语义值和位置(如果使用)通过参数传递给yylex,尽管yylex的声明不是自动的这一事实更令人恼火

当扫描仪再次进入时,它开始出现故障。在这种情况下,解析器必须使用yyscan\u t类型的不透明扫描程序上下文对象调用扫描程序。yyscan_t属于扫描仪,因此只能在扫描仪的标题中定义。但如上所述,这将导致循环依赖链。这揭示了传统模型中的弱点:解析器是扫描器的客户机,因此扫描器依赖于解析器来定义基本数据结构的事实是依赖关系倒置

这是一个非常现实的问题,因为可重入扫描程序的公共接口包括其原型需要特定于解析器的数据类型YYSTYPE和YYLTYPE的函数,而解析器原型几乎肯定需要接受扫描程序上下文对象作为参数,因此,在没有特定于扫描仪的数据类型yyscan_t的情况下无法声明它

这个问题的通常解决方案是通过注意yyscan_t只是一个void*来打破封装,因此它可以在解析器中声明为void*,从而避免解析器需要包括scanner头,只要它不需要访问在该头中声明的任何其他公共方法

在我看来,一个不那么丑陋的解决方案是完全避免这种特殊的配置。Bison允许您请求一个可重入推式解析器,该解析器可以与可重入扫描器一起使用,而不会出现上述任何复杂情况

在推式解析器模型中,scanner是用来解析文件的顶级函数,scanner每次识别令牌时都会调用解析器。头依赖项不再是循环的,因为解析器不需要知道任何关于扫描器上下文对象的信息,也不需要知道任何关于yylex原型的信息。扫描器现在是解析器的客户机,因此对解析器具有自然的头依赖性,因此解析器定义令牌枚举以及语义和位置数据类型的事实不再是例外


除了简化两个组件之间的头依赖关系外,推式解析器通常还简化了扫描仪内部的控制流。在许多用例中,单个扫描器模式将导致识别多个令牌。在传统模型中,扫描器必须保留一个令牌队列,在解析器调用时一次释放一个令牌。但是在推送模型中,扫描器操作可以简单地调用解析器几次,每个标识一次。该模型由sqlite3的Lemon解析器生成器部分推广,随后由其他解析器生成器(包括bison)实现。

flex需要y.tab.h中的yylval定义。野牛只需要外部输入yylex;。我无法理解您的第二点,但您必须编译所有源代码才能链接它。flex需要y.tab.h中的yylval定义。野牛只需要外部输入yylex;。我无法理解你的第二点,但你必须编译所有的源代码才能链接到它。谢谢。如果我在没有flex的情况下使用bison,与在flex的情况下使用bison相比,我需要做哪些不同的事情?例如,@tim:你看过表中的示例了吗?这些都是完整的工作计算器和手写的yylex。bison文件需要从flex得到的只是yylex吗?如果我在bison文件的第三部分中定义了yylex,我就不需要flex文件和flex了吗?@tim:就这么简单。请看我列举的例子。谢谢。如果我在没有flex的情况下使用bison,与在flex的情况下使用bison相比,我需要做哪些不同的事情?例如,@tim:你看过表中的示例了吗?这些都是完整的工作计算器和手写的yylex。bison文件需要从flex得到的只是yylex吗?如果我在bison文件的第三部分中定义了yylex,我就不需要flex文件和flex了吗?@tim:就这么简单。见我列举的例子。