我提取了部分项目以显示解析器的奇怪效果: 我的目标是在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)));
正如您所看到的,开括号和封闭括号的数量也不同。
有什么建议吗?
答案 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
字符串中添加了另一个反斜杠,假设这是预期的行为。)