0

我正在使用野牛为一种简单的语言构建编译器。这是语法的一部分:

stmt: IF '(' exp ')' stmt{
        if(exp) $$=$5;
      }
      |PRINT ';' {
        cout<<"hi";
       }
;

exp: true|false
;

我在解析这个 if 语句时遇到了一个问题:假设我有这个代码:

if(false) print;

无论如何都会打印“hi”,因为 stmt->PRINT 在 stmt-> IF (exp) stmt 之前被解析。我能做些什么?(我是野牛和编译的新手,所以请随时纠正我的问题中的错误)。

4

2 回答 2

1

这很自然。您正在解析 print 语句,因此“cout”被执行。您要做的是创建某种字节码,在其中存储打印指令。然后可以将此打印指令与 if 表达式组合以形成 if 语句指令。

在我的脑海中,我不记得 Bison 中的确切语句(您需要查看文档),但您通常希望为您的值堆栈定义一个类型,通常是结构的联合,例如this(不过,它有一个 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 的节点,评估 if_stmt.expr,如果它返回 true,则评估 if_stmt.stmt,等等。

然后,当您完成语言解析后,您可以“执行”您的字节码,当您点击 if 语句时,评估表达式,如果为真(不是),执行上述语句,然后当你点击一个打印指令(你不会因为表达式是假的),你打印你的'hi',你就会得到你正在寻找的结果(也就是说,什么都没有打印出来)。

这就是你需要做的事情。在使用野牛解析时,您不能(轻松地)进行条件执行。

于 2010-01-10T14:53:35.750 回答
0

如果你想让它只为 if 工作,你可以创建一个堆栈,在 EXP eval 处,将 EXP 的真值压入堆栈,在 IF 块中只需检查你是否可以执行函数调用,分配等,否则最后否定堆栈上的值和 IF 减少时,只需从堆栈中弹出值。

前任:

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

于 2013-12-04T18:00:13.710 回答