import Foundation
enum Token {
case number(Double)
case operatorToken(OperatorType)
case leftParenthesis
case rightParenthesis
case none
}
enum OperatorType: Character {
case addition = "+"
case subtraction = "-"
case multiplication = "*"
case division = "/"
case exponentiation = "^"
case modulus = "%"
}
class Calculator {
var tokens: [Token] = []
var index = 0
func parseInput(_ input: String) {
var currentNumberString = ""
for character in input {
switch character {
case "0"..."9", ".":
currentNumberString.append(character)
case "+", "-", "*", "/", "^", "%":
addNumberToken(¤tNumberString)
tokens.append(.operatorToken(OperatorType(rawValue: character)!))
case "(":
addNumberToken(¤tNumberString)
tokens.append(.leftParenthesis)
case ")":
addNumberToken(¤tNumberString)
tokens.append(.rightParenthesis)
default:
break
}
}
addNumberToken(¤tNumberString)
}
func addNumberToken(_ numberString: inout String) {
if let number = Double(numberString) {
tokens.append(.number(number))
}
numberString = ""
}
func calculate() -> Double {
guard !tokens.isEmpty else { return 0.0 }
return evaluateExpression()
}
func evaluateExpression() -> Double {
var value = evaluateTerm()
while index < tokens.count, case let .operatorToken(op) = tokens[index] {
if op == .addition || op == .subtraction {
index += 1
let termValue = evaluateTerm()
value = (op == .addition) ? value + termValue : value - termValue
} else {
break
}
}
return value
}
func evaluateTerm() -> Double {
var value = evaluateFactor()
while index < tokens.count, case let .operatorToken(op) = tokens[index] {
if op == .multiplication || op == .division || op == .exponentiation || op == .modulus {
index += 1
let factorValue = evaluateFactor()
switch op {
case .multiplication:
value *= factorValue
case .division:
if factorValue != 0 {
value /= factorValue
} else {
fatalError("Division by zero error!")
}
case .exponentiation:
value = pow(value, factorValue)
case .modulus:
if factorValue != 0 {
value = value.truncatingRemainder(dividingBy: factorValue)
} else {
fatalError("Modulus by zero error!")
}
default:
break
}
} else {
break
}
}
return value
}
func evaluateFactor() -> Double {
if index < tokens.count {
switch tokens[index] {
case .number(let value):
index += 1
return value
case .leftParenthesis:
index += 1
let value = evaluateExpression()
guard index < tokens.count, case .rightParenthesis = tokens[index] else {
fatalError("Mismatched parentheses!")
}
index += 1
return value
default:
break
}
}
fatalError("Invalid expression!")
}
}
print("Swift Calculator Start!")
print("Enter some expressions (type 'exit' to quit): ")
var calculator = Calculator()
while true {
print(">>> ", terminator: "")
if let input = readLine(), input.lowercased() != "exit" {
calculator = Calculator()
calculator.parseInput(input)
let result = calculator.calculate()
print("Result: \(result)")
} else {
break
}
}