Interpreter

In computer programming, the interpreter pattern is a particular design pattern. The interpreter pattern specifies how to evaluate sentences in a language. The basic idea is to have a class for each symbol (terminal or nonterminal ) in a specialized computer language . The syntax tree of a sentence in the language is an instance of the composite pattern and is used to evaluate (interpret) the sentence.

 

Image:Interpreter_UML_class_diagram.jpg

 

Uses for the Interpreter pattern

  • Specialized database query languages such as SQL.
  • Specialized computer languages which are often used to describe communication protocols
  • Most general-purpose computer languages actually incorporate several specialized languages.

When the program must parse an algebraic string. This case is fairly
obvious. The program is asked to carry out its operations based on a
computation where the user enters an equation of some sort. This
frequently occurs in mathematical-graphics programs, where the program

renders a curve or surface based on any equation it can evaluate.
Programs like Mathematica and graph drawing packages such as Origin
work in this way.
When the program must produce varying kinds of output. This case
is a little less obvious, but far more useful. Consider a program that can
display columns of data in any order and sort them in various ways.
These programs are frequently referred to as Report Generators, and
while the underlying data may be stored in a relational database, the user
interface to the report program is usually much simpler then the SQL
language which the database uses. In fact, in some cases, the simple
report language may be interpreted by the report program and translated
into SQL.

 

Examples

The following example illustrates the interpreter pattern. The grammar
expression ::= plus | minus | variable
plus ::= expression expression '+'
minus ::= expression expression '-'
variable  ::= 'a' | 'b' | 'c' | ... | 'z'

defines a language which contains reverse polish expressions like:
a b +
a b c + -
a b + c a - -

 

import java.util.*;
interface Expression {
    public int interpret(HashMap<String,Integer> variables);
}
 
class Number implements Expression {
    private int number;
    public Number(int number)       { this.number = number; }
    public int interpret(HashMap<String,Integer> variables)  { return number; }
}
 
class Plus implements Expression {
    Expression leftOperand;
    Expression rightOperand;
    public Plus(Expression left, Expression right) {
        leftOperand = left;
        rightOperand = right;
    }
 
    public int interpret(HashMap<String,Integer> 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(HashMap<String,Integer> 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(HashMap<String,Integer> variables)  {
        return variables.get(name);
    }
}

class Evaluator {
    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("-")) {
                Expression subExpression = new Minus(expressionStack.pop(), expressionStack.pop());
                expressionStack.push( subExpression );
            }
            else                       
                expressionStack.push( new Variable(token) );
        }
        syntaxTree = expressionStack.pop();
    }
 
    public int evaluate(HashMap<String,Integer> context) {
        return syntaxTree.interpret(context);
    }
}

public class Interpretor {
      public static void main(String[] args) {
            String expression = "w x z - +";
            Evaluator sentence = new Evaluator(expression);
            HashMap<String,Integer> variables = new HashMap<String,Integer>();
            variables.put("w", 5);
            variables.put("x", 10);
            variables.put("z", 42);
            int result = sentence.evaluate(variables);
            System.out.println(result);//result==37
        }
}

 

Consequences of the Interpreter Pattern

Whenever you introduce an interpreter into a program, you need to provide a simple way for the program user to enter commands in that language.
Introducing a language and its accompanying grammar also requires fairly extensive error checking for misspelled terms or misplaced grammatical elements. This can easily consume a great deal of programming effort unless some template code is available for implementing this checking. Further, effective methods for notifying the users of these errors are not easy to design and implement.
When you have to have a way to specify the order of sequential operations, a language is a good way to do so, even if the language is generated from the user interface. The Interpreter pattern has the advantage that you can extend or revise the grammar fairly easily one you have built the general parsing and reduction tools. You can also add new verbs or variables quite easily once the foundation is constructed.
If you have many more cases, Design Patterns suggests that you create a class for each one of them. This again makes language extension easier, but has the disadvantage of proliferating lots of similar little classes. Finally, as the syntax of the grammar becomes more complex, you run the risk of creating a hard to maintain program. While interpreters are not all that common in solving general programming problems, the Iterator pattern  is one of the most common ones you'll be using.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章