Bison / Flex奇怪的结果是一些输入

时间:2015-08-22 16:21:35

标签: c++ bison

我提取了部分项目以显示解析器的奇怪效果: 我的目标是在C ++中翻译像ADD(VAL(2),VAL(5))...这样的语法 在下文中,您可以找到light flex和bison文件:

%{
#include <string>
#include "expression.tab.h"
void yyerror(char*);
int yyparse(void);

char linebuf[500]; //for output the row in case of syntax error

%}

blanks          [ \t\n]+
text            [a-zA-Z0-9]+|[0-9]+.[0-9]+
%%

\n.*            { /* saving the next row in case of syntax error */
                  strncpy(linebuf, yytext+1, sizeof(linebuf)); /* save the next line */
                  yyless(1);      /* give back all but the \n to rescan */
                }

{blanks}        { /* ignore */ };

"("             return(OPEN);
")"             return(CLOSE);
"SET"           return(SET);
"STORE"         return(STORE);
"MUL"           return(MUL);
"ADD"           return(ADD);
"DIV"           return(DIV);
"SUB"           return(SUB);
"ABS"           return(ABS);
"IFEL"          return(IFEL);
"NOT"           return(NOT);
"AND"           return(AND);
"OR"            return(OR);
"GEQ"           return(GEQ);
"LEQ"           return(LEQ);
"GREATER"       return(GREATER);
"LESS"          return(LESS);
"EQ"            return(EQ);
"VAR"           return(VAR);
"VAL"           return(VAL);
"GET"           return(GET);
","             return(S);

{text}          { yylval.str_val=(char*)strdup(yytext);
                  return(IDENTIFIER);
                }

.               return yytext[0];

%%

void yyerror(char *s){ 
    printf("<ERR> %s at %s in this line:\n", s, yytext);
    }

int yywrap (void){
    }

int main(int num_args, char** args){
    if(num_args != 2) {printf("usage: ./parser filename\n"); exit(0);}
    FILE* file = fopen(args[1],"r");
    if(file == NULL) {printf("couldn't open %s\n",args[1]); exit(0);}
    yyin = file;
    yyparse();
    fclose(file);
}

%{
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
extern int yylex();
extern void yyerror(char*);
%}

//Symbols
%union
{
    char *str_val;
    int int_val;
};

%token OPEN;
%token CLOSE;
%token SET;
%token STORE;
%token MUL;
%token ADD;
%token DIV;
%token SUB;
%token ABS;
%token IFEL;
%token AND;
%token OR;
%token NOT;
%token GEQ;
%token LEQ;
%token GREATER;
%token LESS;
%token EQ;
%token GET;
%token S; /* separator */
%token VAR;
%token VAL;

%token <str_val> IDENTIFIER

%type <str_val> Code
%type <str_val> Exp
%type <str_val> Cond
%type <str_val> Check
%type <str_val> Var

%start Code

%%

Code:
    /* empty */
    {
        string res = "";
        $$ = (char*)res.c_str();
    }
    | SET OPEN Exp CLOSE
    {
        string t1 = $3;
        string res = "#include <stdio.h>\nint main(){\n\tint x = "+t1+";\n\tprintf(\"%d\n\",x);\n\treturn 1;\n};";
        printf("%s\n",res.c_str());
    }
    | STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
    {
        string t1 = $5;
        string t2 = $8;
        string res = t1+" = "+t2+";";
        printf("%s\n",res.c_str());
    }
    ;

Exp:
    Var
    | IFEL OPEN Cond S Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string t3 = $7;
        string res = "("+t1+" ? "+t2+" : "+t3+")";
        $$ = (char*)res.c_str();
    }
    | ADD OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"+"+t2+")"; 
        $$ = (char*)res.c_str();
    }
    | SUB OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"-"+t2+")"; 
        $$ = (char*)res.c_str();
    }
    | MUL OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"*"+t2+")"; 
        $$ = (char*)res.c_str();
    }
    | DIV OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t2+"==0) ? (0) : ("+t1+"/"+t2+"))";  //TBD substitute (0) in order to raise exception of div for zero
        $$ = (char*)res.c_str();
    }
    | ABS OPEN Exp CLOSE
    {
        string t1 = $3;
        string res = "(("+t1+">0) ? "+t1+" : ("+t1+"*(-1)))";
        $$ = (char*)res.c_str();
    }
    ;

Cond:
    NOT OPEN Cond CLOSE
    {
        string t1 = $3;
        string res = "(("+t1+") ? false : true)";
        $$ = (char*)res.c_str();
    }
    | AND OPEN Cond S Cond CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+" && "+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | OR OPEN Cond S Cond CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+" || "+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | Check
    ;

Check:
    GREATER OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+">"+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | LESS OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"<"+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | EQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"=="+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | GEQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+">="+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    | LEQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"<="+t2+") ? true : false)";
        $$ = (char*)res.c_str();
    }
    ;

Var:
    VAR OPEN IDENTIFIER CLOSE
    {
        string t1 = $3;
        $$ = (char*)t1.c_str();

    }
    | VAL OPEN IDENTIFIER CLOSE
    {
        $$ = $3;
    }
    | GET OPEN CLOSE
    {
        $$ = strdup("1");
    }
    ;

%%

一个小公式的一切都很好,但有些东西会变大。 有了这个输入:

SET(ADD(MUL(VAL(3),SUB(VAL(5),VAL(2))),IFEL(GEQ(IFEL(EQ(VAL(16),MUL(VAL(2),VAL(8))),VAL(11),VAL(10)),VAL(10)),MUL(VAL(3.2),VAL(4)),ADD(VAL(2),VAL(1)))))

我的voutput如下:

$ ./expression1 test.txt 
#include <stdio.h>
int main(){
    int x = (((16==(2*8)) ? true : fa+((((((16==(2*8)) ? true : false) ? 11 : 10)>=10) ? true : false) ? (2 : (2+1)));
    printf("%d
",x);
    return 1;
};

我无法得到这种糟糕结果的原因

(((16==(2*8)) ? true : fa+((((((16==(2*8)) ? true : false) ? 11 : 10)>=10) ? true : false) ? (2 : (2+1)));

正如您所看到的,开括号和封闭括号的数量也不同。

有什么建议吗?

1 个答案:

答案 0 :(得分:3)

问题是,您的个人作品正在指定char *$$,指向str.c_str()的返回值。当str超出块末尾的范围时,指针指向的内存可能会被字符串析构函数释放,并且访问它会导致未定义的行为。为了解决这个问题,您可以为原始字符串超出范围后将保留的字符串分配内存,strdup可用于此目的。

使用您的野牛档案:

%{
#include <stdio.h>
#include <string>
#include <cstring>
using namespace std;
extern int yylex();
extern void yyerror(char*);
%}

//Symbols
%union
{
    char *str_val;
    int int_val;
};

%token OPEN;
%token CLOSE;
%token SET;
%token STORE;
%token MUL;
%token ADD;
%token DIV;
%token SUB;
%token ABS;
%token IFEL;
%token AND;
%token OR;
%token NOT;
%token GEQ;
%token LEQ;
%token GREATER;
%token LESS;
%token EQ;
%token GET;
%token S; /* separator */
%token VAR;
%token VAL;

%token <str_val> IDENTIFIER

%type <str_val> Code
%type <str_val> Exp
%type <str_val> Cond
%type <str_val> Check
%type <str_val> Var

%start Code

%%

Code:
    /* empty */
    {
        string res = "";
        $$ = strdup(res.c_str());
    }
    | SET OPEN Exp CLOSE
    {
        string t1 = $3;
        string res = "#include <stdio.h>\nint main(){\n\tint x = "+t1+";\n\tprintf(\"%d\\n\",x);\n\treturn 1;\n};";
        printf("%s\n",res.c_str());
    }
    | STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
    {
        string t1 = $5;
        string t2 = $8;
        string res = t1+" = "+t2+";";
        printf("%s\n",res.c_str());
    }
    ;

Exp:
    Var
    | IFEL OPEN Cond S Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string t3 = $7;
        string res = "("+t1+" ? "+t2+" : "+t3+")";
        $$ = strdup(res.c_str());
    }
    | ADD OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"+"+t2+")"; 
        $$ = strdup(res.c_str());
    }
    | SUB OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"-"+t2+")"; 
        $$ = strdup(res.c_str());
    }
    | MUL OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "("+t1+"*"+t2+")"; 
        $$ = strdup(res.c_str());
    }
    | DIV OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t2+"==0) ? (0) : ("+t1+"/"+t2+"))";  //TBD substitute (0) in order to raise exception of div for zero
        $$ = strdup(res.c_str());
    }
    | ABS OPEN Exp CLOSE
    {
        string t1 = $3;
        string res = "(("+t1+">0) ? "+t1+" : ("+t1+"*(-1)))";
        $$ = strdup(res.c_str());
    }
    ;

Cond:
    NOT OPEN Cond CLOSE
    {
        string t1 = $3;
        string res = "(("+t1+") ? false : true)";
        $$ = strdup(res.c_str());
    }
    | AND OPEN Cond S Cond CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+" && "+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | OR OPEN Cond S Cond CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+" || "+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | Check
    ;

Check:
    GREATER OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+">"+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | LESS OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"<"+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | EQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"=="+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | GEQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+">="+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    | LEQ OPEN Exp S Exp CLOSE
    {
        string t1 = $3;
        string t2 = $5;
        string res = "(("+t1+"<="+t2+") ? true : false)";
        $$ = strdup(res.c_str());
    }
    ;

Var:
    VAR OPEN IDENTIFIER CLOSE
    {
        string t1 = $3;
        $$ = strdup(t1.c_str());

    }
    | VAL OPEN IDENTIFIER CLOSE
    {
        $$ = $3;
    }
    | GET OPEN CLOSE
    {
        $$ = strdup("1");
    }
    ;

%%

然后返回

#include <stdio.h>
int main(){
    int x = ((3*(5-2))+((((((16==(2*8)) ? true : false) ? 11 : 10)>=10) ? true : false) ? (3.2*4) : (2+1)));
    printf("%d\n",x);
    return 1;
};

正如所料。

请注意,我们无处释放strdup分配的内存,因此这在技术上会导致内存泄漏,但我认为这是解决您特定问题的合适且简单的解决方案。

(我还在printf字符串中添加了另一个反斜杠,假设这是预期的行为。)