迴圈具有類似的結構:條件判斷,迴圈體。
其基類如下所示:
public class Loop : ControlFlow { public Expression.ExpressionNode Condition; public virtual Block Body { get { return Children.Count > 0 ? Children.Last() as Block : null; } } public bool NeedBreak = false; public bool NeedContinue = false;
最簡單的迴圈莫過於while,或do..while。好了,已經將while迴圈都列舉了。先看while迴圈的運行代碼:
public override void Run(Context ctx) { Debug.WriteLine("Begin While."); base.Run(ctx); while (true) { if (Condition != null) { Expression.Operand.Value condVal = Condition.Evaluate(this).GetValue(this); Debug.WriteLine(string.Format("Condition: [{0}] = {1}", Condition.ToString(), condVal.ToString())); if (condVal.AsInt == 0) { break; } } Body.Run(this); if (NeedBreak) break; } // while Debug.WriteLine("End While."); }
do...while與while不同的部分在於,先運行迴圈體,再運行判斷:
public override void Run(Context ctx) { Debug.WriteLine("Begin Do...While."); base.Run(ctx); while(true) { Body.Run(this); if (NeedBreak) break; if (Condition != null) { Expression.Operand.Value val = Condition.Evaluate(this).GetValue(this); Debug.WriteLine(string.Format("Condition : {0} = {1}", Condition.ToString(), val.ToString())); if (val.AsInt == 0) { break; } } } // while Debug.WriteLine("End Do...While."); }
複雜一點的是for迴圈,比其它迴圈結構多出初始化部分和迭代部分:
public class ForLoop : Loop { public Context Initializer { get { return Children.Count > 0 ? Children.First() : null; } } public Expression.ExpressionNode Iterator;
由於初始化部分可以定義迴圈變數,形如:for(int i = 0; ....)。所以,還需要重載以下兩個方法:
public override bool HasDefined(string str) { if (FindByName(str) == null) return base.HasDefined(str); else return true; } public override Context FindByName(string str) { Context res = null; if (Initializer != null) { Initializer.Parent = null; res = Initializer.FindByName(str); Initializer.Parent = this; } if (res == null) return this.Parent.FindByName(str); else return res; }
然後就可以確定for迴圈的運行代碼:
public override void Run(Context ctx) { Debug.WriteLine("Begin For."); if (Initializer != null) Initializer.Run(this); base.Run(ctx); while (true) { if (Condition != null) { Expression.Operand.Value val = Condition.Evaluate(this).GetValue(this); Debug.WriteLine(string.Format("Condition: [{0}] = {1}", Condition.ToString(), val.ToString())); if (val.AsInt == 0) { break; } } Body.Run(this); if (NeedBreak) break; if (Iterator != null) Iterator.Evaluate(this); } // while if (Initializer != null) { Initializer.FreeLocalVariables(); } Debug.WriteLine("End For."); }