https://coderun.yandex.ru/problem/the-value-of-an-arithmetic-expression/description Средняя

Решение

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()
}