Értelmező programtervezési minta

A számítógép programozásban az értelmező minta egy tervezési minta, mely meghatározza, hogyan értékeljen ki mondatokat egy nyelv. Az alap ötlet az volt, hogy legyen egy osztály minden szimbólumra (terminális és nem terminális) egy erre specializált nyelvben. Egy nyelvben a mondat szintaxis fája egy példánya az összetétel mintának, és a mondat megértésére használja a kliens. Lásd még összetétel minta.

Értelmező mintát használók

  • Speciális adatbázis lekérdező nyelvek, mint például az SQL
  • Speciális programozási nyelvek, amelyek általában kommunikációs protokollok leírására használnak.
  • A legtöbb általános célú programozási nyelv valójában magába foglal néhány más speciális nyelvet.
  • Virtuális gép Javához és szkript nyelvekhez.

Struktúra

Az értelmező minta az alábbi struktúrával írható le:

left
Értelmező minta

Példák

BNF, C# és JAVA nyelveken.

BNF

A következő "Backus-Naur-Formula" (BNF) példa illusztrálja az interpreter mintát. A nyelvtan:

expression ::= plus | minus | variable | number
plus ::= expression expression '+'
minus ::= expression expression '-'
variable  ::= 'a' | 'b' | 'c' | ... | 'z'
digit = '0' | '1' | ... | '9'
number ::= digit | digit number

Definiál egy nyelvet, amellyel a fordított lengyel jelöléssel lehet kifejezéseket megadni. Például az alábbiakat:

a b +
a b c + -
a b + c a - -

C#

Ez a strukturális kód bemutatja az értelmező mintát, amely egy definiált nyelvtant alkalmaz.

//IVSR: Interpreter design pattern
namespace IVSR.DesignPaterns.Interpreter
{
// "Context"
  class Context
  {
  }
 
  // "AbstractExpression"
  abstract class AbstractExpression
  {
    public abstract void Interpret(Context context);
  }
 
  // "TerminalExpression"
  class TerminalExpression : AbstractExpression
  {
    public override void Interpret(Context context)
    {
      Console.WriteLine("Called Terminal.Interpret()");
    }
  }
 
  // "NonterminalExpression"
  class NonterminalExpression : AbstractExpression
  {
    public override void Interpret(Context context)
    {
      Console.WriteLine("Called Nonterminal.Interpret()");
    }  
  }
  class MainApp
  {
    static void Main()
    {
      Context context = new Context();
 
      // Usually a tree
      ArrayList list = new ArrayList();
 
      // Populate 'abstract syntax tree'
      list.Add(new TerminalExpression());
      list.Add(new NonterminalExpression());
      list.Add(new TerminalExpression());
      list.Add(new TerminalExpression());
 
      // Interpret
      foreach (AbstractExpression exp in list)
      {
        exp.Interpret(context);
      }
 
      // Wait for user
      Console.Read();
    }
  }
}

Java

A következő példa egy értelmező minta megvalósítását mutatja be, ahol minden nyelvtani szabályra van egy osztály.

import java.util.Map;
 
interface Expression {
    public int interpret(Map<String,Expression> variables);
}
 
class Number implements Expression {
    private int number;
    public Number(int number)       { this.number = number; }
    public int interpret(Map<String,Expression> variables)  { return number; }
}
 
class Plus implements Expression {
    Expression leftOperand;
    Expression rightOperand;
    public Plus(Expression left, Expression right) { 
        leftOperand = left; 
        rightOperand = right;
    }
 
    public int interpret(Map<String,Expression> variables)  { 
        return leftOperand.interpret(variables) + rightOperand.interpret(variables);
    }
}
 
class Minus implements Expression {
    Expression leftOperand;
    Expression rightOperand;
    public Minus(Expression left, Expression right) { 
        leftOperand = left; 
        rightOperand = right;
    }
 
    public int interpret(Map<String,Expression> variables)  { 
        return leftOperand.interpret(variables) - rightOperand.interpret(variables);
    }
}
 
class Variable implements Expression {
    private String name;
    public Variable(String name)       { this.name = name; }
    public int interpret(Map<String,Expression> variables)  { 
        if(null==variables.get(name)) return 0; //Either return new Number(0).
        return variables.get(name).interpret(variables); 
    }
}

import java.util.Map;
import java.util.Stack;
 
class Evaluator implements Expression {
    private Expression syntaxTree;
 
    public Evaluator(String expression) {
        Stack<Expression> expressionStack = new Stack<Expression>();
        for (String token : expression.split(" ")) {
            if  (token.equals("+")) {
                Expression subExpression = new Plus(expressionStack.pop(), expressionStack.pop());
                expressionStack.push( subExpression );
            }
            else if (token.equals("-")) {
                // it's necessary remove first the right operand from the stack
                Expression right = expressionStack.pop();
                // ..and after the left one
                Expression left = expressionStack.pop();
                Expression subExpression = new Minus(left, right);
                expressionStack.push( subExpression );
            }
            else                        
                expressionStack.push( new Variable(token) );
        }
        syntaxTree = expressionStack.pop();
    }
 
    public int interpret(Map<String,Expression> context) {
        return syntaxTree.interpret(context);
    }
}

Végül értékeli a kifejezést : "w x z - +" with w = 5, x = 10, and z = 42.

import java.util.Map;
import java.util.HashMap;
 
public class InterpreterExample {
    public static void main(String[] args) {
        String expression = "w x z - +";
        Evaluator sentence = new Evaluator(expression);
        Map<String,Expression> variables = new HashMap<String,Expression>();
        variables.put("w", new Number(5));
        variables.put("x", new Number(10));
        variables.put("z", new Number(42));
        int result = sentence.interpret(variables);
        System.out.println(result);
    }
}

Kapcsolódó szócikkek

Jegyzetek

További információk

Az angol Wikikönyvekben
további információk találhatók

Fordítás

Ez a szócikk részben vagy egészben az Interpreter pattern című angol Wikipédia-szócikk ezen változatának fordításán alapul. Az eredeti cikk szerkesztőit annak laptörténete sorolja fel. Ez a jelzés csupán a megfogalmazás eredetét és a szerzői jogokat jelzi, nem szolgál a cikkben szereplő információk forrásmegjelöléseként.