Решение
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
private const val LIMIT = 2_000_000_000L
sealed class Token {
data class Number(val value: Long) : Token()
object Plus : Token()
object Minus : Token()
object Mul : Token()
object LParen : Token()
object RParen : Token()
}
class Tokenizer(private val input: String) {
private var pos = 0
private fun skipSpaces() {
while (pos < input.length && input[pos].isWhitespace()) {
pos++
}
}
fun tokenize(): List<Token>? {
val tokens = mutableListOf<Token>()
while (true) {
skipSpaces()
if (pos >= input.length) break
val c = input[pos]
when {
c.isDigit() || c == '-' -> {
if (c == '-') {
if (pos+1 < input.length && input[pos+1].isDigit()) {
if (tokens.isEmpty()) {
val numberToken = readNumber() ?: return null
tokens.add(numberToken)
} else {
val prev = tokens.last()
if (prev is Token.Plus || prev is Token.Minus || prev is Token.Mul || prev is Token.LParen) {
val numberToken = readNumber() ?: return null
tokens.add(numberToken)
} else {
tokens.add(Token.Minus)
pos++
}
}
} else {
tokens.add(Token.Minus)
pos++
}
} else {
val numberToken = readNumber() ?: return null
tokens.add(numberToken)
}
}
c == '+' -> {
tokens.add(Token.Plus)
pos++
}
c == '*' -> {
tokens.add(Token.Mul)
pos++
}
c == '(' -> {
tokens.add(Token.LParen)
pos++
}
c == ')' -> {
tokens.add(Token.RParen)
pos++
}
else -> {
return null
}
}
}
return tokens
}
private fun readNumber(): Token.Number? {
val start = pos
if (input[pos] == '-') {
pos++
}
if (pos >= input.length || !input[pos].isDigit()) {
return null
}
while (pos < input.length && input[pos].isDigit()) {
pos++
}
val numStr = input.substring(start, pos)
return try {
val numVal = numStr.toLong()
if (numVal < -LIMIT || numVal > LIMIT) {
null
} else {
Token.Number(numVal)
}
} catch (e: NumberFormatException) {
null
}
}
}
class Parser(private val tokens: List<Token>) {
private var index = 0
private fun peek(): Token? =
if (index in tokens.indices) tokens[index] else null
private fun nextToken(): Token? =
peek()?.also { index++ }
fun atEnd(): Boolean = (index == tokens.size)
fun parseExpression(): Long? {
var value = parseTerm() ?: return null
while (true) {
val tk = peek()
if (tk is Token.Plus || tk is Token.Minus) {
nextToken()
val right = parseTerm() ?: return null
val res = if (tk is Token.Plus) {
safeAdd(value, right) ?: return null
} else {
safeSub(value, right) ?: return null
}
value = res
} else {
break
}
}
return value
}
fun parseTerm(): Long? {
var value = parseFactor() ?: return null
while (true) {
val tk = peek()
if (tk is Token.Mul) {
nextToken()
val right = parseFactor() ?: return null
val res = safeMul(value, right) ?: return null
value = res
} else {
break
}
}
return value
}
fun parseFactor(): Long? {
val tk = peek() ?: return null
return when (tk) {
is Token.Number -> {
nextToken()
tk.value
}
is Token.LParen -> {
nextToken()
val valExpr = parseExpression() ?: return null
val closing = peek()
if (closing is Token.RParen) {
nextToken()
valExpr
} else {
null
}
}
else -> null
}
}
}
private fun safeAdd(a: Long, b: Long): Long? {
val r = a + b
return if (r in -LIMIT..LIMIT) r else null
}
private fun safeSub(a: Long, b: Long): Long? {
val r = a - b
return if (r in -LIMIT..LIMIT) r else null
}
private fun safeMul(a: Long, b: Long): Long? {
val r = a * b
return if (r in -LIMIT..LIMIT) r else null
}
fun main() {
val reader = BufferedReader(InputStreamReader(System.`in`))
val writer = BufferedWriter(OutputStreamWriter(System.out))
val expression = reader.readLine() ?: ""
reader.close()
val tokenizer = Tokenizer(expression)
val tokens = tokenizer.tokenize()
if (tokens == null) {
writer.write("WRONG\\n")
writer.close()
return
}
val parser = Parser(tokens)
val result = parser.parseExpression()
if (result == null || !parser.atEnd()) {
writer.write("WRONG\\n")
writer.close()
return
}
writer.write("$result\\n")
writer.close()
}