private void AddLoopDec(IlProcessor il) { var p = functionPoints.Peek(); p.LoopDecs.Push(new LoopDec { ContinueLabel = il.DefineLabel(), BreakLabel = il.DefineLabel() }); }
private void GenerateExpression(IlProcessor il, ref Instruction start, ref Instruction current, ParseTreeNode node) { string name; LocalBuilder pn; var prev = start; switch (node.Term.Name) { case "ConstExpr": GenerateConst(il, start, ref current, node.ChildNodes[0]); break; case "BinExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); // left GenerateExpression(il, ref start, ref current, node.ChildNodes[2]); // right var keySymbol = node.ChildNodes[1].Token.ValueString; switch (keySymbol) { case "+": il.Add(ref current, Instruction.Create(OpCodes.Call, value_add)); break; case "-": il.Add(ref current, Instruction.Create(OpCodes.Call, value_sub)); break; case "<": il.Add(ref current, Instruction.Create(OpCodes.Call, value_lt)); break; case ">": il.Add(ref current, Instruction.Create(OpCodes.Call, value_gt)); break; case "==": il.Add(ref current, Instruction.Create(OpCodes.Call, value_eq)); break; case "!=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_neq)); break; case "*": il.Add(ref current, Instruction.Create(OpCodes.Call, value_mul)); break; case "/": il.Add(ref current, Instruction.Create(OpCodes.Call, value_div)); break; case "<=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_lte)); break; case ">=": il.Add(ref current, Instruction.Create(OpCodes.Call, value_gte)); break; default: throw new InvalidOperationException("Unknown bin expression key symbol " + keySymbol); } break; case "TerExpr": // a < b ? c : d Label trueLabel = il.DefineLabel(), endLabel = il.DefineLabel(); GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); // a < b il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, trueLabel)); GenerateExpression(il, ref start, ref current, node.ChildNodes[3]); // d il.Add(ref current, Instruction.Create(OpCodes.Br, endLabel)); il.Add(ref current, Instruction.Create(Specials.Label, trueLabel)); GenerateExpression(il, ref start, ref current, node.ChildNodes[2]); // c il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "FunctionCallExpr": pn = GetSVar(arguments); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, arguments_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); foreach (var arg in node.ChildNodes[1].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); if (arg.ChildNodes.Count == 1) { il.Add(ref prev, Instruction.Create(OpCodes.Ldnull)); } else { il.Add(ref prev, Instruction.Create(OpCodes.Ldstr, arg.ChildNodes[0].Token.ValueString)); } GenerateExpression(il, ref start, ref prev, arg.ChildNodes[arg.ChildNodes.Count - 1]); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, arguments_add)); } start = prev; GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, execute)); break; case "AssignExpr": switch (node.ChildNodes[0].Term.Name) { case "identifier": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_get)); il.Add(ref current, Instruction.Create(OpCodes.Dup)); il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn)); // Increment/decrement and restore if (node.ChildNodes[1].Token.ValueString == "++") { il.Add(ref current, Instruction.Create(OpCodes.Call, value_incr)); } else if (node.ChildNodes[1].Token.ValueString == "--") { il.Add(ref current, Instruction.Create(OpCodes.Call, value_decr)); } else { throw new InvalidOperationException("??"); } il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn2)); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn2)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } break; case "MemberExpr": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[0].ChildNodes[2].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, set_prop)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); } break; case "ArrOpExpr": pn = GetSVar(value); if (node.ChildNodes.Count == 3) // a = b / a += b etc. { GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); il.Add(ref start, Instruction.Create(OpCodes.Stloc, pn)); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[0]); GenerateExpression(il, ref start, ref current, node.ChildNodes[0].ChildNodes[1]); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, value_lookup_set)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); } else { var pn2 = GetSVar(value); GenerateExpression(il, ref start, ref start, node.ChildNodes[2]); } break; default: throw new InvalidOperationException("Invalid QualifiedName term " + node.ChildNodes[0].Term.Name); } break; case "identifier": name = node.Token.ValueString; il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_get)); break; case "FuncDefExpr": if (node.ChildNodes[1] != null && node.ChildNodes[1].Token != null && node.ChildNodes[1].Token.Text == "=>") { name = "anonymous"; var mName = MakeFunctionName(name); IEnumerable <ParseTreeNode> bodyNodes; ParseTreeNodeList parameters; if (node.ChildNodes[2].Term.Name == "Block") { bodyNodes = node.ChildNodes[2].ChildNodes[0].ChildNodes; } else if (node.ChildNodes[2].Term.Name.Contains("Stmt")) { bodyNodes = new ParseTreeNode[] { node.ChildNodes[2] }; } else { var flowCtrlStmtNode = new ParseTreeNode(grammar.FlowControlStmt, new SourceSpan()); flowCtrlStmtNode.ChildNodes.Add(new ParseTreeNode(new Token(grammar.@return, new SourceLocation(), "return", "return"))); flowCtrlStmtNode.ChildNodes.Add(node.ChildNodes[2]); bodyNodes = new ParseTreeNode[] { flowCtrlStmtNode }; } if (node.ChildNodes[0].Term.Name == "identifier") { parameters = new ParseTreeNodeList(); var param = new ParseTreeNode(grammar.Parameter, node.ChildNodes[0].Span); param.ChildNodes.Add(node.ChildNodes[0]); parameters.Add(param); } else { parameters = node.ChildNodes[0].ChildNodes; } GenerateFunction(il, ref start, ref current, name, mName, parameters, bodyNodes); } else { if (node.ChildNodes[1].ChildNodes.Count == 1) { name = node.ChildNodes[1].ChildNodes[0].Token.ValueString; } else { name = "anonymous"; } var mName = MakeFunctionName(name); GenerateFunction(il, ref start, ref current, name, mName, node.ChildNodes[2].ChildNodes, node.ChildNodes[3].ChildNodes[0].ChildNodes); } break; case "MemberExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, node.ChildNodes[2].Token.ValueString)); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, get_prop)); break; case "ObjLitExpr": pn = GetSVar(map); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, map_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); if (node.ChildNodes.Count > 0) { foreach (var prop in node.ChildNodes[0].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); il.Add(ref prev, Instruction.Create(OpCodes.Ldstr, prop.ChildNodes[0].Token.ValueString)); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, string_ctor)); GenerateExpression(il, ref start, ref prev, prop.ChildNodes[1]); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, map_add)); } } il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); start = prev; break; case "ArrLitExpr": pn = GetSVar(array); il.Add(ref prev, Instruction.Create(OpCodes.Newobj, array_ctor)); il.Add(ref prev, Instruction.Create(OpCodes.Stloc, pn)); if (node.ChildNodes.Count > 0) { foreach (var elm in node.ChildNodes[0].ChildNodes) { il.Add(ref prev, Instruction.Create(OpCodes.Ldloc, pn)); GenerateExpression(il, ref start, ref prev, elm); il.Add(ref prev, Instruction.Create(OpCodes.Callvirt, array_add)); } } il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); start = prev; break; case "ArrOpExpr": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); GenerateExpression(il, ref start, ref current, node.ChildNodes[1]); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, value_lookup_get)); break; default: throw new InvalidOperationException("Term " + node.Term.Name + " is not a valid expression term"); } }
private Label CreateStatementLabel(IlProcessor il) { return(functionPoints.Peek().EndOfStatementLabel = il.DefineLabel()); }
private void GenerateStatement(IlProcessor il, ref Instruction current, ParseTreeNode node) { var label = CreateStatementLabel(il); var start = current; LocalBuilder pn = null, pn2 = null; il.Add(ref current, Instruction.Create(OpCodes.Nop)); switch (node.Term.Name) { case "VarStmt": GenerateDeclaration(il, ref start, ref current, node); break; case "FuncDefStmt": var name = node.ChildNodes[1].Token.ValueString; var mName = MakeFunctionName(name); il.Add(ref current, Instruction.Create(OpCodes.Ldarg_0)); il.Add(ref current, Instruction.Create(OpCodes.Ldstr, name)); GenerateFunction(il, ref start, ref current, name, mName, node.ChildNodes[2].ChildNodes, node.ChildNodes[3].ChildNodes[0].ChildNodes); il.Add(ref current, Instruction.Create(OpCodes.Callvirt, function_local_dec)); break; case "FlowControlStmt": var keyword = node.ChildNodes[0].Token.ValueString; switch (keyword) { case "return": if (node.ChildNodes.Count > 1) { GenerateExpression(il, ref start, ref current, node.ChildNodes[1]); } else { il.Add(ref current, Instruction.Create(OpCodes.Call, undefined)); } il.Add(ref current, Instruction.Create(OpCodes.Ret)); break; case "continue": il.Add(ref current, Instruction.Create(OpCodes.Br, GetLoopDec().ContinueLabel)); break; case "break": il.Add(ref current, Instruction.Create(OpCodes.Br, GetLoopDec().BreakLabel)); break; default: throw new InvalidOperationException("Unknown flow control keyword " + keyword); } break; case "ExprStmt": GenerateExpression(il, ref start, ref current, node.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Pop)); break; case "IfElseStmt": pn = GetSVar(sys_bool); var endLabel = il.DefineLabel(); GenerateExpression(il, ref start, ref current, node.ChildNodes[1].ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_0)); il.Add(ref current, Instruction.Create(OpCodes.Ceq)); il.Add(ref current, Instruction.Create(OpCodes.Stloc, pn)); il.Add(ref current, Instruction.Create(OpCodes.Ldloc, pn)); if (node.ChildNodes.Count == 5) { var elseLabel = il.DefineLabel(); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, elseLabel)); GenerateStatement(il, ref current, node.ChildNodes[2]); il.Add(ref current, Instruction.Create(OpCodes.Br, endLabel)); il.Add(ref current, Instruction.Create(Specials.Label, elseLabel)); GenerateStatement(il, ref current, node.ChildNodes[4]); } else { il.Add(ref current, Instruction.Create(OpCodes.Brtrue, endLabel)); GenerateStatement(il, ref current, node.ChildNodes[2]); } il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "ForStmt": AddLoopDec(il); // Push new scope pn = GetVar(scope); il.Add(ref start, Instruction.Create(Specials.BeginTotemScope, pn)); // Initializer il.Add(ref current, Instruction.Create(OpCodes.Nop)); var initializer = node.ChildNodes[1]; if (initializer.ChildNodes.Count != 0) { initializer = initializer.ChildNodes[0]; if (initializer.ChildNodes.Count == 1) { GenerateExpression(il, ref start, ref current, initializer.ChildNodes[0]); il.Add(ref current, Instruction.Create(OpCodes.Pop)); } else { foreach (var dec in initializer.ChildNodes[1].ChildNodes) { GenerateDeclaration(il, ref start, ref current, dec); } } } var conditionLabel = il.DefineLabel(); var bodyLabel = il.DefineLabel(); endLabel = il.DefineLabel(); il.Add(ref current, Instruction.Create(OpCodes.Br, conditionLabel)); // Body il.Add(ref current, Instruction.Create(Specials.Label, bodyLabel)); GenerateStatement(il, ref current, node.ChildNodes[4]); il.Add(ref current, Instruction.Create(OpCodes.Nop)); // Increment Instruction incr = il.Add(ref current, Instruction.Create(Specials.Label, GetLoopDec().ContinueLabel)); var increment = node.ChildNodes[3]; if (increment.ChildNodes.Count != 0) { GenerateExpression(il, ref start, ref current, increment.ChildNodes[0]); } // Condition il.Add(ref current, Instruction.Create(Specials.Label, conditionLabel)); var condition = node.ChildNodes[2]; if (condition.ChildNodes.Count == 0) { il.Add(ref current, Instruction.Create(OpCodes.Ldc_I4_1)); il.Add(ref current, Instruction.Create(OpCodes.Call, bool_ctor)); // Create TotemBool true } else { GenerateExpression(il, ref start, ref current, condition.ChildNodes[0]); } il.Add(ref current, Instruction.Create(OpCodes.Call, value_istrue)); il.Add(ref current, Instruction.Create(OpCodes.Brtrue, bodyLabel)); il.Add(ref current, Instruction.Create(Specials.Label, GetLoopDec().BreakLabel)); il.Add(ref current, Instruction.Create(OpCodes.Leave, endLabel)); pn2 = GetSVar(Load(typeof(bool))); // Pop scope il.Add(ref current, Instruction.Create(Specials.EndTotemScope, pn)); RemLoopDec(); RelVar(pn); il.Add(ref current, Instruction.Create(Specials.Label, endLabel)); break; case "Block": foreach (var stmt in node.ChildNodes[0].ChildNodes) { GenerateStatement(il, ref current, stmt); } break; default: throw new InvalidOperationException("Term " + node.Term.Name + " is not a statement"); } RelSVars(); il.Add(ref current, Instruction.Create(Specials.Label, label)); }