Compiler construction 如何解析bison中的if语句

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和编译,所以请随意更正我问

我正在使用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)}