public void Analyze(CSharpSwitchCase @case) { Debug.Assert(_info.HasGotoDefault == false); Debug.Assert(_info.GotoCases == null); foreach (var stmt in @case.Statements) { Visit(stmt); } if (_info.GotoCases == null) { _info.GotoCases = (s_empty ??= new HashSet <object>()); } SwitchCaseInfos.Add(@case, _info); _info = default; }
public void Analyze(CSharpSwitchCase @case) { Debug.Assert(_info.HasGotoDefault == false); Debug.Assert(_info.GotoCases == null); foreach (var stmt in @case.Statements) { Visit(stmt); } if (_info.GotoCases == null) { _info.GotoCases = (s_empty ?? (s_empty = new HashSet<object>())); } SwitchCaseInfos.Add(@case, _info); _info = default(SwitchCaseInfo); }
public void read(Reader reader) { foreach (ScriptSub sub in subs) { sub.scriptCode.Clear(); sub.blankLines.Clear(); sub.labels.Clear(); sub.jumpTable.Clear(); bool finishedScriptCode = false; int scriptCodeLength = reader.ReadByte() << 8; scriptCodeLength |= reader.ReadByte(); sub.scriptCode.Clear(); while (!finishedScriptCode) { byte scriptOpcode = reader.ReadByte(); if (scriptOpcode == 0xFF) { scriptOpcode = reader.ReadByte(); if (scriptOpcode == 0xFF) { scriptOpcode = reader.ReadByte(); if (scriptOpcode == 0xFF) { scriptOpcode = reader.ReadByte(); if (scriptOpcode == 0xFF) { finishedScriptCode = true; } } } } if (!finishedScriptCode) { OpcodeInfo opInfo = new OpcodeInfo(); opInfo.opcode = scriptOpcode; uint paramCount = (uint)opcodeList[scriptOpcode].paramCount; opInfo.parameters.Clear(); for (int p = 0; p < paramCount; p++) { ParamInfo param = new ParamInfo(); int paramType = reader.ReadByte(); // if 0 then int constant, else variable if (paramType != 0) { param.isVariable = true; param.value = reader.ReadByte(); int arrayIndex = reader.ReadByte(); if (arrayIndex > 0x80) { arrayIndex = 0x80 - arrayIndex; } param.arrayIndex = (sbyte)arrayIndex; } else { param.isVariable = false; param.arrayIndex = -1; int byte1 = reader.ReadByte(); int constVal = 0; if (byte1 < 0x80) // unsigned uint16 { constVal = byte1 << 8; constVal |= reader.ReadByte(); } else // signed uint16 { constVal = (byte1 - 0x80) << 8; constVal |= reader.ReadByte(); constVal = -constVal; } param.value = constVal; } opInfo.parameters.Add(param); } sub.scriptCode.Add(opInfo); } } int blankLineUnused = reader.ReadByte(); int blankLineCount = reader.ReadByte(); for (int u = 0; u < blankLineCount; u++) { int blankLineID = reader.ReadByte() << 8; blankLineID |= reader.ReadByte(); sub.blankLines.Add(blankLineID); } int labelUnused = reader.ReadByte(); int labelCount = reader.ReadByte(); for (int l = 0; l < labelCount; l++) { LabelInfo label = new LabelInfo(); label.scriptCodePos = reader.ReadByte() << 8; label.scriptCodePos |= reader.ReadByte(); label.id = reader.ReadByte() << 8; label.id |= reader.ReadByte(); label.lineID = reader.ReadByte() << 8; label.lineID |= reader.ReadByte(); sub.labels.Add(label); } int jumpTableUnused = reader.ReadByte(); int jumpTableCount = reader.ReadByte(); for (int s = 0; s < jumpTableCount; ++s) { SwitchInfo info = new SwitchInfo(); info.scriptCodePos = reader.ReadByte() << 8; info.scriptCodePos |= reader.ReadByte(); int caseCount = reader.ReadByte() << 8; caseCount |= reader.ReadByte(); info.defaultScriptCodePos = reader.ReadByte() << 8; info.defaultScriptCodePos |= reader.ReadByte(); info.defaultCaseLineID = reader.ReadByte() << 8; info.defaultCaseLineID |= reader.ReadByte(); info.endScriptCodePos = reader.ReadByte() << 8; info.endScriptCodePos |= reader.ReadByte(); // if (info.defaultScriptCodePos == 0) // info.defaultScriptCodePos = info.endScriptCodePos; int lowestCase = 0x8000; int highestCase = 0; info.cases.Clear(); for (int c = 0; c < caseCount; c++) { SwitchCaseInfo caseInfo = new SwitchCaseInfo(); caseInfo.scriptCodePos = reader.ReadByte() << 8; caseInfo.scriptCodePos |= reader.ReadByte(); caseInfo.caseNum = reader.ReadByte() << 8; caseInfo.caseNum |= reader.ReadByte(); if (caseInfo.caseNum < lowestCase) { lowestCase = caseInfo.caseNum; } if (caseInfo.caseNum > highestCase) { highestCase = caseInfo.caseNum; } caseInfo.lineID = reader.ReadByte() << 8; caseInfo.lineID |= reader.ReadByte(); info.cases.Add(caseInfo); } info.lowestCase = lowestCase; info.highestCase = highestCase; // Take any duds and make em default cases // for (int m = lowestCase; m <= highestCase; ++m) // { // int jump = sub.scriptCode[caseTablePos + m]; // if (jump == 0) // sub.scriptCode[caseTablePos + m] = sub.jumpTable[startSwitchTablePos + 2]; // } // wow this is weird // it manually goes and sets up the offsets instead of doing it at compile-time like later RSDK versions int pos = 0; foreach (OpcodeInfo opcodeInfo in sub.scriptCode) { if (pos == info.scriptCodePos) { opcodeInfo.parameters[1].value = pos; break; } pos += opcodeInfo.size; } sub.jumpTable.Add(info); } } reader.Close(); }
static void HandleStatement(Mizu.Parser.ParseNode stmt, ILGenerator ILgen, ref List<LocalBuilderEx> locals, out bool err) { switch (stmt.Token.Type) { case Parser.TokenType.VarStatement: { #region VAR int i = 0; while (i != stmt.Nodes.Count - 1) { var token = stmt.Nodes[i]; if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } if (token.Token.Type == TokenType.IDENTIFIER) //If its a var declaration. { if (locals.Find(it => it.Name == token.Token.Text) == null) { var set = stmt.Nodes[i + 1]; if (set.Token.Type == TokenType.SET) { i += 1; var next = stmt.Nodes[i + 1]; if (next.Token.Type == TokenType.NUMBER) //Integers { //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_I4, int.Parse(next.Token.Text)); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. local.Name = token.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.FLOAT) { //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_R4, float.Parse(next.Token.Text)); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. local.Name = token.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.UPPER) { //A variable that reads from stdin (Console.ReadLne) //Declares a variable and leaves a reference to it. LocalBuilderEx local = new LocalBuilderEx(); local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); local.Name = token.Token.Text; local.Type = LocalType.Var; if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. try { //If theres a WAVEY symbol, print the variable name. var wavey = stmt.Nodes[i + 2]; ILgen.Emit(OpCodes.Ldstr, local.Name + " = "); ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("Write", new Type[] { typeof(string) })); i += 1; } catch (Exception) { } ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); //Sets the number from STDIN. ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer. ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. locals.Add(local); //Remembers the variable. i += 1; } else if (next.Token.Type == TokenType.COMMA) { //An array. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Static arrays are not supported at this time. Line: {0}, Col: {1}", info.Line, info.Col); err = true; return; } else { #region Iterating Variable //Its a range var lowNum = stmt.Nodes[i + 2]; //Name is mis-informing. This is really the first number. var highNum = stmt.Nodes[i + 5]; //Same ^^, this is the second number. LocalBuilderEx local = new LocalBuilderEx(); local.LoopHigh = int.Parse(highNum.Token.Text); local.LoopLow = int.Parse(lowNum.Token.Text); local.Name = token.Token.Text; local.Type = LocalType.LoopVar; local.VariableType = typeof(int); var looplab = ILgen.DefineLabel(); ILgen.BeginScope(); local.Base = ILgen.DeclareLocal(local.VariableType); local.LoopLabel = looplab; if (IsDebug) local.Base.SetLocalSymInfo(token.Token.Text); //Set variable name for debug info. ILgen.Emit(OpCodes.Ldc_I4, local.LoopLow); //Sets the number ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. ILgen.MarkLabel(looplab); //this is where the IL will execute. local.LoopAction = () => { //Updates the iterator by 1 ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Ldc_I4_1); if (local.LoopLow < local.LoopHigh) { ILgen.Emit(OpCodes.Add); //Loop up local.LoopDirection = LoopDirectionEnum.Up; } else if (local.LoopLow > local.LoopHigh) { ILgen.Emit(OpCodes.Sub); //Loop down. local.LoopDirection = LoopDirectionEnum.Down; } else { dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Variable '{0}' should be set as {1}. In this case, looping is not allowed. Line: {2}, Col: {3}", local.Name, local.LoopLow.ToString(), info.Line, info.Col); return true; //Abort because of error. } ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); ILgen.EndScope(); return false; }; locals.Add(local); //Remembers the variable. i += 6; #endregion } } } else { //Report an error and stop compile process. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' already exist! Line: {1}, Col: {2}", token.Token.Text, info.Line, info.Col); return; } } } break; #endregion } case TokenType.PrintStatement: { #region Printing if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, stmt.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, stmt.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } ///Generates output by making a print statement. var period = stmt.Nodes[0]; var outpt = stmt.Nodes[1]; switch (outpt.Token.Type) { case TokenType.IDENTIFIER: { //Prints a variable. LocalBuilderEx local = locals.Find(it => it.Name == outpt.Token.Text); if (local == null) { dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", outpt.Token.Text, info.Line, info.Col); return; } ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { local.VariableType })); //Converts the integer to a string. ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.FLOAT: case TokenType.NUMBER: { //Prints a integer or float (decimal) number. if (outpt.Token.Type == TokenType.NUMBER) //if its a integer { ILgen.Emit(OpCodes.Ldc_I4, int.Parse(outpt.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); //Converts the integer to a string. } else { //Otherwise, its a float (decimal). ILgen.Emit(OpCodes.Ldc_R4, float.Parse(outpt.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(float) })); //Converts the integer to a string. } ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.STRING: { //Prints just a plain string. See the next case for a format string. string formt = outpt.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes. ILgen.Emit(OpCodes.Ldstr, formt); //Loads the string onto the stack ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } case TokenType.SIN: { //Prints a format string ParseNode formtnd = stmt.Nodes[2]; string formt = formtnd.Token.Text.Substring(1); formt = formt.Remove(formt.Length - 1); //Removes surrounding quotes. ILgen.Emit(OpCodes.Ldstr, formt); //Loads the format string. int arrymax = (stmt.Nodes.Count / 2 - 1); ILgen.Emit(OpCodes.Ldc_I4, arrymax); ILgen.Emit(OpCodes.Newarr, typeof(string)); int arry_i = 0; for (int i = 3; i < stmt.Nodes.Count; i++) { if (stmt.Nodes[i].Token.Type == TokenType.WHITESPACE) { if (stmt.Nodes.Count - 1 == i) break; continue; } else if (stmt.Nodes[i].Token.Type == TokenType.PERIOD) { break; } else { ParseNode nd = stmt.Nodes[i]; ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); switch (nd.Token.Type) { case TokenType.IDENTIFIER: { LocalBuilderEx local = locals.Find(it => it.Name == nd.Token.Text); if (local == null) { err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist!", nd.Token.Text); return; } ILgen.Emit(OpCodes.Ldloc, local.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); break; } case TokenType.NUMBER: { ILgen.Emit(OpCodes.Ldc_I4, int.Parse(nd.Token.Text)); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); break; } } ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; } } ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Format", new Type[] { typeof(string), typeof(string[]) })); ILgen.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //Prints the newly formed string. break; } } break; #endregion } case TokenType.EvalStatement: { #region EvalStatement var identifier = stmt.Nodes[1]; var expr = stmt.Nodes[3]; LocalBuilderEx local = new LocalBuilderEx(); //Check if a variable of the same name exist. LocalBuilderEx lct = locals.Find(it => it.Name == identifier.Token.Text); if (lct != null) { //Variable exist, stop compiling. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: {0} variable already exist! Line: {1}, Col: {2}", identifier.Token.Text, info.Line, info.Col); if (lct.Type == LocalType.LoopVar) Console.Error.WriteLine("- Error: Iterating variables are readonly!"); err = true; return; } if (!NoEval) { #region Eval using Mizu.Lib.Evaluator local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number var exprstr = ""; bool localsadded = false; List<LocalBuilder> tmplocals = new List<LocalBuilder>(); foreach (LocalBuilderEx lc in locals) { ILgen.Emit(OpCodes.Ldstr, "var " + lc.Name + "={0}"); ILgen.Emit(OpCodes.Ldloc, (LocalBuilder)lc.Base); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToString", new Type[] { typeof(int) })); ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Format", new Type[] { typeof(string), typeof(string) })); LocalBuilder lb = ILgen.DeclareLocal(typeof(string)); ILgen.Emit(OpCodes.Stloc, lb); tmplocals.Add(lb); localsadded = true; } //Creates an array to store all of the variables for the String.Concat call. int arrymax = (tmplocals.Count * 2) + 1; ILgen.Emit(OpCodes.Ldc_I4, arrymax); ILgen.Emit(OpCodes.Newarr, typeof(string)); int arry_i = 0; if (localsadded) { foreach (LocalBuilder tmploc in tmplocals) { ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); ILgen.Emit(OpCodes.Ldloc, tmploc); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); ILgen.Emit(OpCodes.Ldstr, ";"); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; } } ILgen.Emit(OpCodes.Dup); ILgen.Emit(OpCodes.Ldc_I4, arry_i); exprstr += GenerateExprStr(expr); ILgen.Emit(OpCodes.Ldstr, exprstr); ILgen.Emit(OpCodes.Stelem_Ref); arry_i += 1; ILgen.Emit(OpCodes.Call, typeof(System.String).GetMethod("Concat", new Type[] { typeof(string[]) })); ILgen.Emit(OpCodes.Call, typeof(Mizu.Lib.Evaluator.Evaluator).GetMethod("Eval")); ILgen.Emit(OpCodes.Call, typeof(Convert).GetMethod("ToInt32", new Type[] { typeof(string) })); //Parses it into an integer. ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. #endregion } else { if (ExprStrHasVar(expr)) { HandleMathExpr(ILgen, locals, expr); local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number; } else { //Optimize. If the equation is constant, might as well calculate the result and place it in the code. var res = Mizu.Lib.Evaluator.Evaluator.Eval(GenerateExprStr(expr)); if (res.Contains(".")) { local.VariableType = typeof(float); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number ILgen.Emit(OpCodes.Ldc_R4, float.Parse(res)); } else { local.VariableType = typeof(int); local.Base = ILgen.DeclareLocal(local.VariableType); //Sets the number ILgen.Emit(OpCodes.Ldc_I4, int.Parse(res)); } } ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); //Assigns the number to the variable. } if (IsDebug) local.Base.SetLocalSymInfo(identifier.Token.Text); local.Name = identifier.Token.Text; local.Type = LocalType.Var; locals.Add(local); //Remembers the variable. break; #endregion } case TokenType.MathCMDStatement: { #region MathCommandStatement var cmd = stmt.Nodes[0]; var input = stmt.Nodes[2]; var local = locals.Find(it => it.Name == input.Token.Text); if (local != null) { if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, cmd.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, cmd.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } switch (cmd.Token.Type) { case TokenType.SQRT: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sqrt")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.SIN: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Sin")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.ABS: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Abs", new Type[] { typeof(int) })); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.TAN: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Tan")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } case TokenType.COS: { ILgen.Emit(OpCodes.Ldloca, local.Base); ILgen.Emit(OpCodes.Call, typeof(Math).GetMethod("Cos")); ILgen.Emit(OpCodes.Stloc, (LocalBuilder)local.Base); break; } } } else { //Report an error and stop compile process. dynamic info = GetLineAndCol(code, stmt.Token.StartPos); err = true; Console.Error.WriteLine("Error: '{0}' doesn't exist! Line: {1}, Col: {2}", input.Token.Text, info.Line, info.Col); return; } break; #endregion } case TokenType.BlockedStatement: { //Due to parser limitations, I have to handle this token in order for both the if blocks and the switch blocks to begin with [. HandleStatement(stmt.Nodes[1], ILgen, ref locals, out err); break; } case TokenType.IfStatement: //If block { #region If Statement bool hasElse = false; var left = stmt.Nodes[0]; var com = stmt.Nodes[1]; var right = stmt.Nodes[2]; if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, left.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, right.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } var bodies = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.Statements); hasElse = bodies.Count == 2; //Load the 'left' hand type onto the stack. HandleDataToken(ILgen, locals, left, out err); //Load the 'right' hand type to the stack. HandleDataToken(ILgen, locals, right, out err); //Load the 'comparison' function onto the stack. HandleDataToken(ILgen, locals, com, out err); Label endofifblock = ILgen.DefineLabel(); Label ifbodyloc = ILgen.DefineLabel(); Label elsebodyloc = ILgen.DefineLabel(); if (!hasElse) { //No else block. ILgen.Emit(OpCodes.Brfalse, endofifblock); } else { //Has an else block. //ILgen.Emit(OpCodes.Brtrue, ifbodyloc); //ILgen.Emit(OpCodes.Brtrue, ifbodyloc); ILgen.Emit(OpCodes.Brfalse, elsebodyloc); //ILgen.Emit(OpCodes.Br, ifbodyloc); } // Handle the first body of an if statement. ILgen.MarkLabel(ifbodyloc); ILgen.BeginScope(); var ifbody = bodies[0]; List<LocalBuilderEx> ifbody_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => ifbody_locals.Add(it)); foreach (ParseNode pn in ifbody.Nodes) { bool iferr = false; HandleStatement(pn.Nodes[0], ILgen, ref ifbody_locals, out iferr); if (iferr) { err = true; return; } } ILgen.Emit(OpCodes.Br, endofifblock); ILgen.EndScope(); //Handle the else bit (if any) if (hasElse) { ILgen.MarkLabel(elsebodyloc); ILgen.BeginScope(); var elsebody = bodies[1]; List<LocalBuilderEx> elsebody_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => elsebody_locals.Add(it)); foreach (ParseNode pn in elsebody.Nodes) { bool elerr = false; HandleStatement(pn.Nodes[0], ILgen, ref elsebody_locals, out elerr); if (elerr) { err = true; return; } } ILgen.Emit(OpCodes.Br, endofifblock); ILgen.EndScope(); } ILgen.MarkLabel(endofifblock); break; #endregion } case TokenType.SwitchStatement: //Switch block { #region Switch Statement Label endofswitch = ILgen.DefineLabel(); SwitchCaseInfo defaultcase = new SwitchCaseInfo() { Label = ILgen.DefineLabel() }; List<SwitchCaseInfo> caselist = new List<SwitchCaseInfo>(); bool hasDefault = false; var ident = stmt.Nodes[1]; var compar = new Comparison<ParseNode>((node1, node2) => { try { if (node1 == node2) { return 0; } else if (node1.Nodes[0].Token.Type == TokenType.NUMBER) { return -1; } else { return 1; } } catch (Exception) { return 0; } }); var cases = stmt.Nodes.FindAll(it => it.Token.Type == TokenType.SwitchCaseStatement); cases.Sort(compar); var addedcases = new List<int>(); if (IsDebug) { int sline = 0, scol = 0; FindLineAndCol(code, ident.Token.StartPos, ref sline, ref scol); int eline = 0, ecol = 0; FindLineAndCol(code, ident.Token.EndPos, ref eline, ref ecol); ILgen.MarkSequencePoint(doc, sline, scol, eline, ecol); } foreach (ParseNode casen in cases) { SwitchCaseInfo caseinfo = new SwitchCaseInfo(); var casename = casen.Nodes[0]; if (casename.Token.Text == "*") { defaultcase.Node = casen; defaultcase.CaseName = casename; defaultcase.CaseType = SwitchCase_TypeEnum.Default; if (hasDefault == true) { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block already has a default case. Line: {0}, Col: {1}", info.Line, info.Col); return; } hasDefault = true; } else { caseinfo.Number = int.Parse(casen.Nodes[0].Token.Text); caseinfo.CaseType = SwitchCase_TypeEnum.Number; caseinfo.CaseName = casename; caseinfo.Node = casen; caseinfo.Label = ILgen.DefineLabel(); if (addedcases.Contains(caseinfo.Number)) { err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block already has a case for '{0}'. Line: {1}, Col: {2}",caseinfo.Number, info.Line, info.Col); return; } addedcases.Add(caseinfo.Number); caselist.Add(caseinfo); } } foreach (SwitchCaseInfo cse in caselist) { //Build the instruction table. if (cse.CaseType == SwitchCase_TypeEnum.Number) { HandleDataToken(ILgen, locals, ident, out err); //Load identifier. HandleDataToken(ILgen, locals, cse.CaseName, out err); //Loads the number. ILgen.Emit(OpCodes.Ceq); ILgen.Emit(OpCodes.Brtrue, cse.Label); } else { ILgen.Emit(OpCodes.Br, defaultcase.Label); } } if (hasDefault == false) { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Switch block doesn't have a default case. Line: {0}, Col: {1}", info.Line, info.Col); return; } ///Handle default case var dcase = defaultcase.Node; ILgen.BeginScope(); List<LocalBuilderEx> d_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => d_locals.Add(it)); var dstmts = dcase.Nodes.Find(it => it.Token.Type == TokenType.Statements); ILgen.MarkLabel(defaultcase.Label); foreach (ParseNode pn in dstmts.Nodes) { HandleStatement(pn.Nodes[0], ILgen, ref d_locals, out err); } ILgen.EndScope(); ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method. //// foreach (SwitchCaseInfo inner in caselist) { ILgen.BeginScope(); List<LocalBuilderEx> tmp_locals = new List<LocalBuilderEx>(); locals.ForEach((it) => tmp_locals.Add(it)); var stmts = inner.Node.Nodes.Find(it => it.Token.Type == TokenType.Statements); ILgen.MarkLabel(inner.Label); bool ierr = false; foreach (ParseNode pn in stmts.Nodes) { HandleStatement(pn.Nodes[0], ILgen, ref tmp_locals, out ierr); } if (ierr) { err = true; return; } ILgen.EndScope(); ILgen.Emit(OpCodes.Br, endofswitch); //Jumps out of switvch at the end of the method. } ILgen.MarkLabel(endofswitch); break; #endregion } default: { //Report an error and stop compile process. err = true; dynamic info = GetLineAndCol(code, stmt.Token.StartPos); Console.Error.WriteLine("Error: Unsupported statement: {0}. Line: {1}, Col: {2}", stmt.Text, info.Line, info.Col); return; } } err = false; }