Compiler construction 如何解析bison中的if语句
我正在使用bison为一种简单的语言构建一个编译器。下面是语法的一部分:Compiler construction 如何解析bison中的if语句,compiler-construction,if-statement,bison,Compiler Construction,If Statement,Bison,我正在使用bison为一种简单的语言构建一个编译器。下面是语法的一部分: stmt: IF '(' exp ')' stmt{ if(exp) $$=$5; } |PRINT ';' { cout<<"hi"; } ; exp: true|false ; “hi”仍将被打印,因为stmt->PRINT是在stmt->IF(exp)stmt之前解析的。 我能做什么? (我不熟悉bison和编译,所以请随意更正我问
stmt: IF '(' exp ')' stmt{
if(exp) $$=$5;
}
|PRINT ';' {
cout<<"hi";
}
;
exp: true|false
;
“hi”仍将被打印,因为stmt->PRINT是在stmt->IF(exp)stmt之前解析的。
我能做什么?
(我不熟悉bison和编译,所以请随意更正我问题中的错误)。这很自然。您正在分析print语句,因此执行'cout'。您要做的是创建某种字节码,在其中存储打印指令。然后,可以将此打印指令与if表达式组合以形成if语句指令 在我脑海中,我记不起Bison中的确切语句(您需要查看文档),但是您通常希望为您的值堆栈定义一个类型,通常是一个结构的并集,类似这样的东西(尽管有一个Bison命令,它将成为值堆栈的类型) 这将允许你在语法中加入一条规则,比如
stmt: IF '(' expr ')' stmt { $$.type = IF_STMT; $$.if_stmt.expr = copy ($3); $$.if_stmt.stmt = copy ($5); }
以此类推(这里可能有一个off by one错误,不记得$s是从0还是1开始的)。您需要自己实现copy
函数来管理内存分配,bison只提供一个值堆栈。最后,您将有一个树(我相信通常称为语法树),对于类型为IF_STMT、evalute IF_STMT.expr的节点,您可以运行该树,如果返回true,则计算IF_STMT.STMT,依此类推
然后,当您完成对语言的解析后,您可以“执行”字节码,当您点击if语句时,计算表达式,如果为true(不是true),则按照上面所述执行语句,然后当您点击打印指令时(如果表达式为false,则不会执行该指令),打印“hi”,你得到了你想要的结果(也就是说,没有任何东西被打印出来)
这正是你需要做的。在使用bison进行解析时,您无法(轻松)执行条件执行。如果您想使其仅适用于If,您可以制作一个堆栈,在EXP eval时,在堆栈上推送EXP的真值,在If块中,只需检查您是否可以执行函数调用、赋值等,在else上否定堆栈上的最后一个值,并在If缩减时,只需从堆栈中弹出值 例: 现在,您所要做的就是检查CanExec()是否影响操作
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); }
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)}