如何实现if和else语句?在编写语言编译器时

时间:2014-03-31 19:12:44

标签: c# interpreter

我正在使用Joel Pobar编写的这个示例项目。我得到了这个:

http://msdn.microsoft.com/en-us/magazine/cc136756.aspx

好的,为了实现一个简单的打印命令,我需要:

首先在 Ast.cs

中声明该类
// print <expr>
public class Print : Stmt
{
    public Expr Expr;
}

其次,我将方法实施到 Parser.cs

 // <stmt> := print <expr> 

        // <expr> := <string>
        // | <int>
        // | <arith_expr>
        // | <ident>
        if (this.tokens[this.index].Equals("Printl"))
        {
            this.index++;
            Print print = new Print();
            print.Expr = this.ParseExpr();
            result = print;
        }

最后,我在 CodeGen.cs

中实施了一项检查
  else if (stmt is Print)
    {
        // the "print" statement is an alias for System.Console.WriteLine. 
        // it uses the string case
        this.GenExpr(((Print)stmt).Expr, typeof(string));
        this.il.Emit(Emit.OpCodes.Call, typeof(System.Console).GetMethod("WriteLine", new System.Type[] { typeof(string) }));
    }

现在,这允许我创建一个解释器,并在文件与语法匹配时编译它。此解释器支持变量,循环和基本打印文本和变量值。但是我对如何实现if和else语句感到有点困惑。

1 个答案:

答案 0 :(得分:1)

MSIL具有条件分支指令。您必须安排条件表达式的结果位于值堆栈之上,然后use a conditional branch跳转到else-stuff(跳过then-stuff)或不跳转。那些东西的结束将无条件地分支其他东西。

当然,您需要为else-stuff的开头和结尾定义和标记标签。以上链接涵盖了标签创建。

以下是the OpCodes class中的条件分支指令:

Beq Field
Beq_S Field
Bge Field
Bge_S Field
Bge_Un Field
Bge_Un_S Field
Bgt Field
Bgt_S Field
Bgt_Un Field
Bgt_Un_S Field
Ble Field
Ble_S Field
Ble_Un Field
Ble_Un_S Field
Blt Field
Blt_S Field
Blt_Un Field
Blt_Un_S Field
Bne_Un Field
Bne_Un_S Field 
Brfalse Field
Brfalse_S Field
Brtrue Field
Brtrue_S Field 
Switch Field

请注意,其中许多结合了条件分支的比较。例如,

  

如果 value1 小于或等于 value2 ,则ble指令将控制转移到指定的目标指令。效果与执行cgt指令(浮点数为cgt.un)后跟一个brfalse分支到特定目标指令相同。

The documentation for ILGenerator.DefineLabel()有一个完整的条件示例,实现:

IF A < 100 AND B < 100
    RETURN A + B
ELSE
    RETURN -1