如果我有这个语法
start : TKN id '{' '}' {cout<<$2<<endl;} ;
包含
输出不应该是aaa吗??有时,它打印}和0,有时只是挂起
我想要得到id的价值,如何得到它的正确??
lex.l
%{
#include "yacc.hpp"
#include <math.h>
#include<iostream>
#include<string>
int rows = 1,tmp=0;
%}
Id [a-zA-Z_][0-9a-zA-Z_]*
%x String ...
%option c++
%option noyywrap
%%
{Id} {strcpy(yylval.strVal,yytext);cout<<"lex= "<<yytext<<endl;return Id;}//output line 1
...yacc.y
%output ="yacc.cpp"
%defines
%verbose
%token Id
%token NAMESPACE
%union{
int iVal;
float fVal;
char* strVal;
class Symbol* symPtr;
class NS* nsPtr;
};
%token <iVal> INT_VAL;
%token <fVal> F_VAL;
%token <strVal> STR_VAL INT FLOAT STRING Id ;
%type <nsPtr> namespacedecl
%type <symPtr> ns_closer
%type <strVal> Q_ID
//-------------------------------------------
namespacedecl : NAMESPACE Q_ID '{' '}' {cout<<"ns= "<<$2<< endl ;} // output line 3
| NAMESPACE Q_ID '{' typedecl_closer '}' ;
Q_ID : Q_ID '.' Id {cout<<$3<< endl ;$$ = $3;}
| Id {$$ = $1;cout<<"qid="<<$$<<endl;} // output line 2当然,文件比这个大,但是复制/粘贴任何东西都会让你迷失^^。
如果有附加文件的方法,请告诉我,因为我还是这里的新手,这比复制/粘贴要容易得多。
这就是我跑步时得到的东西:

谢谢你的回复
发布于 2011-02-16 22:52:58
这在很大程度上取决于您的id令牌作为yylval返回的内容,因为这是在标记移动时复制到解析器堆栈的内容,因此,在计算规则时,$2引用了什么。据猜测,您有一个lex规则,类似于:
[a-zA-Z_][a-zA-Z_0-9]* { yylval.str = yytext; return id; }使用
%token<str> id在你的解析器里。在本例中,您正在将指针存储到flex的内部扫描器缓冲区中,该缓冲区在瞬间包含“aaa”,但将被稍后的令牌覆盖,因此在操作运行时,指针以$2的形式指向其他内容。您需要将字符串复制到不会被覆盖的位置,并将yylval设置为指向该字符串。您可以使用strdup(3)将字符串复制到一个错误的缓冲区,这将解决这个问题,但可能会给您留下内存泄漏。
编辑
有了你的附加信息,你的程序没有崩溃是很令人惊讶的--你把标记文本strcpy到yylval.strVal,但是你从来没有初始化yylval.Strval来指向任何地方,所以你把它复制到一些随机的内存位置。您需要将类似于yylval.strVal = malloc(strlen(yytext)+1);的内容添加到lev.l操作中,以确保它指向有效内存,或者只需使用更简单和等效的调用来实现支持,因为这结合了malloc和strcpy:
[a-zA-Z_][a-zA-Z_0-9]* { yylval.str = strdup(yytext); return id; }发布于 2011-02-17 00:06:24
这取决于“id”规则返回了什么!
%%
start : TKN id '{' '}' {cout<<$2<<endl;} ;
id : ID { return "XXXXX"; } // What is returned here
// Is what will be printed out by $2
%%注意:
按照惯例,终端令牌是全大写(TKN).而非终端令牌是小写(id)。根据这个约定,我希望id有一个关于如何扩展它的规则。
我怀疑你在做的是:
%%
id : ID { return yytext; }
%%这是一个指向lex缓冲区的指针。这是一个易失性的缓冲区。您可以而不是依赖于它的内容保持不变(也不能依赖它被'\0‘终止)。您需要做的是在标识令牌时复制它。
%%
id : ID { return strndup(yytext, yylen); }
%%根据新输入编辑:
在以下几行:
{Id} { strcpy(yylval.strVal,yytext);
cout<<"lex= "<<yytext<<endl;
return Id;
}strcpy()可能是坏的。
cout是危险的,因为您不能依赖yytext被“\0”终止。
我会这样做:
{ID} { cout << "lex=" << std::string(yytext,yytext+yylen); // use yylen
return Id;
}不要在lex中乱搞yacc结构。它将您的lex文件紧密耦合到yacc (这不是必要的)。把记号还回去。然后,yacc可以手动获取令牌值。
然后在YACC文件中:
Q_ID : Q_ID '.' ident {$$ = $3; cout<<"Q.id="<<$$<<endl;}
| ident {$$ = $1; cout<<"ID ="<<$$<<endl;}
ident : Id {$$ = strndup(yytext, yylen);}对于每一个具有长令牌的终端(Id),都有一个用于对终端进行去编码的非终端,并在yacc联合结构中生成正确的值。在这种情况下,我们有身份,而不是终端。它只是解码Id终端并获得正确设置的令牌(此Id在联合结构中没有类型)。
另请注意:
此外:
这一行:
%token <strVal> STR_VAL INT FLOAT STRING Id ;看上去不对,尽管不知道INT、FLOAT和STRING是什么是很难分辨的。我猜这些都是关键字int、float、string的终端令牌。在这种情况下,不需要存储实际的令牌字符串。知道它是INT/FLOAT或STRING这一事实就足够了。
这应该是:
%token <strVal> STR_VAL;
%token <strVal> ident;https://stackoverflow.com/questions/5018931
复制相似问题