是否可以将不同文件中的 yacc 片段文件包含/导入到主 YACC 中?
为了举例说明我正在寻找的内容,我想为 3 个不同的文件创建 3 个语法解析器,但它们共享一个公共语法块。
所以,我想将这一语法保留在一个 yacc 片段文件中,这样我就可以更好地维护它。
GNU Bison 的最新版本支持多个语法起始符号。因此,您可以定义一个包含多种语言的语法文件,这些语言共享一些通用的语法规则。
使用一些外部预处理工具,您可以在多个 Yacc 文件中包含常见的语法材料。我所知道的任何类似 Yacc 的程序都不直接支持这种包含。当然,支持 C
#include
,但它会传递到 C 代码,而不是由 Yacc 处理。
在任何Yacc中,您都可以模拟具有多个开始符号的功能。这可以通过在顶级规则中处理秘密短语结构规则来完成,这些规则由秘密令牌分隔。
您需要一个
YYINPUT
运算符,让您可以在解析器和扫描器之间填充这些秘密令牌,以“启动”扫描,以便解析器能够看到秘密令牌并识别以它们为首的规则。当解析器调用yylex()
时,它必须首先获取已注入的秘密令牌;当这些都用尽时,然后调用真正的扫描仪。
秘密令牌是不是由扫描仪生成的抽象令牌值;它们纯粹是内部的。
您可以在这个语法文件中看到该技术;查找包含
SECRET_ESCAPE_R
和其他类似终端符号的规则。
示例
SECRET_ESCAPE_R
代表正则表达式;它创建的入口点用于解析正则表达式。在这个 parser.c
文件中,有一个 regex_parse
函数,它使用参数枚举值 parse
来调用 prime_regex
。这个 prime_regex
枚举值告诉 parse
准备 SECRET_ESCAPE_R
令牌。 parse
再次出现在语法文件中,朝向底部。它使用再次在 prime_parser
中找到的助手 primer_parser_post
和 prime.c
。
该项目中的启动机制不仅处理子语法的解析,还处理来自同一流的多个表达式(或其他单元)的解析。这也是 Lex 和 Yacc “开箱即用”不能很好支持的东西。
在某些语言中,当您尝试读取一种语言的单个表达式(或定义、声明或其他单元)时,会发生的情况是 Yacc 解析器将提前读取一个标记。 (讨厌的 LALR(1) 喜欢这样做。)换句话说,在提取一个表达式时,它最终会消耗下一个表达式的令牌。
prime_parser
函数注意到之前有一个解析以某个前瞻标记结束。该令牌首先被推回流中,然后是任何将引导解析到所需子语法的秘密令牌。