Last active
April 8, 2018 16:13
-
-
Save gzoritchak/4739607 to your computer and use it in GitHub Desktop.
Parsing expressions arithmétiques en kotlin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package codestory2013.gzoritchak | |
import java.math.BigDecimal | |
import java.math.RoundingMode | |
import java.text.DecimalFormat | |
import java.text.DecimalFormatSymbols | |
import java.util.Locale | |
import java.util.StringTokenizer | |
import kotlin.math.* | |
//Extensions | |
fun StringTokenizer.toList(): List<String> { | |
val ret: MutableList<String> = arrayListOf() | |
while (this.hasMoreElements()) ret.add(this.nextToken()) | |
return ret | |
} | |
fun process(val toProcess: String): String = | |
DecimalFormat("#.############################################################################################################" | |
, DecimalFormatSymbols(Locale.FRANCE)) | |
.format(ArithmeticExpression(toProcess).parse().eval()) | |
//Une expression | |
trait Expr { | |
fun eval(): BigDecimal | |
} | |
class Addition (val op1: Expr, val op2: Expr): Expr { override fun eval() = op1.eval() + op2.eval() } | |
class Soustraction (val op1: Expr, val op2: Expr): Expr { override fun eval() = op1.eval() - op2.eval() } | |
class Multiplication(val op1: Expr, val op2: Expr): Expr { override fun eval() = op1.eval() * op2.eval() } | |
class Division (val op1: Expr, val op2: Expr): Expr { override fun eval() = op1.eval().divide(op2.eval(), 10, RoundingMode.HALF_UP) } | |
class Nombre (val value: BigDecimal): Expr { override fun eval() = value } | |
/** | |
* la grammaire des expressions arithmétiques | |
* parsePrecedence3 -> parsePrecedence2. | |
* parsePrecedence3 -> parsePrecedence2 , [+] , parsePrecedence3. | |
* parsePrecedence3 -> parsePrecedence2 , [-] , parsePrecedence3. | |
* | |
* parsePrecedence2 -> parsePrecedence1. | |
* parsePrecedence2 -> parsePrecedence2 , [*] , parsePrecedence1. | |
* parsePrecedence2 -> parsePrecedence2 , [/] , parsePrecedence1. | |
* | |
* parsePrecedence1 -> ['('] , parsePrecedence3 , [')']. | |
* parsePrecedence1 -> [N] , {BigDecimal(N)}. | |
*/ | |
class ArithmeticExpression(val expression: String) { | |
val tokens: List<String> = StringTokenizer(expression + "$", "(),+-*/$", true).toList() | |
var tokenId = -1 | |
var token: String = "" | |
fun toString() = expression | |
// Point d'entrée du parsing | |
fun parse(): Expr { | |
next() | |
return parsePrecedence3() | |
} | |
fun next(): Unit { | |
token = tokens.get(tokenId++) | |
} | |
// | |
fun parsePrecedence3(): Expr { | |
val left = parsePrecedence2() | |
if (token.equals("+") || token.equals("-")) { | |
val op = token | |
next() | |
return when(op){ | |
"+" -> Addition (left, parsePrecedence3()) | |
else -> Soustraction(left, parsePrecedence3()) | |
} | |
} else | |
return left | |
} | |
/** | |
* Le parse de la multiplication et division. Si plusieurs opérations à la suite, on essaye d'étendre de gauche | |
* à droite. | |
*/ | |
fun parsePrecedence2(var left: Expr = parsePrecedence1()): Expr { | |
while ( token.equals("*") || token.equals("/")) { | |
val op = token | |
next() | |
return when(op){ | |
"*" -> parsePrecedence2(Multiplication(left, parsePrecedence1())) | |
else -> parsePrecedence2(Division (left, parsePrecedence1())) | |
} | |
} | |
return left | |
} | |
fun parsePrecedence1(): Expr { | |
var exp: Expr | |
if (token.equals("(")) { | |
next() | |
exp = parsePrecedence3() | |
next() | |
return exp | |
} else { | |
//parsing nombre | |
var sign = 1 | |
if(token.equals("-")){ | |
sign = -1 | |
next() | |
} | |
val partieEntiere = token | |
next() | |
var partieDecimale = "0" | |
if(token.equals(",")){ | |
next() | |
partieDecimale = token | |
next() | |
} | |
return Nombre(BigDecimal(partieEntiere + "." + partieDecimale) * BigDecimal(sign)) | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment