Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jul 31st, 2012  |  syntax: None  |  size: 12.84 KB  |  hits: 13  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. using System;
  2.  
  3. namespace Abstrakte_Uebung1
  4. {
  5.         internal class StackMachine
  6.         {
  7.                 private static void Main()
  8.                 {
  9.                         // escape the static context (this is a C# class)
  10.                         new StackMachine().Interpret();
  11.                 }
  12.  
  13.  
  14.                 // although this is C# code, everything is declared "C-like" (arrays, indexers to arrays ~ pointers... )
  15.  
  16.                 // the stack
  17.                 private int[] stackMemory = new int[1024];
  18.                 private int sp = -1;
  19.                 private int fp = -1;
  20.  
  21.                 // contains the actual program code
  22.                 private Operation[] programMemory = new Operation[1024];
  23.                 private int pc = 0;
  24.  
  25.                 // memory for function arguments
  26.                 private int[] argumentMemory = new int[1024];
  27.  
  28.                 private void Interpret()
  29.                 {
  30.                         // would normally parse an input file
  31.                         LoadProgram(programMemory);
  32.  
  33.                         while(true)
  34.                         {
  35.                                 // fetch instruction
  36.                                 OpCode instruction = programMemory[pc].Instruction;
  37.                                 int intArgument = programMemory[pc].IntArgument;
  38.                                 string stringArgument = programMemory[pc].StringArgument;
  39.  
  40.                                 // increment program counter
  41.                                 pc++;
  42.  
  43.                                 // execute instruction
  44.                                 switch(instruction)
  45.                                 {
  46.                                         case OpCode.Ldc:
  47.  
  48.                                                 // load constant - push argument onto stack
  49.                                                 stackMemory[++sp] = intArgument;
  50.                                                 break;
  51.  
  52.                                         case OpCode.Add:
  53.  
  54.                                                 // add - pop two arguments, add them, push result back onto stack
  55.                                                 sp--;
  56.                                                 stackMemory[sp] = stackMemory[sp] + stackMemory[sp+1];
  57.                                                 break;
  58.  
  59.                                         case OpCode.Eq:
  60.  
  61.                                                 // equals - like add, but compare the values, push 1 if equal, 0 otherwise
  62.                                                 sp--;
  63.                                                 stackMemory[sp] = stackMemory[sp] == stackMemory[sp+1] ? 1 : 0;
  64.                                                 break;
  65.  
  66.                                         case OpCode.End:
  67.  
  68.                                                 // end instruction - print result (= last element on stack) and end interpretation
  69.                                                 Console.WriteLine("Result: " + stackMemory[0]);
  70.                                                 Console.Read();
  71.                                                 return;
  72.  
  73.                                         case OpCode.Call:
  74.  
  75.                                                 // push current PC onto stack
  76.                                                 stackMemory[++sp] = pc;
  77.  
  78.                                                 // update pc to location after the label
  79.                                                 int addressOfLabel = GetAddressOfLabel(stringArgument);
  80.                                                 pc = addressOfLabel + 1;
  81.                                                 break;
  82.  
  83.                                         case OpCode.Ret:
  84.  
  85.                                                 // restore old pc
  86.                                                 pc = stackMemory[sp - 1];
  87.  
  88.                                                 // remember return value
  89.                                                 int retVal = stackMemory[sp];
  90.  
  91.                                                 // move sp down
  92.                                                 sp = fp;
  93.  
  94.                                                 // restore old FP
  95.                                                 fp = stackMemory[fp];
  96.  
  97.                                                 // write return value to sp
  98.                                                 stackMemory[sp] = retVal;
  99.                                                 break;
  100.  
  101.                                         case OpCode.Goto:
  102.  
  103.                                                 // simple update pc
  104.                                                 pc = GetAddressOfLabel(stringArgument);
  105.                                                 break;
  106.  
  107.                                         case OpCode.GoFalse:
  108.  
  109.                                                 // check if top element of stack is 0
  110.                                                 if (stackMemory[sp] == 0)
  111.                                                 {
  112.                                                         // if true, update pc to location after label
  113.                                                         pc = GetAddressOfLabel(stringArgument) + 1;
  114.                                                 }
  115.  
  116.                                                 // discard top element (= condition) in any case
  117.                                                 sp--;
  118.                                                 break;
  119.  
  120.                                         case OpCode.BindArg:
  121.  
  122.                                                 // get from stack (according to Frame Layout)
  123.                                                 argumentMemory[intArgument] = stackMemory[fp + 1 + intArgument];
  124.                                                 break;
  125.  
  126.                                         case OpCode.GetArg:
  127.  
  128.                                                 // load value from specified location and push onto stack
  129.                                                 stackMemory[++sp] = argumentMemory[intArgument];
  130.                                                 break;
  131.  
  132.                                         case OpCode.Mark:
  133.  
  134.                                                 // mark the beginning of a stack frame
  135.                                                 stackMemory[++sp] = fp;
  136.                                                 fp = sp;
  137.                                                 break;
  138.  
  139.                                         /* Stackframe Layout (growing upwards):
  140.                                          *
  141.                                          * ---------------
  142.                                          * Callee Stack...
  143.                                          * ---------------
  144.                                          * Old PC
  145.                                          * ---------------
  146.                                          * ...
  147.                                      * Locals    
  148.                                          * ---------------
  149.                                          * ...
  150.                                      * Arguments      
  151.                                          * ---------------
  152.                                          * Old FP          <- FP
  153.                                          * ---------------
  154.                                          * Caller Stack...
  155.                                          * ---------------
  156.                                          */
  157.  
  158.                                         // calling conventions:
  159.                                     //
  160.                                         // before call:
  161.                                         // caller has to mark the beginning of the stackframe
  162.                                         // and then push the arguments followed by the locals (that need saving)
  163.                                         //
  164.                                         // after call:
  165.                                         // if locals were pushed, caller has to restore them
  166.                                         // (SP will point to the former marked stack location after the call)
  167.                                 }
  168.                         }
  169.                 }
  170.  
  171.                 // helper function, finds the address of a label in the program memory
  172.                 private int GetAddressOfLabel(string label)
  173.                 {
  174.                         int addressOfLabel = 0;
  175.  
  176.                         for (int i = 0; i < 1023; i++)
  177.                                 if (programMemory[i].Instruction == OpCode.Label &&
  178.                                         programMemory[i].StringArgument == label)
  179.                                         addressOfLabel = i;
  180.                         return addressOfLabel;
  181.                 }
  182.  
  183.  
  184.                 // operations are defined by a code and and optional arguments
  185.                 private struct Operation
  186.                 {
  187.                         public OpCode Instruction { get; set; }
  188.                         public int IntArgument { get; set; }
  189.                         public string StringArgument { get; set; }
  190.                 }
  191.  
  192.  
  193.                 enum OpCode
  194.                 {
  195.                         Ldc,
  196.                         Add,
  197.                         Eq,
  198.                         End,
  199.                         Call,
  200.                         Ret,
  201.                         Label,
  202.                         GoFalse,
  203.                         Goto,
  204.                         BindArg,
  205.                         GetArg,
  206.                         Mark,
  207.                 }
  208.  
  209.                 private void LoadProgram(Operation[] memory)
  210.                 {
  211.                         // main function
  212.                         memory[0] = new Operation { Instruction = OpCode.Mark };
  213.                         memory[1] = new Operation { Instruction = OpCode.Ldc, IntArgument = 2 };
  214.                         memory[3] = new Operation { Instruction = OpCode.Call, StringArgument = "DoubleTo65536" };
  215.                         memory[4] = new Operation { Instruction = OpCode.End };
  216.  
  217.  
  218.                         /*
  219.                          * Get constant value.
  220.                          *
  221.                          * FUNC GetFourtyTwo()
  222.                          *    42
  223.                          * END
  224.                          */
  225.                         memory[500] = new Operation { Instruction = OpCode.Label, StringArgument = "GetFourtyTwo" };
  226.                         memory[501] = new Operation { Instruction = OpCode.Ldc, IntArgument = 42 };
  227.                         memory[502] = new Operation { Instruction = OpCode.Ret };
  228.  
  229.                         /*
  230.                          * Get calculated value.
  231.                          *
  232.                          * FUNC GetFivePlusTwo()
  233.                          *    5 + 2
  234.                          * END
  235.                          */
  236.                         memory[600] = new Operation { Instruction = OpCode.Label, StringArgument = "GetFivePlusTwo" };
  237.                         memory[601] = new Operation { Instruction = OpCode.Ldc, IntArgument = 5 };
  238.                         memory[602] = new Operation { Instruction = OpCode.Ldc, IntArgument = 2 };
  239.                         memory[603] = new Operation { Instruction = OpCode.Add };
  240.                         memory[604] = new Operation { Instruction = OpCode.Ret };
  241.  
  242.  
  243.                         /*
  244.                          * Check if without else.
  245.                          *
  246.              * FUNC CheckIf()
  247.              *    IF 4 + 2 = 6 THEN 100 END
  248.              * END
  249.              */
  250.                         memory[700] = new Operation { Instruction = OpCode.Label, StringArgument = "CheckIf" };
  251.                         memory[701] = new Operation { Instruction = OpCode.Ldc, IntArgument = 4 };
  252.                         memory[702] = new Operation { Instruction = OpCode.Ldc, IntArgument = 2 };
  253.                         memory[703] = new Operation { Instruction = OpCode.Add};
  254.                         memory[704] = new Operation { Instruction = OpCode.Ldc, IntArgument = 6 };
  255.                         memory[705] = new Operation { Instruction = OpCode.Eq };
  256.                         memory[706] = new Operation { Instruction = OpCode.GoFalse, StringArgument = "If1_False"};
  257.                         memory[707] = new Operation { Instruction = OpCode.Ldc, IntArgument = 100 };
  258.                         memory[708] = new Operation { Instruction = OpCode.Label, StringArgument = "After_If1" };
  259.                         memory[709] = new Operation { Instruction = OpCode.Ret };
  260.  
  261.                         memory[710] = new Operation { Instruction = OpCode.Label, StringArgument = "If1_False" };
  262.                         memory[711] = new Operation { Instruction = OpCode.Ldc, IntArgument = 0 }; // "empty" expressions are not allowed, return 0 instead
  263.                         memory[712] = new Operation { Instruction = OpCode.Goto, StringArgument = "After_If1" };
  264.  
  265.  
  266.                         /*
  267.                          * Check If with Else.
  268.                          *
  269.                          * FUNC CheckIfElse()
  270.                          *    IF 4 + 2 = 7 THEN 100 ELSE 200 END
  271.                          * END
  272.                          */
  273.                         memory[700] = new Operation { Instruction = OpCode.Label, StringArgument = "CheckIfElse" };
  274.                         memory[701] = new Operation { Instruction = OpCode.Ldc, IntArgument = 4 };
  275.                         memory[702] = new Operation { Instruction = OpCode.Ldc, IntArgument = 2 };
  276.                         memory[703] = new Operation { Instruction = OpCode.Add };
  277.                         memory[704] = new Operation { Instruction = OpCode.Ldc, IntArgument = 7 };
  278.                         memory[705] = new Operation { Instruction = OpCode.Eq };
  279.                         memory[706] = new Operation { Instruction = OpCode.GoFalse, StringArgument = "If1_False" };
  280.                         memory[707] = new Operation { Instruction = OpCode.Ldc, IntArgument = 100 };
  281.                         memory[708] = new Operation { Instruction = OpCode.Label, StringArgument = "After_If1" };
  282.                         memory[709] = new Operation { Instruction = OpCode.Ret };
  283.  
  284.                         memory[710] = new Operation { Instruction = OpCode.Label, StringArgument = "If1_False" };
  285.                         memory[711] = new Operation { Instruction = OpCode.Ldc, IntArgument = 200 };
  286.                         memory[712] = new Operation { Instruction = OpCode.Goto, StringArgument = "After_If1" };
  287.  
  288.  
  289.                         /*
  290.                          * Test parameters.
  291.                          *
  292.                          * FUNC Add(x y)
  293.                          *    x + y
  294.                          * END
  295.                          */
  296.                         memory[800] = new Operation { Instruction = OpCode.Label, StringArgument = "Add" };
  297.                         memory[801] = new Operation { Instruction = OpCode.BindArg, IntArgument = 0 }; // bind argument x to memory location 0
  298.                         memory[802] = new Operation { Instruction = OpCode.BindArg, IntArgument = 1 }; // store argument y in memory location 1
  299.                         memory[803] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  300.                         memory[804] = new Operation { Instruction = OpCode.GetArg, IntArgument = 1 };
  301.                         memory[805] = new Operation { Instruction = OpCode.Add };
  302.                         memory[806] = new Operation { Instruction = OpCode.Ret };
  303.  
  304.  
  305.                         /*
  306.                          * Nested function call.
  307.                          *
  308.              * FUNC Triple(x)
  309.              *    x + Add(x x)
  310.              * END
  311.              */
  312.                         memory[850] = new Operation { Instruction = OpCode.Label, StringArgument = "Triple" };
  313.                         memory[851] = new Operation { Instruction = OpCode.BindArg, IntArgument = 0 }; // bind argument x to memory location 0
  314.                         memory[852] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  315.                         memory[853] = new Operation { Instruction = OpCode.Mark };
  316.                         memory[854] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  317.                         memory[855] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  318.                         memory[856] = new Operation { Instruction = OpCode.Call, StringArgument = "Add"};
  319.                         memory[857] = new Operation { Instruction = OpCode.Add };
  320.                         memory[858] = new Operation { Instruction = OpCode.Ret };
  321.  
  322.  
  323.                         /*
  324.                          * Finally add some recursion ;)
  325.                          * Only call with powers of 2!
  326.                          *
  327.                          * FUNC DoubleTo65536(x)
  328.                          *    IF x = 65536 THEN x ELSE DoubleTo65536(Add(x x) END
  329.                          * END
  330.                          */
  331.                         memory[900] = new Operation { Instruction = OpCode.Label, StringArgument = "DoubleTo65536" };
  332.                         memory[901] = new Operation { Instruction = OpCode.BindArg, IntArgument = 0 }; // bind argument x to memory location 0
  333.  
  334.                         // compare
  335.                         memory[902] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  336.                         memory[903] = new Operation { Instruction = OpCode.Ldc, IntArgument = 65536 };
  337.                         memory[904] = new Operation { Instruction = OpCode.Eq };
  338.  
  339.                         // "True" branch
  340.                         memory[905] = new Operation { Instruction = OpCode.GoFalse, StringArgument = "If2_False" };
  341.                         memory[906] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  342.                         memory[907] = new Operation { Instruction = OpCode.Label, StringArgument = "After_If2" };
  343.                         memory[908] = new Operation { Instruction = OpCode.Ret };
  344.  
  345.                         // "False" branch
  346.                         memory[909] = new Operation { Instruction = OpCode.Label, StringArgument = "If2_False" };
  347.                         memory[910] = new Operation { Instruction = OpCode.Mark };
  348.                         memory[911] = new Operation { Instruction = OpCode.Mark };
  349.                         memory[912] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  350.                         memory[913] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  351.                         memory[914] = new Operation { Instruction = OpCode.Call, StringArgument = "Add"};
  352.                         memory[915] = new Operation { Instruction = OpCode.Call, StringArgument = "DoubleTo65536" };
  353.                         memory[916] = new Operation { Instruction = OpCode.Goto, StringArgument = "After_If2" };
  354.  
  355.  
  356.                         /*
  357.                          * Wrong calculation because local variables are not saved on the stack.
  358.                          * Storing of locals is currently NOT implemented!
  359.                          *
  360.                          * FUNC SaveLocals(x y)
  361.                          *    x + Add(y y) + x
  362.                          * END
  363.                          */
  364.                         memory[960] = new Operation { Instruction = OpCode.Label, StringArgument = "SaveLocals" };
  365.                         memory[961] = new Operation { Instruction = OpCode.BindArg, IntArgument = 0 }; // bind argument x to memory location 0
  366.                         memory[962] = new Operation { Instruction = OpCode.BindArg, IntArgument = 1 }; // bind argument y to memory location 1
  367.                         memory[963] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 };
  368.                         memory[964] = new Operation { Instruction = OpCode.Mark };
  369.                         memory[965] = new Operation { Instruction = OpCode.GetArg, IntArgument = 1 };
  370.                         memory[966] = new Operation { Instruction = OpCode.GetArg, IntArgument = 1 };
  371.                         memory[967] = new Operation { Instruction = OpCode.Call, StringArgument = "Add" };
  372.                         memory[968] = new Operation { Instruction = OpCode.Add };
  373.                         memory[969] = new Operation { Instruction = OpCode.GetArg, IntArgument = 0 }; // x was overridden with y in Call of Add!
  374.                         memory[970] = new Operation { Instruction = OpCode.Add };
  375.                         memory[971] = new Operation { Instruction = OpCode.Ret };
  376.                 }
  377.         }
  378. }