我正在使用bison为简单语言构建编译器。这是语法的一部分:
stmt: IF '(' exp ')' stmt{
if(exp) $$=$5;
}
|PRINT ';' {
cout<<"hi";
}
;
exp: true|false
;
我在解析这个if语句时遇到了一个问题:说我有这段代码:
if(false) print;
“hi”将被打印,因为stmt-&gt; PRINT在stmt-&gt;之前被解析。 IF(exp)stmt。 我能做什么? (我是野牛和编译的新手,所以请随意纠正我的问题中的错误。)
答案 0 :(得分:1)
这很自然。你正在解析print语句,所以'cout'被执行了。您要做的是创建某种字节代码,您可以在其中存储打印指令。然后可以将此打印指令与if-expression组合以形成if语句指令。
在我的脑海中,我记不起Bison中的确切陈述(你需要查看文档),但是你通常想要为你的值栈定义一个类型,通常是结构的联合这样的事情(虽然它有一个bison命令,这将使它成为价值堆栈的类型)。
union {
int type;
struct {
int type; // must always be first, this is a union
union stmt *stmt; // conditional stmt to execute
union expr *expr; // expression to evaluate
} if_stmt;
struct {
int type;
} print_stmt;
} stmt;
这将允许您在语法中加入规则,类似这样的
stmt: IF '(' expr ')' stmt { $$.type = IF_STMT; $$.if_stmt.expr = copy ($3); $$.if_stmt.stmt = copy ($5); }
等等(那里可能存在一个一个错误的错误,不记得$ s是从0还是1开始)。您需要自己实现copy
函数来管理内存分配,bison只会为值提供堆栈。最后,对于类型为IF_STMT,evalute为if_stmt.expr的节点,您将拥有一棵树(我相信通常称为语法树),如果它返回true,则评估if_stmt.stmt,等等。
然后当你完成解析语言时,你可以'执行'你的字节代码,当你点击if语句,评估表达式,如果是真的(不是),执行如上所述的语句,然后当你点击一个打印指令(你不会因为表达式是假的),你打印你的'hi',你就得到了你正在寻找的结果(也就是说,没有任何东西被打印出来)。 / p>
这几乎就是你需要去做的事情。在使用bison解析时,你不能(轻松地)执行条件执行。
答案 1 :(得分:0)
如果你想使它只适用于if,你可以在EXP eval中创建一个堆栈,在堆栈上推送EXP的真值,在IF块中只检查你是否可以执行函数调用,赋值等等。否则在堆栈上取消最后一个值,在IF减少时,只需从Stack中弹出值。
例如:
Stack (bool) x;
CanExec()
{
if x== NULL //no IF yet
return true;
for i in x
if i == false
return false; //if we have at last 1 if banch with FALSE, we cannot execute it
return true;
}
if_stmt: IF if_exp block {Pop()}
|IF if_exp block else block {Pop()}
if_exp: '(' exp ')' {Push((bool)exp)}
else: ELSE {tmp = Pop(); Push(!tmp)}
现在,你所要做的就是检查CanExec()
的所有副作用操作