public static int GenerateCallingCode(int loc, IVirtualMachine vm, CheckerInformation info, ASTProcFuncDecl callee, List <ASTExpression> exprList) { //Allocate Return Location on Stack if (callee.IsFunc) { vm.Alloc(loc++, 1); } //Evaluate argument expressions var paramIttr = callee.Params.GetEnumerator(); //Omit return param for functions if (callee.IsFunc) { if (!paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("No return param found for function"); } } foreach (ASTExpression expr in exprList) { if (!paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("Too many arguments"); } ASTParam param = paramIttr.Current; if (param.OptMechmode != MechMode.COPY || (param.FlowMode == FlowMode.OUT || param.FlowMode == FlowMode.INOUT)) { bool modifiable = param.OptChangemode == ChangeMode.VAR; loc = expr.GenerateLValue(loc, vm, info, modifiable); //Load address on the stack } else { loc = expr.GenerateCode(loc, vm, info); //Load value on the stack } } if (paramIttr.MoveNext()) { throw new IVirtualMachine.InternalError("Too few arguments"); } //Address of the function is not known. //So it has to be stored that at this loc should be a call to the function/procedure. if (callee.Address >= 0) { vm.Call(loc, callee.Address); } else { if (!info.Calls.ContainsKey(callee.Ident)) { info.Calls.Add(callee.Ident, new List <int>()); } info.Calls[callee.Ident].Add(loc); } ++loc; return(loc); }
public int GenerateCode(int loc, IVirtualMachine vm, CheckerInformation info) { //Allocate global storage vm.Alloc(loc++, info.Globals.Count); //Load input params foreach (ASTParam param in Params) { if (param.FlowMode == FlowMode.IN || param.FlowMode == FlowMode.INOUT) { //Load address where to save the input vm.IntLoad(loc++, param.Address); //Switch between types: switch (param.Type) { case Type.INT32: vm.IntInput(loc++, param.Ident); break; case Type.BOOL: vm.BoolInput(loc++, param.Ident); break; case Type.DECIMAL: vm.DecimalInput(loc++, param.Ident); break; } } } //Generate main code foreach (ASTCpsCmd cmd in Commands) { loc = cmd.GenerateCode(loc, vm, info); } //Add output code foreach (ASTParam param in Params) { if (param.FlowMode == FlowMode.OUT || param.FlowMode == FlowMode.INOUT) { //Load output value vm.IntLoad(loc++, param.Address); vm.Deref(loc++); //Switch between types: switch (param.Type) { case Type.INT32: vm.IntOutput(loc++, param.Ident); break; case Type.BOOL: vm.BoolOutput(loc++, param.Ident); break; case Type.DECIMAL: vm.DecimalOutput(loc++, param.Ident); break; } } } //Add stop as last command vm.Stop(loc++); //Generate functions/procedures foreach (string ident in info.ProcFuncs) { ASTProcFuncDecl procFunc = info.ProcFuncs[ident]; procFunc.Address = loc; //Add calls, now that the function/procedure address is known if (info.Calls.ContainsKey(ident) && info.Calls[ident] != null) { foreach (int callLoc in info.Calls[ident]) { vm.Call(callLoc, procFunc.Address); } } //Change current namespace info.CurrentNamespace = ident; //Generate code for function/procedure loc = procFunc.GenerateCode(loc, vm, info); //Reset namespace info.CurrentNamespace = null; } return(loc); }
/* * program intDiv * global * proc divide(in copy m:int, in copy n:int, out ref q:int, out ref r:int) * do * q init := 0; * r init := m; * while r >= n do * q := q + 1; * r := r - n * endwhile * endproc; * * var m:int; * var n:int; * var q:int; * var r:int * do * ? m init; * ? n init; * call divide(m, n, q init, r init); * ! q; * ! r * endprogram */ public static void Test() { try { vm.Alloc(0, 4); vm.IntLoad(1, 0); vm.IntInput(2, "m"); vm.IntLoad(3, 1); vm.IntInput(4, "n"); vm.Alloc(5, 0); vm.IntLoad(6, 0); vm.Deref(7); vm.IntLoad(8, 1); vm.Deref(9); vm.IntLoad(10, 2); vm.IntLoad(11, 3); vm.Call(12, 20); vm.IntLoad(13, 2); vm.Deref(14); vm.IntOutput(15, "q"); vm.IntLoad(16, 3); vm.Deref(17); vm.IntOutput(18, "r"); vm.Stop(19); vm.Enter(20, 0, 0); vm.IntLoad(21, 0); vm.LoadRel(22, (-2)); vm.Deref(23); vm.Store(24); vm.LoadRel(25, (-4)); vm.Deref(26); vm.LoadRel(27, (-1)); vm.Deref(28); vm.Store(29); vm.LoadRel(30, (-1)); vm.Deref(31); vm.Deref(32); vm.LoadRel(33, (-3)); vm.Deref(34); vm.IntGE(35); vm.CondJump(36, 55); vm.LoadRel(37, (-2)); vm.Deref(38); vm.Deref(39); vm.IntLoad(40, 1); vm.IntAdd(41); vm.LoadRel(42, (-2)); vm.Deref(43); vm.Store(44); vm.LoadRel(45, (-1)); vm.Deref(46); vm.Deref(47); vm.LoadRel(48, (-3)); vm.Deref(49); vm.IntSub(50); vm.LoadRel(51, (-1)); vm.Deref(52); vm.Store(53); vm.UncondJump(54, 30); vm.Return(55, 4); } catch (IVirtualMachine.CodeTooSmallError e) { Console.WriteLine(e.ToString()); return; } try { vm.Execute(); } catch (IVirtualMachine.ExecutionError e) { Console.WriteLine(e.ToString()); return; } }