[GO] [Gang of Four] Design pattern learning --Interpreter

Interpreter-Interpreter

** Table of Contents ** This pattern took a long time to understand the structure. it's difficult.

Is it the pattern you want to generate a syntax tree? This pattern expresses a group from the start tag to the end tag with one object. Composite It's like analyzing using a pattern and processing it as a group.

Purpose

For a language, define a grammatical expression and an interpreter that uses it to interpret sentences.

Component

-AbstractExpression Abstract class of all nodes -TerminalExpression A class that represents the end -NonterminalExpression A class that expresses something other than the end ・ Context Context / Situation ・ Client user

Implementation

Implement a sample program that processes the data for four arithmetic operations that has a hierarchical structure. <+> ~ </ +> Addition <-> ~ </-> Subtraction <\ *> ~ </ \ *> Multiplication </> ~ </ /> Division

Target sample data.xml


<+>
    1 
    <-> 
        2 
        3 
        4 
        5 
        6 
        <*> 
            7 
            8 
        </*> 
        9 
    </->
    10 
    11 
    </> 
        12 
        4 
    <//> 
</+>

When the above sample data is shaped into a familiar shape, it becomes `1 + (2 --3 --4 -5 -6-(7 * 8) -9) + 10 + 11 + (12/4) ```, and the solution `-56``` is the expected value.

AbstractExpression Abstract class for all nodes

Expression.kt


package interpreter

interface Expression {
    enum class Operator(val startTag: String, val endTag: String) {
        Plus("<+>", "</+>"),
        Minus("<->", "</->"),
        Multiplication("<*>", "</*>"),
        Divide("</>", "<//>"),
    }
    fun interpret(context: Context): Int

    companion object {
        fun getExpression(token: String?): Expression? {
            return when (token) {
                Operator.Plus.startTag -> {
                    PlusNonterminalExpression()
                }
                Operator.Minus.startTag -> {
                    MinusNonterminalExpression()
                }
                Operator.Multiplication.startTag -> {
                    MultiplicationExpression()
                }
                Operator.Divide.startTag -> {
                    DivideExpression()
                }
                Operator.Plus.endTag,
                Operator.Minus.endTag,
                Operator.Multiplication.endTag,
                Operator.Divide.endTag -> {
                    null
                }
                else -> {
                    TerminalExpression()
                }
            }
        }
    }
}

TerminalExpression A class that represents the end

It is the element that becomes the end of the tree. In this sample data, the numbers correspond to it.

TerminalExpression.kt


package interpreter

class TerminalExpression: Expression {
    private var saveToken: String? = null

    override fun interpret(context: Context): Int {
        saveToken = context.token
        context.nextToken()
        return Integer.parseInt(saveToken ?: "0")
    }

    override fun toString(): String {
        return saveToken ?: "0"
    }
}

NonterminalExpression A class that represents something other than the end

The element that the tree branches. In this sample data, <+> and <-> correspond to it.

Arithmetic class

CalcExpression.kt


package interpreter

import java.util.ArrayList

abstract class CalcExpression: Expression {
    protected val numList = ArrayList<Int>()
    protected val list = ArrayList<Expression>()

    override fun interpret(context: Context): Int {
        context.nextToken()
        loop@ while (!context.isEnd) {
            val childExpressions = Expression.getExpression(context.token)
            if (childExpressions == null) {
                context.nextToken()
                break@loop
            } else {
                numList.add(childExpressions.interpret(context))
                list.add(childExpressions)
            }
        }
        return calc()
    }

    abstract fun calc(): Int
    abstract override fun toString(): String
}

Addition class

PlusNonterminalExpression.kt


package interpreter

/**
 *addition(<+> ~ </+>)
 */
class PlusNonterminalExpression: CalcExpression() {
    override fun calc(): Int {
        var result = numList.first().toInt()
        for (i in 1 until numList.size) {
            result += numList[i]
        }
        return result
    }

    override fun toString(): String {
        return "+$list"
    }
}

Subtraction class

MinusNonterminalExpression.kt


package interpreter

/**
 *subtraction(<-> ~ </->)
 */
class MinusNonterminalExpression: CalcExpression() {
    override fun calc(): Int {
        var result = numList.first().toInt()
        for (i in 1 until numList.size) {
            result -= numList[i]
        }
        return result
    }

    override fun toString(): String {
        return "-$list"
    }
}

Multiplication class

MultiplicationExpression.kt


package interpreter

/**
 *multiplication(<*> ~ </"*>)
 */
class MultiplicationExpression: CalcExpression() {
    override fun calc(): Int {
        var result = numList.first().toInt()
        for (i in 1 until numList.size) {
            result *= numList[i]
        }
        return result
    }

    override fun toString(): String {
        return "*$list"
    }
}

Division class

DivideExpression.kt


package interpreter

class DivideExpression: CalcExpression() {
    override fun calc(): Int {
        var result = numList.first().toInt()
        for (i in 1 until numList.size) {
            result /= numList[i]
        }
        return result
    }

    override fun toString(): String {
        return "/$list"
    }
}

Context Context / Situation

Context.kt


package interpreter

import java.util.*

class Context(source: String) {
    private val tokens: StringTokenizer = StringTokenizer(source)
    var token: String? = null
        private set

    val isEnd: Boolean
        get() = !tokens.hasMoreElements()

    init {
        nextToken()
    }

    fun nextToken() {
        var token: String? = null
        if (!isEnd) {
            token = tokens.nextToken() //standard.nextToken()Call
        }
        this.token = token
    }
}

Client user

Main.kt


package interpreter

import interpreter.Expression.Companion.getExpression

fun main(args: Array<String>) {
    val source = "<+> 1 <-> 2 3 4 5 6 <*> 7 8 </*> 9 </-> 10 11 </> 12 4 <//> </+>"
    val context = Context(source)
    val expression = getExpression(context.token)

    println(expression?.interpret(context))
    println(expression.toString())
}

Output result

[out-put]
-56
+[1, -[2, 3, 4, 5, 6, *[7, 8], 9], 10, 11, /[12, 4]]

The formula and solution were as expected.

Recommended Posts

[Gang of Four] Design pattern learning --Interpreter
[Gang of Four] Design pattern learning --Singleton
[Gang of Four] Design Pattern Learning --Decorator
[Gang of Four] Design pattern learning --Visitor
[Gang of Four] Design pattern learning --Mediator
[Gang of Four] Design pattern learning --Iterator
[Gang of Four] Design pattern learning --Facade
[Gang of Four] Design pattern learning --Composite
[Gang of Four] Design pattern learning --Prototype
[Gang of Four] Design pattern learning --Memento
[Gang of Four] Design pattern learning --State
[Gang of Four] Design pattern learning --Builder
[Gang of Four] Design pattern learning --Bridge
[Gang of Four] Design pattern learning --Proxy
[Gang of Four] Design pattern learning --Strategy
[Gang of Four] Design pattern learning --Adapter
[Gang of Four] Design pattern learning --Observer
[Gang of Four] Design pattern learning --Command
[Gang of Four] Design pattern learning --Fly Weight
[Gang of Four] Design pattern learning --Abstract Factory
[Gang of Four] Design pattern learning --Chain of Responsibility
[Gang of Four] Design pattern learning --Template Method
Gang of Four (GoF) Patterns in Python
Design Pattern #Builder
Design Pattern #Adapter
Design Pattern #Decorator
Pattern recognition learning in video Part 1 Field of Pattern Recognition
Design Pattern #Facade
Design Pattern #Strategy
Design Pattern #Proxy
Learn the design pattern "Chain of Responsibility" in Python
Design Pattern #Factory Method
Deep learning 1 Practice of deep learning
Design Pattern #Template Method