fork download
  1. enum Token {
  2. //rodzaje tokenów
  3. case Number(Int)
  4. case Plus
  5. case Minus
  6. case Division
  7. case Multiplication
  8. case OpeningBracket
  9. case ClosingBracket
  10. }
  11.  
  12. //analizator leksykalny - budowa
  13. class Lexer {
  14. //String.CharacterView ma właściwości startIndex i endIndex
  15. let input: String.CharacterView
  16. var position: String.CharacterView.Index
  17.  
  18. enum theError: Error { //zgłasza błąd
  19. case IncorrectCharacter(Character)
  20. }
  21.  
  22. init(input: String) {
  23. self.input = input.characters //inicjalizujemy właściwośc wraz z danymi wejściowymi,ma wartość wskazującą początek tych danych wejściowych
  24. self.position = self.input.startIndex
  25. }
  26.  
  27. //może być wywołana zawsze
  28. func peek() -> Character? { //spradzenie kolejnego znaku w danych wejściowych. Wskazuje analizatorowi, że zostały przetworzone wszystkie dane wejściowe
  29. guard position < input.endIndex else {
  30. return nil
  31. }
  32. return input[position]
  33. }
  34.  
  35. //IMPLEMENTACJA ALGORYTMU ANALIZATORA
  36.  
  37. //można wywołać tylko wtedy, gdy aktualne położenie nie jest końcem danych wejściowych
  38. func advance() { //przejście do kolejnego znaku
  39. assert(position < input.endIndex, "You can not go beyond the data input") //gdy false - wpadnięcie w pułapkę i wyświetlenie komunikatu
  40. position = input.index(after: position)
  41. }
  42. func getNumber () -> Int { //wyodrębnia liczby całkowite z danych wejściowych
  43. var value = 0
  44.  
  45. while let nextCharacter = peek() {
  46. switch nextCharacter {
  47. case "0"..."9":
  48. let digitValue = Int(String(nextCharacter))!
  49. value = 10*value + digitValue
  50. advance()
  51. default:
  52. return value
  53. }
  54. }
  55. return value
  56. }
  57. func lex() throws -> [Token] { //throws, czyli funkcja/metoda może wygenerować błąd
  58. var tokens = [Token]() //tablica z tokenami
  59.  
  60. while let nextCharacter = peek() { //przetworzenie wszystkich danych wejściowych
  61. switch nextCharacter {
  62. case "(":
  63. tokens.append(.OpeningBracket)
  64. advance()
  65.  
  66. case ")":
  67. tokens.append(.ClosingBracket)
  68. case "0"..."9":
  69. let value = getNumber()
  70. tokens.append(.Number(value))
  71.  
  72. case "*":
  73. tokens.append(.Multiplication)
  74. advance()
  75.  
  76. case "/":
  77. tokens.append(.Multiplication)
  78. advance()
  79.  
  80. case "+":
  81. tokens.append(.Plus)
  82. advance()
  83.  
  84. case "-":
  85. tokens.append(.Minus)
  86. advance()
  87.  
  88. case " ":
  89. advance()
  90.  
  91. default:
  92. throw theError.IncorrectCharacter(nextCharacter) //throws zatrzymuje funkcje i przekazuje błąd do komponentu wywołąjącego dany błąd zgodnego z protokołem Error
  93. }
  94. }
  95. return tokens
  96. }
  97. }
  98.  
  99. class Parser {
  100. let tokens: [Token]
  101. var position = 0
  102.  
  103. enum theError: Error {
  104. case unexpectedEndOfOutput
  105. case incorrectToken(Token)
  106. }
  107.  
  108. init(tokens: [Token]) {
  109. self.tokens = tokens
  110. }
  111.  
  112. func getNextToken() -> Token? { //peek() i advance() w jedną
  113. guard position < tokens.count else {
  114. return nil
  115. }
  116. let token = tokens[position]
  117. position += 1
  118. return token
  119. }
  120.  
  121. func getNumber() throws -> Int {
  122. guard let token = getNextToken() else {
  123. throw theError.unexpectedEndOfOutput
  124. }
  125. switch token {
  126. case .Number(let value):
  127. return value
  128. case .Division:
  129. throw theError.incorrectToken(token)
  130. case .Multiplication:
  131. throw theError.incorrectToken(token)
  132. case .Plus:
  133. throw theError.incorrectToken(token)
  134. case .Minus:
  135. throw theError.incorrectToken(token)
  136. case .OpeningBracket:
  137. throw theError.incorrectToken(token)
  138. case .ClosingBracket:
  139. throw theError.incorrectToken(token)
  140. }
  141. }
  142.  
  143. func parse() throws -> Int {
  144. var value = try getNumber()
  145.  
  146. while let token = getNextToken() {
  147. switch token {
  148. case .OpeningBracket:
  149. try getBrackets()
  150.  
  151. case .ClosingBracket:
  152. try getNumber()
  153.  
  154. case .Multiplication:
  155. let nextNumber = try getNumber()
  156. value *= nextNumber
  157.  
  158. case .Division:
  159. let nextNumber = try getNumber()
  160. value / nextNumber
  161.  
  162. case .Plus:
  163. let nextNumber = try getNumber()
  164. value += nextNumber
  165.  
  166. case .Minus:
  167. let nextNumber = try getNumber()
  168. value -= nextNumber
  169.  
  170. case .Number:
  171. throw theError.incorrectToken(token)
  172. }
  173. }
  174. return value
  175. }
  176.  
  177. func getBrackets() throws {
  178. var value = try getNumber()
  179.  
  180. while let token = getNextToken() {
  181. switch token {
  182. case .Plus:
  183. let nextNumber = try getNumber()
  184. value += nextNumber
  185. case .Minus:
  186. let nextNumber = try getNumber()
  187. value -= nextNumber
  188. }
  189. }
  190.  
  191. }
  192.  
  193. func evaluate(input: String) {
  194. print("Calculation: \(input)")
  195.  
  196. let lexer = Lexer(input: input)
  197. do {
  198. //wprowadza nowy zasięg, jeżeli jakieś wywołanie try spowoduje zgłoszenie błędu nastąpi wykonanie odpowiedniego bloku catch
  199. let tokens = try lexer.lex()
  200. print("Data output lexical analyzer: \(tokens)")
  201.  
  202. let parser = Parser(tokens: tokens)
  203. let result = try parser.parse()
  204. print("Output parser: \(result)")
  205. }
  206. catch Lexer.theError.IncorrectCharacter(let character) { //zgłoszona wartość błędu jest przypisywana stłej error
  207. print("Data output contains invalid character: \(character)")
  208. }
  209. catch Parser.theError.unexpectedEndOfOutput {
  210. print("Unexpected end of data output during processing.")
  211. }
  212. catch Parser.theError.incorrectToken(let token) {
  213. print("Incorrect token during processing: \(token)")
  214. }
  215. catch {
  216. print("Following an unexpected error: \(error).")
  217. }
  218. }
  219.  
  220. evaluate(input: "10 + 5 + 3")
  221. evaluate(input: "10 + + 3")
  222. evaluate(input: "10 - 5 + 3")
  223. evaluate(input: "(10 * 3) - (3 * 5)")
Compilation error #stdin compilation error #stdout 0s 0KB
stdin
Standard input is empty
compilation info
prog.swift:220:1: error: expected declaration
evaluate(input: "10 + 5 + 3")
^
prog.swift:99:7: note: in declaration of 'Parser'
class Parser {
      ^
prog.swift:223:38: error: expected '}' in class
evaluate(input: "(10 * 3) - (3 * 5)")
                                     ^
prog.swift:99:14: note: to match this opening '{'
class Parser {
             ^
prog.swift:152:21: warning: result of call to 'getNumber()' is unused
                try getNumber()
                    ^        ~~
prog.swift:160:23: warning: result of operator '/' is unused
                value / nextNumber
                ~~~~~ ^ ~~~~~~~~~~
<unknown>:0: error: error opening input file 'prog.o' (No such file or directory
)
clang: error: no such file or directory: 'prog.o'
clang: error: no such file or directory: '@prog.autolink'
stdout
Standard output is empty