Sobes.tech
Middle+

What is the 'Interpreter' design pattern?

sobes.tech AI

Answer from AI

The "Interpreter" design pattern is used to define a grammatical representation for a language and provides an interpreter for this representation. The pattern is useful when there is a simple language and a frequent need to interpret it.

Main components of the pattern:

  1. Abstract Expression: Declares an abstract interpret operation that is common to all nodes in the abstract syntax tree.
  2. Terminal Expression: Implements the interpret operation for terminal symbols of the grammar. Each terminal symbol corresponds to one or more instances of the TerminalExpression class.
  3. Nonterminal Expression: Implements the interpret operation for nonterminal symbols of the grammar. Each grammar rule can be represented by such a class. The NonterminalExpression class usually holds references to other AbstractExpression objects (terminal or nonterminal).
  4. Context: Contains information common to the interpreter. It may hold state or operands for interpretation.
  5. Client: Builds (or receives) an abstract syntax tree using the TerminalExpression and NonterminalExpression classes, and calls the interpret operation.

Example usage: parsing and evaluating simple arithmetic expressions.

# Abstract Expression
class Expression:
    def interpret(self, context):
        pass

# Terminal Expression: numbers
class Number(Expression):
    def __init__(self, value):
        self.value = value

    def interpret(self, context):
        return self.value

# Nonterminal Expression: addition
class Add(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) + self.right.interpret(context)

# Nonterminal Expression: subtraction
class Subtract(Expression):
    def __init__(self, left, right):
        self.left = left
        self.right = right

    def interpret(self, context):
        return self.left.interpret(context) - self.right.interpret(context)

# Context (can be a simple dictionary for variables, etc.)
class Context:
    pass

# Client code
context = Context()
tree = Add(Number(5), Subtract(Number(10), Number(2))) # 5 + (10 - 2)

result = tree.interpret(context)
print(result) # Output: 13

Advantages:

  • Easy to add new interpretations or extend the grammar.
  • Grammar is represented as classes, which makes it easier to understand.

Disadvantages:

  • Can become complex if the grammar is very large or complicated. In such cases, other parsing methods might be preferable.