我正在使用flex和bison在C ++中编写ansi-C解析器;它非常复杂。
我遇到的问题是编译错误。错误如下,因为yy_terminate
返回YY_NULL
,其定义为(int)0
,yylex
的返回类型为yy::AnsiCParser::symbol_type
。 yy_terminate();
是flex生成的扫描程序中<<EOF>>
令牌的自动操作。显然这会导致类型问题。
我的扫描仪不会为EOF生成任何特殊标记,因为EOF在C语法中没有任何用途。我可以为<<EOF>>
创建一个令牌规则,但是如果我忽略它,则扫描程序会在yylex
情况下YY_STATE_EOF(INITIAL)
的无限循环中挂起。
编译错误,
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
必须为EOF返回一些内容,否则解析器永远不会停止等待输入,但我的语法不能支持EOF令牌。有没有办法让Bison在0
条件下识别$end
以外的其他内容而不修改我的语法?
或者,我只能从扫描仪中的<<EOF>>
令牌返回以满足Bison $end
条件吗?
答案 0 :(得分:1)
通常,您不会在词法分析器中包含显式EOF规则,不是因为它没有用处,而是因为默认值正是您想要做的。 (它服务的目的是指示输入是完整的;否则,解析器将接受某些无效程序的有效前缀。)
不幸的是,C ++接口可能会破坏默认EOF操作的简单方便,即返回0(或NULL)。我从您的问题描述中假设您已经要求bison使用complete symbols生成解析器。在这种情况下,你不能简单地从yylex
返回0,因为解析器期望一个完整的符号,这是一个比int
更复杂的类型(虽然报告EOF的令牌通常没有语义如果你正在使用locaitons,它确实有一个位置。)对于其他令牌类型,bison将自动生成一个函数,该函数生成一个名为make_FOO_TOKEN
的令牌,您将在扫描仪操作中调用它FOO_TOKEN
。
虽然C bison解析器确实自动定义了文件令牌的结尾(称为END
),但看起来C ++接口却没有。因此,您需要在您的野牛输入文件的%token
声明中手动定义它:
%token END 0 "end of file"
(它定义了令牌类型END
,其整数值为0,人类可读标签&#34;文件末尾为#34;。值0是强制性的。)
完成后,您可以在Flex输入文件中添加显式EOF规则:
<<EOF>> return make_END();
如果您使用的是地理位置,那么您也必须提供make_END
位置参数。
答案 1 :(得分:0)
这是防止编译器错误 var defaultJsonConvertSetting = new JsonSerializerSettings
{
Formatting = Formatting.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new DefaultContractResolver {NamingStrategy = null},
Error = (sender, args) =>
{
Console.WriteLine($"**********************Failed during serialization: {args.ErrorContext.Path}");
args.ErrorContext.Handled = true;
}
// other settings
};
JsonConvert.DefaultSettings = () => defaultJsonConvertSetting;
.AddControllersAsServices().AddNewtonsoftJson(options =>
{
options.UseMemberCasing();
options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
options.AllowInputFormatterExceptionMessages = true;
options.SerializerSettings.Formatting = Formatting.None;
options.SerializerSettings.ContractResolver = new DefaultContractResolver
{
NamingStrategy = null
};
options.SerializerSettings.Error = (sender, args) =>
{
_logger.LogError($"Failed during serialization: {args.ErrorContext.Path}", args.ErrorContext.Error);
args.ErrorContext.Handled = true;
};
});
的另一种方法 - 将 could not convert 0 from int to ...symbol_type
宏的重新定义放在您重新定义 yyterminate
的下方
YY_DECL
当启用野牛位置时会出现编译器错误,例如with // 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 向其 %define locations
构造函数添加一个 location
参数,因此构造函数没有位置
symbol_type
用位置变成这个
symbol_type(int tok)
渲染不再可能将 symbol_type(int tok, location_type l)
转换为 int
,这是未启用野牛位置时 flex 中 symbol_type
的默认定义能够执行的操作
yyterminate
使用此解决方法,如果您不需要,则无需在 flex 中处理 #define yyterminate() return YY_NULL
- 如果您不需要,则不需要在野牛中使用多余的 EOF
令牌