├── .gitignore ├── CompanionGuides └── CoreParse-template.md ├── CoreParse.xcodeproj ├── project.pbxproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── CoreParse.xccheckout ├── CoreParse ├── Built In Parsers │ ├── CPJSONParser.h │ └── CPJSONParser.m ├── CPSenTestKitAssertions.h ├── CoreParse-Info.plist ├── CoreParse-Prefix.pch ├── CoreParse.h ├── Grammar │ ├── CPGrammar.h │ ├── CPGrammar.m │ ├── CPGrammarInternal.h │ ├── CPGrammarInternal.m │ ├── CPGrammarPrivate.h │ ├── CPGrammarPrivate.m │ ├── CPGrammarSymbol.h │ ├── CPGrammarSymbol.m │ ├── CPRHSItem+Private.h │ ├── CPRHSItem.h │ ├── CPRHSItem.m │ ├── CPRHSItemResult.h │ ├── CPRHSItemResult.m │ ├── CPRule+Internal.h │ ├── CPRule.h │ └── CPRule.m ├── NSArray+Functional.h ├── NSArray+Functional.m ├── NSSetFunctional.h ├── NSSetFunctional.m ├── Parsers │ ├── CPParser.h │ ├── CPParser.m │ ├── CPShiftReduceParser.h │ ├── CPShiftReduceParser.m │ ├── CPShiftReduceParsers │ │ ├── CPItem.h │ │ ├── CPItem.m │ │ ├── CPLALR1Parser.h │ │ ├── CPLALR1Parser.m │ │ ├── CPLR1Item.h │ │ ├── CPLR1Item.m │ │ ├── CPLR1Parser.h │ │ ├── CPLR1Parser.m │ │ ├── CPSLRParser.h │ │ ├── CPSLRParser.m │ │ ├── CPShiftAction.h │ │ ├── CPShiftAction.m │ │ ├── CPShiftReduceAction.h │ │ ├── CPShiftReduceAction.m │ │ ├── CPShiftReduceActionTable.h │ │ ├── CPShiftReduceActionTable.m │ │ ├── CPShiftReduceGotoTable.h │ │ ├── CPShiftReduceGotoTable.m │ │ ├── CPShiftReduceParserProtectedMethods.h │ │ ├── CPShiftReduceState.h │ │ └── CPShiftReduceState.m │ └── Error Recovery │ │ ├── CPRecoveryAction.h │ │ └── CPRecoveryAction.m ├── Syntax Tree │ ├── CPSyntaxTree.h │ └── CPSyntaxTree.m ├── Tokenisation │ ├── CPTokenStream.h │ ├── CPTokenStream.m │ ├── CPTokeniser.h │ ├── CPTokeniser.m │ ├── Token Recognisers │ │ ├── CPIdentifierRecogniser.h │ │ ├── CPIdentifierRecogniser.m │ │ ├── CPKeywordRecogniser.h │ │ ├── CPKeywordRecogniser.m │ │ ├── CPNumberRecogniser.h │ │ ├── CPNumberRecogniser.m │ │ ├── CPQuotedRecogniser.h │ │ ├── CPQuotedRecogniser.m │ │ ├── CPRegexpRecogniser.h │ │ ├── CPRegexpRecogniser.m │ │ ├── CPTokenRecogniser.h │ │ ├── CPWhiteSpaceRecogniser.h │ │ └── CPWhiteSpaceRecogniser.m │ └── Token Types │ │ ├── CPEOFToken.h │ │ ├── CPEOFToken.m │ │ ├── CPErrorToken.h │ │ ├── CPErrorToken.m │ │ ├── CPIdentifierToken.h │ │ ├── CPIdentifierToken.m │ │ ├── CPKeywordToken.h │ │ ├── CPKeywordToken.m │ │ ├── CPNumberToken.h │ │ ├── CPNumberToken.m │ │ ├── CPQuotedToken.h │ │ ├── CPQuotedToken.m │ │ ├── CPToken.h │ │ ├── CPToken.m │ │ ├── CPWhiteSpaceToken.h │ │ └── CPWhiteSpaceToken.m └── en.lproj │ └── InfoPlist.strings ├── CoreParseTests ├── CPRegexpRecogniserTest.m ├── CPSTAssertionsTests.h ├── CPSTAssertionsTests.m ├── CPTestErrorEvaluatorDelegate.h ├── CPTestErrorEvaluatorDelegate.m ├── CPTestErrorHandlingDelegate.h ├── CPTestErrorHandlingDelegate.m ├── CPTestEvaluatorDelegate.h ├── CPTestEvaluatorDelegate.m ├── CPTestMapCSSTokenisingDelegate.h ├── CPTestMapCSSTokenisingDelegate.m ├── CPTestWhiteSpaceIgnoringDelegate.h ├── CPTestWhiteSpaceIgnoringDelegate.m ├── CPWillFinishDelegateTest.m ├── CoreParseTests-Info.plist ├── CoreParseTests-Prefix.pch ├── CoreParseTests.m ├── Expression.h ├── Expression.m ├── Expression2.h ├── Expression2.m ├── RuleBase.h ├── RuleBase.m ├── Term.h ├── Term.m ├── Term2.h ├── Term2.m └── en.lproj │ └── InfoPlist.strings ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | /.DS_Store 2 | 3 | /CoreParse.xcodeproj/xcuserdata/ 4 | 5 | /CoreParse.xcodeproj/project.xcworkspace/xcuserdata/ 6 | -------------------------------------------------------------------------------- /CompanionGuides/CoreParse-template.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/beelsebob/CoreParse/9ae4bb59a912d73c4af304d9109a6d9abbb75065/CompanionGuides/CoreParse-template.md -------------------------------------------------------------------------------- /CoreParse.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /CoreParse.xcodeproj/project.xcworkspace/xcshareddata/CoreParse.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 5FCEC138-BD89-4E15-965B-903D778E9B1D 9 | IDESourceControlProjectName 10 | CoreParse 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 933D72C4-BB34-468B-8A2A-F9A5F6A06A65 14 | https://github.com/beelsebob/CoreParse.git 15 | 16 | IDESourceControlProjectPath 17 | CoreParse.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 933D72C4-BB34-468B-8A2A-F9A5F6A06A65 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | ssh://github.com/siuying/CSSSelectorConverter.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 933D72C4-BB34-468B-8A2A-F9A5F6A06A65 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 933D72C4-BB34-468B-8A2A-F9A5F6A06A65 36 | IDESourceControlWCCName 37 | CoreParse 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /CoreParse/Built In Parsers/CPJSONParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPJSONParser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 29/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * The CPJSONParser class is a demonstration of CoreParse. 13 | * 14 | * The parser deals with all JSON except for unicode encoded characters. The reason for not dealing with this corner case is that this parser is simply to demonstrate how to use CoreParse, and 15 | * the code needed to process unicode characters is non-trivial, and not particularly relevant to the demonstration. 16 | */ 17 | @interface CPJSONParser : NSObject 18 | 19 | /** 20 | * Parses a JSON string and returns a standard objective-c data structure reflecting it: 21 | * 22 | * JSON numbers and booleans are returned as NSNumbers; JSON strings as NSStrings; `null` as an NSNull object; JSON arrays are returned as NSArrays; finally JSON objects are returned as NSDictionarys. 23 | * 24 | * @param json The JSON string to parse. 25 | */ 26 | - (id)parse:(NSString *)json; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CoreParse/Built In Parsers/CPJSONParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPJSONParser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 29/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPJSONParser.h" 10 | 11 | #import "CPTokeniser.h" 12 | #import "CPSLRParser.h" 13 | #import "CPKeywordRecogniser.h" 14 | #import "CPNumberRecogniser.h" 15 | #import "CPWhiteSpaceRecogniser.h" 16 | #import "CPQuotedRecogniser.h" 17 | 18 | #import "CPKeywordToken.h" 19 | #import "CPNumberToken.h" 20 | #import "CPQuotedToken.h" 21 | #import "CPWhiteSpaceToken.h" 22 | 23 | @interface CPJSONParser () 24 | @end 25 | 26 | @implementation CPJSONParser 27 | { 28 | CPTokeniser *jsonTokeniser; 29 | CPParser *jsonParser; 30 | } 31 | 32 | - (id)init 33 | { 34 | self = [super init]; 35 | 36 | if (nil != self) 37 | { 38 | jsonTokeniser = [[CPTokeniser alloc] init]; 39 | CPQuotedRecogniser *stringRecogniser = [CPQuotedRecogniser quotedRecogniserWithStartQuote:@"\"" endQuote:@"\"" escapeSequence:@"\\" name:@"String"]; 40 | [stringRecogniser setEscapeReplacer:^ NSString * (NSString *str, NSUInteger *loc) 41 | { 42 | if ([str length] > *loc) 43 | { 44 | switch ([str characterAtIndex:*loc]) 45 | { 46 | case 'b': 47 | *loc = *loc + 1; 48 | return @"\b"; 49 | case 'f': 50 | *loc = *loc + 1; 51 | return @"\f"; 52 | case 'n': 53 | *loc = *loc + 1; 54 | return @"\n"; 55 | case 'r': 56 | *loc = *loc + 1; 57 | return @"\r"; 58 | case 't': 59 | *loc = *loc + 1; 60 | return @"\t"; 61 | default: 62 | break; 63 | } 64 | } 65 | return nil; 66 | }]; 67 | 68 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"{"]]; 69 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"}"]]; 70 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"["]]; 71 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"]"]]; 72 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@":"]]; 73 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@","]]; 74 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"true"]]; 75 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"false"]]; 76 | [jsonTokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"null"]]; 77 | [jsonTokeniser addTokenRecogniser:[CPNumberRecogniser numberRecogniser]]; 78 | [jsonTokeniser addTokenRecogniser:stringRecogniser]; 79 | [jsonTokeniser addTokenRecogniser:[CPWhiteSpaceRecogniser whiteSpaceRecogniser]]; 80 | [jsonTokeniser setDelegate:self]; 81 | 82 | CPGrammar *jsonGrammar = [CPGrammar grammarWithStart:@"value" 83 | backusNaurForm: 84 | @"0 value ::= 'String';" 85 | @"1 value ::= 'Number';" 86 | @"2 value ::= ;" 87 | @"3 value ::= ;" 88 | @"4 value ::= ;" 89 | @"5 value ::= 'null';" 90 | @"6 object ::= '{' '}';" 91 | @"7 object ::= '{' '}';" 92 | @"8 members ::= ;" 93 | @"9 members ::= ',' ;" 94 | @"10 pair ::= 'String' ':' ;" 95 | @"11 array ::= '[' ']';" 96 | @"12 array ::= '[' ']';" 97 | @"13 elements ::= ;" 98 | @"14 elements ::= ',' ;" 99 | @"15 boolean ::= 'true';" 100 | @"16 boolean ::= 'false';" 101 | error:NULL]; 102 | jsonParser = [[CPSLRParser parserWithGrammar:jsonGrammar] retain]; 103 | [jsonParser setDelegate:self]; 104 | } 105 | 106 | return self; 107 | } 108 | 109 | - (void)dealloc 110 | { 111 | [jsonTokeniser release]; 112 | [jsonParser release]; 113 | 114 | [super dealloc]; 115 | } 116 | 117 | - (id)parse:(NSString *)json 118 | { 119 | CPTokenStream *tokenStream = [jsonTokeniser tokenise:json]; 120 | return [jsonParser parse:tokenStream]; 121 | } 122 | 123 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token 124 | { 125 | return YES; 126 | } 127 | 128 | - (NSArray *)tokeniser:(CPTokeniser *)tokeniser willProduceToken:(CPToken *)token 129 | { 130 | if ([token isWhiteSpaceToken]) 131 | { 132 | return [NSArray array]; 133 | } 134 | return [NSArray arrayWithObject:token]; 135 | } 136 | 137 | - (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree 138 | { 139 | NSArray *children = [syntaxTree children]; 140 | switch ([[syntaxTree rule] tag]) 141 | { 142 | case 0: 143 | return [(CPQuotedToken *)[children objectAtIndex:0] content]; 144 | case 1: 145 | return [(CPNumberToken *)[children objectAtIndex:0] numberValue]; 146 | case 2: 147 | case 3: 148 | case 4: 149 | return [children objectAtIndex:0]; 150 | case 5: 151 | return [NSNull null]; 152 | case 6: 153 | return [NSDictionary dictionary]; 154 | case 7: 155 | return [children objectAtIndex:1]; 156 | case 8: 157 | { 158 | NSDictionary *p = [children objectAtIndex:0]; 159 | return [NSMutableDictionary dictionaryWithObject:[p objectForKey:@"v"] forKey:[p objectForKey:@"k"]]; 160 | } 161 | case 9: 162 | { 163 | NSDictionary *p = [children objectAtIndex:0]; 164 | NSMutableDictionary *ms = [children objectAtIndex:2]; 165 | [ms setObject:[p objectForKey:@"v"] forKey:[p objectForKey:@"k"]]; 166 | return ms; 167 | } 168 | case 10: 169 | { 170 | return [NSDictionary dictionaryWithObjectsAndKeys: 171 | [(CPQuotedToken *)[children objectAtIndex:0] content], @"k", 172 | [children objectAtIndex:2], @"v", 173 | nil]; 174 | } 175 | case 11: 176 | return [NSArray array]; 177 | case 12: 178 | return [children objectAtIndex:1]; 179 | case 13: 180 | return [NSMutableArray arrayWithObject:[children objectAtIndex:0]]; 181 | case 14: 182 | { 183 | NSMutableArray *es = [children objectAtIndex:2]; 184 | [es insertObject:[children objectAtIndex:0] atIndex:0]; 185 | return es; 186 | } 187 | case 15: 188 | return [NSNumber numberWithBool:YES]; 189 | case 16: 190 | return [NSNumber numberWithBool:NO]; 191 | } 192 | return nil; 193 | } 194 | 195 | @end 196 | -------------------------------------------------------------------------------- /CoreParse/CPSenTestKitAssertions.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPSenTestKitAssertions.h 3 | // CoreParse 4 | // 5 | // Created by Christopher Miller on 5/18/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | #pragma mark General Assertions 13 | 14 | /* 15 | * Note that you can have this fail under CocoaPods. All you need to do is remove the "libpods.a" item from the unit testing target's linked libraries. This removes duplicate symbols which kludge the test. 16 | */ 17 | #define CPSTAssertKindOfClass(obj, cls) \ 18 | do { \ 19 | id _obj = obj; \ 20 | XCTAssertTrue([_obj isKindOfClass:[cls class]], @"Expecting a kind of class %@; got class %@ from object %@.", NSStringFromClass([_obj class]), NSStringFromClass([cls class]), _obj); \ 21 | } while (0) 22 | #define _CPSTAssertKindOfClass_Unsafe(obj, cls) XCTAssertTrue([obj isKindOfClass:[cls class]], @"Expecting a kind of class %@; got class %@ from object %@.", NSStringFromClass([obj class]), NSStringFromClass([cls class]), obj); 23 | 24 | #pragma mark Token Assertions 25 | 26 | #define CPSTAssertKeywordEquals(token, expectation) \ 27 | do { \ 28 | CPKeywordToken * t = (CPKeywordToken *)token; /* this escapes the potential multiple invocations of popToken */ \ 29 | _CPSTAssertKindOfClass_Unsafe(t, CPKeywordToken); \ 30 | XCTAssertEqualObjects([t keyword], expectation, @"Keyword doesn't match expectation."); \ 31 | } while (0) 32 | #define CPSTAssertIdentifierEquals(token, expectation) \ 33 | do { \ 34 | CPIdentifierToken * _t = (CPIdentifierToken *)token; \ 35 | _CPSTAssertKindOfClass_Unsafe(_t, CPIdentifierToken); \ 36 | XCTAssertEqualObjects([_t identifier], expectation, @"Identifier doesn't match expectation."); \ 37 | } while (0) 38 | #define CPSTAssertIntegerNumberEquals(token, expectation) \ 39 | do { \ 40 | CPNumberToken * t = (CPNumberToken *)token; /* this escapes the potential multiple invocations of popToken */ \ 41 | _CPSTAssertKindOfClass_Unsafe(t, CPNumberToken); \ 42 | NSNumber * n = [t number]; \ 43 | XCTAssertTrue(0==strcmp([n objCType], @encode(NSInteger)), @"Type expectation failure. Wanted %s, got %s.", @encode(NSInteger), [n objCType]); \ 44 | XCTAssertEqual([n integerValue], ((NSInteger)expectation), @"Number fails expectation."); \ 45 | } while (0) 46 | #define CPSTAssertIntegerNumberEqualsWithAccuracy(token, expectation, accuracy) \ 47 | do { \ 48 | CPNumberToken * t = (CPNumberToken *)token; \ 49 | _CPSTAssertKindOfClass_Unsafe(t, CPNumberToken); \ 50 | NSNumber * n = [t number]; \ 51 | XCTAssertTrue(0==strcmp([n objCType], @encode(NSInteger)), @"Type expectation failure. Wanted %s, got %s.", @encode(NSInteger), [n objCType]); \ 52 | XCTAssertEqualWithAccuracy([n integerValue], ((NSInteger)expectation), ((NSInteger)accuracy), @"Number fails expectation."); \ 53 | } while (0) 54 | #define CPSTAssertFloatingNumberEquals(token, expectation) \ 55 | do { \ 56 | CPNumberToken * t = (CPNumberToken *)token; \ 57 | _CPSTAssertKindOfClass_Unsafe(t, CPNumberToken); \ 58 | NSNumber * n = [t number]; \ 59 | XCTAssertTrue(0==strcmp([n objCType], @encode(double)), @"Type expectation failure. Wanted %s, got %s.", @encode(double), [n objCType]); \ 60 | XCTAssertEqual([n doubleValue], ((double)expectation), @"Number fails expectation."); \ 61 | } while (0) 62 | #define CPSTAssertFloatingNumberEqualsWithAccuracy(token, expectation, accuracy) \ 63 | do { \ 64 | CPNumberToken * t = (CPNumberToken *)token; \ 65 | _CPSTAssertKindOfClass_Unsafe(t, CPNumberToken); \ 66 | NSNumber * n = [t number]; \ 67 | XCTAssertTrue(0==strcmp([n objCType], @encode(double)), @"Type expectation failure. Wanted %s, got %s.", @encode(double), [n objCType]); \ 68 | XCTAssertEqualWithAccuracy([n doubleValue], ((double)expectation), ((double)accuracy), @"Number fails expectation."); \ 69 | } while (0) 70 | -------------------------------------------------------------------------------- /CoreParse/CoreParse-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.inthebeginninggames.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.1 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2011 In The Beginning... All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /CoreParse/CoreParse-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CoreParse' target in the 'CoreParse' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /CoreParse/CoreParse.h: -------------------------------------------------------------------------------- 1 | // 2 | // CoreParse.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 10/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTokeniser.h" 10 | 11 | #import "CPTokenStream.h" 12 | 13 | #import "CPTokenRecogniser.h" 14 | #import "CPKeywordRecogniser.h" 15 | #import "CPNumberRecogniser.h" 16 | #import "CPWhitespaceRecogniser.h" 17 | #import "CPIdentifierRecogniser.h" 18 | #import "CPQuotedRecogniser.h" 19 | #import "CPRegexpRecogniser.h" 20 | 21 | #import "CPToken.h" 22 | #import "CPErrorToken.h" 23 | #import "CPEOFToken.h" 24 | #import "CPKeywordToken.h" 25 | #import "CPNumberToken.h" 26 | #import "CPWhiteSpaceToken.h" 27 | #import "CPQuotedToken.h" 28 | #import "CPIdentifierToken.h" 29 | 30 | #import "CPGrammarSymbol.h" 31 | #import "CPGrammarSymbol.h" 32 | #import "CPRule.h" 33 | #import "CPGrammar.h" 34 | 35 | #import "CPRecoveryAction.h" 36 | 37 | #import "CPParser.h" 38 | #import "CPSLRParser.h" 39 | #import "CPLR1Parser.h" 40 | #import "CPLALR1Parser.h" 41 | 42 | #import "CPJSONParser.h" 43 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPGrammarInternal.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPGrammarInternal.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPGrammar.h" 12 | 13 | @interface CPGrammar (CPGrammarInternal) 14 | 15 | - (CPGrammar *)augmentedGrammar; 16 | 17 | - (NSUInteger)indexOfRule:(CPRule *)rule; 18 | 19 | - (NSSet *)lr0Closure:(NSSet *)i; 20 | - (NSSet *)lr0GotoKernelWithItems:(NSSet *)i symbol:(CPGrammarSymbol *)symbol; 21 | - (NSArray *)lr0Kernels; 22 | 23 | - (NSSet *)lr1Closure:(NSSet *)i; 24 | - (NSSet *)lr1GotoKernelWithItems:(NSSet *)i symbol:(CPGrammarSymbol *)symbol; 25 | 26 | - (NSSet *)follow:(NSString *)name; 27 | - (NSSet *)first:(NSArray *)obj; 28 | 29 | - (NSString *)uniqueSymbolNameBasedOnName:(NSString *)name; 30 | - (NSString *)symbolNameNotInSet:(NSSet *)symbols basedOnName:(NSString *)name; 31 | 32 | - (NSArray *)tidyRightHandSides:(NSArray *)oldRules error:(NSError **)error; 33 | - (NSSet *)collectRHSElementsForNewRules:(NSArray *)rightHandSide; 34 | - (NSDictionary *)nameNewRules:(NSSet *)rhsElements withRules:(NSArray *)oldRules; 35 | - (NSArray *)addRHSRules:(NSDictionary *)rules toRules:(NSArray *)oldRules; 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPGrammarPrivate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPGrammarPrivate.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPGrammar.h" 12 | 13 | @interface CPGrammar (CPGrammarPrivate) 14 | 15 | @property (readwrite,copy ) NSArray *rules; 16 | 17 | @property (readwrite,retain) NSMutableDictionary *rulesByNonTerminal; 18 | @property (readwrite,retain) NSMutableDictionary *followCache; 19 | 20 | - (NSArray *)orderedRules; 21 | 22 | - (NSSet *)allSymbolNames; 23 | - (NSSet *)symbolNamesInRules:(NSArray *)rules; 24 | - (NSSet *)firstSymbol:(CPGrammarSymbol *)obj; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPGrammarPrivate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPGrammarPrivate.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPGrammarPrivate.h" 10 | 11 | #import 12 | 13 | @implementation CPGrammar (CPGrammarPrivate) 14 | 15 | static char rulesByNonTerminalKey; 16 | static char followCacheKey; 17 | 18 | - (NSMutableDictionary *)rulesByNonTerminal 19 | { 20 | return (NSMutableDictionary *)objc_getAssociatedObject(self, &rulesByNonTerminalKey); 21 | } 22 | 23 | - (void)setRulesByNonTerminal:(NSMutableDictionary *)newRulesByNonTerminal 24 | { 25 | objc_setAssociatedObject(self, &rulesByNonTerminalKey, newRulesByNonTerminal, OBJC_ASSOCIATION_RETAIN); 26 | } 27 | 28 | - (NSMutableDictionary *)followCache 29 | { 30 | return (NSMutableDictionary *)objc_getAssociatedObject(self, &followCacheKey); 31 | } 32 | 33 | - (void)setFollowCache:(NSMutableDictionary *)newFollowCache 34 | { 35 | objc_setAssociatedObject(self, &followCacheKey, newFollowCache, OBJC_ASSOCIATION_RETAIN); 36 | } 37 | 38 | - (NSArray *)rules 39 | { 40 | NSMutableArray *rs = [NSMutableArray arrayWithCapacity:[[self rulesByNonTerminal] count]]; 41 | 42 | for (NSArray *arr in [[self rulesByNonTerminal] allValues]) 43 | { 44 | [rs addObjectsFromArray:arr]; 45 | } 46 | 47 | return rs; 48 | } 49 | 50 | - (void)setRules:(NSArray *)newRules 51 | { 52 | @synchronized(self) 53 | { 54 | [self setRulesByNonTerminal:[NSMutableDictionary dictionaryWithCapacity:[newRules count]]]; 55 | 56 | for (CPRule *rule in newRules) 57 | { 58 | [self addRule:rule]; 59 | } 60 | } 61 | } 62 | 63 | - (NSArray *)orderedRules 64 | { 65 | return [[[self allRules] allObjects] sortedArrayUsingComparator:^ NSComparisonResult (CPRule *r1, CPRule *r2) 66 | { 67 | NSComparisonResult t = [r1 tag] < [r2 tag] ? NSOrderedDescending : [r1 tag] > [r2 tag] ? NSOrderedAscending: NSOrderedSame; 68 | NSComparisonResult r = NSOrderedSame != t ? t : [[r1 name] compare:[r2 name]]; 69 | return NSOrderedSame != r ? r : ([[r1 rightHandSideElements] count] < [[r2 rightHandSideElements] count] ? NSOrderedAscending : ([[r1 rightHandSideElements] count] > [[r2 rightHandSideElements] count] ? NSOrderedDescending : NSOrderedSame)); 70 | }]; 71 | 72 | } 73 | 74 | - (NSSet *)firstSymbol:(CPGrammarSymbol *)sym 75 | { 76 | NSString *name = [sym name]; 77 | if ([sym isTerminal] && nil != name) 78 | { 79 | return [NSSet setWithObject:name]; 80 | } 81 | else 82 | { 83 | NSMutableSet *f = [NSMutableSet set]; 84 | NSArray *rs = [self rulesForNonTerminalWithName:name]; 85 | BOOL containsEmptyRightHandSide = NO; 86 | for (CPRule *rule in rs) 87 | { 88 | NSArray *rhs = [rule rightHandSideElements]; 89 | NSUInteger numElements = [rhs count]; 90 | if (numElements == 0) 91 | { 92 | containsEmptyRightHandSide = YES; 93 | } 94 | else 95 | { 96 | for (CPGrammarSymbol *symbol in rhs) 97 | { 98 | if (![symbol isEqual:sym]) 99 | { 100 | NSSet *f1 = [self firstSymbol:symbol]; 101 | [f unionSet:f1]; 102 | if (![f1 containsObject:@""]) 103 | { 104 | break; 105 | } 106 | } 107 | } 108 | } 109 | } 110 | if (containsEmptyRightHandSide) 111 | { 112 | [f addObject:@""]; 113 | } 114 | return f; 115 | } 116 | } 117 | 118 | - (NSSet *)allSymbolNames 119 | { 120 | return [self symbolNamesInRules:[self rules]]; 121 | } 122 | 123 | - (NSSet *)symbolNamesInRules:(NSArray *)rules 124 | { 125 | NSMutableSet *symbols = [NSMutableSet set]; 126 | 127 | for (CPRule *rule in rules) 128 | { 129 | [symbols addObject:[rule name]]; 130 | for (id sym in [rule rightHandSideElements]) 131 | { 132 | if ([sym isGrammarSymbol]) 133 | { 134 | [symbols addObject:[sym name]]; 135 | } 136 | } 137 | } 138 | 139 | return symbols; 140 | } 141 | 142 | @end 143 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPGrammarSymbol.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPGrammarSymbol.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * The CPGrammarSymbol class represents a terminal or non-terminal grammar symbol. 13 | * 14 | * All grammar symbols carry a name which is used in constructing CPRules. 15 | */ 16 | @interface CPGrammarSymbol : NSObject 17 | 18 | ///--------------------------------------------------------------------------------------- 19 | /// @name Creating and Initialising a Rule 20 | ///--------------------------------------------------------------------------------------- 21 | 22 | /** 23 | * Creates a non-terminal grammar symbol. 24 | * 25 | * @param name The non-terminal name. 26 | * @return Returns a non-terminal CPGrammarSymbol with the specified name. 27 | * 28 | * @see terminalWithName: 29 | * @see initWithName:isTerminal: 30 | */ 31 | + (id)nonTerminalWithName:(NSString *)name; 32 | 33 | /** 34 | * Creates a terminal grammar symbol. 35 | * 36 | * @param name The terminal name. 37 | * @return Returns a terminal CPGrammarSymbol with the specified name. 38 | * 39 | * @see nonTerminalWithName: 40 | * @see initWithName:isTerminal: 41 | */ 42 | + (id)terminalWithName:(NSString *)name; 43 | 44 | /** 45 | * Initialises a grammar symbol. 46 | * 47 | * @param name The non-terminal name. 48 | * @param terminal Specifies whether the grammar symbol is a terminal or non-terminal. 49 | * @return Returns a CPGrammarSymbol with the specified name. 50 | * 51 | * @see terminalWithName: 52 | * @see nonTerminalWithName: 53 | */ 54 | - (id)initWithName:(NSString *)name isTerminal:(BOOL)terminal; 55 | 56 | ///--------------------------------------------------------------------------------------- 57 | /// @name Configuring a Rule 58 | ///--------------------------------------------------------------------------------------- 59 | 60 | /** 61 | * The grammar symbol's name. 62 | */ 63 | @property (readwrite, copy ) NSString *name; 64 | 65 | /** 66 | * Whether the grammar symbol is a terminal or non-terminal. 67 | */ 68 | @property (readwrite, assign, getter=isTerminal) BOOL terminal; 69 | 70 | /** 71 | * Determines whether the grammar symbol is equal to another. 72 | * @param object The other grammar symbol to compare. 73 | * @return Whether the two symbols are equal. 74 | */ 75 | - (BOOL)isEqualToGrammarSymbol:(CPGrammarSymbol *)object; 76 | 77 | @end 78 | 79 | @interface NSObject (CPGrammarSymbol) 80 | 81 | - (BOOL)isGrammarSymbol; 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPGrammarSymbol.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPGrammarSymbol.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPGrammarSymbol.h" 10 | 11 | @implementation CPGrammarSymbol 12 | 13 | @synthesize name; 14 | @synthesize terminal; 15 | 16 | + (id)nonTerminalWithName:(NSString *)name 17 | { 18 | return [[[self alloc] initWithName:name isTerminal:NO] autorelease]; 19 | } 20 | 21 | + (id)terminalWithName:(NSString *)name 22 | { 23 | return [[[self alloc] initWithName:name isTerminal:YES] autorelease]; 24 | } 25 | 26 | - (id)initWithName:(NSString *)initName isTerminal:(BOOL)isTerminal; 27 | { 28 | self = [super init]; 29 | 30 | if (nil != self) 31 | { 32 | [self setName:initName]; 33 | [self setTerminal:isTerminal]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | - (id)init 40 | { 41 | return [self initWithName:@"" isTerminal:NO]; 42 | } 43 | 44 | #define CPGrammarSymbolNameKey @"n" 45 | #define CPGrammarSymbolTerminalKey @"t" 46 | 47 | - (id)initWithCoder:(NSCoder *)aDecoder 48 | { 49 | self = [super init]; 50 | 51 | if (nil != self) 52 | { 53 | [self setName:[aDecoder decodeObjectForKey:CPGrammarSymbolNameKey]]; 54 | [self setTerminal:[aDecoder decodeBoolForKey:CPGrammarSymbolTerminalKey]]; 55 | } 56 | 57 | return self; 58 | } 59 | 60 | - (void)encodeWithCoder:(NSCoder *)aCoder 61 | { 62 | [aCoder encodeObject:[self name] forKey:CPGrammarSymbolNameKey]; 63 | [aCoder encodeBool:[self isTerminal] forKey:CPGrammarSymbolTerminalKey]; 64 | } 65 | 66 | - (BOOL)isGrammarSymbol 67 | { 68 | return YES; 69 | } 70 | 71 | - (BOOL)isEqual:(id)object 72 | { 73 | return ([object isGrammarSymbol] && 74 | ((CPGrammarSymbol *)object)->terminal == terminal && 75 | [((CPGrammarSymbol *)object)->name isEqualToString:name]); 76 | } 77 | 78 | - (BOOL)isEqualToGrammarSymbol:(CPGrammarSymbol *)object 79 | { 80 | return (object != nil && object->terminal == terminal && [object->name isEqualToString:name]); 81 | } 82 | 83 | - (NSUInteger)hash 84 | { 85 | return [[self name] hash]; 86 | } 87 | 88 | - (NSString *)description 89 | { 90 | if ([self isTerminal]) 91 | { 92 | return [NSString stringWithFormat:@"\"%@\"", [self name]]; 93 | } 94 | else 95 | { 96 | return [NSString stringWithFormat:@"<%@>", [self name]]; 97 | } 98 | } 99 | 100 | - (void)dealloc 101 | { 102 | [name release]; 103 | 104 | [super dealloc]; 105 | } 106 | 107 | @end 108 | 109 | @implementation NSObject (CPGrammarSymbol) 110 | 111 | - (BOOL)isGrammarSymbol 112 | { 113 | return NO; 114 | } 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRHSItem+Private.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRHSItem+Private.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 19/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPRHSItem.h" 10 | 11 | @interface CPRHSItem (Private) 12 | 13 | - (void)addTag:(NSString *)tagName; 14 | - (NSSet *)tagNamesWithError:(NSError **)err; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRHSItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRHSItem.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CPRHSItem : NSObject 12 | 13 | @property (readwrite,copy ) NSArray *alternatives; 14 | 15 | @property (readwrite,assign) BOOL repeats; 16 | @property (readwrite,assign) BOOL mayNotExist; 17 | 18 | @property (readwrite,copy ) NSSet *tags; 19 | 20 | @property (readwrite,assign) BOOL shouldCollapse; 21 | 22 | - (NSSet *)nonTerminalsUsed; 23 | 24 | @end 25 | 26 | @interface NSObject (CPIsRHSItem) 27 | 28 | - (BOOL)isRHSItem; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRHSItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRHSItem.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPRHSItem.h" 10 | 11 | #import "CPRHSItem+Private.h" 12 | #import "CPGrammar.h" 13 | 14 | @implementation CPRHSItem 15 | { 16 | NSMutableSet *_tags; 17 | } 18 | 19 | @synthesize alternatives = _alternatives; 20 | @synthesize repeats = _repeats; 21 | @synthesize mayNotExist = _mayNotExist; 22 | @synthesize shouldCollapse = _shouldCollapse; 23 | 24 | - (NSUInteger)hash 25 | { 26 | return [[self alternatives] hash] ^ ([self repeats] ? 0x2 : 0x0) + ([self mayNotExist] ? 0x1 : 0x0); 27 | } 28 | 29 | - (BOOL)isRHSItem 30 | { 31 | return YES; 32 | } 33 | 34 | - (BOOL)isEqual:(id)object 35 | { 36 | return ([object isRHSItem] && 37 | [[self alternatives] isEqualToArray:[object alternatives]] && 38 | [self repeats] == [object repeats] && 39 | [self mayNotExist] == [object mayNotExist] && 40 | [self shouldCollapse] == [object shouldCollapse] && 41 | ([self tags] == nil || [[self tags] isEqualToSet:[(CPRHSItem *)object tags]])); 42 | } 43 | 44 | - (id)copyWithZone:(NSZone *)zone 45 | { 46 | CPRHSItem *other = [[CPRHSItem allocWithZone:zone] init]; 47 | [other setAlternatives:[self alternatives]]; 48 | [other setRepeats:[self repeats]]; 49 | [other setMayNotExist:[self mayNotExist]]; 50 | [other setTags:[self tags]]; 51 | [other setShouldCollapse:[self shouldCollapse]]; 52 | return other; 53 | } 54 | 55 | - (void)dealloc 56 | { 57 | [_alternatives release]; 58 | [_tags release]; 59 | 60 | [super dealloc]; 61 | } 62 | 63 | - (NSString *)description 64 | { 65 | NSMutableString *desc = [NSMutableString string]; 66 | 67 | if ([[self alternatives] count] != 1 || [[[self alternatives] objectAtIndex:0] count] != 1) 68 | { 69 | [desc appendString:@"("]; 70 | } 71 | NSUInteger i = 0; 72 | for (NSArray *components in [self alternatives]) 73 | { 74 | i++; 75 | NSUInteger j = 0; 76 | for (id comp in components) 77 | { 78 | j++; 79 | if (j != [components count]) 80 | { 81 | [desc appendFormat:@"%@ ", comp]; 82 | } 83 | else 84 | { 85 | [desc appendFormat:@"%@", comp]; 86 | } 87 | } 88 | 89 | if (i != [[self alternatives] count]) 90 | { 91 | [desc appendString:@"| "]; 92 | } 93 | } 94 | if ([[self alternatives] count] != 1 || [[[self alternatives] objectAtIndex:0] count] != 1) 95 | { 96 | [desc appendString:@")"]; 97 | } 98 | [desc appendString:[self repeats] ? ([self mayNotExist] ? @"*" : @"+") : ([self mayNotExist] ? @"?" : @"")]; 99 | return desc; 100 | } 101 | 102 | - (NSSet *)tags 103 | { 104 | return [[_tags retain] autorelease]; 105 | } 106 | 107 | - (void)setTags:(NSSet *)tags 108 | { 109 | if (tags != _tags) 110 | { 111 | [_tags release]; 112 | _tags = [tags mutableCopy]; 113 | } 114 | } 115 | 116 | - (NSSet *)nonTerminalsUsed 117 | { 118 | NSMutableSet *nonTerminals = [NSMutableSet set]; 119 | for (NSArray *alternative in [self alternatives]) 120 | { 121 | for (id item in alternative) 122 | { 123 | if ([item isGrammarSymbol] && ![(CPGrammarSymbol *)item isTerminal]) 124 | { 125 | [nonTerminals addObject:[(CPGrammarSymbol *)item name]]; 126 | } 127 | else if ([item isRHSItem]) 128 | { 129 | [nonTerminals unionSet:[(CPRHSItem *)item nonTerminalsUsed]]; 130 | } 131 | } 132 | } 133 | return nonTerminals; 134 | } 135 | 136 | @end 137 | 138 | @implementation CPRHSItem (Private) 139 | 140 | - (void)addTag:(NSString *)tagName 141 | { 142 | if (nil == _tags) 143 | { 144 | [self setTags:[NSSet set]]; 145 | } 146 | [_tags addObject:tagName]; 147 | } 148 | 149 | - (NSSet *)tagNamesWithError:(NSError **)err 150 | { 151 | NSMutableSet *tagNames = [NSMutableSet set]; 152 | 153 | for (NSArray *components in [self alternatives]) 154 | { 155 | NSMutableSet *tagNamesInAlternative = [NSMutableSet set]; 156 | for (id comp in components) 157 | { 158 | if ([comp isRHSItem]) 159 | { 160 | NSSet *newTagNames = [(CPRHSItem *)comp tagNamesWithError:err]; 161 | if (nil != *err) 162 | { 163 | return nil; 164 | } 165 | NSMutableSet *duplicateTags = [[tagNamesInAlternative mutableCopy] autorelease]; 166 | [duplicateTags intersectSet:newTagNames]; 167 | if ([duplicateTags count] > 0) 168 | { 169 | if (NULL != err) 170 | { 171 | *err = [NSError errorWithDomain:CPEBNFParserErrorDomain 172 | code:CPErrorCodeDuplicateTag 173 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys: 174 | [NSString stringWithFormat:@"Duplicate tag names %@ in same part of alternative is not allowed in \"%@\".", duplicateTags, self], NSLocalizedDescriptionKey, 175 | nil]]; 176 | } 177 | return nil; 178 | } 179 | [tagNamesInAlternative unionSet:newTagNames]; 180 | NSSet *tns = [(CPRHSItem *)comp tags]; 181 | if (nil != tns) 182 | { 183 | if ([tagNamesInAlternative intersectsSet:tns]) 184 | { 185 | if (NULL != err) 186 | { 187 | NSMutableSet *intersection = [[tagNamesInAlternative mutableCopy] autorelease]; 188 | [intersection intersectSet:tns]; 189 | *err = [NSError errorWithDomain:CPEBNFParserErrorDomain 190 | code:CPErrorCodeDuplicateTag 191 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys: 192 | [NSString stringWithFormat:@"Duplicate tag names (%@) in same part of alternative is not allowed in \"%@\".", intersection, self], NSLocalizedDescriptionKey, 193 | nil]]; 194 | } 195 | return nil; 196 | } 197 | [tagNamesInAlternative unionSet:tns]; 198 | } 199 | } 200 | } 201 | [tagNames unionSet:tagNamesInAlternative]; 202 | } 203 | 204 | if ([tagNames count] > 0 && [self repeats]) 205 | { 206 | if (NULL != err) 207 | { 208 | *err = [NSError errorWithDomain:CPEBNFParserErrorDomain 209 | code:CPErrorCodeDuplicateTag 210 | userInfo:[NSDictionary dictionaryWithObjectsAndKeys: 211 | [NSString stringWithFormat:@"Tag names are not allowed within repeating section of rule \"%@\".", self], NSLocalizedDescriptionKey, 212 | nil]]; 213 | } 214 | return nil; 215 | } 216 | 217 | return tagNames; 218 | } 219 | 220 | @end 221 | 222 | @implementation NSObject (CPIsRHSItem) 223 | 224 | - (BOOL)isRHSItem 225 | { 226 | return NO; 227 | } 228 | 229 | @end 230 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRHSItemResult.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRHSItemResult.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 23/10/2011. 6 | // Copyright (c) 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPParser.h" 12 | 13 | @interface CPRHSItemResult : NSObject 14 | 15 | @property (readwrite, retain) NSMutableArray *contents; 16 | @property (readwrite, assign) BOOL shouldCollapse; 17 | @property (readwrite, copy ) NSSet *tagNames; 18 | @property (readwrite, copy ) NSDictionary *tagValues; 19 | 20 | @end 21 | 22 | @interface NSObject (CPIsRHSItemResult) 23 | 24 | - (BOOL)isRHSItemResult; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRHSItemResult.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRHSItemResult.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 23/10/2011. 6 | // Copyright (c) 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPRHSItemResult.h" 10 | 11 | #import "CPRule+Internal.h" 12 | 13 | @implementation CPRHSItemResult 14 | 15 | @synthesize contents = _contents; 16 | @synthesize tagNames = _tagNames; 17 | @synthesize shouldCollapse = _shouldCollapse; 18 | @synthesize tagValues = _tagValues; 19 | 20 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree 21 | { 22 | self = [super init]; 23 | 24 | if (nil != self) 25 | { 26 | NSArray *children = [syntaxTree children]; 27 | CPRule *r = [syntaxTree rule]; 28 | 29 | switch ([r tag]) 30 | { 31 | case 0: 32 | [self setContents:[NSMutableArray array]]; 33 | break; 34 | case 1: 35 | [self setContents:[[children mutableCopy] autorelease]]; 36 | break; 37 | case 2: 38 | { 39 | NSMutableArray *nextContents = (NSMutableArray *)[children lastObject]; 40 | NSUInteger i = 0; 41 | for (id newContent in [children subarrayWithRange:NSMakeRange(0, [children count] - 1)]) 42 | { 43 | [nextContents insertObject:newContent atIndex:i]; 44 | i++; 45 | } 46 | [self setContents:nextContents]; 47 | break; 48 | } 49 | default: 50 | [self setContents:[[children mutableCopy] autorelease]]; 51 | break; 52 | } 53 | 54 | [self setTagValues:[syntaxTree tagValues]]; 55 | [self setTagNames:[r tagNames]]; 56 | [self setShouldCollapse:[r shouldCollapse]]; 57 | } 58 | 59 | return self; 60 | } 61 | 62 | - (void)dealloc 63 | { 64 | [_contents release]; 65 | [_tagNames release]; 66 | [_tagValues release]; 67 | 68 | [super dealloc]; 69 | } 70 | 71 | - (BOOL)isRHSItemResult 72 | { 73 | return YES; 74 | } 75 | 76 | @end 77 | 78 | @implementation NSObject(CPIsRHSItemResult) 79 | 80 | - (BOOL)isRHSItemResult 81 | { 82 | return NO; 83 | } 84 | 85 | @end 86 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRule+Internal.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRule+Internal.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 18/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CoreParse.h" 10 | 11 | @interface CPRule (Internal) 12 | 13 | - (BOOL)shouldCollapse; 14 | - (void)setShouldCollapse:(BOOL)shouldCollapse; 15 | 16 | - (NSSet *)tagNames; 17 | - (void)setTagNames:(NSSet *)tagNames; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRule.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRule.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * The CPRule class represents a context free rule. 13 | * 14 | * Rules are used to specify how your language is structured - each rule specifies that the non-terminal on their left 15 | * can be constructed by finding the sequence specified on the right hand side. 16 | * 17 | * Rules are added to CPGrammars to construct a language to parse. 18 | * 19 | * During parsing, a CPParser will inform its delegate of which CPRule it has matched to form a reduction. The tag 20 | * property is provided to allow you to easily identify which rule has been matched. 21 | */ 22 | @interface CPRule : NSObject 23 | 24 | ///--------------------------------------------------------------------------------------- 25 | /// @name Creating and Initialising a Rule 26 | ///--------------------------------------------------------------------------------------- 27 | 28 | /** 29 | * Creates a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 30 | * 31 | * @param name The non-terminal the rule reduces. 32 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 33 | * @return Returns a CPRule based on the right hand side and non-terminal name. 34 | * 35 | * @see ruleWithName:rightHandSideElements:tag: 36 | * @see ruleWithName:rightHandSideElements:representitiveClass: 37 | * @see initWithName:rightHandSideElements: 38 | */ 39 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements; 40 | 41 | /** 42 | * Creates a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 43 | * Also specifies a tag by which the rule can be identified in a parser delegate 44 | * 45 | * @param name The non-terminal the rule reduces. 46 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 47 | * @param tag A tag to identify the rule by. 48 | * @return Returns a CPRule based on the right hand side and non-terminal name. 49 | * 50 | * @see ruleWithName:rightHandSideElements: 51 | * @see ruleWithName:rightHandSideElements:representitiveClass: 52 | * @see initWithName:rightHandSideElements:tag: 53 | */ 54 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements tag:(NSUInteger)tag; 55 | 56 | /** 57 | * Creates a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 58 | * Also specifies the class to allocate to represent this rule. 59 | * 60 | * @param name The non-terminal the rule reduces. 61 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 62 | * @param representitiveClass The class used to represent this rule. 63 | * @return Returns a CPRule based on the right hand side and non-terminal name. 64 | * 65 | * @see ruleWithName:rightHandSideElements: 66 | * @see ruleWithName:rightHandSideElements:tag: 67 | * @see initWithName:rightHandSideElements:representitiveClass: 68 | */ 69 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements representitiveClass:(Class)representitiveClass; 70 | 71 | /** 72 | * Initialises a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 73 | * 74 | * @param name The non-terminal the rule reduces. 75 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 76 | * @return Returns a CPRule based on the right hand side and non-terminal name. 77 | * 78 | * @see initWithName:rightHandSideElements:tag: 79 | * @see ruleWithName:rightHandSideElements: 80 | */ 81 | - (id)initWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements; 82 | 83 | /** 84 | * Initialises a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 85 | * Also specifies a tag by which the rule can be identified in a parser delegate 86 | * 87 | * @param name The non-terminal the rule reduces. 88 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 89 | * @param tag A tag to identify the rule by. 90 | * @return Returns a CPRule based on the right hand side and non-terminal name. 91 | * 92 | * @see initWithName:rightHandSideElements: 93 | * @see ruleWithName:rightHandSideElements:tag: 94 | */ 95 | - (id)initWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements tag:(NSUInteger)tag; 96 | 97 | /** 98 | * Initialises a rule based on a non-terminal name and an array of grammar symbols to make up the right hand side. 99 | * Also specifies the class to allocate to represent this rule. 100 | * 101 | * @param name The non-terminal the rule reduces. 102 | * @param rightHandSideElements An array of CPGrammarSymbols that make up the right hand side of the rule. 103 | * @param representitiveClass The class used to represent this rule. 104 | * @return Returns a CPRule based on the right hand side and non-terminal name. 105 | * 106 | * @see initWithName:rightHandSideElements: 107 | * @see initWithName:rightHandSideElements:tag: 108 | * @see ruleWithName:rightHandSideElements:representitiveClass: 109 | */ 110 | - (id)initWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements representitiveClass:(Class)representitiveClass; 111 | 112 | ///--------------------------------------------------------------------------------------- 113 | /// @name Configuring a Rule 114 | ///--------------------------------------------------------------------------------------- 115 | 116 | /** 117 | * Specifies the name of the non-terminal this rule describes. 118 | */ 119 | @property (readwrite, retain) NSString *name; 120 | 121 | /** 122 | * Specifies the right hand side of the rule. 123 | * 124 | * Elements of this array must be CPGrammarSymbols. 125 | */ 126 | @property (readwrite, copy ) NSArray *rightHandSideElements; 127 | 128 | /** 129 | * A tag used to identify the rule in the parser delegate. 130 | */ 131 | @property (readwrite, assign) NSUInteger tag; 132 | 133 | /** 134 | * The class used to represent syntax trees based off this rule. 135 | */ 136 | @property (readwrite, assign) Class representitiveClass; 137 | 138 | @end 139 | 140 | @interface NSObject (CPIsRule) 141 | 142 | - (BOOL)isRule; 143 | 144 | @end 145 | -------------------------------------------------------------------------------- /CoreParse/Grammar/CPRule.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRule.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPRule.h" 10 | #import "CPRule+Internal.h" 11 | 12 | #import "CPGrammarSymbol.h" 13 | 14 | @implementation CPRule 15 | { 16 | NSMutableArray *rightHandSide; 17 | BOOL _shouldCollapse; 18 | NSSet *_tagNames; 19 | } 20 | 21 | @synthesize name; 22 | @synthesize tag; 23 | @synthesize representitiveClass; 24 | 25 | - (NSArray *)rightHandSideElements 26 | { 27 | return [[rightHandSide retain] autorelease]; 28 | } 29 | 30 | - (void)setRightHandSideElements:(NSArray *)rightHandSideElements 31 | { 32 | @synchronized(self) 33 | { 34 | if (rightHandSide != rightHandSideElements) 35 | { 36 | [rightHandSide release]; 37 | rightHandSide = [rightHandSideElements mutableCopy]; 38 | } 39 | } 40 | } 41 | 42 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements representitiveClass:(Class)representitiveClass 43 | { 44 | return [[[self alloc] initWithName:name rightHandSideElements:rightHandSideElements representitiveClass:representitiveClass] autorelease]; 45 | } 46 | 47 | - (id)initWithName:(NSString *)initName rightHandSideElements:(NSArray *)rightHandSideElements representitiveClass:(Class)initRepresentitiveClass 48 | { 49 | self = [super init]; 50 | 51 | if (nil != self) 52 | { 53 | [self setName:initName]; 54 | [self setRightHandSideElements:rightHandSideElements]; 55 | [self setTag:0]; 56 | [self setRepresentitiveClass:initRepresentitiveClass]; 57 | } 58 | 59 | return self; 60 | } 61 | 62 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements tag:(NSUInteger)tag 63 | { 64 | return [[[self alloc] initWithName:name rightHandSideElements:rightHandSideElements tag:tag] autorelease]; 65 | } 66 | 67 | - (id)initWithName:(NSString *)initName rightHandSideElements:(NSArray *)rightHandSideElements tag:(NSUInteger)initTag 68 | { 69 | self = [self initWithName:initName rightHandSideElements:rightHandSideElements representitiveClass:nil]; 70 | 71 | if (nil != self) 72 | { 73 | [self setTag:initTag]; 74 | } 75 | 76 | return self; 77 | } 78 | 79 | + (id)ruleWithName:(NSString *)name rightHandSideElements:(NSArray *)rightHandSideElements 80 | { 81 | return [[[CPRule alloc] initWithName:name rightHandSideElements:rightHandSideElements] autorelease]; 82 | } 83 | 84 | - (id)initWithName:(NSString *)initName rightHandSideElements:(NSArray *)rightHandSideElements 85 | { 86 | return [self initWithName:initName rightHandSideElements:rightHandSideElements tag:0]; 87 | } 88 | 89 | - (id)init 90 | { 91 | return [self initWithName:@"" rightHandSideElements:[NSArray array]]; 92 | } 93 | 94 | #define CPRuleTagKey @"t" 95 | #define CPRuleNameKey @"n" 96 | #define CPRuleRHSElementsKey @"r" 97 | #define CPRuleRepresentitiveClassKey @"c" 98 | 99 | - (id)initWithCoder:(NSCoder *)aDecoder 100 | { 101 | self = [super init]; 102 | 103 | if (nil != self) 104 | { 105 | [self setTag:[aDecoder decodeIntegerForKey:CPRuleTagKey]]; 106 | [self setName:[aDecoder decodeObjectForKey:CPRuleNameKey]]; 107 | [self setRightHandSideElements:[aDecoder decodeObjectForKey:CPRuleRHSElementsKey]]; 108 | [self setRepresentitiveClass:NSClassFromString([aDecoder decodeObjectForKey:CPRuleRepresentitiveClassKey])]; 109 | } 110 | 111 | return self; 112 | } 113 | 114 | - (void)encodeWithCoder:(NSCoder *)aCoder 115 | { 116 | [aCoder encodeInteger:[self tag] forKey:CPRuleTagKey]; 117 | [aCoder encodeObject:[self name] forKey:CPRuleNameKey]; 118 | [aCoder encodeObject:[self rightHandSideElements] forKey:CPRuleRHSElementsKey]; 119 | [aCoder encodeObject:NSStringFromClass([self representitiveClass]) forKey:CPRuleRepresentitiveClassKey]; 120 | } 121 | 122 | - (void)dealloc 123 | { 124 | [name release]; 125 | [rightHandSide release]; 126 | 127 | [super dealloc]; 128 | } 129 | 130 | - (NSString *)description 131 | { 132 | return [NSString stringWithFormat:@"%@ ::= %@", [self name], [[rightHandSide valueForKey:@"description"] componentsJoinedByString:@" "]]; 133 | } 134 | 135 | - (NSUInteger)hash 136 | { 137 | return [name hash] ^ [self tag]; 138 | } 139 | 140 | - (BOOL)isRule 141 | { 142 | return YES; 143 | } 144 | 145 | - (BOOL)isEqual:(id)object 146 | { 147 | return ([object isRule] && 148 | ((CPRule *)object)->tag == tag && 149 | [((CPRule *)object)->name isEqualToString:name] && 150 | [((CPRule *)object)->rightHandSide isEqualToArray:rightHandSide] && 151 | (_tagNames == nil || [((CPRule *)object)->_tagNames isEqualToSet:_tagNames])); 152 | } 153 | 154 | @end 155 | 156 | @implementation CPRule (Internal) 157 | 158 | - (BOOL)shouldCollapse 159 | { 160 | return _shouldCollapse; 161 | } 162 | 163 | - (void)setShouldCollapse:(BOOL)shouldCollapse 164 | { 165 | _shouldCollapse = shouldCollapse; 166 | } 167 | 168 | - (NSSet *)tagNames 169 | { 170 | return [[_tagNames retain] autorelease]; 171 | } 172 | 173 | - (void)setTagNames:(NSSet *)tagNames 174 | { 175 | if (_tagNames != tagNames) 176 | { 177 | [_tagNames release]; 178 | _tagNames = [tagNames copy]; 179 | } 180 | } 181 | 182 | @end 183 | 184 | @implementation NSObject (CPIsRule) 185 | 186 | - (BOOL)isRule 187 | { 188 | return NO; 189 | } 190 | 191 | @end 192 | -------------------------------------------------------------------------------- /CoreParse/NSArray+Functional.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Functional.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 20/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSArray (Functional) 12 | 13 | - (NSArray *)cp_map:(id(^)(id obj))block; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CoreParse/NSArray+Functional.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSArray+Functional.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 20/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "NSArray+Functional.h" 10 | 11 | @implementation NSArray (Functional) 12 | 13 | - (NSArray *)cp_map:(id(^)(id obj))block 14 | { 15 | NSUInteger c = [self count]; 16 | id *resultingObjects = malloc(c * sizeof(id)); 17 | 18 | NSUInteger nonNilCount = 0; 19 | for (id obj in self) 20 | { 21 | id r = block(obj); 22 | if (nil != r) 23 | { 24 | resultingObjects[nonNilCount] = r; 25 | nonNilCount++; 26 | } 27 | } 28 | 29 | NSArray *a = [NSArray arrayWithObjects:resultingObjects count:nonNilCount]; 30 | free(resultingObjects); 31 | return a; 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /CoreParse/NSSetFunctional.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSSetFunctional.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface NSSet(Functional) 13 | 14 | - (NSSet *)cp_map:(id(^)(id obj))block; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CoreParse/NSSetFunctional.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSSetFunctional.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "NSSetFunctional.h" 10 | 11 | 12 | @implementation NSSet(Functional) 13 | 14 | - (NSSet *)cp_map:(id(^)(id obj))block 15 | { 16 | NSUInteger c = [self count]; 17 | id *resultingObjects = malloc(c * sizeof(id)); 18 | 19 | NSUInteger nonNilCount = 0; 20 | for (id obj in self) 21 | { 22 | id r = block(obj); 23 | if (nil != r) 24 | { 25 | resultingObjects[nonNilCount] = r; 26 | nonNilCount++; 27 | } 28 | } 29 | 30 | NSSet *s = [NSSet setWithObjects:resultingObjects count:nonNilCount]; 31 | free(resultingObjects); 32 | return s; 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // Parser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPGrammar.h" 12 | #import "CPSyntaxTree.h" 13 | 14 | #import "CPTokenStream.h" 15 | #import "CPRecoveryAction.h" 16 | 17 | @class CPParser; 18 | 19 | /** 20 | * The CPParseResult protocol declares a method that a class must implement so that instances can be created as the result of parsing a token stream. 21 | */ 22 | @protocol CPParseResult 23 | 24 | /** 25 | * Returns an object initialised with the contents of a syntax tree. 26 | * 27 | * @param syntaxTree The syntax tree to initialise the object with. 28 | * 29 | * @return An object created using the contents of the syntax tree. 30 | */ 31 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree; 32 | 33 | @end 34 | 35 | /** 36 | * The delegate of a CPParser must adopt the CPParserDelegate protocol. This allows you to replace the produced syntax trees with data structures of your choice. 37 | * 38 | * Significant processing can be performed in a parser delegate. For example, a parser for numeric expressions could replace each syntax tree with an NSNumber representing 39 | * the resultant value of evaluating the expression. This would allow you to parse, and compute the result of the expression in one pass. 40 | */ 41 | @protocol CPParserDelegate 42 | 43 | @optional 44 | 45 | /** 46 | * Should return an object to replace a produced syntax tree with. 47 | * 48 | * You should not return `nil` from this method. If you do not wish to change the syntax tree, simply return the same value as you are passed. 49 | * 50 | * @warning Note that it is not guarenteed that this method will be called in the same order as the structures appear in your input stream. 51 | * 52 | * @param parser The parser which produced the syntax tree. 53 | * @param syntaxTree The syntax tree the parser has produced. 54 | * @return An object value to replace the syntax tree with. 55 | */ 56 | - (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree; 57 | 58 | /** 59 | * Called when the parser encounters a token for which it can not shift, reduce or accept. 60 | * 61 | * @param parser The parser which produced the syntax tree. 62 | * @param inputStream The input stream containing the token the parser could not cope with. 63 | * @return An action to take to recover from the parse error or nil. If the action is nil, and the problematic token is a CPErrorToken 64 | * the parse stack is unwound a step for the parent rule to deal with the error. 65 | * @bug Warning this method is deprecated, use -parser:didEncounterErrorOnInput:expecting: instead. 66 | */ 67 | - (CPRecoveryAction *)parser:(CPParser *)parser didEncounterErrorOnInput:(CPTokenStream *)inputStream __attribute__((deprecated("use -parser:didEncounterErrorOnInput:expecting: instead."))); 68 | 69 | /** 70 | * Called when the parser encounters a token for which it can not shift, reduce or accept. 71 | * 72 | * @param parser The parser which produced the syntax tree. 73 | * @param inputStream The input stream containing the token the parser could not cope with. 74 | * @param acceptableTokens A set of token names that would have allowed the parser to continue in its current state. 75 | * @return An action to take to recover from the parse error or nil. If the action is nil, and the problematic token is a CPErrorToken 76 | * the parse stack is unwound a step for the parent rule to deal with the error. 77 | */ 78 | - (CPRecoveryAction *)parser:(CPParser *)parser didEncounterErrorOnInput:(CPTokenStream *)inputStream expecting:(NSSet *)acceptableTokens; 79 | 80 | @end 81 | 82 | typedef struct 83 | { 84 | unsigned int didProduceSyntaxTree:1; 85 | unsigned int didEncounterErrorOnInput:1; 86 | unsigned int didEncounterErrorOnInputExpecting:1; 87 | 88 | } CPParserDelegateResponseCache; 89 | 90 | /** 91 | * The CPParser class allows you to parse token streams. 92 | * 93 | * Parsers are built by constructing a grammar, and then using it to create a parser. The parser delegate may be used to monitor and replace output from the parser. 94 | * 95 | * @warning Note that CPParser is an abstract superclass. Use one of its subclasses to construct your parser. 96 | */ 97 | @interface CPParser : NSObject 98 | { 99 | @protected 100 | CPParserDelegateResponseCache delegateRespondsTo; 101 | } 102 | 103 | ///--------------------------------------------------------------------------------------- 104 | /// @name Creating and Initialising a Parser 105 | ///--------------------------------------------------------------------------------------- 106 | 107 | /** 108 | * Creates a parser for a certain grammar. 109 | * 110 | * @param grammar The grammar on which to base the parser. 111 | * @return Returns a parser that parses the input grammar, or nil if no such parser could be created. 112 | */ 113 | + (id)parserWithGrammar:(CPGrammar *)grammar; 114 | 115 | /** 116 | * Initialises a parser for a certain grammar. 117 | * 118 | * @param grammar The grammar on which to base the parser. 119 | * @return Returns a parser that parses the input grammar, or nil if no such parser could be created. 120 | */ 121 | - (id)initWithGrammar:(CPGrammar *)grammar; 122 | 123 | ///--------------------------------------------------------------------------------------- 124 | /// @name Managing the Delegate 125 | ///--------------------------------------------------------------------------------------- 126 | 127 | /** 128 | * The parser's delegate. 129 | */ 130 | @property (readwrite,assign, nonatomic) id delegate; 131 | 132 | ///--------------------------------------------------------------------------------------- 133 | /// @name Finding out about the parsed Grammar 134 | ///--------------------------------------------------------------------------------------- 135 | 136 | /** 137 | * The parser's grammar. 138 | */ 139 | @property (readonly,retain) CPGrammar *grammar; 140 | 141 | ///--------------------------------------------------------------------------------------- 142 | /// @name Parsing a Token Stream. 143 | ///--------------------------------------------------------------------------------------- 144 | 145 | /** 146 | * Parses an input token stream. 147 | * 148 | * Currently if errors are generated, `nil` is returned and the error Logged using NSLog. This behaviour may change in the future to return the error in a more usable form. 149 | * 150 | * @param tokenStream The token stream to parse. 151 | * @return Returns the parsed syntax tree for the whole stream or `nil` if the token stream could not be parsed. 152 | */ 153 | - (id)parse:(CPTokenStream *)tokenStream; 154 | 155 | @end 156 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // Parser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPParser.h" 10 | 11 | @interface CPParser () 12 | 13 | @property (readwrite,retain) CPGrammar *grammar; 14 | 15 | @end 16 | 17 | @implementation CPParser 18 | 19 | @synthesize grammar; 20 | @synthesize delegate; 21 | 22 | + (id)parserWithGrammar:(CPGrammar *)grammar 23 | { 24 | return [[[self alloc] initWithGrammar:grammar] autorelease]; 25 | } 26 | 27 | - (id)initWithGrammar:(CPGrammar *)initGrammar 28 | { 29 | self = [super init]; 30 | 31 | if (nil != self) 32 | { 33 | [self setGrammar:initGrammar]; 34 | } 35 | 36 | return self; 37 | } 38 | 39 | - (id)init 40 | { 41 | return [self initWithGrammar:nil]; 42 | } 43 | 44 | - (void)dealloc 45 | { 46 | [grammar release]; 47 | 48 | [super dealloc]; 49 | } 50 | 51 | - (id)parse:(CPTokenStream *)tokenStream 52 | { 53 | [NSException raise:@"Abstract Class Exception" 54 | format:@"CPParser is an abstract class, use one of the concrete subclasses to parse your token stream"]; 55 | 56 | return nil; 57 | } 58 | 59 | - (void)setDelegate:(id)aDelegate 60 | { 61 | if (delegate != aDelegate) 62 | { 63 | delegate = aDelegate; 64 | 65 | delegateRespondsTo.didProduceSyntaxTree = [delegate respondsToSelector:@selector(parser:didProduceSyntaxTree:)]; 66 | delegateRespondsTo.didEncounterErrorOnInput = [delegate respondsToSelector:@selector(parser:didEncounterErrorOnInput:)]; 67 | delegateRespondsTo.didEncounterErrorOnInputExpecting = [delegate respondsToSelector:@selector(parser:didEncounterErrorOnInput:expecting:)]; 68 | } 69 | } 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPLALR1Parser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPParser.h" 12 | 13 | /** 14 | * The CPShiftReduceParser is a further abstract class based on CPParser. This implements the parts of a parser in common between all shift/reduce type parsers. 15 | * 16 | * @warning Note that to create a parser you should use one of CPShiftReduceParser's subclasses. 17 | */ 18 | @interface CPShiftReduceParser : CPParser 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPItem.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPRule.h" 12 | #import "CPGrammarSymbol.h" 13 | 14 | @interface CPItem : NSObject 15 | {} 16 | 17 | @property (readonly,retain) CPRule *rule; 18 | @property (readonly,assign) NSUInteger position; 19 | 20 | + (id)itemWithRule:(CPRule *)rule position:(NSUInteger)position; 21 | - (id)initWithRule:(CPRule *)rule position:(NSUInteger)position; 22 | 23 | - (CPGrammarSymbol *)nextSymbol; 24 | - (NSArray *)followingSymbols; 25 | 26 | - (id)itemByMovingDotRight; 27 | 28 | - (BOOL)isEqualToItem:(CPItem *)item; 29 | 30 | @end 31 | 32 | @interface NSObject (CPIsItem) 33 | 34 | - (BOOL)isItem; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPItem.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPItem.h" 10 | 11 | @interface CPItem () 12 | 13 | @property (readwrite,retain) CPRule *rule; 14 | @property (readwrite,assign) NSUInteger position; 15 | 16 | @end 17 | 18 | @implementation CPItem 19 | 20 | @synthesize rule; 21 | @synthesize position; 22 | 23 | + (id)itemWithRule:(CPRule *)rule position:(NSUInteger)position 24 | { 25 | return [[[self alloc] initWithRule:rule position:position] autorelease]; 26 | } 27 | 28 | - (id)initWithRule:(CPRule *)initRule position:(NSUInteger)initPosition 29 | { 30 | self = [super init]; 31 | 32 | if (nil != self) 33 | { 34 | rule = [initRule retain]; 35 | position = initPosition; 36 | } 37 | 38 | return self; 39 | } 40 | 41 | - (id)copyWithZone:(NSZone *)zone 42 | { 43 | return [[CPItem allocWithZone:zone] initWithRule:rule position:position]; 44 | } 45 | 46 | - (void)dealloc 47 | { 48 | [rule release]; 49 | 50 | [super dealloc]; 51 | } 52 | 53 | - (CPGrammarSymbol *)nextSymbol 54 | { 55 | NSArray *rse = [rule rightHandSideElements]; 56 | if (position >= [rse count]) 57 | { 58 | return nil; 59 | } 60 | else 61 | { 62 | return [rse objectAtIndex:position]; 63 | } 64 | } 65 | 66 | - (NSArray *)followingSymbols 67 | { 68 | NSArray *rse = [rule rightHandSideElements]; 69 | return [rse subarrayWithRange:NSMakeRange(position, [rse count] - position)]; 70 | } 71 | 72 | - (id)itemByMovingDotRight 73 | { 74 | CPItem *c = [self copy]; 75 | [c setPosition:[self position] + 1]; 76 | return [c autorelease]; 77 | } 78 | 79 | - (BOOL)isItem 80 | { 81 | return YES; 82 | } 83 | 84 | - (BOOL)isEqual:(id)object 85 | { 86 | return [object isItem] && ((CPItem *)object)->position == position && ((CPItem *)object)->rule == rule; 87 | } 88 | 89 | - (BOOL)isEqualToItem:(CPItem *)item 90 | { 91 | return item != nil && item->position == position && item->rule == rule; 92 | } 93 | 94 | - (NSUInteger)hash 95 | { 96 | return ((NSUInteger)rule << 4) + position; 97 | } 98 | 99 | - (NSString *)description 100 | { 101 | NSMutableString *desc = [NSMutableString stringWithFormat:@"%@ ::= ", [[self rule] name]]; 102 | NSUInteger pos = 0; 103 | NSArray *rse = [[self rule] rightHandSideElements]; 104 | for (NSObject *obj in rse) 105 | { 106 | if (pos == [self position]) 107 | { 108 | [desc appendString:@"• "]; 109 | } 110 | [desc appendFormat:@"%@ ", obj]; 111 | pos++; 112 | } 113 | if (pos == [self position]) 114 | { 115 | [desc appendString:@"•"]; 116 | } 117 | return desc; 118 | } 119 | 120 | @end 121 | 122 | @implementation NSObject (CPIsItem) 123 | 124 | - (BOOL)isItem 125 | { 126 | return NO; 127 | } 128 | 129 | @end 130 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPLALR1Parser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPLALR1Parser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 03/04/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPLR1Parser.h" 12 | 13 | /** 14 | * The CPLALR1Parser class is a concrete implementation of CPParser based on the lookahead left-to-right parsing method with a one symbol lookahead. 15 | * 16 | * The LALR1 parser is almost as fast as the SLR parser and covers almost as many grammars as the LR1 parser. LALR1 parsers consume only as much memory as SLR parsers. 17 | */ 18 | @interface CPLALR1Parser : CPShiftReduceParser 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPLR1Item.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPLR1Item.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPItem.h" 12 | #import "CPGrammarSymbol.h" 13 | 14 | @interface CPLR1Item : CPItem 15 | {} 16 | 17 | @property (readonly,retain) CPGrammarSymbol *terminal; 18 | 19 | + (id)lr1ItemWithRule:(CPRule *)rule position:(NSUInteger)position terminal:(CPGrammarSymbol *)terminal; 20 | - (id)initWithRule:(CPRule *)rule position:(NSUInteger)position terminal:(CPGrammarSymbol *)terminal; 21 | 22 | @end 23 | 24 | @interface NSObject (CPIsLR1Item) 25 | 26 | - (BOOL)isLR1Item; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPLR1Item.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPLR1Item.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPLR1Item.h" 10 | 11 | @interface CPLR1Item () 12 | 13 | @property (readwrite,retain) CPGrammarSymbol *terminal; 14 | 15 | @end 16 | 17 | @implementation CPLR1Item 18 | 19 | @synthesize terminal; 20 | 21 | + (id)lr1ItemWithRule:(CPRule *)rule position:(NSUInteger)position terminal:(CPGrammarSymbol *)terminal 22 | { 23 | return [[[self alloc] initWithRule:rule position:position terminal:terminal] autorelease]; 24 | } 25 | 26 | - (id)initWithRule:(CPRule *)rule position:(NSUInteger)position terminal:(CPGrammarSymbol *)initTerminal 27 | { 28 | self = [super initWithRule:rule position:position]; 29 | 30 | if (nil != self) 31 | { 32 | [self setTerminal:initTerminal]; 33 | } 34 | 35 | return self; 36 | } 37 | 38 | - (id)initWithRule:(CPRule *)initRule position:(NSUInteger)initPosition 39 | { 40 | return [self initWithRule:initRule position:initPosition terminal:nil]; 41 | } 42 | 43 | - (id)copyWithZone:(NSZone *)zone 44 | { 45 | return [[CPLR1Item allocWithZone:zone] initWithRule:[self rule] position:[self position] terminal:[self terminal]]; 46 | } 47 | 48 | - (void)dealloc 49 | { 50 | [terminal release]; 51 | 52 | [super dealloc]; 53 | } 54 | 55 | - (BOOL)isLR1Item 56 | { 57 | return YES; 58 | } 59 | 60 | - (BOOL)isEqual:(id)object 61 | { 62 | return ([object isLR1Item] && 63 | [super isEqualToItem:(CPLR1Item *)object] && 64 | [((CPLR1Item *)object)->terminal isEqualToGrammarSymbol:terminal]); 65 | } 66 | 67 | - (NSUInteger)hash 68 | { 69 | return [[self rule] hash] ^ [terminal hash] ^ [self position]; 70 | } 71 | 72 | - (NSString *)description 73 | { 74 | return [[super description] stringByAppendingFormat:@", %@", [[self terminal] name]]; 75 | } 76 | 77 | @end 78 | 79 | @implementation NSObject(CPIsLR1Item) 80 | 81 | - (BOOL)isLR1Item 82 | { 83 | return NO; 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPLR1Parser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPLR1Parser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPShiftReduceParser.h" 12 | 13 | /** 14 | * The CPLR1Parser class is a concrete implementation of CPParser based on the left-to-right parsing method with a one symbol lookahead. 15 | * 16 | * The LR1 parser is the slowest parser type available in CoreParse, but covers the largest set of grammars. LR1 parsers may consume significant amounts of memory. 17 | */ 18 | @interface CPLR1Parser : CPShiftReduceParser 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPLR1Parser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPLR1Parser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPLR1Parser.h" 10 | 11 | #import "CPShiftReduceParserProtectedMethods.h" 12 | 13 | #import "CPLR1Item.h" 14 | #import "NSSetFunctional.h" 15 | 16 | #import "CPShiftReduceAction.h" 17 | 18 | #import "CPGrammarInternal.h" 19 | 20 | @interface CPLR1Parser () 21 | 22 | - (BOOL)constructShiftReduceTables; 23 | 24 | - (NSArray *)kernelsForGrammar:(CPGrammar *)aug; 25 | 26 | @end 27 | 28 | @implementation CPLR1Parser 29 | 30 | - (BOOL)constructShiftReduceTables 31 | { 32 | CPGrammar *aug = [[self grammar] augmentedGrammar]; 33 | NSArray *kernels = [self kernelsForGrammar:aug]; 34 | NSUInteger itemCount = [kernels count]; 35 | NSArray *allNonTerminalNames = [[self grammar] allNonTerminalNames]; 36 | NSString *startSymbol = [aug start]; 37 | 38 | [self setActionTable:[[[CPShiftReduceActionTable alloc] initWithCapacity:itemCount] autorelease]]; 39 | [self setGotoTable: [[[CPShiftReduceGotoTable alloc] initWithCapacity:itemCount] autorelease]]; 40 | 41 | NSUInteger idx = 0; 42 | for (NSSet *kernel in kernels) 43 | { 44 | NSSet *itemsSet = [aug lr1Closure:kernel]; 45 | for (CPLR1Item *item in itemsSet) 46 | { 47 | CPGrammarSymbol *next = [item nextSymbol]; 48 | if (nil == next) 49 | { 50 | if ([[[item rule] name] isEqualToString:startSymbol]) 51 | { 52 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction acceptAction] forState:idx name:@"EOF"]; 53 | if (!success) 54 | { 55 | return NO; 56 | } 57 | } 58 | else 59 | { 60 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction reduceAction:[item rule]] forState:idx name:[[item terminal] name]]; 61 | if (!success) 62 | { 63 | return NO; 64 | } 65 | } 66 | } 67 | else if ([next isTerminal]) 68 | { 69 | NSSet *g = [aug lr1GotoKernelWithItems:itemsSet symbol:next]; 70 | NSUInteger ix = [kernels indexOfObject:g]; 71 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction shiftAction:ix] forState:idx name:[next name]]; 72 | if (!success) 73 | { 74 | return NO; 75 | } 76 | } 77 | } 78 | 79 | for (NSString *nonTerminalName in allNonTerminalNames) 80 | { 81 | NSSet *g = [aug lr1GotoKernelWithItems:itemsSet symbol:[CPGrammarSymbol nonTerminalWithName:nonTerminalName]]; 82 | NSUInteger gotoIndex = [kernels indexOfObject:g]; 83 | BOOL success = [[self gotoTable] setGoto:gotoIndex forState:idx nonTerminalNamed:nonTerminalName]; 84 | if (!success) 85 | { 86 | return NO; 87 | } 88 | } 89 | 90 | idx++; 91 | } 92 | 93 | return YES; 94 | } 95 | 96 | - (NSArray *)kernelsForGrammar:(CPGrammar *)aug 97 | { 98 | CPRule *startRule = [[aug rulesForNonTerminalWithName:[aug start]] objectAtIndex:0]; 99 | NSSet *initialKernel = [NSSet setWithObject:[CPLR1Item lr1ItemWithRule:startRule position:0 terminal:[CPGrammarSymbol terminalWithName:@"EOF"]]]; 100 | NSMutableArray *c = [NSMutableArray arrayWithObject:initialKernel]; 101 | NSMutableArray *processingQueue = [NSMutableArray arrayWithObject:initialKernel]; 102 | 103 | while ([processingQueue count] > 0) 104 | { 105 | NSSet *kernels = [processingQueue objectAtIndex:0]; 106 | NSSet *itemSet = [aug lr1Closure:kernels]; 107 | NSSet *validNexts = [itemSet cp_map:^ id (CPItem *item) 108 | { 109 | return [item nextSymbol]; 110 | }]; 111 | 112 | for (CPGrammarSymbol *s in validNexts) 113 | { 114 | NSSet *g = [aug lr1GotoKernelWithItems:itemSet symbol:s]; 115 | if (![c containsObject:g]) 116 | { 117 | [processingQueue addObject:g]; 118 | [c addObject:g]; 119 | } 120 | } 121 | 122 | [processingQueue removeObjectAtIndex:0]; 123 | } 124 | 125 | return c; 126 | } 127 | 128 | @end 129 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPSLRParser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPSLRParser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPShiftReduceParser.h" 12 | 13 | /** 14 | * The CPSLRParser class is a concrete implementation of CPParser based on the simple left-to-right parsing method. 15 | * 16 | * The SLR parser is the fastest parser type available in CoreParse, but covers the smallest set of grammars. 17 | */ 18 | @interface CPSLRParser : CPShiftReduceParser 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPSLRParser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPSLRParser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPSLRParser.h" 10 | 11 | #import "CPGrammarInternal.h" 12 | 13 | #import "CPItem.h" 14 | #import "CPGrammarSymbol.h" 15 | #import "CPShiftReduceAction.h" 16 | #import "CPShiftReduceParserProtectedMethods.h" 17 | 18 | #import "NSSetFunctional.h" 19 | 20 | @interface CPSLRParser () 21 | 22 | - (BOOL)constructShiftReduceTables; 23 | 24 | @end 25 | 26 | @implementation CPSLRParser 27 | 28 | - (BOOL)constructShiftReduceTables 29 | { 30 | CPGrammar *aug = [[self grammar] augmentedGrammar]; 31 | NSArray *kernels = [aug lr0Kernels]; 32 | NSUInteger itemCount = [kernels count]; 33 | NSString *startSymbol = [aug start]; 34 | 35 | [self setActionTable:[[[CPShiftReduceActionTable alloc] initWithCapacity:itemCount] autorelease]]; 36 | [self setGotoTable: [[[CPShiftReduceGotoTable alloc] initWithCapacity:itemCount] autorelease]]; 37 | 38 | NSArray *allNonTerminalNames = [[self grammar] allNonTerminalNames]; 39 | NSUInteger idx = 0; 40 | for (NSSet *kernel in kernels) 41 | { 42 | NSSet *itemSet = [aug lr0Closure:kernel]; 43 | for (CPItem *item in itemSet) 44 | { 45 | CPGrammarSymbol *next = [item nextSymbol]; 46 | if (nil == next) 47 | { 48 | if ([[[item rule] name] isEqualToString:startSymbol]) 49 | { 50 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction acceptAction] forState:idx name:@"EOF"]; 51 | if (!success) 52 | { 53 | return NO; 54 | } 55 | } 56 | else 57 | { 58 | NSSet *follow = [aug follow:[[item rule] name]]; 59 | for (NSString *f in follow) 60 | { 61 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction reduceAction:[item rule]] forState:idx name:f]; 62 | if (!success) 63 | { 64 | return NO; 65 | } 66 | } 67 | } 68 | } 69 | else if ([next isTerminal]) 70 | { 71 | NSSet *g = [aug lr0GotoKernelWithItems:itemSet symbol:next]; 72 | NSUInteger ix = [kernels indexOfObject:g]; 73 | BOOL success = [[self actionTable] setAction:[CPShiftReduceAction shiftAction:ix] forState:idx name:[next name]]; 74 | if (!success) 75 | { 76 | return NO; 77 | } 78 | } 79 | } 80 | 81 | for (NSString *nonTerminalName in allNonTerminalNames) 82 | { 83 | NSSet *g = [aug lr0GotoKernelWithItems:itemSet symbol:[CPGrammarSymbol nonTerminalWithName:nonTerminalName]]; 84 | NSUInteger gotoIndex = [kernels indexOfObject:g]; 85 | BOOL success = [[self gotoTable] setGoto:gotoIndex forState:idx nonTerminalNamed:nonTerminalName]; 86 | if (!success) 87 | { 88 | return NO; 89 | } 90 | } 91 | 92 | idx++; 93 | } 94 | 95 | return YES; 96 | } 97 | 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftAction.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 20/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftReduceAction.h" 10 | 11 | @interface CPShiftAction : CPShiftReduceAction 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftAction.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 20/08/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftAction.h" 10 | 11 | @implementation CPShiftAction 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceAction.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceAction.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPRule.h" 12 | 13 | #import "CPGrammar.h" 14 | 15 | @interface CPShiftReduceAction : NSObject 16 | 17 | + (id)shiftAction:(NSUInteger)shiftLocation; 18 | + (id)reduceAction:(CPRule *)reduction; 19 | + (id)acceptAction; 20 | 21 | - (id)initWithShift:(NSUInteger)shiftLocation; 22 | - (id)initWithReductionRule:(CPRule *)reduction; 23 | 24 | - (BOOL)isShiftAction; 25 | - (BOOL)isReduceAction; 26 | - (BOOL)isAccept; 27 | 28 | - (NSUInteger)newState; 29 | - (CPRule *)reductionRule; 30 | 31 | - (NSString *)descriptionWithGrammar:(CPGrammar *)g; 32 | 33 | - (BOOL)isEqualToShiftReduceAction:(CPShiftReduceAction *)object; 34 | 35 | @end 36 | 37 | @interface NSObject (CPIsShiftReduceAction) 38 | 39 | - (BOOL)isShiftReduceAction; 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceAction.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftReduceAction.h" 10 | 11 | #import "CPGrammarInternal.h" 12 | 13 | typedef enum 14 | { 15 | kActionTypeShift = 0, 16 | kActionTypeReduce , 17 | kActionTypeAccept 18 | } ActionType; 19 | 20 | typedef union 21 | { 22 | NSUInteger shift; 23 | CPRule *reductionRule; 24 | } 25 | ActionDetails; 26 | 27 | @implementation CPShiftReduceAction 28 | { 29 | ActionType type; 30 | ActionDetails details; 31 | } 32 | 33 | + (id)shiftAction:(NSUInteger)shiftLocation 34 | { 35 | return [[[self alloc] initWithShift:shiftLocation] autorelease]; 36 | } 37 | 38 | + (id)reduceAction:(CPRule *)reduction 39 | { 40 | return [[[self alloc] initWithReductionRule:reduction] autorelease]; 41 | } 42 | 43 | + (id)acceptAction 44 | { 45 | return [[[self alloc] init] autorelease]; 46 | } 47 | 48 | - (id)initWithShift:(NSUInteger)shiftLocation 49 | { 50 | self = [super init]; 51 | 52 | if (nil != self) 53 | { 54 | type = kActionTypeShift; 55 | details.shift = shiftLocation; 56 | } 57 | 58 | return self; 59 | } 60 | 61 | - (id)initWithReductionRule:(CPRule *)reduction 62 | { 63 | self = [super init]; 64 | 65 | if (nil != self) 66 | { 67 | type = kActionTypeReduce; 68 | details.reductionRule = [reduction retain]; 69 | } 70 | 71 | return self; 72 | } 73 | 74 | - (id)init 75 | { 76 | self = [super init]; 77 | 78 | if (nil != self) 79 | { 80 | type = kActionTypeAccept; 81 | } 82 | 83 | return self; 84 | } 85 | 86 | #define CPShiftReduceActionTypeKey @"t" 87 | #define CPShiftReduceActionShiftKey @"s" 88 | #define CPShiftReduceActionRuleKey @"r" 89 | 90 | - (id)initWithCoder:(NSCoder *)aDecoder 91 | { 92 | self = [super init]; 93 | 94 | if (nil != self) 95 | { 96 | type = [aDecoder decodeIntForKey:CPShiftReduceActionTypeKey]; 97 | switch (type) 98 | { 99 | case kActionTypeShift: 100 | details.shift = [aDecoder decodeIntegerForKey:CPShiftReduceActionShiftKey]; 101 | break; 102 | case kActionTypeReduce: 103 | details.reductionRule = [[aDecoder decodeObjectForKey:CPShiftReduceActionRuleKey] retain]; 104 | case kActionTypeAccept: 105 | default: 106 | break; 107 | } 108 | } 109 | 110 | return self; 111 | } 112 | 113 | - (void)encodeWithCoder:(NSCoder *)aCoder 114 | { 115 | [aCoder encodeInt:type forKey:CPShiftReduceActionTypeKey]; 116 | switch (type) 117 | { 118 | case kActionTypeShift: 119 | [aCoder encodeInteger:details.shift forKey:CPShiftReduceActionShiftKey]; 120 | break; 121 | case kActionTypeReduce: 122 | [aCoder encodeObject:details.reductionRule forKey:CPShiftReduceActionRuleKey]; 123 | case kActionTypeAccept: 124 | default: 125 | break; 126 | } 127 | } 128 | 129 | - (void)dealloc 130 | { 131 | if (kActionTypeReduce == type) 132 | { 133 | [details.reductionRule release]; 134 | } 135 | 136 | [super dealloc]; 137 | } 138 | 139 | - (BOOL)isShiftAction 140 | { 141 | return kActionTypeShift == type; 142 | } 143 | 144 | - (BOOL)isReduceAction 145 | { 146 | return kActionTypeReduce == type; 147 | } 148 | 149 | - (BOOL)isAccept 150 | { 151 | return kActionTypeAccept == type; 152 | } 153 | 154 | - (NSUInteger)newState 155 | { 156 | return details.shift; 157 | } 158 | 159 | - (CPRule *)reductionRule 160 | { 161 | return details.reductionRule; 162 | } 163 | 164 | - (NSUInteger)hash 165 | { 166 | return type; 167 | } 168 | 169 | - (BOOL)isShiftReduceAction 170 | { 171 | return YES; 172 | } 173 | 174 | - (BOOL)isEqual:(id)object 175 | { 176 | if ([object isShiftReduceAction] && ((CPShiftReduceAction *)object)->type == type) 177 | { 178 | CPShiftReduceAction *other = (CPShiftReduceAction *)object; 179 | switch (type) 180 | { 181 | case kActionTypeShift: 182 | return [other newState] == details.shift; 183 | case kActionTypeReduce: 184 | return [other reductionRule] == details.reductionRule; 185 | case kActionTypeAccept: 186 | return YES; 187 | } 188 | } 189 | 190 | return NO; 191 | } 192 | 193 | - (BOOL)isEqualToShiftReduceAction:(CPShiftReduceAction *)object 194 | { 195 | if (object != nil && object->type == type) 196 | { 197 | switch (type) 198 | { 199 | case kActionTypeShift: 200 | return [object newState] == details.shift; 201 | case kActionTypeReduce: 202 | return [object reductionRule] == details.reductionRule; 203 | case kActionTypeAccept: 204 | return YES; 205 | } 206 | } 207 | 208 | return NO; 209 | } 210 | 211 | - (NSString *)description 212 | { 213 | switch (type) 214 | { 215 | case kActionTypeShift: 216 | return [NSString stringWithFormat:@"s%ld", (long)details.shift]; 217 | case kActionTypeReduce: 218 | return [NSString stringWithFormat:@"r%@", [details.reductionRule name]]; 219 | case kActionTypeAccept: 220 | return @"acc"; 221 | } 222 | } 223 | 224 | - (NSString *)descriptionWithGrammar:(CPGrammar *)g 225 | { 226 | switch (type) 227 | { 228 | case kActionTypeShift: 229 | return [NSString stringWithFormat:@"s%ld", (long)details.shift]; 230 | case kActionTypeReduce: 231 | return [NSString stringWithFormat:@"r%ld", (long)[g indexOfRule:details.reductionRule]]; 232 | case kActionTypeAccept: 233 | return @"acc"; 234 | } 235 | } 236 | 237 | @end 238 | 239 | @implementation NSObject(CPIsShiftReduceAction) 240 | 241 | - (BOOL)isShiftReduceAction 242 | { 243 | return NO; 244 | } 245 | 246 | @end 247 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceActionTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceActionTable.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CPShiftReduceAction; 12 | 13 | #import "CPToken.h" 14 | #import "CPGrammar.h" 15 | 16 | @interface CPShiftReduceActionTable : NSObject 17 | {} 18 | 19 | - (id)initWithCapacity:(NSUInteger)capacity; 20 | 21 | - (BOOL)setAction:(CPShiftReduceAction *)action forState:(NSUInteger)state name:(NSString *)token; 22 | 23 | - (CPShiftReduceAction *)actionForState:(NSUInteger)state token:(CPToken *)token; 24 | - (NSSet *)acceptableTokenNamesForState:(NSUInteger)state; 25 | 26 | - (NSString *)descriptionWithGrammar:(CPGrammar *)g; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceActionTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceActionTable.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftReduceActionTable.h" 10 | 11 | #import "CPItem.h" 12 | #import "CPGrammarSymbol.h" 13 | #import "CPShiftReduceAction.h" 14 | 15 | @implementation CPShiftReduceActionTable 16 | { 17 | NSMutableDictionary **table; 18 | NSUInteger capacity; 19 | } 20 | 21 | - (id)initWithCapacity:(NSUInteger)initCapacity 22 | { 23 | self = [super init]; 24 | 25 | if (nil != self) 26 | { 27 | capacity = initCapacity; 28 | table = malloc(capacity * sizeof(NSMutableDictionary *)); 29 | for (NSUInteger buildingState = 0; buildingState < capacity; buildingState++) 30 | { 31 | table[buildingState] = [[NSMutableDictionary alloc] init]; 32 | } 33 | } 34 | 35 | return self; 36 | } 37 | 38 | #define CPShiftReduceActionTableTableKey @"t" 39 | 40 | - (id)initWithCoder:(NSCoder *)aDecoder 41 | { 42 | self = [super init]; 43 | 44 | if (nil != self) 45 | { 46 | NSArray *rows = [aDecoder decodeObjectForKey:CPShiftReduceActionTableTableKey]; 47 | capacity = [rows count]; 48 | table = malloc(capacity * sizeof(NSMutableDictionary *)); 49 | [rows getObjects:table range:NSMakeRange(0, capacity)]; 50 | for (NSUInteger i = 0; i < capacity; i++) 51 | { 52 | [table[i] retain]; 53 | } 54 | } 55 | 56 | return self; 57 | } 58 | 59 | - (void)encodeWithCoder:(NSCoder *)aCoder 60 | { 61 | [aCoder encodeObject:[NSArray arrayWithObjects:table count:capacity] forKey:CPShiftReduceActionTableTableKey]; 62 | } 63 | 64 | - (void)dealloc 65 | { 66 | for (NSUInteger state = 0; state < capacity; state++) 67 | { 68 | [table[state] release]; 69 | } 70 | free(table); 71 | 72 | [super dealloc]; 73 | } 74 | 75 | - (BOOL)setAction:(CPShiftReduceAction *)action forState:(NSUInteger)state name:(NSString *)token 76 | { 77 | NSMutableDictionary *row = table[state]; 78 | if (nil != [row objectForKey:token] && ![[row objectForKey:token] isEqualToShiftReduceAction:action]) 79 | { 80 | return NO; 81 | } 82 | [row setObject:action forKey:token]; 83 | return YES; 84 | } 85 | 86 | - (CPShiftReduceAction *)actionForState:(NSUInteger)state token:(CPToken *)token 87 | { 88 | return [table[state] objectForKey:token.name]; 89 | } 90 | 91 | - (NSSet *)acceptableTokenNamesForState:(NSUInteger)state 92 | { 93 | NSMutableSet *toks = [NSMutableSet set]; 94 | for (NSString *tok in table[state]) 95 | { 96 | if (nil != [table[state] objectForKey:tok]) 97 | { 98 | [toks addObject:tok]; 99 | } 100 | } 101 | return [[toks copy] autorelease]; 102 | } 103 | 104 | - (NSString *)description 105 | { 106 | if (capacity > 0) 107 | { 108 | NSMutableString *s = [NSMutableString string]; 109 | NSMutableSet *keys = [NSMutableSet set]; 110 | NSUInteger width = 3; 111 | for (NSUInteger state = 0; state < capacity; state++) 112 | { 113 | [keys addObjectsFromArray:[table[state] allKeys]]; 114 | } 115 | for (NSString *key in keys) 116 | { 117 | width = MAX(width, [key length]); 118 | } 119 | NSArray *orderedKeys = [keys allObjects]; 120 | [s appendString:@"State | "]; 121 | for (NSString *key in orderedKeys) 122 | { 123 | [s appendFormat:@"%@", key]; 124 | NSUInteger numSpaces = 1 + width - [key length]; 125 | for (NSUInteger numAdded = 0; numAdded < numSpaces; numAdded++) 126 | { 127 | [s appendString:@" "]; 128 | } 129 | } 130 | [s appendString:@"\n"]; 131 | 132 | NSUInteger idx = 0; 133 | for (NSUInteger state = 0; state < capacity; state++) 134 | { 135 | NSDictionary *row = table[state]; 136 | [s appendFormat:@"%5ld | ", (long)idx]; 137 | for (NSString *key in orderedKeys) 138 | { 139 | CPShiftReduceAction *action = [row objectForKey:key]; 140 | NSUInteger numSpaces; 141 | if (nil == action) 142 | { 143 | numSpaces = 1 + width; 144 | } 145 | else 146 | { 147 | [s appendFormat:@"%@", action]; 148 | numSpaces = 1 + width - [[action description] length]; 149 | } 150 | for (NSUInteger numAdded = 0; numAdded < numSpaces; numAdded++) 151 | { 152 | [s appendString:@" "]; 153 | } 154 | } 155 | [s appendString:@"\n"]; 156 | idx++; 157 | } 158 | 159 | return s; 160 | } 161 | 162 | return @""; 163 | } 164 | 165 | - (NSString *)descriptionWithGrammar:(CPGrammar *)g 166 | { 167 | if (capacity > 0) 168 | { 169 | NSMutableString *s = [NSMutableString string]; 170 | NSMutableSet *keys = [NSMutableSet set]; 171 | NSUInteger width = 3; 172 | for (NSUInteger state = 0; state < capacity; state++) 173 | { 174 | [keys addObjectsFromArray:[table[state] allKeys]]; 175 | } 176 | for (NSString *key in keys) 177 | { 178 | width = MAX(width, [key length]); 179 | } 180 | NSArray *orderedKeys = [keys allObjects]; 181 | [s appendString:@"State | "]; 182 | for (NSString *key in orderedKeys) 183 | { 184 | [s appendFormat:@"%@", key]; 185 | NSUInteger numSpaces = 1 + width - [key length]; 186 | for (NSUInteger numAdded = 0; numAdded < numSpaces; numAdded++) 187 | { 188 | [s appendString:@" "]; 189 | } 190 | } 191 | [s appendString:@"\n"]; 192 | 193 | NSUInteger idx = 0; 194 | for (NSUInteger state = 0; state < capacity; state++) 195 | { 196 | NSDictionary *row = table[state]; 197 | [s appendFormat:@"%5ld | ", (long)idx]; 198 | for (NSString *key in orderedKeys) 199 | { 200 | CPShiftReduceAction *action = [row objectForKey:key]; 201 | NSUInteger numSpaces; 202 | if (nil == action) 203 | { 204 | numSpaces = 1 + width; 205 | } 206 | else 207 | { 208 | [s appendFormat:@"%@", [action descriptionWithGrammar:g]]; 209 | numSpaces = 1 + width - [[action descriptionWithGrammar:g] length]; 210 | } 211 | for (NSUInteger numAdded = 0; numAdded < numSpaces; numAdded++) 212 | { 213 | [s appendString:@" "]; 214 | } 215 | } 216 | [s appendString:@"\n"]; 217 | idx++; 218 | } 219 | 220 | return s; 221 | } 222 | 223 | return @""; 224 | } 225 | 226 | @end 227 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceGotoTable.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceGotoTable.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class CPRule; 12 | 13 | @interface CPShiftReduceGotoTable : NSObject 14 | {} 15 | 16 | - (id)initWithCapacity:(NSUInteger)capacity; 17 | 18 | - (BOOL)setGoto:(NSUInteger)gotoIndex forState:(NSUInteger)state nonTerminalNamed:(NSString *)nonTerminalName; 19 | 20 | - (NSUInteger)gotoForState:(NSUInteger)state rule:(CPRule *)rule; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceGotoTable.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceGotoTable.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftReduceGotoTable.h" 10 | 11 | 12 | @implementation CPShiftReduceGotoTable 13 | { 14 | NSMutableDictionary **table; 15 | NSUInteger capacity; 16 | } 17 | 18 | - (id)initWithCapacity:(NSUInteger)initCapacity 19 | { 20 | self = [super init]; 21 | 22 | if (nil != self) 23 | { 24 | capacity = initCapacity; 25 | table = malloc(capacity * sizeof(NSMutableDictionary *)); 26 | for (NSUInteger buildingState = 0; buildingState < capacity; buildingState++) 27 | { 28 | table[buildingState] = [[NSMutableDictionary alloc] init]; 29 | } 30 | } 31 | 32 | return self; 33 | } 34 | 35 | #define CPShiftReduceGotoTableTableKey @"t" 36 | 37 | - (id)initWithCoder:(NSCoder *)aDecoder 38 | { 39 | self = [super init]; 40 | 41 | if (nil != self) 42 | { 43 | NSArray *rows = [aDecoder decodeObjectForKey:CPShiftReduceGotoTableTableKey]; 44 | capacity = [rows count]; 45 | table = malloc(capacity * sizeof(NSMutableDictionary *)); 46 | [rows getObjects:table range:NSMakeRange(0, capacity)]; 47 | for (NSUInteger i = 0; i < capacity; i++) 48 | { 49 | [table[i] retain]; 50 | } 51 | } 52 | 53 | return self; 54 | } 55 | 56 | - (void)encodeWithCoder:(NSCoder *)aCoder 57 | { 58 | [aCoder encodeObject:[NSArray arrayWithObjects:table count:capacity] forKey:CPShiftReduceGotoTableTableKey]; 59 | } 60 | 61 | - (void)dealloc 62 | { 63 | for (NSUInteger state = 0; state < capacity; state++) 64 | { 65 | [table[state] release]; 66 | } 67 | free(table); 68 | 69 | [super dealloc]; 70 | } 71 | 72 | - (BOOL)setGoto:(NSUInteger)gotoIndex forState:(NSUInteger)state nonTerminalNamed:(NSString *)nonTerminalName 73 | { 74 | NSMutableDictionary *row = table[state]; 75 | if (nil != [row objectForKey:nonTerminalName] && [[row objectForKey:nonTerminalName] unsignedIntegerValue] != gotoIndex) 76 | { 77 | return NO; 78 | } 79 | [row setObject:[NSNumber numberWithUnsignedInteger:gotoIndex] forKey:nonTerminalName]; 80 | return YES; 81 | } 82 | 83 | - (NSUInteger)gotoForState:(NSUInteger)state rule:(CPRule *)rule 84 | { 85 | return [(NSNumber *)[table[state] objectForKey:[rule name]] unsignedIntegerValue]; 86 | } 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceParserProtectedMethods.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceParserProtectedMethods.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 06/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPShiftReduceParser.h" 12 | 13 | #import "CPShiftReduceActionTable.h" 14 | #import "CPShiftReduceGotoTable.h" 15 | 16 | @interface CPShiftReduceParser () 17 | 18 | @property (readwrite,retain) CPShiftReduceActionTable *actionTable; 19 | @property (readwrite,retain) CPShiftReduceGotoTable *gotoTable; 20 | 21 | - (BOOL)constructShiftReduceTables; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceState.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceState.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CPShiftReduceState : NSObject 12 | 13 | @property (readonly,retain) NSObject *object; 14 | @property (readonly,assign) NSUInteger state; 15 | 16 | + (id)shiftReduceStateWithObject:(NSObject *)object state:(NSUInteger)state; 17 | - (id)initWithObject:(NSObject *)initObject state:(NSUInteger)initState; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /CoreParse/Parsers/CPShiftReduceParsers/CPShiftReduceState.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPShiftReduceState.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 05/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPShiftReduceState.h" 10 | 11 | @interface CPShiftReduceState () 12 | 13 | @property (readwrite,retain) NSObject *object; 14 | @property (readwrite,assign) NSUInteger state; 15 | 16 | @end 17 | 18 | @implementation CPShiftReduceState 19 | 20 | @synthesize object; 21 | @synthesize state; 22 | 23 | + (id)shiftReduceStateWithObject:(NSObject *)object state:(NSUInteger)state 24 | { 25 | return [[[self alloc] initWithObject:object state:state] autorelease]; 26 | } 27 | 28 | - (id)initWithObject:(NSObject *)initObject state:(NSUInteger)initState 29 | { 30 | self = [super init]; 31 | 32 | if (nil != self) 33 | { 34 | [self setObject:initObject]; 35 | [self setState:initState]; 36 | } 37 | 38 | return self; 39 | } 40 | 41 | - (void)dealloc 42 | { 43 | [object release]; 44 | 45 | [super dealloc]; 46 | } 47 | 48 | - (NSString *)description 49 | { 50 | return [NSString stringWithFormat:@" 10 | 11 | #import "CPToken.h" 12 | 13 | typedef enum 14 | { 15 | CPRecoveryTypeAddToken = 0, 16 | CPRecoveryTypeRemoveToken , 17 | CPRecoveryTypeBail 18 | } CPRecoveryType; 19 | 20 | /** 21 | * Represents an action to take to recover from an error. 22 | */ 23 | @interface CPRecoveryAction : NSObject 24 | 25 | /** 26 | * The type of recovery action to take. May be CPRecoveryTypeAddToken or CPRecoveryTypeRemoveToken. 27 | */ 28 | @property (readwrite, assign) CPRecoveryType recoveryType; 29 | 30 | /** 31 | * The token to insert in the token streem if a CPRecoveryTypeAddToken action is taken. 32 | */ 33 | @property (readwrite, retain) CPToken *additionalToken; 34 | 35 | /** 36 | * Allocates an initialises a new CPRecoveryAction asking the parser to add a new token to the token stream. 37 | * 38 | * @param token The token to add to the stream. 39 | * @return A new recovery action. 40 | */ 41 | + (id)recoveryActionWithAdditionalToken:(CPToken *)token; 42 | 43 | /** 44 | * Allocates an initialises a new CPRecoveryAction asking the parser to delete an offending token from the token stream. 45 | * 46 | * @return A new recovery action. 47 | */ 48 | + (id)recoveryActionDeletingCurrentToken; 49 | 50 | /** 51 | * Allocates and initialise a new CPRecovery action asking the parser to stop immediately. 52 | */ 53 | + (id)recoveryActionStop; 54 | 55 | /** 56 | * Initialises a CPRecoveryAction asking the parser to add a new token to the token stream. 57 | * 58 | * @param token The token to add to the stream. 59 | * @return An initialised recovery action. 60 | */ 61 | - (id)initWithAdditionalToken:(CPToken *)token; 62 | 63 | /** 64 | * Initialises a CPRecoveryAction asking the parser to delete an offending token from the token stream. 65 | * 66 | * @return An initialised recovery action. 67 | */ 68 | - (id)initWithDeleteAction; 69 | 70 | /** 71 | * Initialises a CPRecoveryAction asking the parser to stop immediately. 72 | */ 73 | - (id)initWithStopAction; 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /CoreParse/Parsers/Error Recovery/CPRecoveryAction.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRecoveryAction.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPRecoveryAction.h" 10 | 11 | @implementation CPRecoveryAction 12 | 13 | @synthesize recoveryType; 14 | @synthesize additionalToken; 15 | 16 | + (id)recoveryActionWithAdditionalToken:(CPToken *)token 17 | { 18 | return [[[self alloc] initWithAdditionalToken:token] autorelease]; 19 | } 20 | 21 | + (id)recoveryActionDeletingCurrentToken 22 | { 23 | return [[[self alloc] initWithDeleteAction] autorelease]; 24 | } 25 | 26 | + (id)recoveryActionStop 27 | { 28 | return [[[self alloc] initWithStopAction] autorelease]; 29 | } 30 | 31 | - (id)initWithAdditionalToken:(CPToken *)token 32 | { 33 | self = [super init]; 34 | 35 | if (nil != self) 36 | { 37 | [self setRecoveryType:CPRecoveryTypeAddToken]; 38 | [self setAdditionalToken:token]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (id)initWithDeleteAction 45 | { 46 | self = [super init]; 47 | 48 | if (nil != self) 49 | { 50 | [self setRecoveryType:CPRecoveryTypeRemoveToken]; 51 | } 52 | 53 | return self; 54 | } 55 | 56 | - (id)initWithStopAction 57 | { 58 | self = [super init]; 59 | 60 | if (nil != self) 61 | { 62 | [self setRecoveryType:CPRecoveryTypeBail]; 63 | } 64 | 65 | return self; 66 | } 67 | 68 | - (void)dealloc 69 | { 70 | [additionalToken release]; 71 | 72 | [super dealloc]; 73 | } 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /CoreParse/Syntax Tree/CPSyntaxTree.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPSyntaxTree.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPRule.h" 12 | 13 | /** 14 | * The CPSyntaxTree class represents a node in a syntax tree. 15 | * 16 | * Syntax trees carry the rule that was matched to create the tree and the child elements that in order match up with the right hand side of the rule. 17 | */ 18 | @interface CPSyntaxTree : NSObject 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising a Syntax Tree 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates a syntax tree based on a rule and some child trees. 26 | * 27 | * @param nonTerminal The rule that was matched to create this tree node. 28 | * @param children The child trees that represent the components of the right hand side of the rule. 29 | * @return Returns a syntax tree with apropriate children, and matching a specified rule. 30 | * 31 | * @bug Warning this method is deprecated, use -syntaxTreeWithRule:children:tagValues: instead. 32 | * @see syntaxTreeWithRule:children:tagValues 33 | */ 34 | + (id)syntaxTreeWithRule:(CPRule *)nonTerminal children:(NSArray *)children __attribute__((deprecated("use +syntaxTreeWithRule:children:tagValues: instead."))); 35 | 36 | /** 37 | * Initialises a syntax tree based on a rule and some child trees. 38 | * 39 | * @param nonTerminal The rule that was matched to create this tree node. 40 | * @param children The child trees that represent the components of the right hand side of the rule. 41 | * @return Returns a syntax tree with apropriate children, and matching a specified rule. 42 | * 43 | * @bug Warning this method is deprecated, use -initWithRule:children:tagValues: instead. 44 | * @see initWithRule:children:tagValues: 45 | */ 46 | - (id)initWithRule:(CPRule *)nonTerminal children:(NSArray *)children __attribute__((deprecated("use +initWithRule:children:tagValues: instead."))); 47 | 48 | /** 49 | * Creates a syntax tree based on a rule and some child trees. 50 | * 51 | * @param nonTerminal The rule that was matched to create this tree node. 52 | * @param children The child trees that represent the components of the right hand side of the rule. 53 | * @param tagValues The values of each tag beneath the rule. 54 | * @return Returns a syntax tree with apropriate children, and matching a specified rule. 55 | * 56 | * @see initWithRule:children:tagValues: 57 | */ 58 | + (id)syntaxTreeWithRule:(CPRule *)nonTerminal children:(NSArray *)children tagValues:(NSDictionary *)tagValues; 59 | 60 | /** 61 | * Initialises a syntax tree based on a rule and some child trees. 62 | * 63 | * @param nonTerminal The rule that was matched to create this tree node. 64 | * @param children The child trees that represent the components of the right hand side of the rule. 65 | * @param tagValues The values of each tag beneath the rule. 66 | * @return Returns a syntax tree with apropriate children, and matching a specified rule. 67 | * 68 | * @see syntaxTreeWithRule:children:tagValues 69 | */ 70 | - (id)initWithRule:(CPRule *)nonTerminal children:(NSArray *)children tagValues:(NSDictionary *)tagValues; 71 | 72 | ///--------------------------------------------------------------------------------------- 73 | /// @name Configuring a Syntax Tree 74 | ///--------------------------------------------------------------------------------------- 75 | 76 | /** 77 | * The rule matched to create this syntax tree. 78 | */ 79 | @property (readonly,retain) CPRule *rule; 80 | 81 | /** 82 | * The children that match the right hand side of the matched rule. 83 | */ 84 | @property (readonly,copy) NSArray *children; 85 | 86 | /** 87 | * The values of any tags found on the right hand side of the rule. 88 | */ 89 | @property (readonly,copy) NSDictionary *tagValues; 90 | 91 | /** 92 | * Returns the value of a specific tag. 93 | * 94 | * @param tagName The name of the tag you want the value of. 95 | * @return The sub syntax tree associated with that tag. 96 | */ 97 | - (id)valueForTag:(NSString *)tagName; 98 | 99 | /** 100 | * Returns the child at a specific index. 101 | * 102 | * @param idx The index of the child you want to retrieve. 103 | * @return The child at that index. 104 | */ 105 | - (id)childAtIndex:(NSUInteger)idx; 106 | 107 | @end 108 | 109 | @interface NSObject (CPIsSyntaxTree) 110 | 111 | - (BOOL)isSyntaxTree; 112 | 113 | @end 114 | -------------------------------------------------------------------------------- /CoreParse/Syntax Tree/CPSyntaxTree.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPSyntaxTree.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 04/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPSyntaxTree.h" 10 | 11 | @interface CPSyntaxTree () 12 | 13 | @property (readwrite,retain) CPRule *rule; 14 | @property (readwrite,copy) NSArray *children; 15 | @property (readwrite,copy) NSDictionary *tagValues; 16 | 17 | @end 18 | 19 | @implementation CPSyntaxTree 20 | 21 | @synthesize rule; 22 | @synthesize children; 23 | @synthesize tagValues; 24 | 25 | + (id)syntaxTreeWithRule:(CPRule *)rule children:(NSArray *)children 26 | { 27 | return [[[self alloc] initWithRule:rule children:children tagValues:[NSDictionary dictionary]] autorelease]; 28 | } 29 | 30 | - (id)initWithRule:(CPRule *)initRule children:(NSArray *)initChildren; 31 | { 32 | return [self initWithRule:initRule children:initChildren tagValues:[NSDictionary dictionary]]; 33 | } 34 | 35 | + (id)syntaxTreeWithRule:(CPRule *)rule children:(NSArray *)children tagValues:(NSDictionary *)tagValues; 36 | { 37 | return [[[self alloc] initWithRule:rule children:children tagValues:tagValues] autorelease]; 38 | } 39 | 40 | - (id)initWithRule:(CPRule *)initRule children:(NSArray *)initChildren tagValues:(NSDictionary *)initTagValues 41 | { 42 | self = [super init]; 43 | 44 | if (nil != self) 45 | { 46 | [self setRule:initRule]; 47 | [self setChildren:initChildren]; 48 | [self setTagValues:initTagValues]; 49 | } 50 | 51 | return self; 52 | } 53 | 54 | - (id)init 55 | { 56 | return [self initWithRule:nil children:[NSArray array] tagValues:[NSDictionary dictionary]]; 57 | } 58 | 59 | - (void)dealloc 60 | { 61 | [rule release]; 62 | [children release]; 63 | [tagValues release]; 64 | 65 | [super dealloc]; 66 | } 67 | 68 | - (id)valueForTag:(NSString *)tagName 69 | { 70 | return [tagValues objectForKey:tagName]; 71 | } 72 | 73 | - (id)childAtIndex:(NSUInteger)idx 74 | { 75 | return [children objectAtIndex:idx]; 76 | } 77 | 78 | - (NSUInteger)hash 79 | { 80 | return [[self rule] hash]; 81 | } 82 | 83 | - (BOOL)isSyntaxTree 84 | { 85 | return YES; 86 | } 87 | 88 | - (BOOL)isEqual:(id)object 89 | { 90 | return ([object isSyntaxTree] && 91 | ((CPSyntaxTree *)object)->rule == rule && 92 | [((CPSyntaxTree *)object)->children isEqualToArray:children]); 93 | } 94 | 95 | - (NSString *)description 96 | { 97 | NSMutableString *desc = [NSMutableString stringWithString:@"("]; 98 | for (id obj in children) 99 | { 100 | [desc appendFormat:@"%@ ", obj]; 101 | } 102 | [desc replaceCharactersInRange:NSMakeRange([desc length] - 1, 1) withString:@")"]; 103 | return desc; 104 | } 105 | 106 | @end 107 | 108 | @implementation NSObject(CPIsSyntaxTree) 109 | 110 | - (BOOL)isSyntaxTree 111 | { 112 | return NO; 113 | } 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/CPTokenStream.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTokenStream.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 10/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * CPTokenStreams store the output of a tokeniser ready for parsing. 15 | * 16 | * This class manages a thread safe buffer between tokenising and parsing threads, blocking as apropriate to wait for new tokens. 17 | * When a tokeniser has consumed its entire input it should call -closeTokenStream to notify parsers that no further input will be found. 18 | * Tokenisers that consume their entire input with no errors should produce a CPEOFToken at the end of the stream to inform parsers that the stream is complete. 19 | */ 20 | @interface CPTokenStream : NSObject 21 | 22 | ///--------------------------------------------------------------------------------------- 23 | /// @name Creating and Initialising Token Streams 24 | ///--------------------------------------------------------------------------------------- 25 | 26 | /** 27 | * Creates a token stream with a set of tokens already ready for parsing. 28 | * 29 | * @param tokens A set of tokens to place at the start of the token stream. 30 | * @return Returns a token stream containing tokens at its start. 31 | * @see initWithTokens: 32 | */ 33 | + (id)tokenStreamWithTokens:(NSArray *)tokens; 34 | 35 | /** 36 | * Initialises a token stream with a set of tokens already ready for parsing. 37 | * 38 | * @param tokens A set of tokens to place at the start of the token stream. 39 | * @return Returns the token stream, now containing tokens at its start. 40 | * @see tokenStreamWithTokens: 41 | */ 42 | - (id)initWithTokens:(NSArray *)tokens; 43 | 44 | ///--------------------------------------------------------------------------------------- 45 | /// @name Adding and Removing Tokens 46 | ///--------------------------------------------------------------------------------------- 47 | 48 | /** 49 | * Returns the first token in the stream but does not remove it from the stream. 50 | * 51 | * This method will not block waiting for a token to become available. If no token is available the method returns `nil`. If the token stream is closed the method returns `nil`. 52 | * 53 | * @return The first CPToken in the stream. 54 | * @see popToken 55 | */ 56 | - (CPToken *)peekToken; 57 | 58 | /** 59 | * Returns the first token in the stream and removes it from the stream. 60 | * 61 | * This method will block waiting for a token to become available if the token stream is empty. If the token stream is closed the method returns `nil`. 62 | * 63 | * @return The first CPToken in the stream. 64 | * @see peekToken 65 | */ 66 | - (CPToken *)popToken; 67 | 68 | /** 69 | * Adds a CPToken to the end of the token stream. 70 | * 71 | * @param token The token to add to the stream. 72 | * @see pushTokens: 73 | */ 74 | - (void)pushToken:(CPToken *)token; 75 | 76 | /** 77 | * Adds several CPTokens to the end of the token stream. 78 | * 79 | * The tokens are added in order. 80 | * 81 | * @param tokens The array of tokens to add to the token stream. 82 | * @see pushToken: 83 | */ 84 | - (void)pushTokens:(NSArray *)tokens; 85 | 86 | ///--------------------------------------------------------------------------------------- 87 | /// @name Finishing Tokenisation 88 | ///--------------------------------------------------------------------------------------- 89 | 90 | /** 91 | * Closes the token stream, causing popToken to return `nil` when all tokens have been exhausted rather than blocking waiting for new input. 92 | */ 93 | - (void)closeTokenStream; 94 | 95 | @end 96 | 97 | @interface NSObject (CPIsTokenStream) 98 | 99 | - (BOOL)isTokenStream; 100 | 101 | @end 102 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/CPTokenStream.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTokenStream.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 10/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTokenStream.h" 10 | 11 | @interface CPTokenStream () 12 | 13 | @property (readwrite,copy) NSArray *tokens; 14 | 15 | - (void)unlockTokenStream; 16 | 17 | @end 18 | 19 | typedef enum 20 | { 21 | CPTokenStreamAvailable = 0, 22 | CPTokenStreamUnavailable 23 | } CPTokenStreamLockCondition; 24 | 25 | @implementation CPTokenStream 26 | { 27 | BOOL isClosed; 28 | NSMutableArray *tokens; 29 | NSConditionLock *readWriteLock; 30 | } 31 | 32 | + (id)tokenStreamWithTokens:(NSArray *)tokens 33 | { 34 | return [[[self alloc] initWithTokens:tokens] autorelease]; 35 | } 36 | 37 | - (id)initWithTokens:(NSArray *)initTokens 38 | { 39 | self = [self init]; 40 | 41 | if (nil != self) 42 | { 43 | [self setTokens:[[initTokens mutableCopy] autorelease]]; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | - (id)init 50 | { 51 | self = [super init]; 52 | 53 | if (nil != self) 54 | { 55 | isClosed = NO; 56 | readWriteLock = [[NSConditionLock alloc] initWithCondition:CPTokenStreamUnavailable]; 57 | [self setTokens:[NSMutableArray array]]; 58 | } 59 | 60 | return self; 61 | } 62 | 63 | - (void)dealloc 64 | { 65 | [tokens release]; 66 | [readWriteLock release]; 67 | 68 | [super dealloc]; 69 | } 70 | 71 | - (CPToken *)peekToken 72 | { 73 | [readWriteLock lockWhenCondition:CPTokenStreamAvailable]; 74 | CPToken *token = nil; 75 | 76 | if ([tokens count] > 0) 77 | { 78 | token = [[[tokens objectAtIndex:0] retain] autorelease]; 79 | } 80 | [readWriteLock unlockWithCondition:CPTokenStreamAvailable]; 81 | 82 | return token; 83 | } 84 | 85 | - (CPToken *)popToken 86 | { 87 | [readWriteLock lockWhenCondition:CPTokenStreamAvailable]; 88 | CPToken *token = nil; 89 | if ([tokens count] > 0) 90 | { 91 | token = [[[tokens objectAtIndex:0] retain] autorelease]; 92 | [tokens removeObjectAtIndex:0]; 93 | } 94 | [self unlockTokenStream]; 95 | return token; 96 | } 97 | 98 | 99 | - (NSArray *)tokens 100 | { 101 | return [[tokens copy] autorelease]; 102 | } 103 | 104 | - (void)setTokens:(NSMutableArray *)newTokens 105 | { 106 | [readWriteLock lock]; 107 | if (tokens != newTokens) 108 | { 109 | [tokens release]; 110 | tokens = [newTokens mutableCopy]; 111 | } 112 | [self unlockTokenStream]; 113 | } 114 | 115 | - (void)pushToken:(CPToken *)token 116 | { 117 | [readWriteLock lock]; 118 | [tokens addObject:token]; 119 | [readWriteLock unlockWithCondition:CPTokenStreamAvailable]; 120 | } 121 | 122 | - (void)pushTokens:(NSArray *)newTokens 123 | { 124 | [readWriteLock lock]; 125 | [tokens addObjectsFromArray:newTokens]; 126 | [self unlockTokenStream]; 127 | } 128 | 129 | - (void)closeTokenStream 130 | { 131 | [readWriteLock lock]; 132 | isClosed = YES; 133 | [readWriteLock unlockWithCondition:CPTokenStreamAvailable]; 134 | } 135 | 136 | - (NSString *)description 137 | { 138 | NSMutableString *desc = [NSMutableString string]; 139 | 140 | for (CPToken *tok in [self tokens]) 141 | { 142 | [desc appendFormat:@"%@ ", tok]; 143 | } 144 | 145 | return desc; 146 | } 147 | 148 | - (void)unlockTokenStream 149 | { 150 | [readWriteLock unlockWithCondition:isClosed || [tokens count] > 0 ? CPTokenStreamAvailable : CPTokenStreamUnavailable]; 151 | } 152 | 153 | - (NSUInteger)hash 154 | { 155 | return [[self tokens] hash]; 156 | } 157 | 158 | - (BOOL)isTokenStream 159 | { 160 | return YES; 161 | } 162 | 163 | - (BOOL)isEqual:(id)object 164 | { 165 | return ([object isTokenStream] && 166 | [((CPTokenStream *)object)->tokens isEqualToArray:tokens]); 167 | } 168 | 169 | @end 170 | 171 | @implementation NSObject (CPIsTokenStream) 172 | 173 | - (BOOL)isTokenStream 174 | { 175 | return NO; 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPIdentifierRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPIdentifierTokeniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPTokenRecogniser.h" 12 | 13 | /** 14 | * The CPIdentifierRecogniser class attempts to recognise identifiers on the input string. 15 | * 16 | * Identifiers are sequences of characters which begin with a character in one set, and then may contain many characters in a further set subsequently. 17 | * 18 | * This recogniser produces CPIdentifierTokens. 19 | */ 20 | @interface CPIdentifierRecogniser : NSObject 21 | 22 | ///--------------------------------------------------------------------------------------- 23 | /// @name Creating and Initialising an Identifier Recogniser 24 | ///--------------------------------------------------------------------------------------- 25 | 26 | /** 27 | * Creates an identifier recogniser that recognises identifiers starting with any english alphabetic character or underscore, and then containing any number of those characters, hyphens, or numeric characters. 28 | * 29 | * @return Returns a CPIdentifierRecogniser that recognises C like identifiers. 30 | * 31 | * @see identifierRecogniserWithInitialCharacters:identifierCharacters: 32 | */ 33 | + (id)identifierRecogniser; 34 | 35 | /** 36 | * Creates an identifier recogniser that recognises identifiers starting with any character in initialCharacters, and then containing any number of characters in identifierCharacters. 37 | * 38 | * @param initialCharacters The set of characters that the identifier may begin with. 39 | * @param identifierCharacters The set of characters that the identifier may contain, after its first character. 40 | * @return Returns a CPIdentifierRecogniser that recognises identifiers based on the input character sets. 41 | * 42 | * @see initWithInitialCharacters:identifierCharacters: 43 | */ 44 | + (id)identifierRecogniserWithInitialCharacters:(NSCharacterSet *)initialCharacters identifierCharacters:(NSCharacterSet *)identifierCharacters; 45 | 46 | /** 47 | * Initialises an identifier recogniser that recognises identifiers starting with any character in initialCharacters, and then containing any number of characters in identifierCharacters. 48 | * 49 | * @param initialCharacters The set of characters that the identifier may begin with. 50 | * @param identifierCharacters The set of characters that the identifier may contain, after its first character. 51 | * @return Returns the CPIdentifierRecogniser that recognises identifiers based on the input character sets. 52 | * 53 | * @see identifierRecogniserWithInitialCharacters:identifierCharacters: 54 | */ 55 | - (id)initWithInitialCharacters:(NSCharacterSet *)initialCharacters identifierCharacters:(NSCharacterSet *)identifierCharacters; 56 | 57 | ///--------------------------------------------------------------------------------------- 58 | /// @name Configuring an Identifier Recogniser 59 | ///--------------------------------------------------------------------------------------- 60 | 61 | /** 62 | * Specifies the set of characters the recognised identifiers may begin with. 63 | * 64 | * @see identifierCharacters 65 | */ 66 | @property (readwrite,retain) NSCharacterSet *initialCharacters; 67 | 68 | /** 69 | * Specifies the set of characters the recognised identifiers may contain, other than their first character. 70 | * 71 | * @see initialCharacters 72 | */ 73 | @property (readwrite,retain) NSCharacterSet *identifierCharacters; 74 | 75 | @end 76 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPIdentifierRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPIdentifierTokeniser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPIdentifierRecogniser.h" 10 | 11 | #import "CPIdentifierToken.h" 12 | 13 | @implementation CPIdentifierRecogniser 14 | 15 | @synthesize initialCharacters; 16 | @synthesize identifierCharacters; 17 | 18 | + (id)identifierRecogniser 19 | { 20 | return [[[CPIdentifierRecogniser alloc] initWithInitialCharacters:nil identifierCharacters:nil] autorelease]; 21 | } 22 | 23 | + (id)identifierRecogniserWithInitialCharacters:(NSCharacterSet *)initialCharacters identifierCharacters:(NSCharacterSet *)identifierCharacters 24 | { 25 | return [[[CPIdentifierRecogniser alloc] initWithInitialCharacters:initialCharacters identifierCharacters:identifierCharacters] autorelease]; 26 | } 27 | 28 | - (id)initWithInitialCharacters:(NSCharacterSet *)initInitialCharacters identifierCharacters:(NSCharacterSet *)initIdentifierCharacters 29 | { 30 | self = [super init]; 31 | 32 | if (nil != self) 33 | { 34 | [self setInitialCharacters:initInitialCharacters]; 35 | [self setIdentifierCharacters:initIdentifierCharacters]; 36 | } 37 | 38 | return self; 39 | } 40 | 41 | #define CPIdentifierRecogniserInitialCharactersKey @"I.i" 42 | #define CPIdentifierRecogniserIdentifierCharactersKey @"I.c" 43 | 44 | - (id)initWithCoder:(NSCoder *)aDecoder 45 | { 46 | self = [super init]; 47 | 48 | if (nil != self) 49 | { 50 | [self setInitialCharacters:[aDecoder decodeObjectForKey:CPIdentifierRecogniserInitialCharactersKey]]; 51 | [self setIdentifierCharacters:[aDecoder decodeObjectForKey:CPIdentifierRecogniserIdentifierCharactersKey]]; 52 | } 53 | 54 | return self; 55 | } 56 | 57 | - (void)encodeWithCoder:(NSCoder *)aCoder 58 | { 59 | [aCoder encodeObject:[self initialCharacters] forKey:CPIdentifierRecogniserInitialCharactersKey]; 60 | [aCoder encodeObject:[self identifierCharacters] forKey:CPIdentifierRecogniserIdentifierCharactersKey]; 61 | } 62 | 63 | - (void)dealloc 64 | { 65 | [initialCharacters release]; 66 | [identifierCharacters release]; 67 | 68 | [super dealloc]; 69 | } 70 | 71 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 72 | { 73 | NSCharacterSet *identifierStartCharacters = nil == [self initialCharacters] ? [NSCharacterSet characterSetWithCharactersInString: 74 | @"abcdefghijklmnopqrstuvwxyz" 75 | @"ABCDEFGHIJKLMNOPQRSTUVWXYZ" 76 | @"_"] : [self initialCharacters]; 77 | NSCharacterSet *idCharacters = nil == [self identifierCharacters] ? [NSCharacterSet characterSetWithCharactersInString: 78 | @"abcdefghijklmnopqrstuvwxyz" 79 | @"ABCDEFGHIJKLMNOPQRSTUVWXYZ" 80 | @"_-1234567890"] : [self identifierCharacters]; 81 | 82 | unichar firstChar = [tokenString characterAtIndex:*tokenPosition]; 83 | if ([identifierStartCharacters characterIsMember:firstChar]) 84 | { 85 | NSString *identifierString; 86 | NSScanner *scanner = [NSScanner scannerWithString:tokenString]; 87 | [scanner setScanLocation:*tokenPosition + 1]; 88 | [scanner setCharactersToBeSkipped:nil]; 89 | BOOL success = [scanner scanCharactersFromSet:idCharacters intoString:&identifierString]; 90 | if (success) 91 | { 92 | identifierString = [[[[NSString alloc] initWithCharacters:&firstChar length:1] autorelease] stringByAppendingString:identifierString]; 93 | *tokenPosition = [scanner scanLocation]; 94 | } 95 | else 96 | { 97 | identifierString = [[[NSString alloc] initWithCharacters:&firstChar length:1] autorelease]; 98 | *tokenPosition += 1; 99 | } 100 | return [CPIdentifierToken tokenWithIdentifier:identifierString]; 101 | } 102 | 103 | return nil; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPKeywordRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPKeywordRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPTokenRecogniser.h" 12 | #import "CPKeywordToken.h" 13 | 14 | /** 15 | * The CPKeywordRecogniser class attempts to recognise a specific keyword in a token stream. 16 | * 17 | * A keyword recogniser attempts to recognise a specific word or set of symbols. 18 | * Keyword recognisers can also check that the keyword is not followed by specific characters in order to stop it recognising the beginnings of words. 19 | * 20 | * This recogniser produces CPKeywordTokens. 21 | */ 22 | @interface CPKeywordRecogniser : NSObject 23 | 24 | ///--------------------------------------------------------------------------------------- 25 | /// @name Creating and Initialising a Keyword Recogniser 26 | ///--------------------------------------------------------------------------------------- 27 | 28 | /** 29 | * Creates a Keyword Recogniser for a specific keyword. 30 | * 31 | * @param keyword The keyword to recognise. 32 | * 33 | * @return Returns a keyword recogniser for the passed keyword. 34 | * 35 | * @see initWithKeyword: 36 | * @see recogniserForKeyword:invalidFollowingCharacters: 37 | */ 38 | + (id)recogniserForKeyword:(NSString *)keyword; 39 | 40 | /** 41 | * Creates a Keyword Recogniser for a specific keyword. 42 | * 43 | * @param keyword The keyword to recognise. 44 | * @param invalidFollowingCharacters A set of characters that may not follow the keyword in the string being tokenised. 45 | * 46 | * @return Returns a keyword recogniser for the passed keyword. 47 | * 48 | * @see recogniserForKeyword: 49 | * @see initWithKeyword:invalidFollowingCharacters: 50 | */ 51 | + (id)recogniserForKeyword:(NSString *)keyword invalidFollowingCharacters:(NSCharacterSet *)invalidFollowingCharacters; 52 | 53 | /** 54 | * Initialises a Keyword Recogniser to recognise a specific keyword. 55 | * 56 | * @param keyword The keyword to recognise. 57 | * 58 | * @return Returns the keyword recogniser initialised to recognise the passed keyword. 59 | * 60 | * @see recogniserForKeyword: 61 | * @see initWithKeyword:invalidFollowingCharacters: 62 | */ 63 | - (id)initWithKeyword:(NSString *)keyword; 64 | 65 | /** 66 | * Initialises a Keyword Recogniser to recognise a specific keyword. 67 | * 68 | * @param keyword The keyword to recognise. 69 | * @param invalidFollowingCharacters A set of characters that may not follow the keyword in the string being tokenised. 70 | * 71 | * @return Returns the keyword recogniser initialised to recognise the passed keyword. 72 | * 73 | * @see initWithKeyword: 74 | * @see recogniserForKeyword:invalidFollowingCharacters: 75 | */ 76 | - (id)initWithKeyword:(NSString *)keyword invalidFollowingCharacters:(NSCharacterSet *)invalidFollowingCharacters; 77 | 78 | ///--------------------------------------------------------------------------------------- 79 | /// @name Configuring a Keyword Recogniser 80 | ///--------------------------------------------------------------------------------------- 81 | 82 | /** 83 | * The keyword that the recogniser should attempt to recognise. 84 | */ 85 | @property (readwrite,retain,nonatomic) NSString *keyword; 86 | 87 | /** 88 | * A set of characters that may not follow the keyword. 89 | */ 90 | @property (readwrite,retain,nonatomic) NSCharacterSet *invalidFollowingCharacters; 91 | 92 | @end 93 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPKeywordRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPKeywordRecogniser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPKeywordRecogniser.h" 10 | 11 | @implementation CPKeywordRecogniser 12 | 13 | @synthesize keyword; 14 | @synthesize invalidFollowingCharacters; 15 | 16 | + (id)recogniserForKeyword:(NSString *)keyword 17 | { 18 | return [[[self alloc] initWithKeyword:keyword] autorelease]; 19 | } 20 | 21 | - (id)initWithKeyword:(NSString *)initKeyword 22 | { 23 | return [self initWithKeyword:initKeyword invalidFollowingCharacters:nil]; 24 | } 25 | 26 | + (id)recogniserForKeyword:(NSString *)keyword invalidFollowingCharacters:(NSCharacterSet *)invalidFollowingCharacters 27 | { 28 | return [[[self alloc] initWithKeyword:keyword invalidFollowingCharacters:invalidFollowingCharacters] autorelease]; 29 | } 30 | 31 | - (id)initWithKeyword:(NSString *)initKeyword invalidFollowingCharacters:(NSCharacterSet *)initInvalidFollowingCharacters 32 | { 33 | self = [super init]; 34 | 35 | if (nil != self) 36 | { 37 | [self setKeyword:initKeyword]; 38 | [self setInvalidFollowingCharacters:initInvalidFollowingCharacters]; 39 | } 40 | 41 | return self; 42 | } 43 | 44 | - (id)init 45 | { 46 | return [self initWithKeyword:@" "]; 47 | } 48 | 49 | #define CPKeywordRecogniserKeywordKey @"K.k" 50 | #define CPKeywordRecogniserInvalidFollowingCharactersKey @"K.f" 51 | 52 | - (id)initWithCoder:(NSCoder *)aDecoder 53 | { 54 | self = [super init]; 55 | 56 | if (nil != self) 57 | { 58 | [self setKeyword:[aDecoder decodeObjectForKey:CPKeywordRecogniserKeywordKey]]; 59 | [self setInvalidFollowingCharacters:[aDecoder decodeObjectForKey:CPKeywordRecogniserInvalidFollowingCharactersKey]]; 60 | } 61 | 62 | return self; 63 | } 64 | 65 | - (void)encodeWithCoder:(NSCoder *)aCoder 66 | { 67 | [aCoder encodeObject:[self keyword] forKey:CPKeywordRecogniserKeywordKey]; 68 | [aCoder encodeObject:[self invalidFollowingCharacters] forKey:CPKeywordRecogniserInvalidFollowingCharactersKey]; 69 | } 70 | 71 | - (void)dealloc 72 | { 73 | [keyword release]; 74 | [invalidFollowingCharacters release]; 75 | 76 | [super dealloc]; 77 | } 78 | 79 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 80 | { 81 | NSUInteger kwLength = [keyword length]; 82 | NSUInteger remainingChars = [tokenString length] - *tokenPosition; 83 | if (remainingChars >= kwLength) 84 | { 85 | if (CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)keyword, CFRangeMake(*tokenPosition, kwLength), kCFCompareAnchored, NULL)) 86 | { 87 | if (remainingChars == kwLength || 88 | nil == invalidFollowingCharacters || 89 | !CFStringFindCharacterFromSet((CFStringRef)tokenString, (CFCharacterSetRef)invalidFollowingCharacters, CFRangeMake(*tokenPosition + kwLength, 1), kCFCompareAnchored, NULL)) 90 | { 91 | *tokenPosition = *tokenPosition + kwLength; 92 | return [CPKeywordToken tokenWithKeyword:keyword]; 93 | } 94 | } 95 | } 96 | 97 | return nil; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPNumberRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPIntegerRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPTokenRecogniser.h" 12 | 13 | /** 14 | * The CPNumberRecogniser class attempts to recognise integers and floating point numbers in the input string. 15 | * 16 | * Number recognisers can be set up to recognise only integers, only floating point numbers, or both. 17 | * 18 | * This recogniser produces CPNumberTokens. 19 | */ 20 | @interface CPNumberRecogniser : NSObject 21 | 22 | ///--------------------------------------------------------------------------------------- 23 | /// @name Creating and Initialising a Number Recogniser 24 | ///--------------------------------------------------------------------------------------- 25 | 26 | /** 27 | * Creates a number recogniser that recognises only integers. 28 | * 29 | * @return Returns a CPNumberRecogniser that recognises only integers. 30 | * 31 | * @see floatRecogniser 32 | * @see numberRecogniser 33 | */ 34 | + (id)integerRecogniser; 35 | 36 | /** 37 | * Creates a number recogniser that recognises only floating point numbers. 38 | * 39 | * @return Returns a CPNumberRecogniser that recognises only floating point numbers. 40 | * 41 | * @see integerRecogniser 42 | * @see numberRecogniser 43 | */ 44 | + (id)floatRecogniser; 45 | 46 | /** 47 | * Creates a number recogniser that recognises both integers and floating point numbers. 48 | * 49 | * @return Returns a CPNumberRecogniser that recognises both integers and floating point numbers. 50 | * 51 | * @see integerRecogniser 52 | * @see floatRecogniser 53 | */ 54 | + (id)numberRecogniser; 55 | 56 | ///--------------------------------------------------------------------------------------- 57 | /// @name Configuring a Number Recogniser 58 | ///--------------------------------------------------------------------------------------- 59 | 60 | /** 61 | * Specifies whether the recogniser should recognise integers. 62 | * 63 | * @see recognisesFloats 64 | */ 65 | @property (readwrite,assign) BOOL recognisesInts; 66 | 67 | /** 68 | * Specifies whether the recogniser should recognise floating point numbers. 69 | * 70 | * @see recognisesFloats 71 | */ 72 | @property (readwrite,assign) BOOL recognisesFloats; 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPNumberRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPIntegerRecogniser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPNumberRecogniser.h" 10 | 11 | #import "CPNumberToken.h" 12 | 13 | @implementation CPNumberRecogniser 14 | 15 | @synthesize recognisesInts; 16 | @synthesize recognisesFloats; 17 | 18 | #define CPNumberRecogniserRecognisesIntsKey @"N.i" 19 | #define CPNumberRecogniserRecognisesFloatsKey @"N.f" 20 | 21 | - (id)initWithCoder:(NSCoder *)aDecoder 22 | { 23 | self = [super init]; 24 | 25 | if (nil != self) 26 | { 27 | [self setRecognisesInts:[aDecoder decodeBoolForKey:CPNumberRecogniserRecognisesIntsKey]]; 28 | [self setRecognisesFloats:[aDecoder decodeBoolForKey:CPNumberRecogniserRecognisesFloatsKey]]; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (void)encodeWithCoder:(NSCoder *)aCoder 35 | { 36 | [aCoder encodeBool:[self recognisesInts] forKey:CPNumberRecogniserRecognisesIntsKey]; 37 | [aCoder encodeBool:[self recognisesFloats] forKey:CPNumberRecogniserRecognisesFloatsKey]; 38 | } 39 | 40 | + (id)integerRecogniser 41 | { 42 | CPNumberRecogniser *rec = [[[CPNumberRecogniser alloc] init] autorelease]; 43 | [rec setRecognisesInts:YES]; 44 | [rec setRecognisesFloats:NO]; 45 | return rec; 46 | } 47 | 48 | + (id)floatRecogniser 49 | { 50 | CPNumberRecogniser *rec = [[[CPNumberRecogniser alloc] init] autorelease]; 51 | [rec setRecognisesInts:NO]; 52 | [rec setRecognisesFloats:YES]; 53 | return rec; 54 | } 55 | 56 | + (id)numberRecogniser 57 | { 58 | CPNumberRecogniser *rec = [[[CPNumberRecogniser alloc] init] autorelease]; 59 | [rec setRecognisesInts:YES]; 60 | [rec setRecognisesFloats:YES]; 61 | return rec; 62 | } 63 | 64 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 65 | { 66 | NSScanner *scanner = [NSScanner scannerWithString:tokenString]; 67 | [scanner setCharactersToBeSkipped:nil]; 68 | [scanner setScanLocation:*tokenPosition]; 69 | 70 | if (![self recognisesFloats]) 71 | { 72 | NSInteger i; 73 | BOOL success = [scanner scanInteger:&i]; 74 | if (success) 75 | { 76 | *tokenPosition = [scanner scanLocation]; 77 | return [CPNumberToken tokenWithNumber:[NSNumber numberWithInteger:i]]; 78 | } 79 | } 80 | else 81 | { 82 | double d; 83 | BOOL success = [scanner scanDouble:&d]; 84 | if (success && ![self recognisesInts]) 85 | { 86 | NSRange numberRange = NSMakeRange(*tokenPosition, [scanner scanLocation] - *tokenPosition); 87 | if ([tokenString rangeOfString:@"." options:0x0 range:numberRange].location == NSNotFound && 88 | [tokenString rangeOfString:@"e" options:0x0 range:numberRange].location == NSNotFound) 89 | { 90 | success = NO; 91 | } 92 | } 93 | if (success) 94 | { 95 | *tokenPosition = [scanner scanLocation]; 96 | return [CPNumberToken tokenWithNumber:[NSNumber numberWithDouble:d]]; 97 | } 98 | } 99 | 100 | return nil; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPQuotedRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPQuotedRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPTokenRecogniser.h" 12 | 13 | /** 14 | * The CPQuotedRecogniser class is used to recognise quoted literals in the input string. This can be used for quoted strings, characters, comments and many other things. 15 | * 16 | * Quoted tokens are recognised via a start string and end string. You may optionally add an escape sequence string that stops the end quote being recognised at that point in the input. 17 | * You may optionally provide a block used to replace escape sequences with their actual meaning. If you don't provide an escape replcement block it is assumed that the character 18 | * following the escape sequence replaces the whole sequence. 19 | * 20 | * Finally, you may also provide a maximum length for the quoted sequence to recognise. If you want to recognise strings of any length, pass NSNotFound. 21 | * 22 | * This recogniser produces CPQuotedTokens. The name of the produced tokens is determined by the name property. 23 | */ 24 | @interface CPQuotedRecogniser : NSObject 25 | 26 | ///--------------------------------------------------------------------------------------- 27 | /// @name Creating and Initialising a Quoted Recogniser 28 | ///--------------------------------------------------------------------------------------- 29 | 30 | /** 31 | * Creates a quoted recogniser that recognises quoted litterals starting with startQuote and ending with endQuote. 32 | * 33 | * @param startQuote A string that indicates the beginning of a quoted literal. 34 | * @param endQuote A string that indicates the end of the quoted literal. 35 | * @param name The name to attach to recognised tokens. 36 | * @return Returns a CPQuotedRecogniser that recognises C like identifiers. 37 | * 38 | * @see quotedRecogniserWithStartQuote:endQuote:escapeSequence:name: 39 | * @see quotedRecogniserWithStartQuote:endQuote:escapeSequence:maximumLength:name: 40 | */ 41 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote name:(NSString *)name; 42 | 43 | /** 44 | * Creates a quoted recogniser that recognises quoted litterals starting with startQuote and ending with endQuote. Escaped sequences are recognised by the escapeSequence string. 45 | * 46 | * @param startQuote A string that indicates the beginning of a quoted literal. 47 | * @param endQuote A string that indicates the end of the quoted literal. 48 | * @param escapeSequence A string that indicates an escaped character. 49 | * @param name The name to attach to recognised tokens. 50 | * @return Returns a CPQuotedRecogniser that recognises C like identifiers. 51 | * 52 | * @see quotedRecogniserWithStartQuote:endQuote:name: 53 | * @see quotedRecogniserWithStartQuote:endQuote:escapeSequence:maximumLength:name: 54 | */ 55 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote escapeSequence:(NSString *)escapeSequence name:(NSString *)name; 56 | 57 | /** 58 | * Creates a quoted recogniser that recognises quoted litterals starting with startQuote and ending with endQuote. Escaped sequences are recognised by the escapeSequence string. Quoted strings have a maximum length. 59 | * 60 | * @param startQuote A string that indicates the beginning of a quoted literal. 61 | * @param endQuote A string that indicates the end of the quoted literal. 62 | * @param escapeSequence A string that indicates an escaped character. 63 | * @param maximumLength The maximum length of the resulting string. 64 | * @param name The name to attach to recognised tokens. 65 | * @return Returns a CPQuotedRecogniser that recognises C like identifiers. 66 | * 67 | * @see quotedRecogniserWithStartQuote:endQuote:name: 68 | * @see quotedRecogniserWithStartQuote:endQuote:escapeSequence:name: 69 | * @see initWithStartQuote:endQuote:escapeSequence:maximumLength:name: 70 | */ 71 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote escapeSequence:(NSString *)escapeSequence maximumLength:(NSUInteger)maximumLength name:(NSString *)name; 72 | 73 | /** 74 | * Initialises a quoted recogniser that recognises quoted litterals starting with startQuote and ending with endQuote. Escaped sequences are recognised by the escapeSequence string. Quoted strings have a maximum length. 75 | * 76 | * @param startQuote A string that indicates the beginning of a quoted literal. 77 | * @param endQuote A string that indicates the end of the quoted literal. 78 | * @param escapeSequence A string that indicates an escaped character. 79 | * @param maximumLength The maximum length of the resulting string. 80 | * @param name The name to attach to recognised tokens. 81 | * @return Returns a CPQuotedRecogniser that recognises C like identifiers. 82 | * 83 | * @see quotedRecogniserWithStartQuote:endQuote:escapeSequence:maximumLength:name: 84 | */ 85 | - (id)initWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote escapeSequence:(NSString *)escapeSequence maximumLength:(NSUInteger)maximumLength name:(NSString *)name; 86 | 87 | ///--------------------------------------------------------------------------------------- 88 | /// @name Configuring a Quoted Recogniser 89 | ///--------------------------------------------------------------------------------------- 90 | 91 | /** 92 | * Determines the string used to indicate the start of the quoted literal. 93 | * 94 | * @see endQuote 95 | */ 96 | @property (readwrite,copy) NSString *startQuote; 97 | 98 | /** 99 | * Determines the string used to indicate the end of the quoted literal. 100 | * 101 | * @see startQuote 102 | */ 103 | @property (readwrite,copy) NSString *endQuote; 104 | 105 | /** 106 | * Determines the string used to indicate an escaped character in the quoted literal. 107 | */ 108 | @property (readwrite,copy) NSString *escapeSequence; 109 | 110 | /** 111 | * Determines how much of the input string to consume when an escaped literal is found, and what to replace it with. 112 | */ 113 | @property (readwrite,copy) NSString *(^escapeReplacer)(NSString *tokenStream, NSUInteger *quotePosition); 114 | 115 | /** 116 | * Determines the maximum length of the quoted literal not including quotes. To indicate the literal can be any length specify NSNotFound. 117 | */ 118 | @property (readwrite,assign) NSUInteger maximumLength; 119 | 120 | /** 121 | * Determines the name of the CPToken produced. 122 | */ 123 | @property (readwrite,copy) NSString *name; 124 | 125 | @end 126 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPQuotedRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPQuotedRecogniser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPQuotedRecogniser.h" 10 | 11 | #import "CPQuotedToken.h" 12 | 13 | @implementation CPQuotedRecogniser 14 | 15 | @synthesize startQuote; 16 | @synthesize endQuote; 17 | @synthesize escapeSequence; 18 | @synthesize escapeReplacer; 19 | @synthesize maximumLength; 20 | @synthesize name; 21 | 22 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote name:(NSString *)name 23 | { 24 | return [CPQuotedRecogniser quotedRecogniserWithStartQuote:startQuote endQuote:endQuote escapeSequence:nil name:name]; 25 | } 26 | 27 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote escapeSequence:(NSString *)escapeSequence name:(NSString *)name 28 | { 29 | return [CPQuotedRecogniser quotedRecogniserWithStartQuote:startQuote endQuote:endQuote escapeSequence:escapeSequence maximumLength:NSNotFound name:name]; 30 | } 31 | 32 | + (id)quotedRecogniserWithStartQuote:(NSString *)startQuote endQuote:(NSString *)endQuote escapeSequence:(NSString *)escapeSequence maximumLength:(NSUInteger)maximumLength name:(NSString *)name 33 | { 34 | return [[[CPQuotedRecogniser alloc] initWithStartQuote:startQuote endQuote:endQuote escapeSequence:escapeSequence maximumLength:maximumLength name:name] autorelease]; 35 | } 36 | 37 | - (id)initWithStartQuote:(NSString *)initStartQuote endQuote:(NSString *)initEndQuote escapeSequence:(NSString *)initEscapeSequence maximumLength:(NSUInteger)initMaximumLength name:(NSString *)initName 38 | { 39 | self = [super init]; 40 | 41 | if (nil != self) 42 | { 43 | [self setStartQuote:initStartQuote]; 44 | [self setEndQuote:initEndQuote]; 45 | [self setEscapeSequence:initEscapeSequence]; 46 | [self setMaximumLength:initMaximumLength]; 47 | [self setName:initName]; 48 | } 49 | 50 | return self; 51 | } 52 | 53 | #define CPQuotedRecogniserStartQuoteKey @"Q.s" 54 | #define CPQuotedRecogniserEndQuoteKey @"Q.e" 55 | #define CPQuotedRecogniserEscapeSequenceKey @"Q.es" 56 | #define CPQuotedRecogniserMaximumLengthKey @"Q.m" 57 | #define CPQuotedRecogniserNameKey @"Q.n" 58 | 59 | - (id)initWithCoder:(NSCoder *)aDecoder 60 | { 61 | self = [super init]; 62 | 63 | if (nil != self) 64 | { 65 | [self setStartQuote:[aDecoder decodeObjectForKey:CPQuotedRecogniserStartQuoteKey]]; 66 | [self setEndQuote:[aDecoder decodeObjectForKey:CPQuotedRecogniserEndQuoteKey]]; 67 | [self setEscapeSequence:[aDecoder decodeObjectForKey:CPQuotedRecogniserEscapeSequenceKey]]; 68 | @try 69 | { 70 | [self setMaximumLength:[aDecoder decodeIntegerForKey:CPQuotedRecogniserMaximumLengthKey]]; 71 | } 72 | @catch (NSException *exception) 73 | { 74 | NSLog(@"Warning, value for maximum length too long for this platform, allowing infinite lengths"); 75 | [self setMaximumLength:NSNotFound]; 76 | } 77 | [self setName:[aDecoder decodeObjectForKey:CPQuotedRecogniserNameKey]]; 78 | } 79 | 80 | return self; 81 | } 82 | 83 | - (void)encodeWithCoder:(NSCoder *)aCoder 84 | { 85 | if (nil != [self escapeReplacer]) 86 | { 87 | NSLog(@"Warning: encoding CPQuoteRecogniser with an escapeReplacer set. This will not be recreated when decoded."); 88 | } 89 | [aCoder encodeObject:[self startQuote] forKey:CPQuotedRecogniserStartQuoteKey]; 90 | [aCoder encodeObject:[self endQuote] forKey:CPQuotedRecogniserEndQuoteKey]; 91 | [aCoder encodeObject:[self escapeSequence] forKey:CPQuotedRecogniserEscapeSequenceKey]; 92 | [aCoder encodeInteger:[self maximumLength] forKey:CPQuotedRecogniserMaximumLengthKey]; 93 | [aCoder encodeObject:[self name] forKey:CPQuotedRecogniserNameKey]; 94 | } 95 | 96 | - (void)dealloc 97 | { 98 | [startQuote release]; 99 | [endQuote release]; 100 | [escapeSequence release]; 101 | [escapeReplacer release]; 102 | [name release]; 103 | 104 | [super dealloc]; 105 | } 106 | 107 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 108 | { 109 | NSString *(^er)(NSString *tokenStream, NSUInteger *quotePosition) = [self escapeReplacer]; 110 | NSUInteger startQuoteLength = [startQuote length]; 111 | NSUInteger endQuoteLength = [endQuote length]; 112 | 113 | long inputLength = [tokenString length]; 114 | CFRange searchRange = CFRangeMake(*tokenPosition, MIN(inputLength - *tokenPosition,startQuoteLength + endQuoteLength + maximumLength)); 115 | CFRange range; 116 | BOOL matched = CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)startQuote, searchRange, kCFCompareAnchored, &range); 117 | 118 | CFMutableStringRef outputString = CFStringCreateMutable(kCFAllocatorDefault, 0); 119 | 120 | if (matched) 121 | { 122 | searchRange.location = searchRange.location + range.length; 123 | searchRange.length = searchRange.length - range.length; 124 | 125 | CFRange endRange; 126 | CFRange escapeRange; 127 | BOOL matchedEndSequence = CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)endQuote, searchRange, 0L, &endRange); 128 | BOOL matchedEscapeSequence = nil == escapeSequence ? NO : CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)escapeSequence, searchRange, 0L, &escapeRange); 129 | 130 | while (matchedEndSequence && searchRange.location < inputLength) 131 | { 132 | if (!matchedEscapeSequence || endRange.location < escapeRange.location) 133 | { 134 | *tokenPosition = endRange.location + endRange.length; 135 | CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, (CFStringRef)tokenString, CFRangeMake(searchRange.location, endRange.location - searchRange.location)); 136 | CFStringAppend(outputString, substr); 137 | CFRelease(substr); 138 | CPQuotedToken *t = [CPQuotedToken content:(NSString *)outputString quotedWith:startQuote name:[self name]]; 139 | CFRelease(outputString); 140 | return t; 141 | } 142 | else 143 | { 144 | NSUInteger quotedPosition = escapeRange.location + escapeRange.length; 145 | CFStringRef substr = CFStringCreateWithSubstring(kCFAllocatorDefault, (CFStringRef)tokenString, CFRangeMake(searchRange.location, escapeRange.location - searchRange.location)); 146 | CFStringAppend(outputString, substr); 147 | CFRelease(substr); 148 | BOOL appended = NO; 149 | if (nil != er) 150 | { 151 | NSString *s = er(tokenString, "edPosition); 152 | if (nil != s) 153 | { 154 | appended = YES; 155 | CFStringAppend(outputString, (CFStringRef)s); 156 | } 157 | } 158 | if (!appended) 159 | { 160 | substr = CFStringCreateWithSubstring(kCFAllocatorDefault, (CFStringRef)tokenString, CFRangeMake(escapeRange.location + escapeRange.length, 1)); 161 | CFStringAppend(outputString, substr); 162 | CFRelease(substr); 163 | quotedPosition += 1; 164 | } 165 | searchRange.length = searchRange.location + searchRange.length - quotedPosition; 166 | searchRange.location = quotedPosition; 167 | 168 | if (endRange.location < searchRange.location) 169 | { 170 | matchedEndSequence = CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)endQuote, searchRange, 0L, &endRange); 171 | } 172 | if (escapeRange.location < searchRange.location) 173 | { 174 | matchedEscapeSequence = CFStringFindWithOptions((CFStringRef)tokenString, (CFStringRef)escapeSequence, searchRange, 0L, &escapeRange); 175 | } 176 | } 177 | } 178 | } 179 | 180 | CFRelease(outputString); 181 | return nil; 182 | } 183 | 184 | @end 185 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPRegexpRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPRegexpRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CPTokenRecogniser.h" 11 | 12 | typedef CPToken* (^CPRegexpKeywordRecogniserMatchHandler)(NSString* tokenString, NSTextCheckingResult* match); 13 | 14 | /** 15 | * The CPRegexpRecogniser class attempts to recognise a specific NSRegularExpression. 16 | * 17 | * A regexp recogniser attempts to recognise a regexp. 18 | * 19 | * This recogniser produces a token via matchHandler. 20 | */ 21 | @interface CPRegexpRecogniser : NSObject 22 | 23 | @property (nonatomic, retain) NSRegularExpression* regexp; 24 | 25 | ///--------------------------------------------------------------------------------------- 26 | /// @name Creating and Initialising a Regexp Keyword Recogniser 27 | ///--------------------------------------------------------------------------------------- 28 | 29 | /** 30 | * Initialises a Regexp Recogniser to recognise a specific regexp. 31 | * 32 | * @param regexp The NSRegularExpression to recognise. 33 | * @param matchHandler A block that process first match result of the regular expression, and return a CPToken. 34 | * 35 | * @return Returns the regexp recogniser initialised to recognise the passed regexp. 36 | * 37 | * @see recogniserForRegexp: 38 | */ 39 | - (id)initWithRegexp:(NSRegularExpression *)regexp matchHandler:(CPRegexpKeywordRecogniserMatchHandler)matchHandler; 40 | 41 | /** 42 | * Initialises a Regexp Recogniser to recognise a specific regexp. 43 | * 44 | * @param regexp The NSRegularExpression to recognise. 45 | * @param matchHandler A block that process first match result of the regular expression, and return a CPToken. 46 | * 47 | * @return Returns the regexp recogniser initialised to recognise the passed regexp. 48 | * 49 | * @see initWithRegexp: 50 | */ 51 | + (id)recogniserForRegexp:(NSRegularExpression *)regexp matchHandler:(CPRegexpKeywordRecogniserMatchHandler)matchHandler; 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPRegexpRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRegexpRecogniser.m 3 | // CoreParse 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 Ignition Soft. All rights reserved. 7 | // 8 | 9 | #import "CPRegexpRecogniser.h" 10 | #import "CPToken.h" 11 | #import "CPKeywordToken.h" 12 | 13 | @interface CPRegexpRecogniser() 14 | @property (nonatomic, copy) CPRegexpKeywordRecogniserMatchHandler matchHandler; 15 | @end 16 | 17 | @implementation CPRegexpRecogniser 18 | 19 | @synthesize regexp; 20 | @synthesize matchHandler; 21 | 22 | - (id)initWithRegexp:(NSRegularExpression *)initRegexp matchHandler:(CPRegexpKeywordRecogniserMatchHandler)initMatchHandler 23 | { 24 | self = [super init]; 25 | if (self) { 26 | [self setRegexp:initRegexp]; 27 | [self setMatchHandler:initMatchHandler]; 28 | } 29 | return self; 30 | } 31 | 32 | + (id)recogniserForRegexp:(NSRegularExpression *)regexp matchHandler:(CPRegexpKeywordRecogniserMatchHandler)initMatchHandler 33 | { 34 | return [[[self alloc] initWithRegexp:regexp matchHandler:initMatchHandler] autorelease]; 35 | } 36 | 37 | - (void)dealloc 38 | { 39 | [matchHandler release]; 40 | [regexp release]; 41 | [super dealloc]; 42 | } 43 | 44 | #pragma mark - NSCoder 45 | 46 | #define CPRegexpRecogniserRegexpKey @"R.r" 47 | 48 | - (id)initWithCoder:(NSCoder *)aDecoder 49 | { 50 | self = [super init]; 51 | 52 | if (nil != self) 53 | { 54 | [self setRegexp:[aDecoder decodeObjectForKey:CPRegexpRecogniserRegexpKey]]; 55 | } 56 | 57 | return self; 58 | } 59 | 60 | - (void)encodeWithCoder:(NSCoder *)aCoder 61 | { 62 | [aCoder encodeObject:[self regexp] forKey:CPRegexpRecogniserRegexpKey]; 63 | } 64 | 65 | #pragma mark - CPRecognizer 66 | 67 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 68 | { 69 | long inputLength = [tokenString length]; 70 | NSRange searchRange = NSMakeRange(*tokenPosition, inputLength - *tokenPosition); 71 | NSTextCheckingResult* result = [[self regexp] firstMatchInString:tokenString options:NSMatchingAnchored range:searchRange]; 72 | if (nil != result && nil != matchHandler && result.range.location == *tokenPosition && result.range.length > 0) 73 | { 74 | CPToken* token = matchHandler(tokenString, result); 75 | if (token) 76 | { 77 | *tokenPosition = result.range.location + result.range.length; 78 | return token; 79 | } 80 | } 81 | return nil; 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPTokenRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTokenRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 10/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPTokenRecogniser protocol defines methods needed to recognise tokens in a string. 15 | */ 16 | @protocol CPTokenRecogniser 17 | 18 | @required 19 | /** 20 | * Attempts to recognise a token at tokenPosition in tokenString. 21 | * 22 | * If a token is successfully recognised, it should be returned, and tokenPosition advanced to after the consumed characters. 23 | * If no valid token is found `nil` must be returned instead, and tokenPosition left unchanged. 24 | * 25 | * @param tokenString The string in which to recognise tokens. 26 | * @param tokenPosition The position at which to try to find the token. On output, the position after the recognised token. 27 | * @return Returns the token recognised. 28 | */ 29 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPWhiteSpaceRecogniser.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPWhiteSpaceRecogniser.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPTokenRecogniser.h" 12 | 13 | /** 14 | * The CPWhiteSpaceRecogniser class attempts to recognise white space on the input string. 15 | * 16 | * This recogniser produces CPWhiteSpaceTokens. 17 | */ 18 | @interface CPWhiteSpaceRecogniser : NSObject 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising a WhiteSpace Recogniser 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates a whitespace recogniser. 26 | * 27 | * @return Returns a CPWhiteSpaceRecogniser. 28 | */ 29 | + (id)whiteSpaceRecogniser; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Recognisers/CPWhiteSpaceRecogniser.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPWhiteSpaceRecogniser.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPWhiteSpaceRecogniser.h" 10 | 11 | #import "CPWhiteSpaceToken.h" 12 | 13 | @implementation CPWhiteSpaceRecogniser 14 | 15 | - (id)initWithCoder:(NSCoder *)aDecoder 16 | { 17 | return [super init]; 18 | } 19 | 20 | - (void)encodeWithCoder:(NSCoder *)aCoder 21 | { 22 | } 23 | 24 | + (id)whiteSpaceRecogniser 25 | { 26 | return [[[CPWhiteSpaceRecogniser alloc] init] autorelease]; 27 | } 28 | 29 | - (CPToken *)recogniseTokenInString:(NSString *)tokenString currentTokenPosition:(NSUInteger *)tokenPosition 30 | { 31 | NSScanner *scanner = [NSScanner scannerWithString:tokenString]; 32 | [scanner setCharactersToBeSkipped:nil]; 33 | [scanner setScanLocation:*tokenPosition]; 34 | NSString *scannedString; 35 | BOOL success = [scanner scanCharactersFromSet:[NSCharacterSet whitespaceAndNewlineCharacterSet] intoString:&scannedString]; 36 | if (success) 37 | { 38 | *tokenPosition = [scanner scanLocation]; 39 | return [CPWhiteSpaceToken whiteSpace:scannedString]; 40 | } 41 | 42 | return nil; 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPEOFToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPEOFToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPEOFToken class reperesents the end of a token stream. 15 | * 16 | * These tokens return `@"EOF"` as their name. 17 | */ 18 | @interface CPEOFToken : CPToken 19 | 20 | /** 21 | * Creates an end of file token. 22 | * 23 | * @return A token representing the end of the input stream. 24 | */ 25 | + (id)eof; 26 | 27 | @end 28 | 29 | @interface NSObject (CPIsEOFToken) 30 | 31 | - (BOOL)isEOFToken; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPEOFToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPEOFToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPEOFToken.h" 10 | 11 | @implementation CPEOFToken 12 | 13 | + (id)eof 14 | { 15 | return [[[CPEOFToken alloc] init] autorelease]; 16 | } 17 | 18 | - (NSString *)name 19 | { 20 | return @"EOF"; 21 | } 22 | 23 | - (NSUInteger)hash 24 | { 25 | return 0; 26 | } 27 | 28 | - (BOOL)isEOFToken 29 | { 30 | return YES; 31 | } 32 | 33 | - (BOOL)isEqual:(id)object 34 | { 35 | return [object isEOFToken]; 36 | } 37 | 38 | @end 39 | 40 | @implementation NSObject (CPIsEOFToken) 41 | 42 | - (BOOL)isEOFToken 43 | { 44 | return NO; 45 | } 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPErrorToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPErrorToken.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPToken.h" 10 | 11 | /** 12 | * The CPErrorToken class reperesents an error during tokenisation. 13 | * 14 | * These tokens return `@"Error"` as their name. They may carry an error message with them. 15 | */ 16 | @interface CPErrorToken : CPToken 17 | 18 | /** 19 | * The error message generated when the tokeniser failed. 20 | */ 21 | @property (readwrite, copy) NSString *errorMessage; 22 | 23 | /** 24 | * Creates and initializes a new CPErrorToken with a given message. 25 | * 26 | * @param errorMessage The message for the error. 27 | * @return A CPErrorToken with the message. 28 | */ 29 | + (id)errorWithMessage:(NSString *)errorMessage; 30 | 31 | /** 32 | * Returns a CPErrorToken initialized with a given message. 33 | * 34 | * @param errorMessage The message for the error. 35 | * @return A CPErrorToken with the message. 36 | */ 37 | - (id)initWithMesage:(NSString *)errorMessage; 38 | 39 | @end 40 | 41 | @interface NSObject (CPErrorToken) 42 | 43 | - (BOOL)isErrorToken; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPErrorToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPErrorToken.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPErrorToken.h" 10 | 11 | @implementation CPErrorToken 12 | 13 | @synthesize errorMessage; 14 | 15 | + (id)errorWithMessage:(NSString *)errorMessage 16 | { 17 | return [[[self alloc] initWithMesage:errorMessage] autorelease]; 18 | } 19 | 20 | - (id)initWithMesage:(NSString *)initErrorMessage 21 | { 22 | self = [super init]; 23 | 24 | if (nil != self) 25 | { 26 | [self setErrorMessage:initErrorMessage]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (void)dealloc 33 | { 34 | [errorMessage release]; 35 | 36 | [super dealloc]; 37 | } 38 | 39 | - (NSString *)name 40 | { 41 | return @"Error"; 42 | } 43 | 44 | - (NSUInteger)hash 45 | { 46 | return 0; 47 | } 48 | 49 | - (BOOL)isErrorToken 50 | { 51 | return YES; 52 | } 53 | 54 | - (BOOL)isEqual:(id)object 55 | { 56 | return [object isErrorToken]; 57 | } 58 | 59 | @end 60 | 61 | @implementation NSObject (CPIsErrorToken) 62 | 63 | - (BOOL)isErrorToken 64 | { 65 | return NO; 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPIdentifierToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPIdentifierToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPIdentifierToken class reperesents an identifier appearing in the input. 15 | * 16 | * These tokens return `@"Identifier"` as their name. 17 | */ 18 | @interface CPIdentifierToken : CPToken 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising an Identifier Token 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates an identifier token with the identifier found in the input. 26 | * 27 | * @param identifier The identifier found in the input stream. 28 | * @return Returns a CPIdentifierToken representing the specified identifier. 29 | * 30 | * @see initWithIdentifier: 31 | */ 32 | + (id)tokenWithIdentifier:(NSString *)identifier; 33 | 34 | /** 35 | * Initialises an identifier token with the identifier found in the input. 36 | * 37 | * @param identifier The identifier found in the input stream. 38 | * @return Returns a CPIdentifierToken representing the specified identifier. 39 | * 40 | * @see tokenWithIdentifier: 41 | */ 42 | - (id)initWithIdentifier:(NSString *)identifier; 43 | 44 | ///--------------------------------------------------------------------------------------- 45 | /// @name Configuring an Identifier Token 46 | ///--------------------------------------------------------------------------------------- 47 | 48 | /** 49 | * The identifier found in the input stream 50 | */ 51 | @property (readwrite,copy) NSString *identifier; 52 | 53 | @end 54 | 55 | @interface NSObject (CPIsIdentifierToken) 56 | 57 | - (BOOL)isIdentifierToken; 58 | 59 | @end 60 | 61 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPIdentifierToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPIdentifierToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPIdentifierToken.h" 10 | 11 | @implementation CPIdentifierToken 12 | { 13 | NSString *identifier; 14 | } 15 | 16 | @synthesize identifier; 17 | 18 | + (id)tokenWithIdentifier:(NSString *)identifier 19 | { 20 | return [[(CPIdentifierToken *)[CPIdentifierToken alloc] initWithIdentifier:identifier] autorelease]; 21 | } 22 | 23 | - (id)initWithIdentifier:(NSString *)initIdentifier 24 | { 25 | self = [super init]; 26 | 27 | if (nil != self) 28 | { 29 | [self setIdentifier:initIdentifier]; 30 | } 31 | 32 | return self; 33 | } 34 | 35 | - (id)init 36 | { 37 | return [self initWithIdentifier:@""]; 38 | } 39 | 40 | - (void)dealloc 41 | { 42 | [identifier release]; 43 | 44 | [super dealloc]; 45 | } 46 | 47 | - (NSString *)description 48 | { 49 | return [NSString stringWithFormat:@"", [self identifier]]; 50 | } 51 | 52 | - (NSString *)name 53 | { 54 | return @"Identifier"; 55 | } 56 | 57 | - (NSUInteger)hash 58 | { 59 | return [[self identifier] hash]; 60 | } 61 | 62 | - (BOOL)isIdentifierToken 63 | { 64 | return YES; 65 | } 66 | 67 | - (BOOL)isEqual:(id)object 68 | { 69 | return ([object isIdentifierToken] && 70 | [((CPIdentifierToken *)object)->identifier isEqualToString:identifier]); 71 | } 72 | 73 | @end 74 | 75 | @implementation NSObject(CPIsIdentifierToken) 76 | 77 | - (BOOL)isIdentifierToken 78 | { 79 | return NO; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPKeywordToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPKeywordToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPKeywordToken class reperesents a keyword appearing in the input. 15 | * 16 | * These tokens can be used to return both language keywords and predetermined operators amongst other things. 17 | * 18 | * These tokens return the keyword name as their name. 19 | */ 20 | @interface CPKeywordToken : CPToken 21 | 22 | ///--------------------------------------------------------------------------------------- 23 | /// @name Creating and Initialising a Keyword Token 24 | ///--------------------------------------------------------------------------------------- 25 | 26 | /** 27 | * Creates a keyword token with a certain name. 28 | * 29 | * @param keyword The name of the keyword found in the input stream. 30 | * @return Returns a CPKeywordToken representing the specified keyword. 31 | * 32 | * @see initWithKeyword: 33 | */ 34 | + (id)tokenWithKeyword:(NSString *)keyword; 35 | 36 | /** 37 | * Initialises a keyword token with a certain name. 38 | * 39 | * @param keyword The name of the keyword found in the input stream. 40 | * @return Returns a CPKeywordToken representing the specified keyword. 41 | * 42 | * @see tokenWithKeyword: 43 | */ 44 | - (id)initWithKeyword:(NSString *)keyword; 45 | 46 | ///--------------------------------------------------------------------------------------- 47 | /// @name Configuring a Keyword Token 48 | ///--------------------------------------------------------------------------------------- 49 | 50 | /** 51 | * The name of the keyword found in the input stream. 52 | */ 53 | @property (readwrite,copy) NSString *keyword; 54 | 55 | @end 56 | 57 | @interface NSObject (CPIsKeywordToken) 58 | 59 | - (BOOL)isKeywordToken; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPKeywordToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPKeywordToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPKeywordToken.h" 10 | 11 | @implementation CPKeywordToken 12 | 13 | @synthesize keyword; 14 | 15 | + (id)tokenWithKeyword:(NSString *)keyword 16 | { 17 | return [[[CPKeywordToken alloc] initWithKeyword:keyword] autorelease]; 18 | } 19 | 20 | - (id)initWithKeyword:(NSString *)initKeyword 21 | { 22 | self = [super init]; 23 | 24 | if (nil != self) 25 | { 26 | [self setKeyword:initKeyword]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (id)init 33 | { 34 | return [self initWithKeyword:@" "]; 35 | } 36 | 37 | - (void)dealloc 38 | { 39 | [keyword release]; 40 | [super dealloc]; 41 | } 42 | 43 | - (NSString *)description 44 | { 45 | return [NSString stringWithFormat:@"", [self keyword]]; 46 | } 47 | 48 | - (NSString *)name 49 | { 50 | return [self keyword]; 51 | } 52 | 53 | - (NSUInteger)hash 54 | { 55 | return [[self keyword] hash]; 56 | } 57 | 58 | - (BOOL)isKeywordToken 59 | { 60 | return YES; 61 | } 62 | 63 | - (BOOL)isEqual:(id)object 64 | { 65 | return ([object isKeywordToken] && 66 | [((CPKeywordToken *)object)->keyword isEqualToString:keyword]); 67 | } 68 | 69 | @end 70 | 71 | @implementation NSObject (CPIsKeywordToken) 72 | 73 | - (BOOL)isKeywordToken 74 | { 75 | return NO; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPNumberToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPNumberToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPNumberToken class reperesents a number appearing in the input. 15 | * 16 | * These tokens return `@"Number"` as their name. 17 | */ 18 | @interface CPNumberToken : CPToken 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising a Number Token 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates a number token with the number found in the input. 26 | * 27 | * @param number The number found in the input stream. 28 | * @return Returns a CPNumberToken representing the specified number. 29 | * 30 | * @see initWithNumber: 31 | */ 32 | + (id)tokenWithNumber:(NSNumber *)number; 33 | 34 | /** 35 | * Initialises a number token with the number found in the input. 36 | * 37 | * @param number The number found in the input stream. 38 | * @return Returns a CPNumberToken representing the specified number. 39 | * 40 | * @see tokenWithNumber: 41 | */ 42 | - (id)initWithNumber:(NSNumber *)number; 43 | 44 | ///--------------------------------------------------------------------------------------- 45 | /// @name Configuring a Number Token 46 | ///--------------------------------------------------------------------------------------- 47 | 48 | /** 49 | * The number found in the input stream. 50 | */ 51 | @property (readwrite,copy) NSNumber *numberValue; 52 | 53 | @end 54 | 55 | @interface NSObject (CPIsNumberToken) 56 | 57 | - (BOOL)isNumberToken; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPNumberToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPNumberToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPNumberToken.h" 10 | 11 | @implementation CPNumberToken 12 | 13 | @synthesize numberValue; 14 | 15 | + (id)tokenWithNumber:(NSNumber *)number 16 | { 17 | return [[[CPNumberToken alloc] initWithNumber:number] autorelease]; 18 | } 19 | 20 | - (id)initWithNumber:(NSNumber *)initNumber 21 | { 22 | self = [super init]; 23 | 24 | if (nil != self) 25 | { 26 | [self setNumberValue:initNumber]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (id)init 33 | { 34 | return [self initWithNumber:[NSNumber numberWithInteger:0]]; 35 | } 36 | 37 | - (void)dealloc 38 | { 39 | [numberValue release]; 40 | [super dealloc]; 41 | } 42 | 43 | - (NSString *)description 44 | { 45 | return [NSString stringWithFormat:@"", [self numberValue]]; 46 | } 47 | 48 | - (NSString *)name 49 | { 50 | return @"Number"; 51 | } 52 | 53 | - (NSUInteger)hash 54 | { 55 | return [[self numberValue] hash]; 56 | } 57 | 58 | - (BOOL)isNumberToken 59 | { 60 | return YES; 61 | } 62 | 63 | - (BOOL)isEqual:(id)object 64 | { 65 | return ([object isNumberToken] && 66 | [((CPNumberToken *)object)->numberValue isEqualToNumber:numberValue]); 67 | } 68 | 69 | @end 70 | 71 | @implementation NSObject (CPIsNumberToken) 72 | 73 | - (BOOL)isNumberToken 74 | { 75 | return NO; 76 | } 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPQuotedToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPQuotedToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPQuotedToken class reperesents a quoted literal appearing in the input. 15 | * 16 | * These tokens return the name specified on their creation as their name. 17 | */ 18 | @interface CPQuotedToken : CPToken 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising a Quoted Literal Token 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates a quoted literal token with the quoted literal found in the input. 26 | * 27 | * @param content The string found inside the quotes. 28 | * @param startQuote The symbol used to quote the content. 29 | * @param name The name to use for this token. 30 | * @return Returns a CPQuotedToken representing the specified quoted literal. 31 | * 32 | * @see initWithContent:quoteType:name: 33 | */ 34 | + (id)content:(NSString *)content quotedWith:(NSString *)startQuote name:(NSString *)name; 35 | 36 | /** 37 | * Initialises a quoted literal token with the quoted literal found in the input. 38 | * 39 | * @param content The string found inside the quotes. 40 | * @param startQuote The symbol used to quote the content. 41 | * @param name The name to use for this token. 42 | * @return Returns a CPQuotedToken representing the specified quoted literal. 43 | * 44 | * @see content:quotedWith:name: 45 | */ 46 | - (id)initWithContent:(NSString *)content quoteType:(NSString *)startQuote name:(NSString *)name; 47 | 48 | ///--------------------------------------------------------------------------------------- 49 | /// @name Configuring a Quoted Literal Token 50 | ///--------------------------------------------------------------------------------------- 51 | 52 | /** 53 | * The content found inside the quoted literal. 54 | */ 55 | @property (readwrite,copy) NSString *content; 56 | 57 | /** 58 | * The quote used to begin the quoted literal. 59 | */ 60 | @property (readwrite,copy) NSString *quoteType; 61 | 62 | @end 63 | 64 | @interface NSObject (CPIsQuotedToken) 65 | 66 | - (BOOL)isQuotedToken; 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPQuotedToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPQuotedToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 13/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPQuotedToken.h" 10 | 11 | 12 | @implementation CPQuotedToken 13 | { 14 | @private 15 | NSString *content; 16 | NSString *quoteType; 17 | NSString *name; 18 | } 19 | 20 | @synthesize content; 21 | @synthesize quoteType; 22 | 23 | + (id)content:(NSString *)content quotedWith:(NSString *)quoteType name:(NSString *)name 24 | { 25 | return [[[CPQuotedToken alloc] initWithContent:content quoteType:quoteType name:name] autorelease]; 26 | } 27 | 28 | - (id)initWithContent:(NSString *)initContent quoteType:(NSString *)initQuoteType name:(NSString *)initName 29 | { 30 | self = [super init]; 31 | 32 | if (nil != self) 33 | { 34 | [self setContent:initContent]; 35 | [self setQuoteType:initQuoteType]; 36 | name = [initName copy]; 37 | } 38 | 39 | return self; 40 | } 41 | 42 | - (id)init 43 | { 44 | return [self initWithContent:@"" quoteType:@"" name:@""]; 45 | } 46 | 47 | - (void)dealloc 48 | { 49 | [content release]; 50 | [quoteType release]; 51 | [name release]; 52 | 53 | [super dealloc]; 54 | } 55 | 56 | - (NSString *)description 57 | { 58 | return [NSString stringWithFormat:@"<%@: %@>", [self name], [self content]]; 59 | } 60 | 61 | - (NSString *)name 62 | { 63 | return name; 64 | } 65 | 66 | - (NSUInteger)hash 67 | { 68 | return [[self content] hash]; 69 | } 70 | 71 | - (BOOL)isQuotedToken 72 | { 73 | return YES; 74 | } 75 | 76 | - (BOOL)isEqual:(id)object 77 | { 78 | return ([object isQuotedToken] && 79 | [((CPQuotedToken *)object)->content isEqualToString:content] && 80 | [((CPQuotedToken *)object)->name isEqualToString:name] && 81 | [((CPQuotedToken *)object)->quoteType isEqualToString:quoteType]); 82 | } 83 | 84 | @end 85 | 86 | @implementation NSObject (CPIsQuotedToken) 87 | 88 | - (BOOL)isQuotedToken 89 | { 90 | return NO; 91 | } 92 | 93 | @end 94 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * The CPToken class reperesents a token in the token stream. 13 | * 14 | * All tokens respond to the -name message which is used to identify the token while parsing. 15 | * 16 | * CPToken is an abstract class. CPTokenRegnisers should add instances of CPTokens concrete subclasses to their token stream. 17 | */ 18 | @interface CPToken : NSObject 19 | 20 | /** 21 | * The token name. 22 | */ 23 | @property (readonly) NSString *name; 24 | 25 | /** 26 | * The line on which the token can be found. 27 | */ 28 | @property (readwrite, assign) NSUInteger lineNumber; 29 | 30 | /** 31 | * The column on which the token can be found. 32 | */ 33 | @property (readwrite, assign) NSUInteger columnNumber; 34 | 35 | /** 36 | * The index in the input string of the first character in this token. 37 | */ 38 | @property (readwrite, assign) NSUInteger characterNumber; 39 | 40 | /** 41 | * The character length of the token. 42 | */ 43 | @property (readwrite, assign) NSUInteger length; 44 | 45 | @end 46 | 47 | @interface NSObject (CPIsToken) 48 | 49 | - (BOOL)isToken; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPToken.h" 10 | 11 | @implementation CPToken 12 | 13 | @synthesize lineNumber; 14 | @synthesize columnNumber; 15 | @synthesize characterNumber; 16 | @synthesize length; 17 | 18 | - (NSString *)name 19 | { 20 | [NSException raise:@"Abstract method called exception" format:@"CPToken is abstract, and should not have name called."]; 21 | return @""; 22 | } 23 | 24 | - (NSUInteger)hash 25 | { 26 | return [[self name] hash]; 27 | } 28 | 29 | - (BOOL)isEqual:(id)object 30 | { 31 | return ([object isToken] && 32 | [[self name] isEqualToString:[(CPToken *)object name]]); 33 | } 34 | 35 | - (NSString *)description 36 | { 37 | return [NSString stringWithFormat:@"<%@>", [self name]]; 38 | } 39 | 40 | @end 41 | 42 | @implementation NSObject (CPIsToken) 43 | 44 | - (BOOL)isToken 45 | { 46 | return NO; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPWhiteSpaceToken.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPWhiteSpaceToken.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CPToken.h" 12 | 13 | /** 14 | * The CPWhiteSpaceToken class reperesents some white space appearing in the input. 15 | * 16 | * These tokens return `@"Whitespace"` as their name. 17 | */ 18 | @interface CPWhiteSpaceToken : CPToken 19 | 20 | ///--------------------------------------------------------------------------------------- 21 | /// @name Creating and Initialising a WhiteSpace Token 22 | ///--------------------------------------------------------------------------------------- 23 | 24 | /** 25 | * Creates a white space token with the white space found in the input. 26 | * 27 | * @param whiteSpace The white space found in the input stream. 28 | * @return Returns a CPWhiteSpaceToken representing the specified white space. 29 | * 30 | * @see initWithWhiteSpace: 31 | */ 32 | + (id)whiteSpace:(NSString *)whiteSpace; 33 | 34 | /** 35 | * Initialises a white space token with the white space found in the input. 36 | * 37 | * @param whiteSpace The white space found in the input stream. 38 | * @return Returns a CPWhiteSpaceToken representing the specified white space. 39 | * 40 | * @see whiteSpace: 41 | */ 42 | - (id)initWithWhiteSpace:(NSString *)whiteSpace; 43 | 44 | ///--------------------------------------------------------------------------------------- 45 | /// @name Configuring a WhiteSpace Token 46 | ///--------------------------------------------------------------------------------------- 47 | 48 | /** 49 | * The white space string found in the input stream. 50 | */ 51 | @property (readwrite,copy) NSString *whiteSpace; 52 | 53 | @end 54 | 55 | @interface NSObject (CPIsWhiteSpaceToken) 56 | 57 | - (BOOL)isWhiteSpaceToken; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /CoreParse/Tokenisation/Token Types/CPWhiteSpaceToken.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPWhiteSpaceToken.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/02/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPWhiteSpaceToken.h" 10 | 11 | @implementation CPWhiteSpaceToken 12 | 13 | @synthesize whiteSpace; 14 | 15 | + (id)whiteSpace:(NSString *)whiteSpace 16 | { 17 | return [[[CPWhiteSpaceToken alloc] initWithWhiteSpace:whiteSpace] autorelease]; 18 | } 19 | 20 | - (id)initWithWhiteSpace:(NSString *)initWhiteSpace 21 | { 22 | self = [super init]; 23 | 24 | if (nil != self) 25 | { 26 | [self setWhiteSpace:initWhiteSpace]; 27 | } 28 | 29 | return self; 30 | } 31 | 32 | - (id)init 33 | { 34 | return [self initWithWhiteSpace:@""]; 35 | } 36 | 37 | - (void)dealloc 38 | { 39 | [whiteSpace release]; 40 | 41 | [super dealloc]; 42 | } 43 | 44 | - (NSString *)name 45 | { 46 | return @"Whitespace"; 47 | } 48 | 49 | - (NSUInteger)hash 50 | { 51 | return 1; 52 | } 53 | 54 | - (BOOL)isWhiteSpaceToken 55 | { 56 | return YES; 57 | } 58 | 59 | - (BOOL)isEqual:(id)object 60 | { 61 | return [object isWhiteSpaceToken]; 62 | } 63 | 64 | @end 65 | 66 | @implementation NSObject (CPIsWhiteSpaceToken) 67 | 68 | - (BOOL)isWhiteSpaceToken 69 | { 70 | return NO; 71 | } 72 | 73 | @end 74 | -------------------------------------------------------------------------------- /CoreParse/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /CoreParseTests/CPRegexpRecogniserTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRegexpRecogniserTest.m 3 | // CoreParse 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CPRegexpRecogniser.h" 11 | #import "CPKeywordToken.h" 12 | 13 | @interface CPRegexpRecogniserTest : XCTestCase 14 | 15 | @end 16 | 17 | @implementation CPRegexpRecogniserTest 18 | 19 | - (void)setUp 20 | { 21 | [super setUp]; 22 | // Put setup code here; it will be run once, before the first test case. 23 | } 24 | 25 | - (void)tearDown 26 | { 27 | // Put teardown code here; it will be run once, after the last test case. 28 | [super tearDown]; 29 | } 30 | 31 | - (void)testRecognizeRegexp 32 | { 33 | NSUInteger position = 0; 34 | CPRegexpRecogniser* recognizer = [[CPRegexpRecogniser alloc] initWithRegexp:[[NSRegularExpression alloc] initWithPattern:@"[a-z]+" options:0 error:nil] 35 | matchHandler:^CPToken *(NSString *tokenString, NSTextCheckingResult *match) { 36 | NSString* matchedString = [tokenString substringWithRange:[match range]]; 37 | return [CPKeywordToken tokenWithKeyword:matchedString]; 38 | }]; 39 | CPKeywordToken* token = (CPKeywordToken*) [recognizer recogniseTokenInString:@"hello world" currentTokenPosition:&position]; 40 | XCTAssertEqualObjects([token class], [CPKeywordToken class], @"should be keyword token"); 41 | XCTAssertEqualObjects(@"hello", [token keyword], @"should match the string hello"); 42 | 43 | position = 5; 44 | token = (CPKeywordToken*) [recognizer recogniseTokenInString:@"hello world" currentTokenPosition:&position]; 45 | XCTAssertNil(token, @"should not match space"); 46 | 47 | position = 6; 48 | token = (CPKeywordToken*) [recognizer recogniseTokenInString:@"hello world" currentTokenPosition:&position]; 49 | XCTAssertEqualObjects([token class], [CPKeywordToken class], @"should be keyword token"); 50 | XCTAssertEqualObjects(@"world", [token keyword], @"should match the string world"); 51 | } 52 | 53 | - (void)testReturnNilFromCallbackWillNotSkipContent 54 | { 55 | NSUInteger position = 0; 56 | CPRegexpRecogniser* recognizer = [[CPRegexpRecogniser alloc] initWithRegexp:[[NSRegularExpression alloc] initWithPattern:@"[a-z]+" options:0 error:nil] 57 | matchHandler:^CPToken *(NSString *tokenString, NSTextCheckingResult *match) { 58 | return nil; 59 | }]; 60 | CPKeywordToken* token = (CPKeywordToken*) [recognizer recogniseTokenInString:@"hello world" currentTokenPosition:&position]; 61 | XCTAssertNil(token, @"should be nil"); 62 | XCTAssertTrue(position == 0, @"should not skip content if callback return nil"); 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /CoreParseTests/CPSTAssertionsTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPSTAssertionsTests.h 3 | // CoreParse 4 | // 5 | // Created by Christopher Miller on 5/18/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CPSTAssertionsTests : XCTestCase 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /CoreParseTests/CPSTAssertionsTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPSTAssertionsTests.m 3 | // CoreParse 4 | // 5 | // Created by Christopher Miller on 5/18/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPSTAssertionsTests.h" 10 | #import "CoreParse.h" 11 | #import "CPSenTestKitAssertions.h" 12 | 13 | @implementation CPSTAssertionsTests 14 | 15 | #pragma mark Tokenization Tests 16 | 17 | - (void)testTokenizerKeywordAssertions 18 | { 19 | CPTokeniser * tk = [[CPTokeniser alloc] init]; 20 | [tk addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"{"]]; 21 | [tk addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"}"]]; 22 | 23 | /* 2012-05-18 11:01:17.780 otest[3862:403] ts: */ 24 | CPTokenStream * ts = [tk tokenise:@"{}"]; 25 | CPSTAssertKeywordEquals([ts popToken], @"{"); 26 | CPSTAssertKeywordEquals([ts popToken], @"}"); 27 | CPSTAssertKindOfClass([ts popToken], CPEOFToken); 28 | } 29 | 30 | - (void)testTokenizerIdentifierAssertion 31 | { 32 | CPIdentifierToken * t = [CPIdentifierToken tokenWithIdentifier:@"foobar"]; 33 | CPSTAssertIdentifierEquals(t, @"foobar"); 34 | } 35 | 36 | - (void)testTokenizerNumberAssertions 37 | { 38 | CPTokeniser * qTokenizer = [[CPTokeniser alloc] init]; 39 | CPTokeniser * dTokenizer = [[CPTokeniser alloc] init]; 40 | CPTokeniser * russianRoulette = [[CPTokeniser alloc] init]; 41 | [qTokenizer addTokenRecogniser:[CPNumberRecogniser integerRecogniser]]; 42 | [dTokenizer addTokenRecogniser:[CPNumberRecogniser floatRecogniser]]; 43 | [russianRoulette addTokenRecogniser:[CPNumberRecogniser numberRecogniser]]; 44 | 45 | // test basic ideas about how to recognize numbers 46 | NSString * qs = @"1337", * ds_us = @"13.37", * ds_uk = @"13,37"; 47 | NSInteger q = 1337, qa = 1336, qa_v = 1, qe = 13, qea = 12, qea_v = 1; 48 | double d = 13.37, da = 12.37, da_v = 1.00f; 49 | 50 | CPTokenStream * ts = [qTokenizer tokenise:qs]; 51 | CPSTAssertIntegerNumberEquals([ts peekToken], q); 52 | CPSTAssertIntegerNumberEqualsWithAccuracy([ts popToken], qa, qa_v); 53 | CPSTAssertKindOfClass([ts popToken], CPEOFToken); 54 | 55 | ts = [qTokenizer tokenise:ds_us]; 56 | CPSTAssertIntegerNumberEquals([ts peekToken], qe); 57 | CPSTAssertIntegerNumberEqualsWithAccuracy([ts popToken], qea, qea_v); 58 | CPSTAssertKindOfClass([ts popToken], CPErrorToken); 59 | 60 | ts = [qTokenizer tokenise:ds_uk]; 61 | CPSTAssertIntegerNumberEquals([ts peekToken], qe); 62 | CPSTAssertIntegerNumberEqualsWithAccuracy([ts popToken], qea, qea_v); 63 | CPSTAssertKindOfClass([ts popToken], CPErrorToken); 64 | 65 | // for some reason, the default tokenizer always uses floating point 66 | ts = [russianRoulette tokenise:qs]; 67 | CPSTAssertFloatingNumberEquals([ts peekToken], q); 68 | CPSTAssertFloatingNumberEqualsWithAccuracy([ts popToken], qa, qa_v); 69 | CPSTAssertKindOfClass([ts popToken], CPEOFToken); 70 | 71 | ts = [russianRoulette tokenise:ds_us]; 72 | CPSTAssertFloatingNumberEquals([ts peekToken], d); 73 | CPSTAssertFloatingNumberEqualsWithAccuracy([ts popToken], da, da_v); 74 | CPSTAssertKindOfClass([ts popToken], CPEOFToken); 75 | 76 | ts = [russianRoulette tokenise:ds_uk]; 77 | CPSTAssertFloatingNumberEquals([ts peekToken], qe); 78 | CPSTAssertFloatingNumberEqualsWithAccuracy([ts popToken], qea, qea_v); 79 | CPSTAssertKindOfClass([ts popToken], CPErrorToken); 80 | 81 | ts = [dTokenizer tokenise:qs]; 82 | CPSTAssertKindOfClass([ts popToken], CPErrorToken); 83 | 84 | ts = [dTokenizer tokenise:ds_us]; 85 | CPSTAssertFloatingNumberEquals([ts peekToken], d); 86 | CPSTAssertFloatingNumberEqualsWithAccuracy([ts popToken], da, da_v); 87 | CPSTAssertKindOfClass([ts popToken], CPEOFToken); 88 | 89 | ts = [dTokenizer tokenise:ds_uk]; 90 | CPSTAssertKindOfClass([ts popToken], CPErrorToken); 91 | 92 | } 93 | 94 | @end 95 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestErrorEvaluatorDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestErrorEvaluatorDelegate.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CoreParse.h" 12 | 13 | @interface CPTestErrorEvaluatorDelegate : NSObject 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestErrorEvaluatorDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestErrorEvaluatorDelegate.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTestErrorEvaluatorDelegate.h" 10 | 11 | @implementation CPTestErrorEvaluatorDelegate 12 | 13 | - (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree 14 | { 15 | CPRule *r = [syntaxTree rule]; 16 | NSArray *c = [syntaxTree children]; 17 | 18 | switch ([r tag]) 19 | { 20 | case 0: 21 | case 2: 22 | return [c objectAtIndex:0]; 23 | case 1: 24 | { 25 | int v1 = [[c objectAtIndex:0] isErrorToken] ? 0.0 : [[c objectAtIndex:0] intValue]; 26 | int v2 = [[c objectAtIndex:2] isErrorToken] ? 0.0 : [[c objectAtIndex:2] intValue]; 27 | return [NSNumber numberWithInt:v1 + v2]; 28 | } 29 | case 3: 30 | { 31 | int v1 = [[c objectAtIndex:0] isErrorToken] ? 1.0 : [[c objectAtIndex:0] intValue]; 32 | int v2 = [[c objectAtIndex:2] isErrorToken] ? 1.0 : [[c objectAtIndex:2] intValue]; 33 | return [NSNumber numberWithInt:v1 * v2]; 34 | } 35 | case 4: 36 | return [(CPNumberToken *)[c objectAtIndex:0] numberValue]; 37 | case 5: 38 | return [c objectAtIndex:1]; 39 | default: 40 | return syntaxTree; 41 | } 42 | } 43 | 44 | - (CPRecoveryAction *)parser:(CPParser *)parser didEncounterErrorOnInput:(CPTokenStream *)inputStream expecting:(NSSet *)acceptableTokens 45 | { 46 | return [CPRecoveryAction recoveryActionWithAdditionalToken:[CPErrorToken errorWithMessage:@"Expected expression"]]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestErrorHandlingDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestErrorHandlingDelegate.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CoreParse.h" 12 | 13 | @interface CPTestErrorHandlingDelegate : NSObject 14 | 15 | @property (readwrite, assign) BOOL hasEncounteredError; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestErrorHandlingDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestErrorHandlingDelegate.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 05/02/2012. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTestErrorHandlingDelegate.h" 10 | 11 | @implementation CPTestErrorHandlingDelegate 12 | 13 | @synthesize hasEncounteredError; 14 | 15 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token 16 | { 17 | return YES; 18 | } 19 | 20 | - (NSArray *)tokeniser:(CPTokeniser *)tokeniser willProduceToken:(CPToken *)token 21 | { 22 | return [NSArray arrayWithObject:token]; 23 | } 24 | 25 | - (NSUInteger)tokeniser:(CPTokeniser *)tokeniser didNotFindTokenOnInput:(NSString *)input position:(NSUInteger)position error:(NSString **)errorMessage 26 | { 27 | *errorMessage = @"Found something that wasn't a comment"; 28 | NSRange nextSlashStar = [input rangeOfString:@"/*" options:NSLiteralSearch range:NSMakeRange(position, [input length] - position)]; 29 | return nextSlashStar.location; 30 | } 31 | 32 | - (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree 33 | { 34 | return syntaxTree; 35 | } 36 | 37 | - (CPRecoveryAction *)parser:(CPParser *)parser didEncounterErrorOnInput:(CPTokenStream *)inputStream expecting:(NSSet *)acceptableTokens 38 | { 39 | hasEncounteredError = YES; 40 | return [CPRecoveryAction recoveryActionDeletingCurrentToken]; 41 | } 42 | 43 | @end 44 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestEvaluatorDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestEvaluatorDelegate.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CoreParse.h" 12 | 13 | @interface CPTestEvaluatorDelegate : NSObject 14 | {} 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestEvaluatorDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestEvaluatorDelegate.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 12/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTestEvaluatorDelegate.h" 10 | 11 | #import "CPNumberToken.h" 12 | 13 | @implementation CPTestEvaluatorDelegate 14 | 15 | - (id)parser:(CPParser *)parser didProduceSyntaxTree:(CPSyntaxTree *)syntaxTree 16 | { 17 | CPRule *r = [syntaxTree rule]; 18 | NSArray *c = [syntaxTree children]; 19 | 20 | switch ([r tag]) 21 | { 22 | case 0: 23 | case 2: 24 | return [c objectAtIndex:0]; 25 | case 1: 26 | return [NSNumber numberWithInt:[[c objectAtIndex:0] intValue] + [[c objectAtIndex:2] intValue]]; 27 | case 3: 28 | return [NSNumber numberWithInt:[[c objectAtIndex:0] intValue] * [[c objectAtIndex:2] intValue]]; 29 | case 4: 30 | return [(CPNumberToken *)[c objectAtIndex:0] numberValue]; 31 | case 5: 32 | return [c objectAtIndex:1]; 33 | default: 34 | return syntaxTree; 35 | } 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestMapCSSTokenisingDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestMapCSSTokenisingDelegate.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 15/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @interface CPTestMapCSSTokenisingDelegate : NSObject 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestMapCSSTokenisingDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestMapCSSTokenisingDelegate.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 15/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTestMapCSSTokenisingDelegate.h" 10 | 11 | @implementation CPTestMapCSSTokenisingDelegate 12 | { 13 | NSCharacterSet *symbolsSet; 14 | int nestingDepth; 15 | BOOL justTokenisedObject; 16 | BOOL inRange; 17 | } 18 | 19 | - (id)init 20 | { 21 | self = [super init]; 22 | 23 | if (nil != self) 24 | { 25 | symbolsSet = [NSCharacterSet characterSetWithCharactersInString:@"*[]{}().,;@|-!=<>:!"]; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token 32 | { 33 | NSString *name = [token name]; 34 | if ([name isEqualToString:@"{"] || [name isEqualToString:@"["]) 35 | { 36 | nestingDepth++; 37 | } 38 | else if ([name isEqualToString:@"}"] || [name isEqualToString:@"]"]) 39 | { 40 | nestingDepth--; 41 | } 42 | else if ([name isEqualToString:@"|z"]) 43 | { 44 | inRange = YES; 45 | } 46 | else if (inRange && ![token isNumberToken] && ![name isEqualToString:@"-"]) 47 | { 48 | inRange = NO; 49 | } 50 | else if (inRange && [token isNumberToken]) 51 | { 52 | return [[(CPNumberToken *)token numberValue] floatValue] >= 0; 53 | } 54 | else if ([token isKeywordToken]) 55 | { 56 | return 0 == nestingDepth || [symbolsSet characterIsMember:[name characterAtIndex:0]] || [name isEqualToString:@"eval"] || [name isEqualToString:@"url"] || [name isEqualToString:@"set"] || [name isEqualToString:@"pt"] || [name isEqualToString:@"px"]; 57 | } 58 | 59 | return YES; 60 | } 61 | 62 | - (void)tokeniser:(CPTokeniser *)tokeniser requestsToken:(CPToken *)token pushedOntoStream:(CPTokenStream *)stream 63 | { 64 | if ([token isWhiteSpaceToken]) 65 | { 66 | if (justTokenisedObject) 67 | { 68 | [stream pushToken:token]; 69 | } 70 | } 71 | else 72 | { 73 | NSString *name = [token name]; 74 | justTokenisedObject = ([name isEqualToString:@"node"] || [name isEqualToString:@"way" ] || [name isEqualToString:@"relation"] || 75 | [name isEqualToString:@"area"] || [name isEqualToString:@"line"] || [name isEqualToString:@"canvas"] || [name isEqualToString:@"*"]); 76 | 77 | if (![name isEqualToString:@"Comment"]) 78 | { 79 | [stream pushToken:token]; 80 | } 81 | } 82 | } 83 | 84 | @end 85 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestWhiteSpaceIgnoringDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestWhiteSpaceIgnoringDelegate.h 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 15/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "CoreParse.h" 12 | 13 | @interface CPTestWhiteSpaceIgnoringDelegate : NSObject 14 | {} 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CoreParseTests/CPTestWhiteSpaceIgnoringDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPTestWhiteSpaceIgnoringDelegate.m 3 | // CoreParse 4 | // 5 | // Created by Tom Davie on 15/03/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "CPTestWhiteSpaceIgnoringDelegate.h" 10 | 11 | @implementation CPTestWhiteSpaceIgnoringDelegate 12 | 13 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token 14 | { 15 | return YES; 16 | } 17 | 18 | - (void)tokeniser:(CPTokeniser *)tokeniser requestsToken:(CPToken *)token pushedOntoStream:(CPTokenStream *)stream 19 | { 20 | if (![token isWhiteSpaceToken]) 21 | { 22 | [stream pushToken:token]; 23 | } 24 | } 25 | 26 | - (NSUInteger)tokeniser:(CPTokeniser *)tokeniser didNotFindTokenOnInput:(NSString *)input position:(NSUInteger)position error:(NSString **)errorMessage 27 | { 28 | *errorMessage = @"Found something that wasn't a numeric expression"; 29 | NSRange nextSafeStuff = [input rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"1234567890+*()"] options:NSLiteralSearch range:NSMakeRange(position, [input length] - position)]; 30 | return nextSafeStuff.location; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /CoreParseTests/CPWillFinishDelegateTest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CPRegexpRecogniserTest.m 3 | // CoreParse 4 | // 5 | // Created by Francis Chong on 1/22/14. 6 | // Copyright (c) 2014 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CPTokeniser.h" 11 | #import "CPKeywordRecogniser.h" 12 | #import "CPKeywordToken.h" 13 | #import "CPEOFToken.h" 14 | 15 | @interface CPWillFinishDelegateTest : XCTestCase 16 | 17 | @end 18 | 19 | @implementation CPWillFinishDelegateTest 20 | 21 | - (void)setUp 22 | { 23 | [super setUp]; 24 | // Put setup code here; it will be run once, before the first test case. 25 | } 26 | 27 | - (void)tearDown 28 | { 29 | // Put teardown code here; it will be run once, after the last test case. 30 | [super tearDown]; 31 | } 32 | 33 | - (void)testWillFinishCalled 34 | { 35 | CPTokeniser *tokeniser = [[CPTokeniser alloc] init]; 36 | tokeniser.delegate = self; 37 | [tokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"{"]]; 38 | [tokeniser addTokenRecogniser:[CPKeywordRecogniser recogniserForKeyword:@"}"]]; 39 | CPTokenStream *tokenStream = [tokeniser tokenise:@"{}"]; 40 | CPTokenStream *expectedTokenStream = [CPTokenStream tokenStreamWithTokens:[NSArray arrayWithObjects:[CPKeywordToken tokenWithKeyword:@"{"], [CPKeywordToken tokenWithKeyword:@"}"], [CPKeywordToken tokenWithKeyword:@"done"], [CPEOFToken eof], nil]]; 41 | XCTAssertEqualObjects(tokenStream, expectedTokenStream, @"tokeniser:WillFinish:stream not called", nil); 42 | } 43 | 44 | - (BOOL)tokeniser:(CPTokeniser *)tokeniser shouldConsumeToken:(CPToken *)token 45 | { 46 | return YES; 47 | } 48 | 49 | - (void)tokeniserWillFinish:(CPTokeniser *)tokeniser stream:(CPTokenStream *)stream 50 | { 51 | [stream pushToken:[CPKeywordToken tokenWithKeyword:@"done"]]; 52 | } 53 | 54 | @end 55 | -------------------------------------------------------------------------------- /CoreParseTests/CoreParseTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | com.inthebeginninggames.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CoreParseTests/CoreParseTests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CoreParseTests' target in the 'CoreParseTests' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /CoreParseTests/Expression.h: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @interface Expression : NSObject 14 | 15 | @property (readwrite,assign) float value; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CoreParseTests/Expression.m: -------------------------------------------------------------------------------- 1 | // 2 | // Expression.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "Expression.h" 10 | 11 | #import "Term.h" 12 | 13 | @implementation Expression 14 | 15 | @synthesize value; 16 | 17 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree 18 | { 19 | self = [self init]; 20 | 21 | if (nil != self) 22 | { 23 | NSArray *components = [syntaxTree children]; 24 | if ([components count] == 1) 25 | { 26 | [self setValue:[(Term *)[components objectAtIndex:0] value]]; 27 | } 28 | else 29 | { 30 | [self setValue:[(Expression *)[components objectAtIndex:0] value] + [(Term *)[components objectAtIndex:2] value]]; 31 | } 32 | } 33 | 34 | return self; 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /CoreParseTests/Expression2.h: -------------------------------------------------------------------------------- 1 | // 2 | // Expression2.h 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface Expression2 : NSObject 13 | 14 | @property (readwrite,assign) float value; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /CoreParseTests/Expression2.m: -------------------------------------------------------------------------------- 1 | // 2 | // Expression2.m 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "Expression2.h" 10 | #import "Term2.h" 11 | 12 | @implementation Expression2 13 | 14 | @synthesize value; 15 | 16 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree{ 17 | self = [self init]; 18 | 19 | if (nil != self){ 20 | NSArray *components = [syntaxTree children]; 21 | if ([components count] == 1){ 22 | NSObject *term2 = [components objectAtIndex:0]; 23 | if ([term2 isMemberOfClass:[Term2 class]]){ 24 | self.value = [(Term2 *)term2 value]; 25 | } else { 26 | self.value = -1; 27 | } 28 | } else { 29 | NSObject *term2 = [components objectAtIndex:2]; 30 | if ([term2 isMemberOfClass:[Term2 class]]){ 31 | self.value = [(Expression2 *)[components objectAtIndex:0] value] + [(Term2 *)term2 value]; 32 | } else { 33 | self.value = -1; 34 | } 35 | } 36 | } 37 | 38 | return self; 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /CoreParseTests/RuleBase.h: -------------------------------------------------------------------------------- 1 | // 2 | // RuleBase.h 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface RuleBase : NSObject 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /CoreParseTests/RuleBase.m: -------------------------------------------------------------------------------- 1 | // 2 | // RuleBase.m 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "RuleBase.h" 10 | 11 | @implementation RuleBase 12 | 13 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree{ 14 | self = [super init]; 15 | if (nil != self){ 16 | } 17 | 18 | return self; 19 | } 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /CoreParseTests/Term.h: -------------------------------------------------------------------------------- 1 | // 2 | // Term.h 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import 12 | 13 | @interface Term : NSObject 14 | 15 | @property (readwrite,assign) float value; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /CoreParseTests/Term.m: -------------------------------------------------------------------------------- 1 | // 2 | // Term.m 3 | // CoreParse 4 | // 5 | // Created by Thomas Davie on 26/06/2011. 6 | // Copyright 2011 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "Term.h" 10 | 11 | @implementation Term 12 | 13 | @synthesize value; 14 | 15 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree 16 | { 17 | self = [super init]; 18 | 19 | if (nil != self) 20 | { 21 | [self setValue:[[(CPNumberToken *)[[syntaxTree children] objectAtIndex:0] numberValue] floatValue]]; 22 | } 23 | 24 | return self; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /CoreParseTests/Term2.h: -------------------------------------------------------------------------------- 1 | // 2 | // Term2.h 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "RuleBase.h" 10 | 11 | @interface Term2 : RuleBase 12 | 13 | @property (readwrite,assign) float value; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /CoreParseTests/Term2.m: -------------------------------------------------------------------------------- 1 | // 2 | // Term2.m 3 | // CoreParse 4 | // 5 | // Created by Ayal Spitz on 10/4/12. 6 | // Copyright (c) 2012 In The Beginning... All rights reserved. 7 | // 8 | 9 | #import "Term2.h" 10 | 11 | @implementation Term2 12 | 13 | @synthesize value; 14 | 15 | - (id)initWithSyntaxTree:(CPSyntaxTree *)syntaxTree{ 16 | self = [super init]; 17 | if (nil != self){ 18 | [self setValue:[[(CPNumberToken *)[[syntaxTree children] objectAtIndex:0] numberValue] floatValue]]; 19 | } 20 | 21 | return self; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /CoreParseTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, Thomas Davie 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | * Neither the name of In The Beginning... nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 9 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. --------------------------------------------------------------------------------