Browse files

initial commit

  • Loading branch information...
1 parent 25e7690 commit 6fa4925afc777132ea432b584eab3f62acad8405 @davedelong davedelong committed Nov 20, 2010
View
46 DDExpression.h
@@ -0,0 +1,46 @@
+//
+// DDExpression.h
+// DDMathParser
+//
+// Created by Dave DeLong on 11/16/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+typedef enum {
+ DDExpressionTypeNumber = 0,
+ DDExpressionTypeFunction = 1,
+ DDExpressionTypeVariable = 2
+} DDExpressionType;
+
+@class DDMathEvaluator;
+
+@interface DDExpression : NSObject {
+
+}
+
++ (id) expressionFromString:(NSString *)expressionString;
++ (id) numberExpressionWithNumber:(NSNumber *)number;
++ (id) functionExpressionWithFunction:(NSString *)function arguments:(NSArray *)arguments;
++ (id) variableExpressionWithVariable:(NSString *)variable;
+
+- (DDExpressionType) expressionType;
+
+- (NSNumber *) evaluateWithSubstitutions:(NSDictionary *)substitutions evaluator:(DDMathEvaluator *)evaluator;
+
+- (NSExpression *) expressionValue;
+- (NSExpression *) expressionValueForEvaluator:(DDMathEvaluator *)evaluator;
+
+#pragma mark Number methods
+- (NSNumber *) number;
+
+#pragma mark Function methods
+- (NSString *) function;
+//returns an array of DDExpression objects
+- (NSArray *) arguments;
+
+#pragma mark Variable
+- (NSString *) variable;
+
+@end
View
73 DDExpression.m
@@ -0,0 +1,73 @@
+//
+// DDExpression.m
+// DDMathParser
+//
+// Created by Dave DeLong on 11/16/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import "DDExpression.h"
+#import "DDMathEvaluator.h"
+#import "DDMathEvaluator+Private.h"
+#import "DDMathParser.h"
+
+#import "_DDNumberExpression.h"
+#import "_DDFunctionExpression.h"
+#import "_DDVariableExpression.h"
+
+
+@implementation DDExpression
+
++ (id) expressionFromString:(NSString *)expressionString {
+ return [[DDMathParser mathParserWithString:expressionString] parsedExpression];
+}
+
++ (id) numberExpressionWithNumber:(NSNumber *)number {
+ return [[[_DDNumberExpression alloc] initWithNumber:number] autorelease];
+}
+
++ (id) functionExpressionWithFunction:(NSString *)function arguments:(NSArray *)arguments {
+ return [[[_DDFunctionExpression alloc] initWithFunction:function arguments:arguments] autorelease];
+}
+
++ (id) variableExpressionWithVariable:(NSString *)variable {
+ return [[[_DDVariableExpression alloc] initWithVariable:variable] autorelease];
+}
+
+#pragma mark -
+#pragma mark Abstract method implementations
+
+- (DDExpressionType) expressionType {
+ [NSException raise:NSInvalidArgumentException format:@"this method should be overridden: %@", NSStringFromSelector(_cmd)];
+ return 0;
+}
+- (NSNumber *) evaluateWithSubstitutions:(NSDictionary *)substitutions evaluator:(DDMathEvaluator *)evaluator {
+ [NSException raise:NSInvalidArgumentException format:@"this method should be overridden: %@", NSStringFromSelector(_cmd)];
+ return nil;
+}
+- (NSExpression *) expressionValue {
+ return [self expressionValueForEvaluator:[DDMathEvaluator sharedMathEvaluator]];
+}
+
+- (NSExpression *) expressionValueForEvaluator:(DDMathEvaluator *)evaluator {
+ [NSException raise:NSInvalidArgumentException format:@"this method should be overridden: %@", NSStringFromSelector(_cmd)];
+ return nil;
+}
+- (NSNumber *) number {
+ [NSException raise:NSInvalidArgumentException format:@"This is not a numeric expression"];
+ return nil;
+}
+- (NSString *) function {
+ [NSException raise:NSInvalidArgumentException format:@"This is not a function expression"];
+ return nil;
+}
+- (NSArray *) arguments {
+ [NSException raise:NSInvalidArgumentException format:@"This is not a function expression"];
+ return nil;
+}
+- (NSString *) variable {
+ [NSException raise:NSInvalidArgumentException format:@"This is not a variable expression"];
+ return nil;
+}
+
+@end
View
20 DDMathEvaluator+Private.h
@@ -0,0 +1,20 @@
+//
+// DDMathEvaluator+Private.h
+// DDMathParser
+//
+// Created by Dave DeLong on 11/17/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "DDMathEvaluator.h"
+
+@interface DDMathEvaluator ()
+
+- (DDMathFunction) functionWithName:(NSString *)functionName;
+- (NSInteger) numberOfArgumentsForFunction:(NSString *)functionName;
+
+- (NSNumber *) evaluateFunction:(DDExpression *)function withSubstitutions:(NSDictionary *)variables;
+- (NSString *) nsexpressionFunctionWithName:(NSString *)functionName;
+
+@end
View
27 DDMathEvaluator.h
@@ -0,0 +1,27 @@
+//
+// DDMathEvaluator.h
+// DDMathParser
+//
+// Created by Dave DeLong on 11/17/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "DDTypes.h"
+
+@class DDMathEvaluator;
+@class DDExpression;
+
+@interface DDMathEvaluator : NSObject {
+ NSMutableDictionary * functions;
+}
+
++ (id) sharedMathEvaluator;
+
+- (BOOL) registerFunction:(DDMathFunction)function forName:(NSString *)functionName numberOfArguments:(NSInteger)argCount;
+- (void) unregisterFunctionWithName:(NSString *)functionName;
+- (NSArray *) registeredFunctions;
+
+- (NSNumber *) evaluateString:(NSString *)expressionString withSubstitutions:(NSDictionary *)substitutions;
+
+@end
View
196 DDMathEvaluator.m
@@ -0,0 +1,196 @@
+//
+// DDMathEvaluator.m
+// DDMathParser
+//
+// Created by Dave DeLong on 11/17/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import "DDMathEvaluator.h"
+#import "DDMathEvaluator+Private.h"
+#import "DDMathParser.h"
+#import "DDExpression.h"
+#import "DDMathFunctionContainer.h"
+
+@interface DDMathEvaluator ()
+
+- (NSSet *) _standardFunctions;
+- (void) _registerStandardFunctions;
+
+@end
+
+
+@implementation DDMathEvaluator
+
+static DDMathEvaluator * _sharedEvaluator = nil;
+
++ (id) sharedMathEvaluator {
+ if (_sharedEvaluator == nil) {
+ _sharedEvaluator = [[DDMathEvaluator alloc] init];
+ }
+ return _sharedEvaluator;
+}
+
+- (id) init {
+ self = [super init];
+ if (self) {
+ functions = [[NSMutableDictionary alloc] init];
+ [self _registerStandardFunctions];
+ }
+ return self;
+}
+
+- (void) dealloc {
+ if (self == _sharedEvaluator) {
+ _sharedEvaluator = nil;
+ }
+ [functions release];
+ [super dealloc];
+}
+
+- (BOOL) registerFunction:(DDMathFunction)function forName:(NSString *)functionName numberOfArguments:(NSInteger)argCount {
+ if ([self functionWithName:functionName] != nil) { return NO; }
+ if ([[self _standardFunctions] containsObject:[functionName lowercaseString]]) { return NO; }
+
+ DDMathFunctionContainer * c = [DDMathFunctionContainer mathFunctionWithName:[functionName lowercaseString] function:function numberOfArguments:argCount];
+ if (c != nil) {
+ [functions setObject:c forKey:[c name]];
+ return YES;
+ }
+ return NO;
+}
+
+- (void) unregisterFunctionWithName:(NSString *)functionName {
+ //can't unregister built-in functions
+ if ([[self _standardFunctions] containsObject:[functionName lowercaseString]]) { return; }
+
+ [functions removeObjectForKey:[functionName lowercaseString]];
+}
+
+- (DDMathFunction) functionWithName:(NSString *)functionName {
+ DDMathFunctionContainer * c = [functions objectForKey:[functionName lowercaseString]];
+ return [c function];
+}
+
+- (NSInteger) numberOfArgumentsForFunction:(NSString *)functionName {
+ DDMathFunctionContainer * c = [functions objectForKey:[functionName lowercaseString]];
+ return [c numberOfArguments];
+}
+
+- (NSArray *) registeredFunctions {
+ return [functions allKeys];
+}
+
+- (NSString *) nsexpressionFunctionWithName:(NSString *)functionName {
+ NSDictionary * map = [DDMathFunctionContainer nsexpressionFunctions];
+ NSString * function = [map objectForKey:[functionName lowercaseString]];
+ return function;
+}
+
+#pragma mark Evaluation
+
+- (NSNumber *) evaluateString:(NSString *)expressionString withSubstitutions:(NSDictionary *)variables {
+ NSNumber * returnValue = nil;
+ @try {
+ DDMathParser * parser = [DDMathParser mathParserWithString:expressionString];
+ DDExpression * parsedExpression = [parser parsedExpression];
+ returnValue = [parsedExpression evaluateWithSubstitutions:variables evaluator:self];
+ }
+ @catch (NSException * e) {
+ NSLog(@"caught exception: %@", e);
+ returnValue = nil;
+ }
+ @finally {
+ return returnValue;
+ }
+}
+
+- (NSNumber *) evaluateFunction:(DDExpression *)expression withSubstitutions:(NSDictionary *)variables {
+ DDMathFunction function = [self functionWithName:[expression function]];
+ if (function == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"unrecognized function: %@", [expression function]];
+ return nil;
+ }
+
+ DDExpression * evaluatedValue = function([expression arguments], variables, self);
+ if (evaluatedValue != nil && [evaluatedValue expressionType] == DDExpressionTypeNumber) {
+ return [evaluatedValue number];
+ }
+
+ [NSException raise:NSInvalidArgumentException format:@"invalid function response: %@", evaluatedValue];
+ return nil;
+}
+
+- (id) performFunction:(NSArray *)parameters {
+ NSMutableArray * mutableParameters = [parameters mutableCopy];
+ NSString * functionName = [[mutableParameters objectAtIndex:0] constantValue];
+ [mutableParameters removeObjectAtIndex:0];
+ NSLog(@"stuff to %@: %@", functionName, mutableParameters);
+ [mutableParameters release];
+ return [NSNumber numberWithInt:0];
+}
+
+#pragma mark Built-In Functions
+
+- (NSSet *) _standardFunctions {
+ return [NSSet setWithObjects:
+ //arithmetic functions (2 parameters)
+ @"add",
+ @"subtract",
+ @"multiply",
+ @"divide",
+ @"mod",
+ @"factorial",
+ @"pow",
+
+ //bitwise functions (2 parameters)
+ @"and",
+ @"or",
+ @"xor",
+ @"rshift",
+ @"lshift",
+
+ //functions that take n parameters
+ @"average",
+ @"sum",
+ @"count",
+ @"min",
+ @"max",
+ @"median",
+ @"mode",
+ @"stddev",
+
+ //functions that take 1 parameter
+ @"negate",
+ @"not",
+ @"sqrt",
+ @"log",
+ @"ln",
+ @"exp",
+ @"ceil",
+ @"trunc",
+ @"floor",
+ @"onescomplement",
+
+ //functions that take 0 parameters
+ @"pi", //yes, this is equivalent to $pi or $e
+ @"e",
+ nil];
+
+}
+
+- (void) _registerStandardFunctions {
+ for (NSString * functionName in [self _standardFunctions]) {
+
+ NSString * methodName = [NSString stringWithFormat:@"_%@FunctionContainer", [functionName lowercaseString]];
+
+ DDMathFunctionContainer * container = [DDMathFunctionContainer performSelector:NSSelectorFromString(methodName)];
+ if (container != nil) {
+ [functions setObject:container forKey:[functionName lowercaseString]];
+ } else {
+ NSLog(@"error registering function: %@", functionName);
+ }
+ }
+}
+
+@end
View
24 DDMathFunctionContainer.h
@@ -0,0 +1,24 @@
+//
+// DDMathFunctionContainer.h
+// DDMathParser
+//
+// Created by Dave DeLong on 11/18/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "DDTypes.h"
+
+@interface DDMathFunctionContainer : NSObject {
+ DDMathFunction function;
+ NSString * name;
+}
+
+@property (nonatomic, copy) DDMathFunction function;
+@property (nonatomic, copy) NSString * name;
+@property (nonatomic) NSInteger numberOfArguments;
+
++ (NSDictionary *) nsexpressionFunctions;
++ (id) mathFunctionWithName:(NSString *)name function:(DDMathFunction)function numberOfArguments:(NSInteger)numberOfArguments;
+
+@end
View
316 DDMathFunctionContainer.m
@@ -0,0 +1,316 @@
+//
+// DDMathFunctionContainer.m
+// DDMathParser
+//
+// Created by Dave DeLong on 11/18/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import "DDMathFunctionContainer.h"
+
+#import "DDExpression.h"
+
+@implementation DDMathFunctionContainer
+@synthesize function;
+@synthesize name;
+@synthesize numberOfArguments;
+
++ (NSDictionary *) nsexpressionFunctions {
+ static NSDictionary * functions = nil;
+ if (functions == nil) {
+ functions = [[NSDictionary alloc] initWithObjectsAndKeys:
+ @"add:to:", @"add",
+ @"from:subtract:", @"subtract",
+ @"multiply:by:", @"multiply",
+ @"divide:by:", @"divide",
+ @"modulus:by:", @"mod",
+ @"raise:toPower:", @"pow",
+ @"bitwiseAnd:with:", @"and",
+ @"bitwiseOr:with:", @"or",
+ @"bitwiseXor:with:", @"xor",
+ @"rightshift:by:", @"rshift",
+ @"leftshift:by:", @"lshift",
+ @"average:", @"average",
+ @"sum:", @"sum",
+ @"count:", @"count",
+ @"min:", @"min",
+ @"max:", @"max",
+ @"median:", @"median",
+ @"mode:", @"mode",
+ @"stddev:", @"stddev",
+ @"sqrt:", @"sqrt",
+ @"log:", @"log",
+ @"ln:", @"ln",
+ @"exp:", @"exp",
+ @"ceiling:", @"ceil",
+ @"abs:", @"abs",
+ @"trunc:", @"trunc",
+ @"floor:", @"floor",
+ @"onesComplement:", @"onescomplement",
+ nil];
+ }
+ return functions;
+}
+
++ (DDMathFunction) oneArgumentFunctionForMethod:(NSString *)method {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 1) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+
+ NSNumber * firstValue = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator];
+
+ NSArray * parameters = [NSArray arrayWithObject:[NSExpression expressionForConstantValue:firstValue]];
+
+ NSExpression * e = [NSExpression expressionForFunction:method arguments:parameters];
+ NSNumber * value = [e expressionValueWithObject:nil context:nil];
+ return [DDExpression numberExpressionWithNumber:value];
+ };
+ return [[function copy] autorelease];
+}
+
++ (DDMathFunction) twoArgumentFunctionForMethod:(NSString *)method {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 2) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+
+ NSNumber * firstValue = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator];
+ NSNumber * secondValue = [[arguments objectAtIndex:1] evaluateWithSubstitutions:variables evaluator:evaluator];
+
+ NSArray * parameters = [NSArray arrayWithObjects:
+ [NSExpression expressionForConstantValue:firstValue],
+ [NSExpression expressionForConstantValue:secondValue],
+ nil];
+
+ NSExpression * add = [NSExpression expressionForFunction:method arguments:parameters];
+ NSNumber * value = [add expressionValueWithObject:nil context:nil];
+ return [DDExpression numberExpressionWithNumber:value];
+ };
+ return [[function copy] autorelease];
+}
+
++ (id) nArgumentFunctionForMethod:(NSString *)method {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+
+ NSMutableArray * parameters = [NSMutableArray array];
+ for (DDExpression * argument in arguments) {
+ NSNumber * value = [argument evaluateWithSubstitutions:variables evaluator:evaluator];
+ [parameters addObject:[NSExpression expressionForConstantValue:value]];
+ }
+
+ NSExpression * e = [NSExpression expressionForFunction:method arguments:parameters];
+ NSNumber * value = [e expressionValueWithObject:nil context:nil];
+ return [DDExpression numberExpressionWithNumber:value];
+ };
+ return [[function copy] autorelease];
+}
+
++ (id) _addFunctionContainer {
+ DDMathFunction function = [self twoArgumentFunctionForMethod:@"add:to:"];
+ return [self mathFunctionWithName:@"add" function:function numberOfArguments:2];
+}
+
++ (id) _subtractFunctionContainer {
+ DDMathFunction function = [self twoArgumentFunctionForMethod:@"from:subtract:"];
+ return [self mathFunctionWithName:@"subtract" function:function numberOfArguments:2];
+}
+
++ (id) _multiplyFunctionContainer {
+ return [self mathFunctionWithName:@"multiply" function:[self twoArgumentFunctionForMethod:@"multiply:by:"] numberOfArguments:2];
+}
++ (id) _divideFunctionContainer {
+ return [self mathFunctionWithName:@"divide" function:[self twoArgumentFunctionForMethod:@"divide:by:"] numberOfArguments:2];
+}
++ (id) _modFunctionContainer {
+ return [self mathFunctionWithName:@"mod" function:[self twoArgumentFunctionForMethod:@"modulus:by:"] numberOfArguments:2];
+}
++ (id) _negateFunctionContainer {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 1) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+
+ NSNumber * firstValue = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator];
+ NSNumber * secondValue = [NSNumber numberWithInt:-1];
+
+ NSArray * parameters = [NSArray arrayWithObjects:
+ [NSExpression expressionForConstantValue:firstValue],
+ [NSExpression expressionForConstantValue:secondValue],
+ nil];
+
+ NSExpression * add = [NSExpression expressionForFunction:@"multiply:by:" arguments:parameters];
+ NSNumber * value = [add expressionValueWithObject:nil context:nil];
+ return [DDExpression numberExpressionWithNumber:value];
+ };
+ return [self mathFunctionWithName:@"negate" function:function numberOfArguments:1];
+}
++ (id) _factorialFunctionContainer {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 1) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+
+ NSNumber * firstValue = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator];
+ NSInteger intValue = [firstValue integerValue];
+ NSInteger total = 1;
+ while (intValue > 1) {
+ total *= intValue;
+ intValue--;
+ }
+ NSNumber * result = [NSNumber numberWithInteger:total];
+ return [DDExpression numberExpressionWithNumber:result];
+ };
+ return [self mathFunctionWithName:@"factorial" function:function numberOfArguments:1];
+}
++ (id) _powFunctionContainer {
+ return [self mathFunctionWithName:@"pow" function:[self twoArgumentFunctionForMethod:@"raise:toPower:"] numberOfArguments:2];
+}
+
++ (id) _andFunctionContainer {
+ return [self mathFunctionWithName:@"and" function:[self twoArgumentFunctionForMethod:@"bitwiseAnd:with:"] numberOfArguments:2];
+}
++ (id) _orFunctionContainer {
+ return [self mathFunctionWithName:@"or" function:[self twoArgumentFunctionForMethod:@"bitwiseOr:with:"] numberOfArguments:2];
+}
++ (id) _notFunctionContainer {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 1) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+
+ NSNumber * firstValue = [[arguments objectAtIndex:0] evaluateWithSubstitutions:variables evaluator:evaluator];
+ NSInteger intValue = [firstValue integerValue];
+ intValue = ~intValue;
+ NSNumber * value = [NSNumber numberWithInteger:intValue];
+ return [DDExpression numberExpressionWithNumber:value];
+ };
+ return [self mathFunctionWithName:@"not" function:function numberOfArguments:1];
+}
++ (id) _xorFunctionContainer {
+ return [self mathFunctionWithName:@"xor" function:[self twoArgumentFunctionForMethod:@"bitwiseXor:with:"] numberOfArguments:2];
+}
++ (id) _rshiftFunctionContainer {
+ return [self mathFunctionWithName:@"rshift" function:[self twoArgumentFunctionForMethod:@"rightshift:by:"] numberOfArguments:2];
+}
++ (id) _lshiftFunctionContainer {
+ return [self mathFunctionWithName:@"lshift" function:[self twoArgumentFunctionForMethod:@"leftshift:by:"] numberOfArguments:2];
+}
+
+#pragma mark NSExpression parity
+
++ (id) _averageFunctionContainer {
+ return [self mathFunctionWithName:@"average" function:[self nArgumentFunctionForMethod:@"average:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _sumFunctionContainer {
+ return [self mathFunctionWithName:@"sum" function:[self nArgumentFunctionForMethod:@"sum:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _countFunctionContainer {
+ return [self mathFunctionWithName:@"count" function:[self nArgumentFunctionForMethod:@"count:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _minFunctionContainer {
+ return [self mathFunctionWithName:@"min" function:[self nArgumentFunctionForMethod:@"min:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _maxFunctionContainer {
+ return [self mathFunctionWithName:@"max" function:[self nArgumentFunctionForMethod:@"max:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _medianFunctionContainer {
+ return [self mathFunctionWithName:@"median" function:[self nArgumentFunctionForMethod:@"median:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _modeFunctionContainer {
+ return [self mathFunctionWithName:@"mode" function:[self nArgumentFunctionForMethod:@"mode:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _stddevFunctionContainer {
+ return [self mathFunctionWithName:@"stddev" function:[self nArgumentFunctionForMethod:@"stddev:"] numberOfArguments:DDMathFunctionUnlimitedArguments];
+}
+
++ (id) _sqrtFunctionContainer {
+ return [self mathFunctionWithName:@"sqrt" function:[self oneArgumentFunctionForMethod:@"sqrt:"] numberOfArguments:1];
+}
+
++ (id) _logFunctionContainer {
+ return [self mathFunctionWithName:@"log" function:[self oneArgumentFunctionForMethod:@"log:"] numberOfArguments:1];
+}
+
++ (id) _lnFunctionContainer {
+ return [self mathFunctionWithName:@"ln" function:[self oneArgumentFunctionForMethod:@"ln:"] numberOfArguments:1];
+}
+
++ (id) _expFunctionContainer {
+ return [self mathFunctionWithName:@"exp" function:[self oneArgumentFunctionForMethod:@"exp:"] numberOfArguments:1];
+}
+
++ (id) _ceilFunctionContainer {
+ return [self mathFunctionWithName:@"ceil" function:[self oneArgumentFunctionForMethod:@"ceiling:"] numberOfArguments:1];
+}
+
++ (id) _absFunctionContainer {
+ return [self mathFunctionWithName:@"abs" function:[self oneArgumentFunctionForMethod:@"abs:"] numberOfArguments:1];
+}
+
++ (id) _truncFunctionContainer {
+ return [self mathFunctionWithName:@"trunc" function:[self oneArgumentFunctionForMethod:@"trunc:"] numberOfArguments:1];
+}
+
++ (id) _floorFunctionContainer {
+ return [self mathFunctionWithName:@"floor" function:[self oneArgumentFunctionForMethod:@"floor:"] numberOfArguments:1];
+}
+
++ (id) _onescomplementFunctionContainer {
+ return [self mathFunctionWithName:@"onescomplement" function:[self oneArgumentFunctionForMethod:@"onesComplement:"] numberOfArguments:1];
+}
+
++ (id) _piFunctionContainer {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 0) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+ return [DDExpression numberExpressionWithNumber:[NSNumber numberWithDouble:M_PI]];
+ };
+ return [self mathFunctionWithName:@"pi" function:function numberOfArguments:0];
+}
+
++ (id) _eFunctionContainer {
+ DDMathFunction function = ^ DDExpression* (NSArray * arguments, NSDictionary * variables, DDMathEvaluator * evaluator) {
+ if ([arguments count] != 0) {
+ [NSException raise:NSInvalidArgumentException format:@"invalid number of arguments: %ld", [arguments count]];
+ return nil;
+ }
+ return [DDExpression numberExpressionWithNumber:[NSNumber numberWithDouble:M_E]];
+ };
+ return [self mathFunctionWithName:@"e" function:function numberOfArguments:0];
+}
+
++ (id) mathFunctionWithName:(NSString *)name function:(DDMathFunction)function numberOfArguments:(NSInteger)numberOfArguments {
+ if (name == nil) { return nil; }
+ if (function == nil) { return nil; }
+
+ if (numberOfArguments < 0) { numberOfArguments = DDMathFunctionUnlimitedArguments; }
+
+ DDMathFunctionContainer * c = [[self alloc] init];
+ [c setName:name];
+ [c setFunction:function];
+ [c setNumberOfArguments:numberOfArguments];
+ return [c autorelease];
+}
+
+- (void) dealloc {
+ [name release];
+ [function release];
+ [super dealloc];
+}
+
+@end
View
79 DDMathParser.1
@@ -0,0 +1,79 @@
+.\"Modified from man(1) of FreeBSD, the NetBSD mdoc.template, and mdoc.samples.
+.\"See Also:
+.\"man mdoc.samples for a complete listing of options
+.\"man mdoc for the short list of editing options
+.\"/usr/share/misc/mdoc.template
+.Dd 11/11/10 \" DATE
+.Dt DDMathParser 1 \" Program name and manual section number
+.Os Darwin
+.Sh NAME \" Section Header - required - don't modify
+.Nm DDMathParser,
+.\" The following lines are read in generating the apropos(man -k) database. Use only key
+.\" words here as the database is built based on the words here and in the .ND line.
+.Nm Other_name_for_same_program(),
+.Nm Yet another name for the same program.
+.\" Use .Nm macro to designate other names for the documented program.
+.Nd This line parsed for whatis database.
+.Sh SYNOPSIS \" Section Header - required - don't modify
+.Nm
+.Op Fl abcd \" [-abcd]
+.Op Fl a Ar path \" [-a path]
+.Op Ar file \" [file]
+.Op Ar \" [file ...]
+.Ar arg0 \" Underlined argument - use .Ar anywhere to underline
+arg2 ... \" Arguments
+.Sh DESCRIPTION \" Section Header - required - don't modify
+Use the .Nm macro to refer to your program throughout the man page like such:
+.Nm
+Underlining is accomplished with the .Ar macro like this:
+.Ar underlined text .
+.Pp \" Inserts a space
+A list of items with descriptions:
+.Bl -tag -width -indent \" Begins a tagged list
+.It item a \" Each item preceded by .It macro
+Description of item a
+.It item b
+Description of item b
+.El \" Ends the list
+.Pp
+A list of flags and their descriptions:
+.Bl -tag -width -indent \" Differs from above in tag removed
+.It Fl a \"-a flag as a list item
+Description of -a flag
+.It Fl b
+Description of -b flag
+.El \" Ends the list
+.Pp
+.\" .Sh ENVIRONMENT \" May not be needed
+.\" .Bl -tag -width "ENV_VAR_1" -indent \" ENV_VAR_1 is width of the string ENV_VAR_1
+.\" .It Ev ENV_VAR_1
+.\" Description of ENV_VAR_1
+.\" .It Ev ENV_VAR_2
+.\" Description of ENV_VAR_2
+.\" .El
+.Sh FILES \" File used or created by the topic of the man page
+.Bl -tag -width "/Users/joeuser/Library/really_long_file_name" -compact
+.It Pa /usr/share/file_name
+FILE_1 description
+.It Pa /Users/joeuser/Library/really_long_file_name
+FILE_2 description
+.El \" Ends the list
+.\" .Sh DIAGNOSTICS \" May not be needed
+.\" .Bl -diag
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .It Diagnostic Tag
+.\" Diagnostic informtion here.
+.\" .El
+.Sh SEE ALSO
+.\" List links in ascending order by section, alphabetically within a section.
+.\" Please do not reference files that do not exist without filing a bug report
+.Xr a 1 ,
+.Xr b 1 ,
+.Xr c 1 ,
+.Xr a 2 ,
+.Xr b 2 ,
+.Xr a 3 ,
+.Xr b 3
+.\" .Sh BUGS \" Document known, unremedied bugs
+.\" .Sh HISTORY \" Document history if command behaves in a unique manner
View
24 DDMathParser.h
@@ -0,0 +1,24 @@
+//
+// DDMathParser.h
+// DDMathParser
+//
+// Created by Dave DeLong on 11/11/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+@class DDMathStringTokenizer;
+@class DDExpression;
+
+@interface DDMathParser : NSObject {
+ DDMathStringTokenizer * tokenizer;
+ NSUInteger currentTokenIndex;
+}
+
++ (id) mathParserWithString:(NSString *)string;
+- (id) initWithString:(NSString *)string;
+
+- (DDExpression *) parsedExpression;
+
+@end
View
372 DDMathParser.m
@@ -0,0 +1,372 @@
+//
+// DDMathParser.m
+// DDMathParser
+//
+// Created by Dave DeLong on 11/11/10.
+// Copyright 2010 Home. All rights reserved.
+//
+
+#define DEBUG 0
+#define POWER_IS_RIGHT_ASSOCIATIVE 0
+
+#if DEBUG
+#define LOGMETHOD() (NSLog(@"%s", _cmd))
+#else
+#define LOGMETHOD()
+#endif
+
+#import "DDMathParser.h"
+#import "DDMathStringTokenizer.h"
+#import "DDMathStringToken.h"
+#import "DDExpression.h"
+
+@interface DDMathParser ()
+
+- (DDMathStringToken *) nextToken;
+- (DDMathStringToken *) peekNextToken;
+
+- (DDExpression *) parseBitwiseOrExpression;
+- (DDExpression *) parseBitwiseXorExpression;
+- (DDExpression *) parseBitwiseAndExpression;
+- (DDExpression *) parseBitwiseLeftShiftExpression;
+- (DDExpression *) parseBitwiseRightShiftExpression;
+
+- (DDExpression *) parseSubtractionExpression;
+- (DDExpression *) parseAdditionExpression;
+- (DDExpression *) parseDivisionExpression;
+- (DDExpression *) parseMultiplicationExpression;
+- (DDExpression *) parseModuloExpression;
+
+- (DDExpression *) parseFactorialExpression;
+- (DDExpression *) parsePowerExpression;
+- (DDExpression *) parseUnaryExpression;
+- (DDExpression *) parseTerminalExpression;
+
+@end
+
+
+@implementation DDMathParser
+
++ (id) mathParserWithString:(NSString *)string {
+ return [[[self alloc] initWithString:string] autorelease];
+}
+
+- (id) initWithString:(NSString *)string {
+ self = [super init];
+ if (self) {
+ tokenizer = [[DDMathStringTokenizer alloc] initWithString:string];
+ currentTokenIndex = 0;
+ }
+ return self;
+}
+
+- (void) dealloc {
+ [tokenizer release];
+ [super dealloc];
+}
+
+- (DDMathStringToken *) nextToken {
+ if (currentTokenIndex >= [[tokenizer tokens] count]) { return nil; }
+ DDMathStringToken * next = [[tokenizer tokens] objectAtIndex:currentTokenIndex];
+ currentTokenIndex++;
+ return next;
+}
+
+- (DDMathStringToken *) peekNextToken {
+ DDMathStringToken * next = [self nextToken];
+ if (next != nil) { currentTokenIndex--; }
+ return next;
+}
+
+- (DDExpression *) parsedExpression {
+ currentTokenIndex = 0;
+
+ return [self parseBitwiseOrExpression];
+}
+
+#pragma mark -
+
+/**
+ What's with the while() loop?
+ It's because most of these operators are left associative, but using a normal recursive descent parser
+ with a left associative operator results in infinite recursive.
+
+ So if I have the left associative rule:
+
+ E => E "-" T | T
+
+ Then I can make this into non-left associative by writing it as:
+
+ E => T B
+ B => "-" T B | ε
+
+ Ref: http://stackoverflow.com/questions/4007479#4010791
+ **/
+
+- (DDExpression *) parseBitwiseOrExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseBitwiseXorExpression];
+ while ([[[self peekNextToken] token] isEqual:@"|"]) {
+ [self nextToken]; //consume the |
+ DDExpression * right = [self parseBitwiseXorExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary |"];
+ return nil;
+ }
+
+ left = [DDExpression functionExpressionWithFunction:@"OR" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseBitwiseXorExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseBitwiseAndExpression];
+ while ([[[self peekNextToken] token] isEqual:@"^"]) {
+ [self nextToken]; //consume the ^
+ DDExpression * right = [self parseBitwiseAndExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression for binary ^"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"XOR" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+
+ return left;
+}
+
+- (DDExpression *) parseBitwiseAndExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseBitwiseLeftShiftExpression];
+ while ([[[self peekNextToken] token] isEqual:@"&"]) {
+ [self nextToken]; //consume the &
+ DDExpression * right = [self parseBitwiseLeftShiftExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary &"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"AND" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseBitwiseLeftShiftExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseBitwiseRightShiftExpression];
+ while ([[[self peekNextToken] token] isEqual:@"<<"]) {
+ [self nextToken]; //consume the <<
+ DDExpression * right = [self parseBitwiseRightShiftExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary <<"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"LSHIFT" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseBitwiseRightShiftExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseSubtractionExpression];
+ while ([[[self peekNextToken] token] isEqual:@">>"]) {
+ [self nextToken]; //consume the >>
+ DDExpression * right = [self parseSubtractionExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary >>"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"RSHIFT" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseSubtractionExpression {
+ DDExpression * left = [self parseAdditionExpression];
+ while ([[[self peekNextToken] token] isEqual:@"-"]) {
+ [self nextToken]; //consume the -
+ DDExpression * right = [self parseAdditionExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary -"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"SUBTRACT" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseAdditionExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseDivisionExpression];
+ while ([[[self peekNextToken] token] isEqual:@"+"]) {
+ [self nextToken]; //consume the +
+ DDExpression * right = [self parseDivisionExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary +"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"ADD" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseDivisionExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseMultiplicationExpression];
+ while ([[[self peekNextToken] token] isEqual:@"/"]) {
+ [self nextToken]; //consume the /
+ DDExpression * right = [self parseMultiplicationExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary /"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"DIVIDE" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseMultiplicationExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseModuloExpression];
+ while ([[[self peekNextToken] token] isEqual:@"*"]) {
+ [self nextToken]; //consume the *
+ DDExpression * right = [self parseModuloExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary *"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"MULTIPLY" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+}
+
+- (DDExpression *) parseModuloExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parseUnaryExpression];
+ while ([[[self peekNextToken] token] isEqual:@"%"]) {
+ [self nextToken]; //consume the %
+ DDExpression * right = [self parseUnaryExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary %"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"MOD" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+
+}
+
+- (DDExpression *) parseUnaryExpression {
+ LOGMETHOD();
+ DDMathStringToken * next = [self peekNextToken];
+ if ([[next token] isEqual:@"-"] || [[next token] isEqual:@"~"]) {
+ [self nextToken]; //consume the operator
+ DDExpression * unary = [self parseUnaryExpression];
+ if (unary == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary %@", [next token]];
+ return nil;
+ }
+ NSString * function = ([[next token] isEqual:@"-"] ? @"NEGATE" : @"NOT");
+ return [DDExpression functionExpressionWithFunction:function arguments:[NSArray arrayWithObject:unary]];
+ }
+ return [self parseFactorialExpression];
+}
+
+- (DDExpression *) parseFactorialExpression {
+ LOGMETHOD();
+ DDExpression * left = [self parsePowerExpression];
+ while ([[[self peekNextToken] token] isEqual:@"!"]) {
+ [self nextToken]; //consume the !
+ left = [DDExpression functionExpressionWithFunction:@"factorial" arguments:[NSArray arrayWithObject:left]];
+ }
+ return left;
+}
+
+- (DDExpression *) parsePowerExpression {
+ LOGMETHOD();
+
+#if POWER_IS_RIGHT_ASSOCIATIVE
+ DDExpression * terminal = [self parseTerminalExpression];
+ if ([[[self peekNextToken] token] isEqual:@"**"]) {
+ [self nextToken]; //consume the **
+ DDExpression * power = [self parsePowerExpression];
+ if (power == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary **"];
+ return nil;
+ }
+ return [DDExpression functionExpressionWithFunction:@"POW" arguments:[NSArray arrayWithObjects:terminal, power, nil]];
+ }
+ return terminal;
+#else
+ DDExpression * left = [self parseTerminalExpression];
+ while ([[[self peekNextToken] token] isEqual:@"**"]) {
+ [self nextToken]; //consume the **
+ DDExpression * right = [self parseTerminalExpression];
+ if (right == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"no right expression to binary **"];
+ return nil;
+ }
+ left = [DDExpression functionExpressionWithFunction:@"pow" arguments:[NSArray arrayWithObjects:left, right, nil]];
+ }
+ return left;
+#endif
+}
+
+- (DDExpression *) parseTerminalExpression {
+ LOGMETHOD();
+ DDMathStringToken * next = [self nextToken];
+ if ([next tokenType] == DDTokenTypeNumber) {
+ return [DDExpression numberExpressionWithNumber:[next numberValue]];
+ } else if ([next tokenType] == DDTokenTypeVariable) {
+ return [DDExpression variableExpressionWithVariable:[next token]];
+ } else if ([next tokenType] == DDTokenTypeFunction) {
+ NSString * function = [next token];
+ NSMutableArray * arguments = [NSMutableArray array];
+
+ next = [self nextToken];
+ if ([[next token] isEqual:@"("] == NO) {
+ //this should be unreachable, since a Function token is only generated if the following character is (
+ [NSException raise:NSInvalidArgumentException format:@"function not followed by (. should be unreachable"];
+ return nil;
+ }
+ next = [self peekNextToken];
+ if (next == nil) {
+ [NSException raise:NSInvalidArgumentException format:@"formula must have closing parenthesis"];
+ return nil;
+ }
+ if ([[next token] isEqual:@")"] == NO) {
+ DDExpression * argument = [self parseBitwiseOrExpression];
+ if (argument != nil) {
+ [arguments addObject:argument];
+ }
+ do {
+ next = [self nextToken];
+ if ([[next token] isEqual:@","]) {
+ argument = [self parseBitwiseOrExpression];
+ if (argument != nil) {
+ [arguments addObject:argument];
+ }
+ } else if ([[next token] isEqual:@")"]) {
+ break;
+ } else {
+ [NSException raise:NSInvalidArgumentException format:@"unexpected token found in function: %@", [next token]];
+ return nil;
+ }
+ } while (1);
+ }
+
+ return [DDExpression functionExpressionWithFunction:function arguments:arguments];
+ } else if ([[next token] isEqual:@"("]) {
+ DDExpression * parenthetical = [self parseBitwiseOrExpression];
+ DDMathStringToken * closing = [self nextToken];
+ if ([[closing token] isEqual:@")"] == NO) {
+ [NSException raise:NSInvalidArgumentException format:@"no closing parenthesis found"];
+ return nil;
+ }
+ return parenthetical;
+ }
+
+ [NSException raise:NSInvalidArgumentException format:@"unexpected token: %@", [next token]];
+ return nil;
+}
+
+@end
View
1,574 DDMathParser.xcodeproj/dave.perspectivev3
@@ -0,0 +1,1574 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>ActivePerspectiveName</key>
+ <string>Debug</string>
+ <key>AllowedModules</key>
+ <array>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXSmartGroupTreeModule</string>
+ <key>Name</key>
+ <string>Groups and Files Outline View</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXNavigatorGroup</string>
+ <key>Name</key>
+ <string>Editor</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>XCTaskListModule</string>
+ <key>Name</key>
+ <string>Task List</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>XCDetailModule</string>
+ <key>Name</key>
+ <string>File and Smart Group Detail Viewer</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>1</string>
+ <key>Module</key>
+ <string>PBXBuildResultsModule</string>
+ <key>Name</key>
+ <string>Detailed Build Results Viewer</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>1</string>
+ <key>Module</key>
+ <string>PBXProjectFindModule</string>
+ <key>Name</key>
+ <string>Project Batch Find Tool</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>XCProjectFormatConflictsModule</string>
+ <key>Name</key>
+ <string>Project Format Conflicts List</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXBookmarksModule</string>
+ <key>Name</key>
+ <string>Bookmarks Tool</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXClassBrowserModule</string>
+ <key>Name</key>
+ <string>Class Browser</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXCVSModule</string>
+ <key>Name</key>
+ <string>Source Code Control Tool</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXDebugBreakpointsModule</string>
+ <key>Name</key>
+ <string>Debug Breakpoints Tool</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>XCDockableInspector</string>
+ <key>Name</key>
+ <string>Inspector</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>PBXOpenQuicklyModule</string>
+ <key>Name</key>
+ <string>Open Quickly Tool</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>1</string>
+ <key>Module</key>
+ <string>PBXDebugSessionModule</string>
+ <key>Name</key>
+ <string>Debugger</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>1</string>
+ <key>Module</key>
+ <string>PBXDebugCLIModule</string>
+ <key>Name</key>
+ <string>Debug Console</string>
+ </dict>
+ <dict>
+ <key>BundleLoadPath</key>
+ <string></string>
+ <key>MaxInstances</key>
+ <string>n</string>
+ <key>Module</key>
+ <string>XCSnapshotModule</string>
+ <key>Name</key>
+ <string>Snapshots Tool</string>
+ </dict>
+ </array>
+ <key>BundlePath</key>
+ <string>/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources</string>
+ <key>Description</key>
+ <string>AIODescriptionKey</string>
+ <key>DockingSystemVisible</key>
+ <false/>
+ <key>Extension</key>
+ <string>perspectivev3</string>
+ <key>FavBarConfig</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>55BFA9F0128CFCF800A80228</string>
+ <key>XCBarModuleItemNames</key>
+ <dict/>
+ <key>XCBarModuleItems</key>
+ <array/>
+ </dict>
+ <key>FirstTimeWindowDisplayed</key>
+ <false/>
+ <key>Identifier</key>
+ <string>com.apple.perspectives.project.defaultV3</string>
+ <key>MajorVersion</key>
+ <integer>34</integer>
+ <key>MinorVersion</key>
+ <integer>0</integer>
+ <key>Name</key>
+ <string>All-In-One</string>
+ <key>Notifications</key>
+ <array/>
+ <key>OpenEditors</key>
+ <array>
+ <dict>
+ <key>Content</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>5554D62C1294DC3300A62529</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>MathGrammar.grammar</string>
+ <key>PBXSplitModuleInNavigatorKey</key>
+ <dict>
+ <key>Split0</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>5554D62D1294DC3300A62529</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>MathGrammar.grammar</string>
+ <key>_historyCapacity</key>
+ <integer>0</integer>
+ <key>bookmark</key>
+ <string>554DA16912985E8400433840</string>
+ <key>history</key>
+ <array>
+ <string>55F9F0D21296CA8F00F4A9FD</string>
+ </array>
+ </dict>
+ <key>SplitCount</key>
+ <string>1</string>
+ </dict>
+ <key>StatusBarVisibility</key>
+ <true/>
+ </dict>
+ <key>Geometry</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 20}, {537, 767}}</string>
+ <key>PBXModuleWindowStatusBarHidden2</key>
+ <false/>
+ <key>RubberWindowFrame</key>
+ <string>903 67 537 808 0 0 1440 878 </string>
+ </dict>
+ </dict>
+ </array>
+ <key>PerspectiveWidths</key>
+ <array>
+ <integer>1231</integer>
+ <integer>1231</integer>
+ </array>
+ <key>Perspectives</key>
+ <array>
+ <dict>
+ <key>ChosenToolbarItems</key>
+ <array>
+ <string>XCToolbarPerspectiveControl</string>
+ <string>NSToolbarSeparatorItem</string>
+ <string>active-combo-popup</string>
+ <string>action</string>
+ <string>NSToolbarFlexibleSpaceItem</string>
+ <string>get-info</string>
+ <string>toggle-editor</string>
+ <string>com.apple.pbx.toolbar.searchfield</string>
+ </array>
+ <key>ControllerClassBaseName</key>
+ <string></string>
+ <key>IconName</key>
+ <string>WindowOfProject</string>
+ <key>Identifier</key>
+ <string>perspective.project</string>
+ <key>IsVertical</key>
+ <false/>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXBottomSmartGroupGIDs</key>
+ <array>
+ <string>1C37FBAC04509CD000000102</string>
+ <string>1C37FAAC04509CD000000102</string>
+ <string>1C37FABC05509CD000000102</string>
+ <string>1C37FABC05539CD112110102</string>
+ <string>E2644B35053B69B200211256</string>
+ <string>1C37FABC04509CD000100104</string>
+ <string>1CC0EA4004350EF90044410B</string>
+ <string>1CC0EA4004350EF90041110B</string>
+ <string>1C77FABC04509CD000000102</string>
+ </array>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CA23ED40692098700951B8B</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Files</string>
+ <key>PBXProjectStructureProvided</key>
+ <string>yes</string>
+ <key>PBXSmartGroupTreeModuleColumnData</key>
+ <dict>
+ <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+ <array>
+ <real>267</real>
+ </array>
+ <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+ <array>
+ <string>MainColumn</string>
+ </array>
+ </dict>
+ <key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+ <dict>
+ <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+ <array>
+ <string>08FB7794FE84155DC02AAC07</string>
+ <string>08FB7795FE84155DC02AAC07</string>
+ <string>55BFA9B2128CDEA200A80228</string>
+ <string>55F7966612934F8900EF2716</string>
+ <string>55BFA9BA128CDF8F00A80228</string>
+ <string>1C37FBAC04509CD000000102</string>
+ </array>
+ <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+ <array>
+ <array>
+ <integer>3</integer>
+ <integer>1</integer>
+ <integer>0</integer>
+ </array>
+ </array>
+ <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+ <string>{{0, 0}, {267, 703}}</string>
+ </dict>
+ <key>PBXTopSmartGroupGIDs</key>
+ <array/>
+ <key>XCIncludePerspectivesSwitch</key>
+ <false/>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {284, 721}}</string>
+ <key>GroupTreeTableConfiguration</key>
+ <array>
+ <string>MainColumn</string>
+ <real>267</real>
+ </array>
+ </dict>
+ <key>Module</key>
+ <string>PBXSmartGroupTreeModule</string>
+ <key>Proportion</key>
+ <string>284pt</string>
+ </dict>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>55BFA9E0128CFCF800A80228</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>main.m</string>
+ <key>PBXSplitModuleInNavigatorKey</key>
+ <dict>
+ <key>Split0</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>55BFA9E1128CFCF800A80228</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>main.m</string>
+ <key>_historyCapacity</key>
+ <integer>0</integer>
+ <key>bookmark</key>
+ <string>554DA16012985E8400433840</string>
+ <key>history</key>
+ <array>
+ <string>55F795FD12932B5C00EF2716</string>
+ <string>55F7960012932B5C00EF2716</string>
+ <string>55F796BD1293BD5000EF2716</string>
+ <string>55F796C31293BD5000EF2716</string>
+ <string>55F796FE1293C68600EF2716</string>
+ <string>5554D61A1294DC3300A62529</string>
+ <string>55D2AD6212958C7500BA2905</string>
+ <string>55F9F0AA1296CA8F00F4A9FD</string>
+ <string>55F9F0AC1296CA8F00F4A9FD</string>
+ <string>55F9F0B01296CA8F00F4A9FD</string>
+ <string>55F9F0B11296CA8F00F4A9FD</string>
+ <string>55F9F0B31296CA8F00F4A9FD</string>
+ <string>55F9F0B41296CA8F00F4A9FD</string>
+ <string>55F9F0B51296CA8F00F4A9FD</string>
+ <string>55F9F0BA1296CA8F00F4A9FD</string>
+ <string>55F9F0BC1296CA8F00F4A9FD</string>
+ <string>55F9F0C41296CA8F00F4A9FD</string>
+ <string>554DA13312985DB800433840</string>
+ <string>554DA13412985DB800433840</string>
+ <string>554DA13512985DB800433840</string>
+ <string>554DA13612985DB800433840</string>
+ <string>554DA13712985DB800433840</string>
+ <string>554DA13812985DB800433840</string>
+ <string>554DA13912985DB800433840</string>
+ <string>554DA13A12985DB800433840</string>
+ <string>554DA13B12985DB800433840</string>
+ <string>554DA13C12985DB800433840</string>
+ <string>554DA13D12985DB800433840</string>
+ <string>554DA13E12985DB800433840</string>
+ <string>554DA13F12985DB800433840</string>
+ <string>554DA14212985DB800433840</string>
+ <string>554DA14312985DB800433840</string>
+ <string>554DA14B12985DD300433840</string>
+ <string>554DA15612985DEE00433840</string>
+ <string>554DA15C12985E6F00433840</string>
+ </array>
+ </dict>
+ <key>SplitCount</key>
+ <string>1</string>
+ </dict>
+ <key>StatusBarVisibility</key>
+ <true/>
+ <key>XCSharingToken</key>
+ <string>com.apple.Xcode.CommonNavigatorGroupSharingToken</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {942, 482}}</string>
+ </dict>
+ <key>Module</key>
+ <string>PBXNavigatorGroup</string>
+ <key>Proportion</key>
+ <string>482pt</string>
+ </dict>
+ <dict>
+ <key>Proportion</key>
+ <string>234pt</string>
+ <key>Tabs</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CA23EDF0692099D00951B8B</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Detail</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{10, 27}, {942, -27}}</string>
+ </dict>
+ <key>Module</key>
+ <string>XCDetailModule</string>
+ </dict>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CA23EE00692099D00951B8B</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Project Find</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{10, 27}, {942, 194}}</string>
+ </dict>
+ <key>Module</key>
+ <string>PBXProjectFindModule</string>
+ </dict>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXCVSModuleFilterTypeKey</key>
+ <integer>1032</integer>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CA23EE10692099D00951B8B</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>SCM Results</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{10, 31}, {603, 297}}</string>
+ </dict>
+ <key>Module</key>
+ <string>PBXCVSModule</string>
+ </dict>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>XCMainBuildResultsModuleGUID</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Build Results</string>
+ <key>XCBuildResultsTrigger_Collapse</key>
+ <integer>1021</integer>
+ <key>XCBuildResultsTrigger_Open</key>
+ <integer>1011</integer>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{10, 27}, {942, 207}}</string>
+ </dict>
+ <key>Module</key>
+ <string>PBXBuildResultsModule</string>
+ </dict>
+ </array>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>942pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Project</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>XCModuleDock</string>
+ <string>PBXSmartGroupTreeModule</string>
+ <string>XCModuleDock</string>
+ <string>PBXNavigatorGroup</string>
+ <string>XCDockableTabModule</string>
+ <string>XCDetailModule</string>
+ <string>PBXProjectFindModule</string>
+ <string>PBXCVSModule</string>
+ <string>PBXBuildResultsModule</string>
+ </array>
+ <key>TableOfContents</key>
+ <array>
+ <string>554DA16112985E8400433840</string>
+ <string>1CA23ED40692098700951B8B</string>
+ <string>554DA16212985E8400433840</string>
+ <string>55BFA9E0128CFCF800A80228</string>
+ <string>554DA16312985E8400433840</string>
+ <string>1CA23EDF0692099D00951B8B</string>
+ <string>1CA23EE00692099D00951B8B</string>
+ <string>1CA23EE10692099D00951B8B</string>
+ <string>XCMainBuildResultsModuleGUID</string>
+ </array>
+ <key>ToolbarConfigUserDefaultsMinorVersion</key>
+ <string>2</string>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.defaultV3</string>
+ </dict>
+ <dict>
+ <key>ChosenToolbarItems</key>
+ <array>
+ <string>XCToolbarPerspectiveControl</string>
+ <string>NSToolbarSeparatorItem</string>
+ <string>active-combo-popup</string>
+ <string>NSToolbarFlexibleSpaceItem</string>
+ <string>buildOrClean</string>
+ <string>build-and-go</string>
+ <string>com.apple.ide.PBXToolbarStopButton</string>
+ <string>debugger-restart-executable</string>
+ <string>debugger-pause</string>
+ <string>debugger-step-over</string>
+ <string>debugger-step-into</string>
+ <string>debugger-step-out</string>
+ <string>debugger-enable-breakpoints</string>
+ <string>NSToolbarFlexibleSpaceItem</string>
+ <string>clear-log</string>
+ </array>
+ <key>ControllerClassBaseName</key>
+ <string>PBXDebugSessionModule</string>
+ <key>IconName</key>
+ <string>DebugTabIcon</string>
+ <key>Identifier</key>
+ <string>perspective.debug</string>
+ <key>IsVertical</key>
+ <true/>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>BecomeActive</key>
+ <true/>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CCC7628064C1048000F2A68</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Debugger Console</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {1231, 273}}</string>
+ <key>RubberWindowFrame</key>
+ <string>0 116 1231 762 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXDebugCLIModule</string>
+ <key>Proportion</key>
+ <string>273pt</string>
+ </dict>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>Debugger</key>
+ <dict>
+ <key>HorizontalSplitView</key>
+ <dict>
+ <key>_collapsingFrameDimension</key>
+ <real>0.0</real>
+ <key>_indexOfCollapsedView</key>
+ <integer>0</integer>
+ <key>_percentageOfCollapsedView</key>
+ <real>0.0</real>
+ <key>isCollapsed</key>
+ <string>yes</string>
+ <key>sizes</key>
+ <array>
+ <string>{{0, 0}, {616, 221}}</string>
+ <string>{{0, 221}, {616, 222}}</string>
+ </array>
+ </dict>
+ <key>VerticalSplitView</key>
+ <dict>
+ <key>_collapsingFrameDimension</key>
+ <real>0.0</real>
+ <key>_indexOfCollapsedView</key>
+ <integer>0</integer>
+ <key>_percentageOfCollapsedView</key>
+ <real>0.0</real>
+ <key>isCollapsed</key>
+ <string>yes</string>
+ <key>sizes</key>
+ <array>
+ <string>{{0, 0}, {616, 443}}</string>
+ <string>{{616, 0}, {615, 443}}</string>
+ </array>
+ </dict>
+ </dict>
+ <key>LauncherConfigVersion</key>
+ <string>8</string>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CCC7629064C1048000F2A68</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Debug</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>DebugConsoleVisible</key>
+ <string>None</string>
+ <key>DebugConsoleWindowFrame</key>
+ <string>{{200, 200}, {500, 300}}</string>
+ <key>DebugSTDIOWindowFrame</key>
+ <string>{{200, 200}, {500, 300}}</string>
+ <key>Frame</key>
+ <string>{{0, 278}, {1231, 443}}</string>
+ <key>PBXDebugSessionStackFrameViewKey</key>
+ <dict>
+ <key>DebugVariablesTableConfiguration</key>
+ <array>
+ <string>Name</string>
+ <real>120</real>
+ <string>Value</string>
+ <real>85</real>
+ <string>Summary</string>
+ <real>386</real>
+ </array>
+ <key>Frame</key>
+ <string>{{0, 221}, {616, 222}}</string>
+ <key>RubberWindowFrame</key>
+ <string>0 116 1231 762 0 0 1440 878 </string>
+ </dict>
+ <key>RubberWindowFrame</key>
+ <string>0 116 1231 762 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXDebugSessionModule</string>
+ <key>Proportion</key>
+ <string>443pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Debug</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>XCModuleDock</string>
+ <string>PBXDebugCLIModule</string>
+ <string>PBXDebugSessionModule</string>
+ <string>PBXDebugProcessAndThreadModule</string>
+ <string>PBXDebugProcessViewModule</string>
+ <string>PBXDebugThreadViewModule</string>
+ <string>PBXDebugStackFrameViewModule</string>
+ <string>PBXNavigatorGroup</string>
+ </array>
+ <key>TableOfContents</key>
+ <array>
+ <string>554DA16412985E8400433840</string>
+ <string>1CCC7628064C1048000F2A68</string>
+ <string>1CCC7629064C1048000F2A68</string>
+ <string>554DA16512985E8400433840</string>
+ <string>554DA16612985E8400433840</string>
+ <string>554DA16712985E8400433840</string>
+ <string>554DA16812985E8400433840</string>
+ <string>55BFA9E0128CFCF800A80228</string>
+ </array>
+ <key>ToolbarConfigUserDefaultsMinorVersion</key>
+ <string>2</string>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.debugV3</string>
+ </dict>
+ </array>
+ <key>PerspectivesBarVisible</key>
+ <true/>
+ <key>ShelfIsVisible</key>
+ <false/>
+ <key>SourceDescription</key>
+ <string>file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec'</string>
+ <key>StatusbarIsVisible</key>
+ <true/>
+ <key>TimeStamp</key>
+ <real>0.0</real>
+ <key>ToolbarConfigUserDefaultsMinorVersion</key>
+ <string>2</string>
+ <key>ToolbarDisplayMode</key>
+ <integer>1</integer>
+ <key>ToolbarIsVisible</key>
+ <true/>
+ <key>ToolbarSizeMode</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Perspectives</string>
+ <key>UpdateMessage</key>
+ <string></string>
+ <key>WindowJustification</key>
+ <integer>5</integer>
+ <key>WindowOrderList</key>
+ <array>
+ <string>554DA16A12985E8400433840</string>
+ <string>554DA16B12985E8400433840</string>
+ <string>5554D62C1294DC3300A62529</string>
+ <string>/Users/dave/Developer/Open Source/Git Projects/DDMathParser/DDMathParser.xcodeproj</string>
+ </array>
+ <key>WindowString</key>
+ <string>0 116 1231 762 0 0 1440 878 </string>
+ <key>WindowToolsV3</key>
+ <array>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.debugger</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>Debugger</key>
+ <dict>
+ <key>HorizontalSplitView</key>
+ <dict>
+ <key>_collapsingFrameDimension</key>
+ <real>0.0</real>
+ <key>_indexOfCollapsedView</key>
+ <integer>0</integer>
+ <key>_percentageOfCollapsedView</key>
+ <real>0.0</real>
+ <key>isCollapsed</key>
+ <string>yes</string>
+ <key>sizes</key>
+ <array>
+ <string>{{0, 0}, {317, 164}}</string>
+ <string>{{317, 0}, {377, 164}}</string>
+ </array>
+ </dict>
+ <key>VerticalSplitView</key>
+ <dict>
+ <key>_collapsingFrameDimension</key>
+ <real>0.0</real>
+ <key>_indexOfCollapsedView</key>
+ <integer>0</integer>
+ <key>_percentageOfCollapsedView</key>
+ <real>0.0</real>
+ <key>isCollapsed</key>
+ <string>yes</string>
+ <key>sizes</key>
+ <array>
+ <string>{{0, 0}, {694, 164}}</string>
+ <string>{{0, 164}, {694, 216}}</string>
+ </array>
+ </dict>
+ </dict>
+ <key>LauncherConfigVersion</key>
+ <string>8</string>
+ <key>PBXProjectModuleGUID</key>
+ <string>1C162984064C10D400B95A72</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Debug - GLUTExamples (Underwater)</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>DebugConsoleDrawerSize</key>
+ <string>{100, 120}</string>
+ <key>DebugConsoleVisible</key>
+ <string>None</string>
+ <key>DebugConsoleWindowFrame</key>
+ <string>{{200, 200}, {500, 300}}</string>
+ <key>DebugSTDIOWindowFrame</key>
+ <string>{{200, 200}, {500, 300}}</string>
+ <key>Frame</key>
+ <string>{{0, 0}, {694, 380}}</string>
+ <key>RubberWindowFrame</key>
+ <string>321 238 694 422 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXDebugSessionModule</string>
+ <key>Proportion</key>
+ <string>100%</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>100%</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Debugger</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>PBXDebugSessionModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <integer>1</integer>
+ <key>TableOfContents</key>
+ <array>
+ <string>1CD10A99069EF8BA00B06720</string>
+ <string>1C0AD2AB069F1E9B00FABCE6</string>
+ <string>1C162984064C10D400B95A72</string>
+ <string>1C0AD2AC069F1E9B00FABCE6</string>
+ </array>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.debugV3</string>
+ <key>WindowString</key>
+ <string>321 238 694 422 0 0 1440 878 </string>
+ <key>WindowToolGUID</key>
+ <string>1CD10A99069EF8BA00B06720</string>
+ <key>WindowToolIsVisible</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.build</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CD0528F0623707200166675</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>&lt;No Editor&gt;</string>
+ <key>PBXSplitModuleInNavigatorKey</key>
+ <dict>
+ <key>Split0</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CD052900623707200166675</string>
+ </dict>
+ <key>SplitCount</key>
+ <string>1</string>
+ </dict>
+ <key>StatusBarVisibility</key>
+ <integer>1</integer>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {500, 215}}</string>
+ <key>RubberWindowFrame</key>
+ <string>192 257 500 500 0 0 1280 1002 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXNavigatorGroup</string>
+ <key>Proportion</key>
+ <string>218pt</string>
+ </dict>
+ <dict>
+ <key>BecomeActive</key>
+ <integer>1</integer>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>XCMainBuildResultsModuleGUID</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Build Results</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 222}, {500, 236}}</string>
+ <key>RubberWindowFrame</key>
+ <string>192 257 500 500 0 0 1280 1002 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXBuildResultsModule</string>
+ <key>Proportion</key>
+ <string>236pt</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>458pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Build Results</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>PBXBuildResultsModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <integer>1</integer>
+ <key>TableOfContents</key>
+ <array>
+ <string>1C78EAA5065D492600B07095</string>
+ <string>1C78EAA6065D492600B07095</string>
+ <string>1CD0528F0623707200166675</string>
+ <string>XCMainBuildResultsModuleGUID</string>
+ </array>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.buildV3</string>
+ <key>WindowString</key>
+ <string>192 257 500 500 0 0 1280 1002 </string>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.find</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CDD528C0622207200134675</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>&lt;No Editor&gt;</string>
+ <key>PBXSplitModuleInNavigatorKey</key>
+ <dict>
+ <key>Split0</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CD0528D0623707200166675</string>
+ </dict>
+ <key>SplitCount</key>
+ <string>1</string>
+ </dict>
+ <key>StatusBarVisibility</key>
+ <integer>1</integer>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {781, 167}}</string>
+ <key>RubberWindowFrame</key>
+ <string>62 385 781 470 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXNavigatorGroup</string>
+ <key>Proportion</key>
+ <string>781pt</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>50%</string>
+ </dict>
+ <dict>
+ <key>BecomeActive</key>
+ <integer>1</integer>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CD0528E0623707200166675</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Project Find</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{8, 0}, {773, 254}}</string>
+ <key>RubberWindowFrame</key>
+ <string>62 385 781 470 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXProjectFindModule</string>
+ <key>Proportion</key>
+ <string>50%</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>428pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Project Find</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>PBXProjectFindModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <integer>1</integer>
+ <key>TableOfContents</key>
+ <array>
+ <string>1C530D57069F1CE1000CFCEE</string>
+ <string>1C530D58069F1CE1000CFCEE</string>
+ <string>1C530D59069F1CE1000CFCEE</string>
+ <string>1CDD528C0622207200134675</string>
+ <string>1C530D5A069F1CE1000CFCEE</string>
+ <string>1CE0B1FE06471DED0097A5F4</string>
+ <string>1CD0528E0623707200166675</string>
+ </array>
+ <key>WindowString</key>
+ <string>62 385 781 470 0 0 1440 878 </string>
+ <key>WindowToolGUID</key>
+ <string>1C530D57069F1CE1000CFCEE</string>
+ <key>WindowToolIsVisible</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.snapshots</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>Module</key>
+ <string>XCSnapshotModule</string>
+ <key>Proportion</key>
+ <string>100%</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>100%</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Snapshots</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>XCSnapshotModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <string>Yes</string>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.snapshots</string>
+ <key>WindowString</key>
+ <string>315 824 300 550 0 0 1440 878 </string>
+ <key>WindowToolIsVisible</key>
+ <string>Yes</string>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.debuggerConsole</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>BecomeActive</key>
+ <integer>1</integer>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1C78EAAC065D492600B07095</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Debugger Console</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {700, 358}}</string>
+ <key>RubberWindowFrame</key>
+ <string>149 87 700 400 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXDebugCLIModule</string>
+ <key>Proportion</key>
+ <string>358pt</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>358pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>Debugger Console</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>PBXDebugCLIModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <integer>1</integer>
+ <key>TableOfContents</key>
+ <array>
+ <string>1C530D5B069F1CE1000CFCEE</string>
+ <string>1C530D5C069F1CE1000CFCEE</string>
+ <string>1C78EAAC065D492600B07095</string>
+ </array>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.consoleV3</string>
+ <key>WindowString</key>
+ <string>149 87 440 400 0 0 1440 878 </string>
+ <key>WindowToolGUID</key>
+ <string>1C530D5B069F1CE1000CFCEE</string>
+ <key>WindowToolIsVisible</key>
+ <integer>0</integer>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.scm</string>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1C78EAB2065D492600B07095</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>&lt;No Editor&gt;</string>
+ <key>PBXSplitModuleInNavigatorKey</key>
+ <dict>
+ <key>Split0</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1C78EAB3065D492600B07095</string>
+ </dict>
+ <key>SplitCount</key>
+ <string>1</string>
+ </dict>
+ <key>StatusBarVisibility</key>
+ <integer>1</integer>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {452, 0}}</string>
+ <key>RubberWindowFrame</key>
+ <string>743 379 452 308 0 0 1280 1002 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXNavigatorGroup</string>
+ <key>Proportion</key>
+ <string>0pt</string>
+ </dict>
+ <dict>
+ <key>BecomeActive</key>
+ <integer>1</integer>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CD052920623707200166675</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>SCM</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>ConsoleFrame</key>
+ <string>{{0, 259}, {452, 0}}</string>
+ <key>Frame</key>
+ <string>{{0, 7}, {452, 259}}</string>
+ <key>RubberWindowFrame</key>
+ <string>743 379 452 308 0 0 1280 1002 </string>
+ <key>TableConfiguration</key>
+ <array>
+ <string>Status</string>
+ <real>30</real>
+ <string>FileName</string>
+ <real>199</real>
+ <string>Path</string>
+ <real>197.09500122070312</real>
+ </array>
+ <key>TableFrame</key>
+ <string>{{0, 0}, {452, 250}}</string>
+ </dict>
+ <key>Module</key>
+ <string>PBXCVSModule</string>
+ <key>Proportion</key>
+ <string>262pt</string>
+ </dict>
+ </array>
+ <key>Proportion</key>
+ <string>266pt</string>
+ </dict>
+ </array>
+ <key>Name</key>
+ <string>SCM</string>
+ <key>ServiceClasses</key>
+ <array>
+ <string>PBXCVSModule</string>
+ </array>
+ <key>StatusbarIsVisible</key>
+ <integer>1</integer>
+ <key>TableOfContents</key>
+ <array>
+ <string>1C78EAB4065D492600B07095</string>
+ <string>1C78EAB5065D492600B07095</string>
+ <string>1C78EAB2065D492600B07095</string>
+ <string>1CD052920623707200166675</string>
+ </array>
+ <key>ToolbarConfiguration</key>
+ <string>xcode.toolbar.config.scmV3</string>
+ <key>WindowString</key>
+ <string>743 379 452 308 0 0 1280 1002 </string>
+ </dict>
+ <dict>
+ <key>Identifier</key>
+ <string>windowTool.breakpoints</string>
+ <key>IsVertical</key>
+ <integer>0</integer>
+ <key>Layout</key>
+ <array>
+ <dict>
+ <key>Dock</key>
+ <array>
+ <dict>
+ <key>BecomeActive</key>
+ <integer>1</integer>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXBottomSmartGroupGIDs</key>
+ <array>
+ <string>1C77FABC04509CD000000102</string>
+ </array>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CE0B1FE06471DED0097A5F4</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Files</string>
+ <key>PBXProjectStructureProvided</key>
+ <string>no</string>
+ <key>PBXSmartGroupTreeModuleColumnData</key>
+ <dict>
+ <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+ <array>
+ <real>168</real>
+ </array>
+ <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+ <array>
+ <string>MainColumn</string>
+ </array>
+ </dict>
+ <key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+ <dict>
+ <key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+ <array>
+ <string>1C77FABC04509CD000000102</string>
+ </array>
+ <key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+ <array>
+ <array>
+ <integer>0</integer>
+ </array>
+ </array>
+ <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+ <string>{{0, 0}, {168, 350}}</string>
+ </dict>
+ <key>PBXTopSmartGroupGIDs</key>
+ <array/>
+ <key>XCIncludePerspectivesSwitch</key>
+ <integer>0</integer>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>
+ <string>{{0, 0}, {185, 368}}</string>
+ <key>GroupTreeTableConfiguration</key>
+ <array>
+ <string>MainColumn</string>
+ <real>168</real>
+ </array>
+ <key>RubberWindowFrame</key>
+ <string>315 424 744 409 0 0 1440 878 </string>
+ </dict>
+ <key>Module</key>
+ <string>PBXSmartGroupTreeModule</string>
+ <key>Proportion</key>
+ <string>185pt</string>
+ </dict>
+ <dict>
+ <key>ContentConfiguration</key>
+ <dict>
+ <key>PBXProjectModuleGUID</key>
+ <string>1CA1AED706398EBD00589147</string>
+ <key>PBXProjectModuleLabel</key>
+ <string>Detail</string>
+ </dict>
+ <key>GeometryConfiguration</key>
+ <dict>
+ <key>Frame</key>