** 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.
For a language, define a grammatical expression and an interpreter that uses it to interpret sentences.
-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
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.
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()
}
}
}
}
}
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"
}
}
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.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
}
}
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())
}
[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