Bison 韩元价值';t在令牌之外的Yacc中分配

Bison 韩元价值';t在令牌之外的Yacc中分配,bison,yacc,lex,Bison,Yacc,Lex,在Yacc中,我编写了一个解析器,它应该识别一个数字或字符串,并将其分配给我创建的名称标记。它似乎是在变量被赋值的情况下工作的,如果我打印它们的值,它们是正确的。但是,一旦Yacc移动到下一个标记,这些值就会被擦除,就好像从未将变量分配给它一样。规则NAME'='NAME是在规则中指定的位置,而不是在其他位置。这只是将一个名称/变量的值复制到另一个变量时出现的问题。底部是我所指内容的照片,这是我的代码: 简单 %{ #包括“ch3hdr.h” #包括 int yylex(无效); 无效错误(字符

在Yacc中,我编写了一个解析器,它应该识别一个数字或字符串,并将其分配给我创建的
名称
标记。它似乎是在变量被赋值的情况下工作的,如果我打印它们的值,它们是正确的。但是,一旦Yacc移动到下一个标记,这些值就会被擦除,就好像从未将变量分配给它一样。规则
NAME'='NAME
是在规则中指定的位置,而不是在其他位置。这只是将一个
名称
/变量的值复制到另一个变量时出现的问题。底部是我所指内容的照片,这是我的代码:

简单
%{
#包括“ch3hdr.h”
#包括
int yylex(无效);
无效错误(字符*);
%}
%联合{
char*str;
双dval;
结构符号表*符号;
}
%令牌名
%令牌号
%令牌串
%左''''+'
%左'*''/'
%非寄生性耳鸣
%numexpr型
%类型strexpr
%%
语句列表:语句'\n'
|语句\u列表语句'\n'
;
语句:NAME'='numexpr{$1->num=$3;$1->type=num;}
|名称“=”strexpr{$1->str=$3;$1->type=str;}
|名称“=”名称{
$1 = $3;
开关($3->类型)
{
案例编号:
{  
$1->num=$3->num;
$1->type=NUM;
打破
}
案例STR:
{
$1->str=$3->str;
$1->type=STR;
打破
}
默认值:yyerror(“声明无效”);中断;
}
}
|名称{
开关($1->类型)
{
案例编号:fprintf(stderr,“NUM=%g\n”,$1->NUM);break;
案例STR:fprintf(stderr,“STR=%s\n”,$1->STR);break;
默认值:fprintf(stderr,“未定义变量%g\n”,$1->num);中断;
}
}
|numexpr{fprintf(stderr,“numexpr=%g\n”,$1);}
|strexpr{fprintf(stderr,“strexpr=%s\n”,$1);}
;
numexpr:numexpr'+'numexpr{$$=$1+$3;//其中$1是第一个输入的令牌
//$3是“=”之后的下一个令牌
}
|numexpr'-'numexpr{$$=$1-$3;}
|numexpr'*'numexpr{$$=$1*$3;}
|numexpr'/'numexpr
{ 
如果($3==0.0)
yyerror(“除以零”);
其他的
$$ = $1 / $3;
}
|“-”numexpr%prec-UMINUS{$$=-$2;}
|“('numexpr')”{$$=$2;}
|数
|名称“('numexpr')”{$$=($1->funcptr)($3);}
;
strexpr:STRING
;
%% 
无效错误(字符*str)
{
fprintf(stderr,“错误%s”,str);
}
结构symtab*symlook(字符*s){
char*p;
结构符号表*sp;
对于(sp=symtab;sp<&symtab[NSYMS];sp++){
/*已经到了吗*/
如果(sp->name&&!strcmp(sp->name,s))
返回sp;
如果(!sp->name){/*它是免费的吗*/
sp->name=strdup;
返回sp;
}
/*否则继续下一步*/
}
yyerror(“符号太多”);
退出(1);/*无法继续*/
}/*符号外观*/
void addfunc(字符*名称,双(*func)()
{
结构symtab*sp=symlook(名称);
sp->funcptr=func;
}
int main(){
外部双sqrt(),exp(),log();
addfunc(“sqrt”,sqrt);
addfunc(“exp”,exp);
addfunc(“log”,log);
yyparse();
返回0;
}
很简单
%{
#包括“simple.tab.h”
#包括“ch3hdr.h”
#包括
%}
%%
([0-9]+|([0-9]*\[0-9]+)([eE][-+]?[0-9]+)?){
yylval.dval=atof(yytext);
返回号码;
}
[\t];/*忽略空白*/
[A-Za-z][A-Za-z0-9]*{
yylval.symp=symlook(yytext);
返回名称;
}
\“[^”\n]*[”\n]{
yylval.str=yytext;
返回字符串;
}
“$”返回0;/*逻辑EOF*/
\n|
.返回文本[0];
%%
ch3hdr.h
#包括
#包括
#定义NSYMS 20
类型定义枚举
{
NUM=1,
STR=2
}类型;
结构符号表
{
字符*名称;
//如果此条目是功能名称,则调用ptr to C函数
双(*funcptr)();
双重价值;
双数;
char*str;
类型;
}符号表[NSYMS];
结构symtab*symlook();

问题是您在
Simple.l
中返回
yytext
,假定其值将保持不变。它不会保持不变,因为它是lexer的内部值,每次调用
yylex
时都会更新

lexer中的这个块就是我看到的:

\"[^"\n]*["\n] { 
        yylval.str = yytext;
        return STRING; 
    }
在yacc语法中,使用值时不进行复制,例如

                                    case STR:
                                    {
                                        $1->str = $3->str;
                                        $1->type = STR;
                                        break;
                                    }

偶尔会出现这种情况,但上次我在中回答时,没有找到合适的公认答案将其标记为重复。

问题在于lexer规则:

yylval.str = yytext;
这只是复制一个指针,指向将来某个时间将被覆盖的数据。您需要复制数据:

yylval.str = strdup(yytext);
这将导致内存泄漏,除非您在解析阶段或更晚的某个时间完成后立即发出相应的
free()
case STR: { $1->str = $3->str; $1->type = STR; break; }
yylval.str = yytext;
yylval.str = strdup(yytext);