Can anyone point me to C# code for an interpreted stack machine?
I'm looking for a C#开发者_如何转开发 implementation of a stack machine, preferably one with accompaning unit tests or at least couple of examples. The code at http://en.wikipedia.org/wiki/P-code_machine appears to be the sort of thing that I'm looking for. Unfortunately, it's been more than a decade since I programmed in Pascal and ran into a bunch of problems porting it to C#. Also, there was no example(s) of using the code.
Anyway, any help in this regard would be greatly appreciated....
Interpreted stack machines are very similar in concept to Reverse Polish notation.
The expression
3 + (6 - 2)
is expressed in RPN as
3 6 2 - +
This gets evaluated as follows:
Input Operation Stack Comment 3 Push value 3 6 Push value 6 3 2 Push value 2 6 3 - Subtract 4 Pop two values (6, 2) and push result (4) 3 + Add 7 Pop two values (3, 4) and push result (7)
From there, it should be easy to build a simple interpreted stack machine in C#. E.g.
var stack = new Stack<int>();
var program = new[]
{
OpCode.Ldc_3,
OpCode.Ldc_6,
OpCode.Ldc_2,
OpCode.Sub,
OpCode.Add,
};
for (int i = 0; i < program.Length; i++)
{
int a, b;
switch (program[i])
{
case OpCode.Add: b = stack.Pop(); a = stack.Pop(); stack.Push(a + b); break;
case OpCode.Sub: b = stack.Pop(); a = stack.Pop(); stack.Push(a - b); break;
case OpCode.Mul: b = stack.Pop(); a = stack.Pop(); stack.Push(a * b); break;
case OpCode.Div: b = stack.Pop(); a = stack.Pop(); stack.Push(a / b); break;
case OpCode.Ldc_0: stack.Push(0); break;
case OpCode.Ldc_1: stack.Push(1); break;
case OpCode.Ldc_2: stack.Push(2); break;
case OpCode.Ldc_3: stack.Push(3); break;
case OpCode.Ldc_4: stack.Push(4); break;
case OpCode.Ldc_5: stack.Push(5); break;
case OpCode.Ldc_6: stack.Push(6); break;
case OpCode.Ldc_7: stack.Push(7); break;
case OpCode.Ldc_8: stack.Push(8); break;
}
}
var result = stack.Pop();
with
enum OpCode
{
Nop, // No operation is performed.
Add, // Adds two values and pushes the result onto the evaluation stack.
Sub, // Subtracts one value from another and pushes the result onto the
// evaluation stack.
Mul, // Multiplies two values and pushes the result on the evaluation
// stack.
Div, // Divides two values and pushes the result onto the evaluation
// stack.
Ldc_0, // Pushes the integer value of 0 onto the evaluation stack.
Ldc_1, // Pushes the integer value of 1 onto the evaluation stack.
Ldc_2, // Pushes the integer value of 2 onto the evaluation stack.
Ldc_3, // Pushes the integer value of 3 onto the evaluation stack.
Ldc_4, // Pushes the integer value of 4 onto the evaluation stack.
Ldc_5, // Pushes the integer value of 5 onto the evaluation stack.
Ldc_6, // Pushes the integer value of 6 onto the evaluation stack.
Ldc_7, // Pushes the integer value of 7 onto the evaluation stack.
Ldc_8, // Pushes the integer value of 8 onto the evaluation stack.
}
For a real world example, have a look at the fields of the OpCodes class in the .NET Framework.
The original Magpie interpreter was written in C# and compiled down to stack-based bytecode. Take a look at Machine.cs for the core intepreter class. The compiler that translates source code to this bytecode is in Magpie.Compiler.
精彩评论