---
# System prepended metadata

title: Interpreter Pattern

---

# Interpreter Pattern
```swift
// MARK: - Abstract Expression
// Abstract Syntax Tree의 모든 노드에서 사용할 Interpreter 작업을 정의

protocol IntegerExpression {
    func evaluate(_ context: IntegerContext) -> Int
}

// MARK: - Context
// InterPreter가 해석할 문장

final class IntegerContext {
    private var data: [Character:Int] = [:]

    // 각 Character별로 Int값을 key value로 대입
    func assign(expression: IntegerVariableExpression, value: Int) {
        self.data[expression.name] = value
    }
    
    // 위에서 assign으로 값을 넣어주고 lookup 메서드로 Character값으로 해당 value인 Int값 찾기
    func lookup(name: Character) -> Int {
        return self.data[name]!
    }
}

// MARK: - Terminal Experssion
// 터미널 기호와 관련된 작업을 구현함
// 여기서 말하는 터미널 기호라고 함은 어떤 문장에서 의미있는 최소의 단위
// 일종의 단위를 재가공 하는 작업 ex) Int -> String, Int -> Double, String -> Int

final class IntegerVariableExpression: IntegerExpression {
    let name: Character

    init(name: Character) {
        self.name = name
    }

    func evaluate(_ context: IntegerContext) -> Int {
        return context.lookup(name: self.name)
    }
}

// MARK: - NonTerminal Experssion
// 하나의 클래스는 문법이 가진 모든 규칙을 필요로 함
// Grammar에서 Nonterminal Symbol에 대한 해석 연산을 구현함
// 재가공 된 단위를 가지고 어떠한 규칙을 만들어서 다시 재가공을 해주는 것 ex) 1 + 2 -> 3, 가 + 나 -> 가나
// 문법이기에 손쉽게 대체 및 추가 가능 ex) 더해주는 규칙을 빼주는 규칙으로 구현부분이 거의 비슷해 쉽게 변경해줄 수 있고(대체),
//                                더해주는 규칙 하나만 있으면 빼주는 규칙도 손쉽게 생성해줄 수 있음(추가)

final class AddExpression: IntegerExpression {
    private var leftOperand: IntegerExpression
    private var rightOperand: IntegerExpression

    init(leftOperand: IntegerExpression, rightOperand: IntegerExpression) {
        self.leftOperand = leftOperand
        self.rightOperand = rightOperand
    }

    func evaluate(_ context: IntegerContext) -> Int {
        return self.leftOperand.evaluate(context) + self.rightOperand.evaluate(context)
    }
}

var context = IntegerContext()

var a = IntegerVariableExpression(name: "A")
var b = IntegerVariableExpression(name: "B")
var c = IntegerVariableExpression(name: "C")

// AddExpression(a, AddExpression(b, c))
// Client
var expression = AddExpression(leftOperand: a, rightOperand: AddExpression(leftOperand: b, rightOperand: c)) // a + (b + c)
context.assign(expression: a, value: 2) // a = 2
context.assign(expression: b, value: 1) // b = 1
context.assign(expression: c, value: 3) // c = 3

var result1 = expression.evaluate(context)  // 6

// MARK: - Client

final class Interpreter {
    // 인터프리터가 해석할 문장
    private var context = IntegerContext()
    
    // Abstract Syntax Tree 문법을 정의하는 특정 문장
    func solve(problems: String) -> Int {
        
        // context가 해석할 수 있도록 String -> Character 형변환
        var problemList: [Character] = problems.map { Character(extendedGraphemeClusterLiteral: $0) }
        
        let firstProblem = problemList.removeFirst()
        let secondProblem = problemList.removeFirst()
        let thirdProblem = problemList.removeFirst()
        
        // Terminal Experssion Instance
        let firstOperand = IntegerVariableExpression(name: firstProblem)
        let secondOperand = IntegerVariableExpression(name: secondProblem)
        let thirdOperand = IntegerVariableExpression(name: thirdProblem)
        
        // NonTerminal Experssion Instance
        let solvedExpression = AddExpression(leftOperand: firstOperand, rightOperand: AddExpression(leftOperand: secondOperand, rightOperand: thirdOperand))
        
        context.assign(expression: firstOperand, value: 1)
        context.assign(expression: secondOperand, value: 2)
        context.assign(expression: thirdOperand, value: 3)
        
        let result = solvedExpression.evaluate(context)
        
        return result
    }
}

let interpreter = Interpreter()
//interpreter.solve(problems: "123") // 6
interpreter.solve(problems: "CBC")






// first operand와 third operand의 value는 다른데 왜 third operand의 value로 둘다 저장이 될까




// key value값으로 assign해주었기에 처음 3은 1로 값이 들어갔지만 마지막에 3으로 다시 변경이됨
```