package com.vgmlr.wedge
import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
import java.util.Locale
object WedgeCalculator {
fun doCalc(expr: String): String {
return try {
val res = object {
var pos = -1
var ch = 0
fun next() { ch = if (++pos < expr.length) expr[pos].code else -1 }
fun eat(c: Int): Boolean {
while (ch == ' '.code) next()
if (ch == c) { next(); while (ch == ' '.code) next(); return true }
return false
}
fun parse(): Double { next(); val x = pExp(); if (pos < expr.length) throw Exception(); return x }
fun pExp(): Double {
var x = pTerm()
while (true) {
if (eat('+'.code)) { val y = pTerm(); x += if (pos > 0 && expr[pos - 1] == '%') x * y else y }
else if (eat('-'.code)) { val y = pTerm(); x -= if (pos > 0 && expr[pos - 1] == '%') x * y else y }
else return x
}
}
fun pTerm(): Double {
var x = pFact()
while (true) { if (eat('*'.code)) x *= pFact() else if (eat('/'.code)) x /= pFact() else return x }
}
fun pFact(): Double {
if (eat('+'.code)) return pFact()
if (eat('-'.code)) return -pFact()
var x: Double
val start = pos
if (eat('('.code)) { x = pExp(); eat(')'.code) }
else if (ch in '0'.code..'9'.code || ch == '.'.code) {
while (ch in '0'.code..'9'.code || ch == '.'.code) next()
x = expr.substring(start, pos).toDouble()
} else throw Exception()
if (eat('%'.code)) x /= 100.0
return x
}
}.parse()
DecimalFormat("#.#######", DecimalFormatSymbols(Locale.US)).format(res)
} catch (_: Exception) { "Error" }
}
}