我在逻辑运算符中遇到问题
在我的.y档案中,我有:
expr: expr oper1 expr { $$=insert_expression($2, $1, $3); }
| expr oper2 expr { $$=insert_expression($2, $1, $3); }
;
在我的.l文件中,我确定oper1和oper2是:
"<" | ">" | "=" | "<>" | "<=" | ">=" { return oper1; }
"AND" | "OR" { return oper2; }
然后我有一个结构来将值放在:
typedef struct _Expression
{
char *oper;
struct _Expression *ex1;
struct _Expression *ex2;
} is_expression;
并将值放入:
is_expression* insert_expression(char* oper, is_expression *expr1, is_expression *expr2)
{
is_expression* e = (is_expression*)malloc(sizeof(is_expression));
e->ex1 = expr1;
e->ex2 = expr2;
e->oper = oper;
return e;
}
最后告诉他们:
void show_expression(is_expression *e)
{
show_expression(e->ex1);
printf("%s", e->oper);
show_expression(e->ex2);
}
但每次我使用expr oper expr时都会出现分段错误:
Program received signal SIGSEGV, Segmentation Fault
关于我做错了什么的想法?
由于
答案 0 :(得分:1)
让我们看看:
void show_expression(is_expression *e)
{
show_expression(e->ex1);
printf("%s", e->oper);
show_expression(e->ex2);
}
递归必须有终止的方法!
一个很大的线索是你只有一个printf
来打印操作员。但除了运算符之外,树中还有其他内容:即操作数!
在表达式树中,这些操作数是叶节点。他们是如何代表的?他们可能有ex1
和ex2
的空指针,对吧? (希望不是垃圾:你的所有解析器规则都会$$
为某个值,对吗?)
此外,您的yacc文件必须有更多。您显示的expr
规则本身不存在,因为它不能简化为一系列终端符号。
答案 1 :(得分:0)
所有令牌的默认类型为int
。如果你没有
%union {
char *oper1
char *oper2
}
会有问题。实际上,你是混合指针和整数。这会导致您的程序尝试访问任意内存,从而导致段错误。
修改强>
好的,然后在gdb或我首选的cgdb中解开那个东西。
cgdb yourCompiledParser
> r (add necessary command line switches)
when it segfaults
> backtrace
这将为您提供失败的大致位置,并显示您需要断点的位置。有关gdb / cgdb调试提示,请查看此article。
答案 2 :(得分:0)
为了获得$n
的合理值,您需要%union
指令来指定所有可能的类型,然后您需要在%token
/ {{1中使用这些类型指令:
%type
然后您还需要确保在.l文件中正确设置值:
%union {
is_expression *exp;
char *str;
}
%token<str> oper1 oper2
%type<exp> expr
否则,您将把随机垃圾作为第一个操作数传递给"<" | ">" | "=" | "<>" | "<=" | ">=" { yylval.str = strdup(yytext); return oper1; }
"AND" | "OR" { yylval.str = strdup(yytext); return oper2; }
,然后当您尝试对insert_expression
执行任何操作时崩溃(因为它指向随机垃圾)