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

Bison/Flex strange result for some input

本文关键字:结果 输入 Flex Bison      更新时间:2023-10-16

我提取了我的项目的一部分,以显示我的解析器的奇怪效果:我的目标是翻译像ADD(VAL(2),VAL(5))…在c++中在下面你可以找到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          [ tn]+
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 filenamen"); exit(0);}
    FILE* file = fopen(args[1],"r");
    if(file == NULL) {printf("couldn't open %sn",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(){ntint x = "+t1+";ntprintf("%dn",x);ntreturn 1;n};";
        printf("%sn",res.c_str());
    }
    | STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
    {
        string t1 = $5;
        string t2 = $8;
        string res = t1+" = "+t2+";";
        printf("%sn",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)));

正如你所看到的,左括号和右括号的数量是不同的。

任何建议吗?

问题是您的个人产品将char *分配给指向str.c_str()返回值的$$。当str在块末尾超出作用域时,指针所指向的内存可能被字符串析构函数释放,访问它会导致未定义的行为。为了克服这个问题,您可以为在原始字符串超出作用域后仍然存在的字符串分配内存,strdup可以用于此。

Using your bison 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 = "";
        $$ = strdup(res.c_str());
    }
    | SET OPEN Exp CLOSE
    {
        string t1 = $3;
        string res = "#include <stdio.h>nint main(){ntint x = "+t1+";ntprintf("%d\n",x);ntreturn 1;n};";
        printf("%sn",res.c_str());
    }
    | STORE OPEN VAR OPEN IDENTIFIER CLOSE S Exp CLOSE
    {
        string t1 = $5;
        string t2 = $8;
        string res = t1+" = "+t2+";";
        printf("%sn",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("%dn",x);
    return 1;
};

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

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

相关文章: