Bison/Flex的一些输入奇怪的结果
Bison/Flex strange result for some input
我提取了我的项目的一部分,以显示我的解析器的奇怪效果:我的目标是翻译像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
字符串中添加了另一个反斜杠,假设这是预期的行为。)
相关文章:
- ";结果类型必须是可从输入范围的值类型""构造的;创建std::vector时
- 将公式的结果链接到用户输入,并验证它们是否匹配
- 读取一组用户输入,按升序排序,然后打印结果
- 我有两棵二叉树.我想在不更改输入树的情况下深度复制两个二叉树的结果
- 为什么在我的程序中输入另一个输入会给我不同的结果
- 如何将C++输入流分隔符包含在结果令牌中
- 当我输入分数值时,它返回不正确的结果
- 二项式系数程序输出错误的结果,如果输入是大的(C++)
- 为什么 protobuf 只读取最后一条消息作为输入结果
- C++ microshell,输入一个命令并使用fork(),dup(),pipe()将其通过管道传输到进程。只是我没有得到我想要的结果
- 在C++中使用用户输入变量声明数组大小。不同的 IDE 会产生不同的结果?
- 如果我输入错误的 dos 命令,shellexecute 会给出正确的结果
- 相机校准结果:为什么与输入相似
- 对于相同的输入参数,多个函数调用返回不同的结果
- C++简单的程序 - 为什么我的"res"不进入我的向量?创建一个接受输入 (4+44-67+235) 并输出结果的程序
- 将结果与用户输入-SQLITE3 C 进行比较
- OpenCV级联分类器检测输入Mat边界外的MultiScale结果Rect
- 将 QByteArray 转换为“long”会为相同的输入输出不同的结果
- 对输入'age'名称进行排序,然后显示结果
- 执行控制台程序,写入标准输入并使用管道读取结果