Assignment #2 Task #1

Please note, this blog entry is from a previous course. You might want to check out the current one.

The second assignment is a further extension of the calculator built in the previous assignment.

Add the capability to your CalculatorBrain to accept variables as operands (in addition to still accepting doubles as operands). You will need new public API in your CalculatorBrain to support this.

A variable will be specified as an NSString object. To simplify your implementation, you can ignore attempts to push a variable whose name is the same as an operation (e.g. you can ignore an attempt to push a variable named “sqrt”).

The values of the variables will only be supplied when the “program” is “run.” You must add a new version of the runProgram: class method with the following signature …

+ (double)runProgram:(id)program usingVariableValues:(NSDictionary *)variableValues;

The keys in the passed variableValues dictionary are NSString objects corresponding to the names of variables used in the passed program, and the values in the dictionary are NSNumber objects specifying the value of the corresponding variable (for this assignment we will supply “test” values, see Required Task #3).

If there are variables in the specified program for which there are no values in the specified NSDictionary, use a value of 0 for those variables when you run the program. This should be the case if someone calls the original runProgram: method (the one shown in the demo in class).
In addition, create another class method to get all the names of the variables used in a given program (returned as an NSSet of NSString objects) …

+ (NSSet *)variablesUsedInProgram:(id)program;

If the program has no variables return nil from this method (not an empty set).

We will start by implementing the new runProgram method. If we have an actual program meaning array we loop through the program and replace variables by its values and finally run the cleaned up program:

+ (double)runProgram:(id)program 
 usingVariableValues:(NSDictionary *)variableValues 
    NSMutableArray *stack;
    if ([program isKindOfClass:[NSArray class]]) {
        stack = [program mutableCopy];
        NSInteger stackSize = [stack count];
        NSNumber *varibleValue;
        NSSet *usedVariables = [CalculatorBrain variablesUsedInProgram:stack];
        for (NSInteger i = 0; i < stackSize; i++) {
            id currentItem = [stack objectAtIndex:i];
            if (![usedVariables containsObject:currentItem]) continue;
            varibleValue = [variableValues objectForKey:currentItem];
            if (varibleValue)
                [stack replaceObjectAtIndex:i withObject:varibleValue];
            else [stack replaceObjectAtIndex:i withObject:[NSNumber numberWithInt:0]];
    return [self runProgram:stack];

To know if we a program item is a variable we checked against the used variables, thus we have to implement the function which provides them. Again we loop through the program and assume that if we have no actual number or operator that the item is an variable:

+ (NSSet *)variablesUsedInProgram:(id)program 
    if (![program isKindOfClass:[NSArray class]]) return nil;    
    NSMutableSet *usedVariables = [NSMutableSet set];    
    for (id obj in program) {
        if ([obj isKindOfClass:[NSNumber class]]) continue;
        if ([self isOperation:obj]) continue;
        [usedVariables addObject:obj];        
    if (!usedVariables) return nil;
    return usedVariables;

… and as we have used here an other helper function to check for operations this has function has to be implemented next:

+ (BOOL)isOperation:(NSString *)operation
    NSSet *operators = [NSSet setWithObjects: @"+", @"*", @"-", @"/", @"sin", @"cos", @"sqrt", @"π", @"+/-", nil];
    return [operators containsObject:operation];

As we will implement the test functionality in task #3 we have no way of knowing if our code works, yet 😉


Leave a Reply

Your email address will not be published.