yacc输出帮助

时间:2011-02-16 16:14:21

标签: compiler-construction yacc bison

如果我有这个语法,例如

start : TKN id '{' '}' {cout<<$2<<endl;} ;

  • 包含iostream,TKN声明为令牌,id类型声明为char *

  • 作为输入我输入tkn aaa { }

输出不应该是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

当然文件比这个大,但复制/粘贴一切都会让你迷路^^

如果有办法附加文件,请告诉我,因为我现在还是新手,这比复制/粘贴容易得多。

这就是我跑步时得到的:

enter image description here

感谢您的回复

2 个答案:

答案 0 :(得分:1)

这取决于'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()可能不好。

  • 您是否为副本预留了空间?
  • 你不能依赖yytext被'\ 0'终止。

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联合结构中生成正确值的非终端。在这种情况下,我们有ident而不是终端。它只是解码Id终端并正确设置令牌(此Id在union结构中没有类型)。

另请注意:

  • 传统的终端是全部大写。我失败了。
  • 传统的非终端是小写的。 Q_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;

答案 1 :(得分:0)

这在很大程度上取决于你的词法分析器作为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)将字符串复制到malloced缓冲区,这可以解决这个问题,但可能会让你内存泄漏。

修改

有了您的其他信息,令您惊讶的是您的程序没有崩溃 - 您strcpy将令牌文本yylval.strVal转换为yylval.Strval,但您永远不会将yylval.strVal = malloc(strlen(yytext)+1);初始化为指向任何地方,所以你将它复制到一些随机的内存位置。你需要在lex.l动作中加入类似[a-zA-Z_][a-zA-Z_0-9]* { yylval.str = strdup(yytext); return id; } 的东西,以确保它指向有效的内存,或者只使用更简单和等效的strdup调用,因为它结合了malloc和strcpy:

{{1}}