如何用野牛返回功能名称?

时间:2016-08-31 10:07:44

标签: c bison flex-lexer

我正在使用bison和flex构建一个简化的C解析器。我编写了一个语法规则来检测我的Bison文件中的函数,我希望解析器将函数的名称发送到我的C监视程序。以下是我实施的极其简化的示例:

我的监控程序

/*monitor.h*/
#ifndef MONITOR_H
#define MONITOR_H

extern int noLig;
extern char* yytext;

#endif

/*monitor.c*/
#include <stdio.h>
#include <monitor.h>
#include <project.tab.h>

int noLig=0;

int main (int argc, char * argv[]) {
    printf("flex-\n");
    int err_code=yyparse();
    if (err_code == 0) {
        printf("It went fine\n");
    } else {printf("It didn't go well\n");}
    return 0;
}

project.l file

%{
#include <stdio.h>
#include <monitor.h>
#include <project.tab.h>
%}

%%
"\"[a-zA-Z0-9]+"\"  {ECHO; yylval.str=yytext; return STR;}
[.,;=()\[\]\{\}]        { return yytext[0]; }

"char"      {ECHO; printf("-"); yylval.str=yytext; return TYPE;}
"int"       {ECHO; printf("-");yylval.str=yytext; return TYPE;}
"float"     {ECHO; printf("-");yylval.str=yytext; return TYPE;}
"double"    {ECHO; printf("-");yylval.str=yytext;return TYPE;}

[a-zA-Z][a-zA-Z0-9]* {ECHO; printf("-");yylval.str = yytext; return VAR;}

[ \t\n\b]+  {noLig++;}
"//".*      {}
.       {printf(":%cwhat is this",yytext[0]);}
%%

project.y file

%{
#include    <stdio.h>
#include    <monitor.h>
int yylex();
int yyerror ();
%}
%union {
    char *str;
    int i;
}
%define parse.error verbose
%type <i> INT
%type <str> TYPE STR VAR

%token TYPE INT STR VAR

%start Program
%%
Program: function_l
    ;

function_l: function
    | function_l function
    ;

function: TYPE VAR '(' param_prototype_ld ')' '{' instruction_l '}'
    {printf("\n\nbison-\n%s\n",$1);}
    ;

param_prototype_ld: /*empty*/
    | param_prototype_l
    ;

param_prototype_l: param_prototype
    | param_prototype_l ',' param_prototype
    ;

param_prototype: TYPE VAR
    ;

instruction_l: /*empty*/
    | VAR ';'
    | VAR instruction_l
    ;
%%
int yyerror (char* s) {
    fprintf(stderr, "Compilator3000:l.%d: %s\n", noLig, s);
}

test.c文件

int main (int arg) {
    a;
}

它编译正常,没有任何警告。但是,当我运行./monitor < test.c时,我得到以下输出:

flex-
int-main-int-arg-a-

bison-
int main (int arg) {
    a;
}
It went fine

为什么bison变量$1会返回整个功能块?我怎样才能获得返回类型? (最后,我的目标是打印返回类型,函数名称和参数类型)

2 个答案:

答案 0 :(得分:3)

yytext is not guaranteed to persist的值,并且要使yytext保持不变,必须将其复制到单独的缓冲区。这通常使用strdup

完成
...
"\"[a-zA-Z0-9]+"\"  {ECHO; yylval.str=strdup(yytext); return STR;}
[.,;=()\[\]\{\}]    { return yytext[0]; }

"char"      {ECHO; printf("-"); yylval.str=strdup(yytext); return TYPE;}
"int"       {ECHO; printf("-");yylval.str=strdup(yytext); return TYPE;}
"float"     {ECHO; printf("-");yylval.str=strdup(yytext); return TYPE;}
"double"    {ECHO; printf("-");yylval.str=strdup(yytext);return TYPE;}

[a-zA-Z][a-zA-Z0-9]* {ECHO; printf("-");yylval.str = strdup(yytext); return VAR;}
...

虽然strdup可以返回NULL,但可以使用包装函数使该失败显式

char *
strdup_checked(char *str)
{
        char *p;

        if ((p = strdup(str)) == NULL) {
                perror("strdup");
                exit(EXIT_FAILURE);
        }
        return (p);
}

答案 1 :(得分:1)

虽然OP找到了解决方案,但我会尝试提供一个完整的答案。

这是根据你的代码定义函数的语法。

function

每个符号都是位置变量。例如TYPE是$ 1,VAR是$ 2(我相信函数名称)。 $$是任何规则的返回值。在这种情况下function_l: function | function_l function ; 。要返回函数名称,您需要在操作部分中设置$$ = $ 2。将$$设置为$ 1将返回函数名称。或者,您可以在操作中创建数据结构(如数组或结构)以保存多个$变量,然后将其返回。

效果将在以下规则中看到

yylval.str=strdup(yytext)

非终端符号功能将保存该功能的名称。在这个规则&#34; function_l&#34;是$ 1和&#34;功能&#34; 2美元。如果您打印$ 2,它将为您提供从规则&#34;函数&#34;传递的函数名称。

自终端&#34; VAR&#34;是一个字符串,您需要在lex或语法规则中将yylval.str=strdup($<pos>)设置为{{1}}