如何在野牛中解析if语句

时间:2010-01-10 14:35:55

标签: compiler-construction if-statement bison

我正在使用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。 我能做什么? (我是野牛和编译的新手,所以请随意纠正我的问题中的错误。)

2 个答案:

答案 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()

的所有副作用操作