2010-10-05 3 views
1

Je cherche une implémentation en C# d'une machine à pile, de préférence une avec des tests unitaires d'accompagnement ou au moins quelques exemples. Le code à http://en.wikipedia.org/wiki/P-code_machine semble être le genre de chose que je cherche. Malheureusement, cela fait plus de dix ans que j'ai programmé en Pascal et que j'ai eu beaucoup de problèmes à le transférer en C#. En outre, il n'y avait pas d'exemple (s) d'utilisation du code.Quelqu'un peut-il me diriger vers un code C# pour une machine à pile interprétée?

Quoi qu'il en soit, toute aide à cet égard serait grandement apprécié ....

Répondre

2

L'interpréteur original Magpie a été écrit en C# et compilé jusqu'au bytecode basé sur la pile. Jetez un oeil à Machine.cs pour la classe d'interpréteur de base. Le compilateur qui traduit le code source en ce bytecode est dans Magpie.Compiler.

+0

Beuatiful! Exactement ce que je cherchais .... –

3

machines à pile Interprété sont très similaires dans leur concept à Reverse Polish notation.

L'expression

3 + (6 - 2) 

est exprimé en RPN

3 6 2 - + 

Cela s'évalué comme suit:

 
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) 

À partir de là, il devrait être facile à construire simple interprété empiler la machine en C#. Par exemple.

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(); 

avec

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. 
} 

Pour un exemple du monde réel, un coup d'oeil à la fields of the OpCodes class dans le .NET Framework.

+0

Merci pour votre réponse rapide! –

+0

Je pourrais utiliser un exemple plus complet, cependant. Par exemple, comment gérer le chargement/récupération de données et pas seulement les nombres entiers simples. –

+0

@lsb: Bien sûr. Pouvez-vous développer ce que vous entendez par chargement/récupération de données? C'est à dire. charger/récupérer quel type de données d'où? – dtb

Questions connexes