com.mthaler.aparser.arithmetic.Parsers.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aparser Show documentation
Show all versions of aparser Show documentation
An arithmetic expression parser written in Kotlin
package com.mthaler.aparser.arithmetic
import com.mthaler.aparser.*
import com.mthaler.aparser.tokens.*
import com.mthaler.aparser.tokens.number as tnumber
import kotlin.math.PI
import kotlin.math.E
fun ws(p: Parser): Parser = (optional(whitespaces) and p and optional(whitespaces)).map { it.middle() }
// terminals
val number: Parser = ws(tnumber).map { Expr.Number(it.toDouble()) }
val pi: Parser = (ws(stringLiteral("pi")) or ws(stringLiteral("\u03C0"))).map { Expr.Number(PI) }
val e: Parser = ws(stringLiteral("e")).map { Expr.Number(E) }
val globalVar: Parser = ws(charLiteral('[') and lettersOrDigits and charLiteral(']')).map { Expr.GlobalVar(it.middle()) }
val plus = ws(charLiteral('+'))
val minus = ws(charLiteral('-'))
val times = ws(charLiteral('*'))
val div = ws(charLiteral('/'))
val exp = ws(charLiteral('^'))
// unary -
val neg = ws(charLiteral('-'))
val lpar = ws(charLiteral('('))
val rpar = ws(charLiteral(')'))
val funcname = identifier or charLiteral('\u221A')
object Expression: RecursiveParser() {
init {
val func: Parser = (funcname and lpar and this and rpar).map { Expr.UnaryOp(it.first.second, it.first.first.first) }
val group: Parser = (lpar and this and rpar).map { it.middle() }
val factor: Parser = (neg and number).map { Expr.UnaryOp(it.second, it.first) as Expr } or number or pi or e
val operand: Parser = func or factor or globalVar or group
val power: Parser = (operand and zeroOrMore(exp and operand)).map { p ->
if (p.second.isEmpty()) {
p.first
} else {
val rest = p.second
var e = p.first
val result = arrayListOf>()
for (item in rest) {
result.add(Pair(item.first, e))
e = item.second
}
result.foldRight(e) { item, expr -> Expr.BinOp(item.second, expr, item.first) }
}
}
val term: Parser = (power and zeroOrMore((times or div) and power)).map { p ->
p.second.fold(p.first) { expr, item -> Expr.BinOp(expr, item.second, item.first) }
}
val expr: Parser = (term and zeroOrMore((plus or minus) and term)).map { p ->
p.second.fold(p.first) { expr, item -> Expr.BinOp(expr, item.second, item.first) }
}
this.parser = expr or number
}
}