我正在使用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
会返回整个功能块?我怎样才能获得返回类型? (最后,我的目标是打印返回类型,函数名称和参数类型)
答案 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}}