├── ParserCombinator ├── ParserCombinator.xcodeproj │ ├── project.pbxproj │ └── xcuserdata │ │ └── wenjin.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ └── ParserCombinator.xcscheme └── ParserCombinator │ ├── Interpreter.swift │ ├── Parser.swift │ ├── Syntax.swift │ └── main.swift └── README.md /ParserCombinator/ParserCombinator.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 7519A8D41C9AF1BB00C41F51 /* Interpreter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7519A8D31C9AF1BB00C41F51 /* Interpreter.swift */; }; 11 | 756E43971C99B3F0009F5C71 /* Parser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756E43961C99B3F0009F5C71 /* Parser.swift */; }; 12 | 756E43991C99B40E009F5C71 /* Syntax.swift in Sources */ = {isa = PBXBuildFile; fileRef = 756E43981C99B40E009F5C71 /* Syntax.swift */; }; 13 | BC27381F1C98F6C90094C799 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC27381E1C98F6C90094C799 /* main.swift */; }; 14 | /* End PBXBuildFile section */ 15 | 16 | /* Begin PBXCopyFilesBuildPhase section */ 17 | BC2738191C98F6C90094C799 /* CopyFiles */ = { 18 | isa = PBXCopyFilesBuildPhase; 19 | buildActionMask = 2147483647; 20 | dstPath = /usr/share/man/man1/; 21 | dstSubfolderSpec = 0; 22 | files = ( 23 | ); 24 | runOnlyForDeploymentPostprocessing = 1; 25 | }; 26 | /* End PBXCopyFilesBuildPhase section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 7519A8D31C9AF1BB00C41F51 /* Interpreter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Interpreter.swift; sourceTree = ""; }; 30 | 756E43961C99B3F0009F5C71 /* Parser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Parser.swift; sourceTree = ""; }; 31 | 756E43981C99B40E009F5C71 /* Syntax.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Syntax.swift; sourceTree = ""; }; 32 | BC27381B1C98F6C90094C799 /* ParserCombinator */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = ParserCombinator; sourceTree = BUILT_PRODUCTS_DIR; }; 33 | BC27381E1C98F6C90094C799 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 34 | /* End PBXFileReference section */ 35 | 36 | /* Begin PBXFrameworksBuildPhase section */ 37 | BC2738181C98F6C90094C799 /* Frameworks */ = { 38 | isa = PBXFrameworksBuildPhase; 39 | buildActionMask = 2147483647; 40 | files = ( 41 | ); 42 | runOnlyForDeploymentPostprocessing = 0; 43 | }; 44 | /* End PBXFrameworksBuildPhase section */ 45 | 46 | /* Begin PBXGroup section */ 47 | BC2738121C98F6C90094C799 = { 48 | isa = PBXGroup; 49 | children = ( 50 | BC27381D1C98F6C90094C799 /* ParserCombinator */, 51 | BC27381C1C98F6C90094C799 /* Products */, 52 | ); 53 | sourceTree = ""; 54 | }; 55 | BC27381C1C98F6C90094C799 /* Products */ = { 56 | isa = PBXGroup; 57 | children = ( 58 | BC27381B1C98F6C90094C799 /* ParserCombinator */, 59 | ); 60 | name = Products; 61 | sourceTree = ""; 62 | }; 63 | BC27381D1C98F6C90094C799 /* ParserCombinator */ = { 64 | isa = PBXGroup; 65 | children = ( 66 | BC27381E1C98F6C90094C799 /* main.swift */, 67 | 756E43961C99B3F0009F5C71 /* Parser.swift */, 68 | 756E43981C99B40E009F5C71 /* Syntax.swift */, 69 | 7519A8D31C9AF1BB00C41F51 /* Interpreter.swift */, 70 | ); 71 | path = ParserCombinator; 72 | sourceTree = ""; 73 | }; 74 | /* End PBXGroup section */ 75 | 76 | /* Begin PBXNativeTarget section */ 77 | BC27381A1C98F6C90094C799 /* ParserCombinator */ = { 78 | isa = PBXNativeTarget; 79 | buildConfigurationList = BC2738221C98F6C90094C799 /* Build configuration list for PBXNativeTarget "ParserCombinator" */; 80 | buildPhases = ( 81 | BC2738171C98F6C90094C799 /* Sources */, 82 | BC2738181C98F6C90094C799 /* Frameworks */, 83 | BC2738191C98F6C90094C799 /* CopyFiles */, 84 | ); 85 | buildRules = ( 86 | ); 87 | dependencies = ( 88 | ); 89 | name = ParserCombinator; 90 | productName = ParserCombinator; 91 | productReference = BC27381B1C98F6C90094C799 /* ParserCombinator */; 92 | productType = "com.apple.product-type.tool"; 93 | }; 94 | /* End PBXNativeTarget section */ 95 | 96 | /* Begin PBXProject section */ 97 | BC2738131C98F6C90094C799 /* Project object */ = { 98 | isa = PBXProject; 99 | attributes = { 100 | LastSwiftUpdateCheck = 0720; 101 | LastUpgradeCheck = 0720; 102 | ORGANIZATIONNAME = wenjin; 103 | TargetAttributes = { 104 | BC27381A1C98F6C90094C799 = { 105 | CreatedOnToolsVersion = 7.2; 106 | }; 107 | }; 108 | }; 109 | buildConfigurationList = BC2738161C98F6C90094C799 /* Build configuration list for PBXProject "ParserCombinator" */; 110 | compatibilityVersion = "Xcode 3.2"; 111 | developmentRegion = English; 112 | hasScannedForEncodings = 0; 113 | knownRegions = ( 114 | en, 115 | ); 116 | mainGroup = BC2738121C98F6C90094C799; 117 | productRefGroup = BC27381C1C98F6C90094C799 /* Products */; 118 | projectDirPath = ""; 119 | projectRoot = ""; 120 | targets = ( 121 | BC27381A1C98F6C90094C799 /* ParserCombinator */, 122 | ); 123 | }; 124 | /* End PBXProject section */ 125 | 126 | /* Begin PBXSourcesBuildPhase section */ 127 | BC2738171C98F6C90094C799 /* Sources */ = { 128 | isa = PBXSourcesBuildPhase; 129 | buildActionMask = 2147483647; 130 | files = ( 131 | 7519A8D41C9AF1BB00C41F51 /* Interpreter.swift in Sources */, 132 | 756E43991C99B40E009F5C71 /* Syntax.swift in Sources */, 133 | 756E43971C99B3F0009F5C71 /* Parser.swift in Sources */, 134 | BC27381F1C98F6C90094C799 /* main.swift in Sources */, 135 | ); 136 | runOnlyForDeploymentPostprocessing = 0; 137 | }; 138 | /* End PBXSourcesBuildPhase section */ 139 | 140 | /* Begin XCBuildConfiguration section */ 141 | BC2738201C98F6C90094C799 /* Debug */ = { 142 | isa = XCBuildConfiguration; 143 | buildSettings = { 144 | ALWAYS_SEARCH_USER_PATHS = NO; 145 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 146 | CLANG_CXX_LIBRARY = "libc++"; 147 | CLANG_ENABLE_MODULES = YES; 148 | CLANG_ENABLE_OBJC_ARC = YES; 149 | CLANG_WARN_BOOL_CONVERSION = YES; 150 | CLANG_WARN_CONSTANT_CONVERSION = YES; 151 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 152 | CLANG_WARN_EMPTY_BODY = YES; 153 | CLANG_WARN_ENUM_CONVERSION = YES; 154 | CLANG_WARN_INT_CONVERSION = YES; 155 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 156 | CLANG_WARN_UNREACHABLE_CODE = YES; 157 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 158 | CODE_SIGN_IDENTITY = "-"; 159 | COPY_PHASE_STRIP = NO; 160 | DEBUG_INFORMATION_FORMAT = dwarf; 161 | ENABLE_STRICT_OBJC_MSGSEND = YES; 162 | ENABLE_TESTABILITY = YES; 163 | GCC_C_LANGUAGE_STANDARD = gnu99; 164 | GCC_DYNAMIC_NO_PIC = NO; 165 | GCC_NO_COMMON_BLOCKS = YES; 166 | GCC_OPTIMIZATION_LEVEL = 0; 167 | GCC_PREPROCESSOR_DEFINITIONS = ( 168 | "DEBUG=1", 169 | "$(inherited)", 170 | ); 171 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 172 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 173 | GCC_WARN_UNDECLARED_SELECTOR = YES; 174 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 175 | GCC_WARN_UNUSED_FUNCTION = YES; 176 | GCC_WARN_UNUSED_VARIABLE = YES; 177 | MACOSX_DEPLOYMENT_TARGET = 10.11; 178 | MTL_ENABLE_DEBUG_INFO = YES; 179 | ONLY_ACTIVE_ARCH = YES; 180 | SDKROOT = macosx; 181 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 182 | }; 183 | name = Debug; 184 | }; 185 | BC2738211C98F6C90094C799 /* Release */ = { 186 | isa = XCBuildConfiguration; 187 | buildSettings = { 188 | ALWAYS_SEARCH_USER_PATHS = NO; 189 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 190 | CLANG_CXX_LIBRARY = "libc++"; 191 | CLANG_ENABLE_MODULES = YES; 192 | CLANG_ENABLE_OBJC_ARC = YES; 193 | CLANG_WARN_BOOL_CONVERSION = YES; 194 | CLANG_WARN_CONSTANT_CONVERSION = YES; 195 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 196 | CLANG_WARN_EMPTY_BODY = YES; 197 | CLANG_WARN_ENUM_CONVERSION = YES; 198 | CLANG_WARN_INT_CONVERSION = YES; 199 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 200 | CLANG_WARN_UNREACHABLE_CODE = YES; 201 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 202 | CODE_SIGN_IDENTITY = "-"; 203 | COPY_PHASE_STRIP = NO; 204 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 205 | ENABLE_NS_ASSERTIONS = NO; 206 | ENABLE_STRICT_OBJC_MSGSEND = YES; 207 | GCC_C_LANGUAGE_STANDARD = gnu99; 208 | GCC_NO_COMMON_BLOCKS = YES; 209 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 210 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 211 | GCC_WARN_UNDECLARED_SELECTOR = YES; 212 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 213 | GCC_WARN_UNUSED_FUNCTION = YES; 214 | GCC_WARN_UNUSED_VARIABLE = YES; 215 | MACOSX_DEPLOYMENT_TARGET = 10.11; 216 | MTL_ENABLE_DEBUG_INFO = NO; 217 | SDKROOT = macosx; 218 | }; 219 | name = Release; 220 | }; 221 | BC2738231C98F6C90094C799 /* Debug */ = { 222 | isa = XCBuildConfiguration; 223 | buildSettings = { 224 | PRODUCT_NAME = "$(TARGET_NAME)"; 225 | }; 226 | name = Debug; 227 | }; 228 | BC2738241C98F6C90094C799 /* Release */ = { 229 | isa = XCBuildConfiguration; 230 | buildSettings = { 231 | PRODUCT_NAME = "$(TARGET_NAME)"; 232 | }; 233 | name = Release; 234 | }; 235 | /* End XCBuildConfiguration section */ 236 | 237 | /* Begin XCConfigurationList section */ 238 | BC2738161C98F6C90094C799 /* Build configuration list for PBXProject "ParserCombinator" */ = { 239 | isa = XCConfigurationList; 240 | buildConfigurations = ( 241 | BC2738201C98F6C90094C799 /* Debug */, 242 | BC2738211C98F6C90094C799 /* Release */, 243 | ); 244 | defaultConfigurationIsVisible = 0; 245 | defaultConfigurationName = Release; 246 | }; 247 | BC2738221C98F6C90094C799 /* Build configuration list for PBXNativeTarget "ParserCombinator" */ = { 248 | isa = XCConfigurationList; 249 | buildConfigurations = ( 250 | BC2738231C98F6C90094C799 /* Debug */, 251 | BC2738241C98F6C90094C799 /* Release */, 252 | ); 253 | defaultConfigurationIsVisible = 0; 254 | defaultConfigurationName = Release; 255 | }; 256 | /* End XCConfigurationList section */ 257 | }; 258 | rootObject = BC2738131C98F6C90094C799 /* Project object */; 259 | } 260 | -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator.xcodeproj/xcuserdata/wenjin.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator.xcodeproj/xcuserdata/wenjin.xcuserdatad/xcschemes/ParserCombinator.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator/Interpreter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Interpreter.swift 3 | // ParserCombinator 4 | // 5 | // Created by aaaron7 on 16/3/17. 6 | // Copyright © 2016年 wenjin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | var varTable : [String:Int] = [:] 12 | 13 | func getvar(name : String) -> Int{ 14 | return varTable[name]! 15 | } 16 | 17 | func eval(exp : Exp) -> Int{ 18 | switch exp{ 19 | case let Exp.Constant(x): 20 | return x 21 | case let Exp.Var(name): 22 | return getvar(name) 23 | case let Exp.Add(exp1, exp2): 24 | return eval(exp1) + eval(exp2) 25 | case let Exp.Less(exp1, exp2): 26 | let a = eval(exp1) 27 | let b = eval(exp2) 28 | if a > b { 29 | return 0 30 | }else{ 31 | return 1 32 | } 33 | case let Exp.Times(exp1, exp2): 34 | return eval(exp1) * eval(exp2) 35 | default: 36 | return 0 37 | } 38 | } 39 | 40 | func interpreter(stmt : Com) { 41 | 42 | func loopHelper(cond : Exp,st : Com){ 43 | if eval(cond) == 0{ 44 | return 45 | }else{ 46 | interpreter(st) 47 | loopHelper(cond, st: st) 48 | } 49 | } 50 | 51 | switch stmt{ 52 | case let Com.Assign(name, exp1): 53 | varTable[name] = eval(exp1) 54 | case let Com.Seq(st1, st2): 55 | interpreter(st1) 56 | interpreter(st2) 57 | case let Com.While(cond, st1): 58 | loopHelper(cond, st: st1) 59 | case let Com.Print(exp): 60 | print(eval(exp)) 61 | default: 62 | return 63 | } 64 | } -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator/Parser.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Parser.swift 3 | // ParserCombinator 4 | // 5 | // Created by aaaron7 on 16/3/16. 6 | // Copyright © 2016年 wenjin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | struct Parser{ 12 | let p : String -> [(a,String)] 13 | 14 | } 15 | 16 | 17 | // Utility function 18 | func isSpace(c : Character) -> Bool{ 19 | let s = String(c) 20 | let result = s.rangeOfCharacterFromSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) 21 | return result != nil 22 | } 23 | 24 | func isDigit(c : Character) -> Bool{ 25 | let s = String(c) 26 | return Int(s) != nil 27 | } 28 | 29 | func isAlpha(c : Character) -> Bool{ 30 | if c >= "a" && c <= "z" || c >= "A" && c <= "Z"{ 31 | return true 32 | }else{ 33 | return false 34 | } 35 | } 36 | 37 | //MARK: Basic Element 38 | 39 | infix operator >>= {associativity left precedence 150} 40 | 41 | func >>= (p : Parser, f : a->Parser) -> Parser{ 42 | return Parser { cs in 43 | let p1 = parse(p, input: cs) 44 | guard p1.count>0 else{ 45 | return [] 46 | } 47 | let p = p1[0] 48 | 49 | let p2 = parse(f(p.0), input: p.1) 50 | guard p2.count > 0 else{ 51 | return [] 52 | } 53 | 54 | return p2 55 | } 56 | } 57 | 58 | func mzero()->Parser{ 59 | return Parser { xs in [] } 60 | } 61 | 62 | func pure( item : a) -> Parser{ 63 | return Parser { cs in [(item,cs)] } 64 | } 65 | 66 | func satisfy(condition : Character -> Bool) -> Parser{ 67 | return Parser { x in 68 | guard let head = x.characters.first where condition(head) else{ 69 | return [] 70 | } 71 | return [(head,String(x.characters.dropFirst()))] 72 | } 73 | } 74 | 75 | 76 | 77 | //MARK: combinator 78 | 79 | infix operator +++ {associativity left precedence 130} 80 | func +++ (l : Parser, r:Parser) -> Parser { 81 | return Parser { x in 82 | let result = l.p(x) 83 | if result.count > 0{ 84 | return result 85 | }else{ 86 | return r.p(x) 87 | } 88 | } 89 | } 90 | 91 | 92 | 93 | func many(p: Parser) -> Parser<[a]>{ 94 | return many1(p) +++ pure([]) 95 | } 96 | 97 | func many1(p : Parser) -> Parser<[a]>{ 98 | return p >>= { x in 99 | many(p) >>= { xs in 100 | pure([x] + xs) 101 | } 102 | } 103 | } 104 | 105 | func parserChar(c : Character) -> Parser{ 106 | return Parser { x in 107 | guard let head = x.characters.first where head == c else{ 108 | return [] 109 | } 110 | return [(c,String(x.characters.dropFirst()))] 111 | } 112 | } 113 | 114 | func parserCharA() -> Parser{ 115 | let parser = Parser { x in 116 | guard let head = x.characters.first where head == "a" else{ 117 | return [] 118 | } 119 | return [("a",String(x.characters.dropFirst()))] 120 | } 121 | 122 | return parser 123 | } 124 | 125 | func parse(parser : Parser , input: String) -> [(a,String)]{ 126 | var result :[(a,String)] = [] 127 | for (x,s) in parser.p(input){ 128 | result.append((x,s)) 129 | } 130 | return result 131 | } 132 | 133 | 134 | 135 | //MARK: handle string 136 | func string(str : String) -> Parser{ 137 | guard str != "" else{ 138 | return pure("") 139 | } 140 | 141 | let head = str.characters.first! 142 | return parserChar(head) >>= { c in 143 | string(String(str.characters.dropFirst())) >>= { cs in 144 | let result = [c] + cs.characters 145 | return pure(String(result)) 146 | } 147 | } 148 | } 149 | 150 | func space()->Parser{ 151 | return many(satisfy(isSpace)) >>= { x in pure("") } 152 | } 153 | 154 | func symbol(sym : String) -> Parser{ 155 | return string(sym) >>= { sym in 156 | space() >>= { _ in 157 | pure(sym) 158 | } 159 | } 160 | } 161 | 162 | 163 | 164 | 165 | //MARK: process numbers 166 | func digit() -> Parser{ 167 | return satisfy(isDigit) >>= { x in 168 | pure(Exp.Constant(Int(String(x))!)) 169 | } 170 | } 171 | 172 | func number() -> Parser{ 173 | return many1(digit()) >>= { cs in 174 | space() >>= { _ in 175 | let sum = cs.reduce(Exp.Constant(0), combine: { (exp1 , exp2 ) -> Exp in 176 | return Exp.Constant((exp1.pConstant * 10 + exp2.pConstant)) 177 | }) 178 | return pure(sum) 179 | } 180 | } 181 | } 182 | 183 | 184 | //MARK: handle expression 185 | 186 | func identifier() -> Parser{ 187 | return satisfy(isAlpha) >>= { c in 188 | many(satisfy({ (c) -> Bool in isAlpha(c) || isDigit(c) })) >>= { cs in 189 | space() >>= { _ in 190 | pure(String([c] + cs)) 191 | } 192 | } 193 | } 194 | } 195 | 196 | func variables() -> Parser{ 197 | return identifier() >>= { name in 198 | pure(Exp.Var(name)) 199 | } 200 | } 201 | 202 | func factor()->Parser{ 203 | return variables() +++ number() +++ (symbol("(") >>= { c in 204 | expr() >>= { n in 205 | symbol(")") >>= { _ in 206 | pure(n) 207 | } 208 | } 209 | }) 210 | } 211 | 212 | func oper()->Parser{ 213 | return ["=","+","-","*","/"].map({ (x:String) -> Parser in 214 | parserChar(x.characters[x.characters.startIndex]) 215 | }).reduce(mzero()) { (x, y) -> Parser in 216 | x +++ y 217 | } 218 | } 219 | 220 | func op()->Parser{ 221 | return many1(oper()) >>= { xs in 222 | return pure(String(xs)) 223 | } 224 | } 225 | 226 | infix operator >=< {associativity left precedence 130} 227 | 228 | func >=<(p : Parser, op : Parser<(a,a) -> a>) -> Parser{ 229 | return p >>= { x in 230 | rest(p, x: x, op: op) 231 | } 232 | } 233 | 234 | func rest(p : Parser, x : a, op : Parser<(a,a) -> a>) -> Parser{ 235 | return op >>= { f in 236 | p >>= { y in 237 | rest(p, x: f(x,y), op: op) 238 | } 239 | } +++ pure(x) 240 | } 241 | 242 | func addop() -> Parser<(Exp,Exp)->Exp>{ 243 | return symbol("+") >>= { _ in 244 | pure({(x,y) -> Exp in 245 | Exp.Add(x, y) 246 | }) 247 | } 248 | } 249 | 250 | func mulop() -> Parser<(Exp,Exp) -> Exp>{ 251 | return symbol("*") >>= { _ in 252 | pure({ (x,y) -> Exp in 253 | Exp.Times(x, y) 254 | }) 255 | 256 | } 257 | } 258 | 259 | func relop() -> Parser<(Exp,Exp) -> Exp>{ 260 | return symbol("<") >>= { _ in 261 | pure({(x,y) -> Exp in 262 | Exp.Less(x, y) 263 | }) 264 | } 265 | } 266 | 267 | func expr() -> Parser{ 268 | return term() >=< addop() 269 | } 270 | 271 | func rexp() -> Parser{ 272 | return expr() >=< relop() 273 | } 274 | 275 | func term() -> Parser{ 276 | return factor() >=< mulop() 277 | } 278 | 279 | 280 | //MARK: handle statement 281 | 282 | func assign() -> Parser{ 283 | return identifier() >>= { name in 284 | symbol("=") >>= { _ in 285 | expr() >>= { exp in 286 | pure(Com.Assign(name, exp)) 287 | } 288 | } 289 | } 290 | } 291 | 292 | func com() -> Parser{ 293 | return seq() +++ com1() 294 | } 295 | 296 | func com1() -> Parser{ 297 | return assign() +++ whileloop() +++ print() 298 | } 299 | 300 | 301 | func whileloop() -> Parser{ 302 | return symbol("while") >>= { _ in 303 | rexp() >>= { cond in 304 | symbol("{") >>= { _ in 305 | com() >>= { stmt in 306 | symbol("}") >>= { _ in 307 | pure(Com.While(cond, stmt)) 308 | } 309 | } 310 | } 311 | } 312 | } 313 | } 314 | 315 | 316 | func print() -> Parser{ 317 | return symbol("print") >>= { _ in 318 | expr() >>= { exp in 319 | pure(Com.Print(exp)) 320 | } 321 | } 322 | } 323 | 324 | func seq() -> Parser{ 325 | return com1() >>= { stmt in 326 | com() >>= { stmt2 in 327 | pure(Com.Seq(stmt, stmt2)) 328 | } 329 | } 330 | } -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator/Syntax.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Syntax.swift 3 | // ParserCombinator 4 | // 5 | // Created by aaaron7 on 16/3/16. 6 | // Copyright © 2016年 wenjin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | 13 | indirect enum Exp{ 14 | case Constant (Int) 15 | case Var (String) 16 | case Add (Exp,Exp) 17 | case Times (Exp,Exp) 18 | case Equal (Exp,Exp) 19 | case Greater (Exp,Exp) 20 | case Less (Exp,Exp) 21 | 22 | var pConstant : Int { 23 | switch self{ 24 | case let .Constant(x): 25 | return x 26 | default: 27 | return 0 28 | } 29 | } 30 | } 31 | 32 | indirect enum Com{ 33 | case Assign (String,Exp) 34 | case Seq (Com,Com) 35 | case Cond (Exp,Com,Com) 36 | case While (Exp,Com) 37 | case Print (Exp) 38 | } -------------------------------------------------------------------------------- /ParserCombinator/ParserCombinator/main.swift: -------------------------------------------------------------------------------- 1 | // 2 | // main.swift 3 | // ParserCombinator 4 | // 5 | // Created by wenjin on 3/16/16. 6 | // Copyright © 2016 wenjin. All rights reserved. 7 | // 8 | 9 | import Foundation 10 | 11 | 12 | 13 | 14 | print("Hello, World!") 15 | 16 | let a:String = "a" 17 | let b: String = " 12345 + 42 * 5+(12 + 4) abcergebac" 18 | let c: String = " i = 0 print i sum = 0 while i<100 {sum=sum+i i=i+1 } print sum" 19 | let d : String = "dd= 12*3 * (12+1) print dd" 20 | 21 | let ast = (space() >>= {_ in com()}).p(c)[0].0 22 | interpreter(ast) 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Monadic Parser Combinator written in swift 2 | A simple haskell-style monadic combinator-based parser written in Swift. 3 | 4 | A minium interpreter is also implemented in this tiny project. 5 | 6 | ## Try 7 | 8 | ```swift 9 | let c: String = " i = 0 print i sum = 0 while i<100 {sum=sum+i i=i+1 } print sum" 10 | let ast = (space() >>= {_ in com()}).p(c)[0].0 11 | interpreter(ast) 12 | ``` 13 | 14 | ## Features: 15 | 16 | - Pure parser process without any side effects. 17 | - Implemented with Haskell-like monad based operator `return`,`>>=`, and `zero`. 18 | - Easy to scale up to deal with complex language parse and interprete. 19 | - Concise code which extremely easy to understand and modify. 20 | 21 | 22 | ## Drawbacks: 23 | 24 | - In order to keep it simple and stupid, there are lots of string construct operation, which has pool performance. 25 | - Same reason as above, there are lots of direct array construct/deconstruct operation, which has pool performance, consider replace it with swift lazy evaluation feature such as AnyGenerator/AnySequence if u want imporve it. 26 | --------------------------------------------------------------------------------