我正在使用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语句感到有点困惑。
答案 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