• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

[SWIFT]Obsługa błędów w prostym kalkulatorze

VPS Starter Arubacloud
0 głosów
751 wizyt
pytanie zadane 7 marca 2017 w Android, Swift, Symbian przez Piotrinformatyk Początkujący (340 p.)

Witam :) Pisałem wcześniej, ale nikt nie odpowiedział: https://forum.pasja-informatyki.pl/232719/swift-obsluga-bledow-mnozenie-i-dzielenie-przed-dodawaniem-i-odejmowaniem?show=232719#q232719 

Zmieniłem kod na tyle, że myślę, że lepiej będzie jak nowe pytanie zadam. Gdyby nie jeden błąd to pewnie bym nie napisał, ale nie rozumiem skąd on wynika:

Błąd: Expected declaration. Jak rozwinę to mi pisze: In declaration of 'Parser'. Znajduje się on przy wywoływaniu funkcji na samym dole. 

Uczę się z książki i mam dodać odejmowanie (zrobiłem bardzo szybko), mnożenie i dzielenie (połowicznie bo nie uwzględnia pierwszeństwa co próbuję zrobić) i dodanie index-u do komunikatu błędu(tak średnio wiem co mam zrobić).

Ktoś pomoże mi zrozumieć co źle robię? Najlepiej też z tym indexem jakby mi ktoś pomógł

 


enum Token {
    //rodzaje tokenów
    case Number(Int)
    case Plus
    case Minus
    case Division
    case Multiplication
    case OpeningBracket
    case ClosingBracket
}

//analizator leksykalny - budowa
class Lexer {
    //String.CharacterView ma właściwości startIndex i endIndex
    let input: String.CharacterView
    var position: String.CharacterView.Index
    
    enum theError: Error {                        //zgłasza błąd
        case IncorrectCharacter(Character)
    }
    
    init(input: String) {
        self.input = input.characters             //inicjalizujemy właściwośc wraz z danymi wejściowymi,ma wartość wskazującą początek tych danych wejściowych
        self.position = self.input.startIndex
    }
    
    //może być wywołana zawsze
    func peek() -> Character? {                  //spradzenie kolejnego znaku w danych wejściowych. Wskazuje analizatorowi, że zostały przetworzone wszystkie dane wejściowe
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    
    //IMPLEMENTACJA ALGORYTMU ANALIZATORA
    
    //można wywołać tylko wtedy, gdy aktualne położenie nie jest końcem danych wejściowych
    func advance() {                                                //przejście do kolejnego znaku
        assert(position < input.endIndex, "You can not go beyond the data input") //gdy false - wpadnięcie w pułapkę i wyświetlenie komunikatu
        position = input.index(after: position)
    }
    func getNumber () -> Int {              //wyodrębnia liczby całkowite z danych wejściowych
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
            default:
                return value
            }
        }
        return value
    }
    func lex() throws -> [Token] { //throws, czyli funkcja/metoda może wygenerować błąd
        var tokens = [Token]()      //tablica z tokenami
        
        while let nextCharacter = peek() {   //przetworzenie wszystkich danych wejściowych
            switch nextCharacter {
             case "(":
                tokens.append(.OpeningBracket)
                advance()
                
            case ")":
                tokens.append(.ClosingBracket)
            case "0"..."9":
                let value = getNumber()
                tokens.append(.Number(value))
                
            case "*":
                tokens.append(.Multiplication)
                advance()
                
            case "/":
                tokens.append(.Multiplication)
                advance()
                
            case "+":
                tokens.append(.Plus)
                advance()
                
            case "-":
                tokens.append(.Minus)
                advance()
                
            case " ":
                advance()
                
            default:
                throw theError.IncorrectCharacter(nextCharacter)   //throws  zatrzymuje funkcje i przekazuje błąd do komponentu wywołąjącego dany błąd zgodnego z protokołem Error
            }
        }
        return tokens
    }
}

class Parser {
    let tokens: [Token]
    var position = 0
    
    enum theError: Error {
        case unexpectedEndOfOutput
        case incorrectToken(Token)
    }
    
    init(tokens: [Token]) {
        self.tokens = tokens
    }
    
    func getNextToken() -> Token? {                     //peek() i advance() w jedną
        guard position < tokens.count else {
            return nil
        }
        let token = tokens[position]
        position += 1
        return token
    }
    
    func getNumber() throws -> Int {
        guard let token = getNextToken() else {
            throw theError.unexpectedEndOfOutput
        }
        switch token {
        case .Number(let value):
            return value
        case .Division:
            throw theError.incorrectToken(token)
        case .Multiplication:
            throw theError.incorrectToken(token)
        case .Plus:
            throw theError.incorrectToken(token)
        case .Minus:
            throw theError.incorrectToken(token)
        case .OpeningBracket:
            throw theError.incorrectToken(token)
        case .ClosingBracket:
            throw theError.incorrectToken(token)
        }
    }
    
    func parse() throws -> Int {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
            case .OpeningBracket:
                try getBrackets()
            
            case .ClosingBracket:
                try getNumber()
                
            case .Multiplication:
                let nextNumber = try getNumber()
                value *= nextNumber
                
            case .Division:
                let nextNumber = try getNumber()
                value / nextNumber
                
            case .Plus:
                let nextNumber = try getNumber()
                value += nextNumber
                
            case .Minus:
                let nextNumber = try getNumber()
                value -= nextNumber
                
            case .Number:
                throw theError.incorrectToken(token)
            }
        }
        return value
    }
    
    func getBrackets() throws {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
            case .Plus:
                let nextNumber = try getNumber()
                value += nextNumber
            case .Minus:
                let nextNumber = try getNumber()
                value -= nextNumber
            }
        }
    
}

func evaluate(input: String) {
    print("Calculation: \(input)")
    
    let lexer = Lexer(input: input)
    do {
        //wprowadza nowy zasięg, jeżeli jakieś wywołanie try spowoduje zgłoszenie błędu nastąpi wykonanie odpowiedniego bloku catch
        let tokens = try lexer.lex()
        print("Data output lexical analyzer: \(tokens)")
        
        let parser = Parser(tokens: tokens)
        let result = try parser.parse()
        print("Output parser: \(result)")
    }
    catch Lexer.theError.IncorrectCharacter(let character) {                        //zgłoszona wartość błędu jest przypisywana stłej error
        print("Data output contains invalid character: \(character)")
    }
    catch Parser.theError.unexpectedEndOfOutput {
        print("Unexpected end of data output during processing.")
    }
    catch Parser.theError.incorrectToken(let token) {
        print("Incorrect token during processing: \(token)")
    }
    catch {
        print("Following an unexpected error: \(error).")
    }
}

evaluate(input: "10 + 5 + 3")
evaluate(input: "10 + + 3")
evaluate(input: "10 - 5 + 3")
evaluate(input: "(10 * 3) - (3 * 5)")

 

komentarz 8 marca 2017 przez Raymond.Z Obywatel (1,800 p.)
No z tym już sam sobie musisz poradzić to Twój kod i Twoje błędy, na łatwiznę po gotową odpowiedź nie ma co chodzić :-)
komentarz 8 marca 2017 przez Piotrinformatyk Początkujący (340 p.)

Dostając gotową odpowiedź niewiele się nowicjusz nie nauczy pewnie. Choć są jakieś wyjątki od tej reguły?

 

Pozbyłem się nawiasu, ale ciągle mam problem z minusem.

Mój aktualny kod:

enum Token {
    //rodzaje tokenów
    case Number(Int)
    case Plus
    case Minus
    case Division
    case Multiplication
//    case OpeningBracket
//    case ClosingBracket
}

//analizator leksykalny - budowa
class Lexer {
    //String.CharacterView ma właściwości startIndex i endIndex
    let input: String.CharacterView
    var position: String.CharacterView.Index
    
    enum theError: Error {                        //zgłasza błąd
        case IncorrectCharacter(Character)
    }
    
    init(input: String) {
        self.input = input.characters             //inicjalizujemy właściwośc wraz z danymi wejściowymi,ma wartość wskazującą początek tych danych wejściowych
        self.position = self.input.startIndex
    }
    
    //może być wywołana zawsze
    func peek() -> Character? {                  //spradzenie kolejnego znaku w danych wejściowych. Wskazuje analizatorowi, że zostały przetworzone wszystkie dane wejściowe
        guard position < input.endIndex else {
            return nil
        }
        return input[position]
    }
    
    //IMPLEMENTACJA ALGORYTMU ANALIZATORA
    
    //można wywołać tylko wtedy, gdy aktualne położenie nie jest końcem danych wejściowych
    func advance() {                                                //przejście do kolejnego znaku
        assert(position < input.endIndex, "You can not go beyond the data input") //gdy false - wpadnięcie w pułapkę i wyświetlenie komunikatu
        position = input.index(after: position)
    }
    func getNumber () -> Int {              //wyodrębnia liczby całkowite z danych wejściowych
        var value = 0
        
        while let nextCharacter = peek() {
            switch nextCharacter {
            case "0"..."9":
                let digitValue = Int(String(nextCharacter))!
                value = 10*value + digitValue
                advance()
            default:
                return value
            }
        }
        return value
    }
    func lex() throws -> [Token] { //throws, czyli funkcja/metoda może wygenerować błąd
        var tokens = [Token]()      //tablica z tokenami
        
        while let nextCharacter = peek() {   //przetworzenie wszystkich danych wejściowych
            switch nextCharacter {
//             case "(":
//                tokens.append(.OpeningBracket)
//                advance()
//                
//            case ")":
//                tokens.append(.ClosingBracket)
//                advance()
//                
            case "0"..."9":
                let value = getNumber()
                tokens.append(.Number(value))
                
            case "*":
                tokens.append(.Multiplication)
                advance()
                
            case "/":
                tokens.append(.Multiplication)
                advance()
                
            case "+":
                tokens.append(.Plus)
                advance()
                
            case "-":
                tokens.append(.Minus)
                advance()
                
            case " ":
                advance()
                
            default:
                throw theError.IncorrectCharacter(nextCharacter)   //throws  zatrzymuje funkcje i przekazuje błąd do komponentu wywołąjącego dany błąd zgodnego z protokołem Error
            }
        }
        return tokens
    }
}

class Parser {
    let tokens: [Token]
    var position = 0
    
    enum theError: Error {
        case unexpectedEndOfOutput
        case incorrectToken(Token)
    }
    
    init(tokens: [Token]) {
        self.tokens = tokens
    }
    
    func getNextToken() -> Token? {                     //peek() i advance() w jedną
        guard position < tokens.count else {
            return nil
        }
        let token = tokens[position]
        position += 1
        return token
    }
    
    func getNumber() throws -> Int {
        guard let token = getNextToken() else {
            throw theError.unexpectedEndOfOutput
        }
        switch token {
        case .Number(let value):
            return value
        case .Division:
            throw theError.incorrectToken(token)
        case .Multiplication:
            throw theError.incorrectToken(token)
        case .Plus:
            throw theError.incorrectToken(token)
        case .Minus:
            throw theError.incorrectToken(token)
//        case .OpeningBracket:
//            throw theError.incorrectToken(token)
//        case .ClosingBracket:
//            throw theError.incorrectToken(token)
        }
    }
    
    func parse() throws -> Int {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
//            case .OpeningBracket:
//                try getBrackets()
//            
//            case .ClosingBracket:
//                 try getBrackets()
//                
            case .Multiplication:
                let nextNumber = try getNumber()
                value *= nextNumber
                try anotherPlusMinus()
                
            case .Division:
                let nextNumber = try getNumber()
                value / nextNumber
                try anotherPlusMinus()
                
            case .Plus:
                let nextNumber = try getNumber()
                value += nextNumber
                
            case .Minus:
                let nextNumber = try getNumber()
                value -= nextNumber
                
            case .Number:
                throw theError.incorrectToken(token)
            }
        }
        return value
    }
    
    func anotherPlusMinus() throws {
        var value = try getNumber()
        
        while let token = getNextToken() {
            switch token {
            case .Number:
                let nextNumber = try getNumber()
                value += nextNumber
                switch token {
                case .Plus:
                    let nextNumber = try getNumber()
                    value += nextNumber
                case .Minus:
                    let nextNumber = try getNumber()
                    value -= nextNumber
                    
                default:
                   try parse()

                }
                
            default:
                try parse()
                
            }
        }
    }
    
}

func evaluate(input: String) {
    print("Calculation: \(input)")
    
    let lexer = Lexer(input: input)
    do {
        //wprowadza nowy zasięg, jeżeli jakieś wywołanie try spowoduje zgłoszenie błędu nastąpi wykonanie odpowiedniego bloku catch
        let tokens = try lexer.lex()
        print("Data output lexical analyzer: \(tokens)")
        
        let parser = Parser(tokens: tokens)
        let result = try parser.parse()
        print("Output parser: \(result)")
    }
    catch Lexer.theError.IncorrectCharacter(let character) {                        //zgłoszona wartość błędu jest przypisywana stłej error
        print("Data output contains invalid character: \(character)")
    }
    catch Parser.theError.unexpectedEndOfOutput {
        print("Unexpected end of data output during processing.")
    }
    catch Parser.theError.incorrectToken(let token) {
        print("Incorrect token during processing: \(token)")
    }
    catch {
        print("Following an unexpected error: \(error).")
    }
}

evaluate(input: "10 + 5 + 3")
evaluate(input: "10 + + 3")
evaluate(input: "10 - 5 + 3")
evaluate(input: "10 * 3 - 3 * 5")

 

komentarz 8 marca 2017 przez Piotrinformatyk Początkujący (340 p.)
Można poprosić o podpowiedź? :)
komentarz 8 marca 2017 przez Raymond.Z Obywatel (1,800 p.)
No widać ewidentnie, że throwuje Ci incorrectToken, kiedy jest minus... szukasz, gdzie to jest no i znajduje się to w funkcji getNumber... i tak dalej... dlaczego tam jest -? No kij wie... jest tam wywoływan metod getNextToken()... co się w niej dzieję takiego, że zwraca tego minusa... i myślisz i myślisz... aż przyniesie skutek, a jak nie ma to odpocznij godzine, dwie, dzień, tydzień.

Jutro zobaczę jak nie dasz rady, ale polecam samemu pogłówkować.
komentarz 8 marca 2017 przez Piotrinformatyk Początkujący (340 p.)
Próbuję :) Na dzisiaj dam sobie spokój już i jak wrócę z dni otwartych Politechniki Wrocławskiej (chcę zobaczyć oba wydziały gdzie jest informatyka w tym tygodniu) spróbuje znowu. Oki :)

Zaloguj lub zarejestruj się, aby odpowiedzieć na to pytanie.

Podobne pytania

0 głosów
1 odpowiedź 2,405 wizyt
pytanie zadane 29 sierpnia 2017 w C i C++ przez Mithriandil Początkujący (250 p.)
0 głosów
2 odpowiedzi 266 wizyt
pytanie zadane 25 stycznia 2017 w C i C++ przez Akiro Bywalec (2,910 p.)

93,005 zapytań

141,970 odpowiedzi

321,249 komentarzy

62,341 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 2

Można już zamawiać tom 2 książki "Wprowadzenie do bezpieczeństwa IT" - będzie to około 650 stron wiedzy o ITsec (17 rozdziałów, 14 autorów, kolorowy druk).

Planowana premiera: 30.09.2024, zaś planowana wysyłka nastąpi w drugim tygodniu października 2024.

Warto preorderować, tym bardziej, iż mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy dodatkowe 15% zniżki! Dziękujemy zaprzyjaźnionej ekipie Sekuraka za kod dla naszej Społeczności!

...