让 Bison 接受替代的 EOF 令牌
Make Bison accept an alternative EOF token
我正在使用 flex 和 bison 在 C++ 中编写一个 ansi-C 解析器;这很复杂。
我遇到的问题是编译错误。错误如下,这是因为 yy_terminate
returns YY_NULL
定义为 (an int) 0
and yylex
具有 return 类型yy::AnsiCParser::symbol_type
个。 yy_terminate();
是 flex 生成的扫描器中 <<EOF>>
令牌的自动操作。显然,这会导致类型问题。
我的扫描器没有为 EOF 生成任何特殊标记,因为 EOF 在 C 语法中没有任何用途。我可以为 <<EOF>>
创建一个令牌规则,但如果我忽略它,那么在 YY_STATE_EOF(INITIAL)
的情况下,扫描器会在 yylex
中陷入无限循环。
编译错误,
ansi-c.yy.cc: In function ‘yy::AnsiCParser::symbol_type yylex(AnsiCDriver&)’:
ansi-c.yy.cc:145:17: error: could not convert ‘0’ from ‘int’ to ‘yy::AnsiCParser::symbol_type {aka yy::AnsiCParser::basic_symbol<yy::AnsiCParser::by_type>}’
ansi-c.yy.cc:938:30: note: in expansion of macro ‘YY_NULL’
ansi-c.yy.cc:1583:2: note: in expansion of macro ‘yyterminate’
此外,Bison 为我的开始规则 (translation_unit) 和 EOF ($end) 生成了这条规则。
$accept: translation_unit $end
所以 yylex
必须 return EOF 或解析器永远不会停止等待输入,但我的语法不支持 EOF 标记。有没有办法让 Bison 在不修改我的语法的情况下识别 $end
条件下的 0
以外的东西?
或者,我可以从扫描仪中的 <<EOF>>
令牌 return 满足 Bison $end
条件吗?
通常,您不会在词法分析器中包含明确的 EOF 规则,不是因为它没有任何用处,而是因为默认值正是您想要做的。 (它的作用是表明输入是完整的;否则,解析器将接受某些无效程序的有效前缀。)
不幸的是,C++ 接口可能会破坏默认 EOF 操作的简单便利,即 return 0(或 NULL)。根据您的问题描述,我假设您已要求 bison 使用 complete symbols 生成解析器。在这种情况下,您不能简单地 return 来自 yylex
的 0,因为解析器需要一个完整的符号,这是一个比 int
更复杂的类型(尽管报告 EOF 的标记不通常有一个语义值,它确实有一个位置,如果你使用的是位置。)对于其他令牌类型,bison 将自动生成一个函数来生成一个令牌,命名为 make_FOO_TOKEN
,你将在FOO_TOKEN
.
的扫描仪操作
虽然 C bison 解析器确实自动定义文件结束标记(称为 END
),但 C++ 接口似乎没有。所以你需要在你的 bison 输入文件的 %token
声明中手动定义它:
%token END 0 "end of file"
(用整数值 0 和人类可读标签 "end of file" 定义令牌类型 END
。值 0 是必需的。)
完成后,您可以在 flex 输入文件中添加明确的 EOF 规则:
<<EOF>> return make_END();
如果您使用位置,则还必须提供 make_END
位置参数。
这是防止编译器错误的另一种方法 could not convert 0 from int to ...symbol_type
- 将 yyterminate
宏的重新定义放在重新定义 YY_DECL
的位置下方
// change curLocation to the name of the location object used in yylex
// qualify symbol_type with the bison namespace used
#define yyterminate() return symbol_type(YY_NULL, curLocation)
启用 bison 位置时会出现编译器错误,例如with %define locations
- 这使得 bison 向其 symbol_type
构造函数添加一个 location
参数,因此没有位置的构造函数
symbol_type(int tok)
用位置
变成这个
symbol_type(int tok, location_type l)
不再可能将 int
转换为 symbol_type
,这是 flex 中 yyterminate
的默认定义在未启用 bison 位置时能够执行的操作
#define yyterminate() return YY_NULL
有了这个解决方法,如果您不需要,就不需要在 flex 中处理 EOF
- 如果您不需要,就不需要在 bison 中处理多余的 END
令牌
我正在使用 flex 和 bison 在 C++ 中编写一个 ansi-C 解析器;这很复杂。
我遇到的问题是编译错误。错误如下,这是因为 yy_terminate
returns YY_NULL
定义为 (an int) 0
and yylex
具有 return 类型yy::AnsiCParser::symbol_type
个。 yy_terminate();
是 flex 生成的扫描器中 <<EOF>>
令牌的自动操作。显然,这会导致类型问题。
我的扫描器没有为 EOF 生成任何特殊标记,因为 EOF 在 C 语法中没有任何用途。我可以为 <<EOF>>
创建一个令牌规则,但如果我忽略它,那么在 YY_STATE_EOF(INITIAL)
的情况下,扫描器会在 yylex
中陷入无限循环。
编译错误,
ansi-c.yy.cc: In function ‘yy::AnsiCParser::symbol_type yylex(AnsiCDriver&)’:
ansi-c.yy.cc:145:17: error: could not convert ‘0’ from ‘int’ to ‘yy::AnsiCParser::symbol_type {aka yy::AnsiCParser::basic_symbol<yy::AnsiCParser::by_type>}’
ansi-c.yy.cc:938:30: note: in expansion of macro ‘YY_NULL’
ansi-c.yy.cc:1583:2: note: in expansion of macro ‘yyterminate’
此外,Bison 为我的开始规则 (translation_unit) 和 EOF ($end) 生成了这条规则。
$accept: translation_unit $end
所以 yylex
必须 return EOF 或解析器永远不会停止等待输入,但我的语法不支持 EOF 标记。有没有办法让 Bison 在不修改我的语法的情况下识别 $end
条件下的 0
以外的东西?
或者,我可以从扫描仪中的 <<EOF>>
令牌 return 满足 Bison $end
条件吗?
通常,您不会在词法分析器中包含明确的 EOF 规则,不是因为它没有任何用处,而是因为默认值正是您想要做的。 (它的作用是表明输入是完整的;否则,解析器将接受某些无效程序的有效前缀。)
不幸的是,C++ 接口可能会破坏默认 EOF 操作的简单便利,即 return 0(或 NULL)。根据您的问题描述,我假设您已要求 bison 使用 complete symbols 生成解析器。在这种情况下,您不能简单地 return 来自 yylex
的 0,因为解析器需要一个完整的符号,这是一个比 int
更复杂的类型(尽管报告 EOF 的标记不通常有一个语义值,它确实有一个位置,如果你使用的是位置。)对于其他令牌类型,bison 将自动生成一个函数来生成一个令牌,命名为 make_FOO_TOKEN
,你将在FOO_TOKEN
.
虽然 C bison 解析器确实自动定义文件结束标记(称为 END
),但 C++ 接口似乎没有。所以你需要在你的 bison 输入文件的 %token
声明中手动定义它:
%token END 0 "end of file"
(用整数值 0 和人类可读标签 "end of file" 定义令牌类型 END
。值 0 是必需的。)
完成后,您可以在 flex 输入文件中添加明确的 EOF 规则:
<<EOF>> return make_END();
如果您使用位置,则还必须提供 make_END
位置参数。
这是防止编译器错误的另一种方法 could not convert 0 from int to ...symbol_type
- 将 yyterminate
宏的重新定义放在重新定义 YY_DECL
// change curLocation to the name of the location object used in yylex
// qualify symbol_type with the bison namespace used
#define yyterminate() return symbol_type(YY_NULL, curLocation)
启用 bison 位置时会出现编译器错误,例如with %define locations
- 这使得 bison 向其 symbol_type
构造函数添加一个 location
参数,因此没有位置的构造函数
symbol_type(int tok)
用位置
变成这个symbol_type(int tok, location_type l)
不再可能将 int
转换为 symbol_type
,这是 flex 中 yyterminate
的默认定义在未启用 bison 位置时能够执行的操作
#define yyterminate() return YY_NULL
有了这个解决方法,如果您不需要,就不需要在 flex 中处理 EOF
- 如果您不需要,就不需要在 bison 中处理多余的 END
令牌