问题描述
我正在尝试移植从flex.bison生成的旧版32位解析器代码。 我必须使用Visual Studio 2019并编译为x64目标。 解析此代码中的参数时,发生崩溃(读取访问冲突):
case 42:
{ registerTypedef( (yyvsp[(2) - (4)]),(yyvsp[(3) - (4)]) ); }
break;
void registerTypedef(char* typeref,char* typeName)
{
//SG_TRACE_INFO("registerTypedef %s %s",typeName,typeref);
std::string typeNameStr = typeName;
std::string typeRefStr = typeref;
TheSGFactory::GetInstance().SG_Factory::RegisterTypeDef(typeNameStr,typeRefStr);
相应的规则如下:
declaration_typedef
: TYPEDEF TYPEDEF_NAME IDENTIFIER ';' { registerTypedef( $2,$3 ); }
| TYPEDEF basic_type IDENTIFIER ';' { registerTypedef( $2,$3 ); }
;
似乎使用负索引(2)-(4)= -2。访问了 yyvsp 。 这应该可以,因为同一代码可以与32位编译器完美配合。 C99标准似乎也可以。
我试图使用Windows和UNIX下可用的最新flex / bison版本。生成的代码非常相似,而且问题相同。
是否有一个神奇的Visual Studio Option可以使其接受负索引? 是否有一个神奇的Flex / bison参数可以解决此问题?
非常感谢!
解决方法
几乎可以肯定您在错误的位置看
yyvsp
始终指向解析器堆栈的 top ,因此负索引是完全正常的。并且完全合法。问题在于,应该是char*
的东西不是有效的指针,可能是因为默认语义值类型未从int
更改而来。在32位体系结构上,通常可以将指针存储到int
中,因为它们的大小可能相同。但是64位编译将中断,因为一半指针将被截断。
如果在启用警告的情况下进行编译,则此错误应该很明显。
请注意,没有什么可以保证YYSTYPE
在词法扫描器和解析器中是相同的,因为它们是由不同的代码生成器从不同的源文件生成的独立程序。因此,两者之一或两者都可能是错误的。 (编译器警告将有助于区分情况。)
您最好的选择是确保在YYSTYPE
中正确定义了bison生成的头文件,以避免类型不匹配的问题。最简单的方法是使用%define api.value.type
野牛声明,但这是一个相对较新的功能。较早的样式是将#define YYSTYPE whatever
放在野牛%code requires
块中。而且,更老的样式是在YYSTYPE
和.y
文件中都复制.l
定义。 (或者通过抑制或忽略编译器警告来“解决”该问题,将问题留给将来的维护程序员使用。:-))
我认为这里有两个问题:
-
@rici对于不同类型的YYSTYPE是正确的:它们必须相同。就我而言,char *
-
回调词法分析器代码正在使用strdup()。默认情况下,Visual Studio 2019将此函数解析为返回int的函数。
yylval = strdup(yytext);
这破坏了堆栈内容
我不得不强制#include
注意:我已经需要强制包含
谜团解决了!非常感谢所有贡献者