Assignment #2 Task #2

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

Re-implement the descriptionOfProgram: method from the last lecture to display the passed program in a more user-friendly manner. Specifically …

a. It should display all single-operand operations using “function” notation. For example, 10 sqrt should display as sqrt(10).
b. It should display all multi-operand operations using “infix” notation if appropriate, else function notation. For example, 3 Enter 5 + should display as 3 + 5.
c. Any no-operand operations, like π, should appear unadorned. For example, π.
d. Variables (Required Task #1) should also appear unadorned. For example, x.

Any combination of operations, operands and variables should display properly.
Examples (E means “Enter key”) …

a. 3 E 5 E 6 E 7 + * – should display as 3 – (5 * (6 + 7)) or an even cleaner
output would be 3 – 5 * (6 + 7).
b. 3 E 5 + sqrt should display as sqrt(3 + 5).
c. 3 sqrt sqrt should display as sqrt(sqrt(3)).
d. 3 E 5 sqrt + should display as 3 + sqrt(5).
e. π r r * * should display as π * (r * r) or, even better, π * r * r.
f. a a * b b * + sqrt would be, at best, sqrt(a * a + b * b).

As you can see, you will have to use parentheses in your output to correctly display the program. For example, 3 E 5 + 6 * is not 3 + 5 * 6, it is (3 + 5) * 6. Try to keep extraneous parentheses to a minimum though (see Hints).

It might be that there are multiple things on the stack. If so, separate them by commas in the output with the top of the stack first, for example 3 E 5 E would display as “5, 3”. 3 E 5 + 6 E 7 * 9 sqrt would be “sqrt(9), 6 * 7, 3 + 5”.

Analog to the runProgram method we first have to check if we actually have a valid program. We use call descriptionOfTopOfStack which will work through the stack like popOperandOffStack already does. If after that there is something still on the stack we call descriptionOfProgram for the rest. To beautify the result we call stripUnneccessaryParenthesis.

+ (NSString *)descriptionOfProgram:(id)program
    NSString *result = @"";
    NSMutableArray *stack;
    if ([program isKindOfClass:[NSArray class]]) {
        stack = [program mutableCopy];
        result = [self stripUnneccessaryParenthesis:
            [self descriptionOfTopOfStack:stack] for:@"+"];
        if ([stack count])
            result = [NSString stringWithFormat:@"%@, %@", 
                result, [self descriptionOfProgram:stack]];
    return result;

descriptionOfTopOfStack gets and removes the last object from the stack. If it is a number we return it as string. Otherwise we check if it isSingleOperandOperation or isTwoOperandOperation format the output accordingly and call the method again for the rest of the stack. To simply the beautification we use square brackets where they might not be needed later on.

+ (NSString *)descriptionOfTopOfStack:(NSMutableArray *)stack
    NSString *result = @"";    
    id topOfStack = [stack lastObject];
    if (topOfStack) [stack removeLastObject];
    if ([topOfStack isKindOfClass:[NSNumber class]]) 
        result = [topOfStack stringValue];
    else if ([topOfStack isKindOfClass:[NSString class]]) {
        NSString *operation = topOfStack;
        if ([self isSingleOperandOperation:operation]) {
            result = [NSString stringWithFormat:@"%@(%@)", operation, 
                [self stripUnneccessaryParenthesis:
                    [self descriptionOfTopOfStack:stack]for:operation]];            
        } else if ([self isTwoOperandOperation:operation]) {
            NSString *secondOperand = [self descriptionOfTopOfStack:stack];
            secondOperand = [self stripUnneccessaryParenthesis:secondOperand for:operation];
            NSString *firstOperand = [self descriptionOfTopOfStack:stack];
            firstOperand = [self stripUnneccessaryParenthesis:firstOperand for:operation];
            result = [NSString stringWithFormat:@"%@ %@ %@", 
                firstOperand, operation, secondOperand];            
            if ([operation isEqualToString:@"+"] || [operation isEqualToString:@"-"])
                result = [NSString stringWithFormat:@"[%@]", result];            
        } else if ([operation isEqualToString:@"+/-"]) {
            NSString *operand = [self descriptionOfTopOfStack:stack];
            if (!operand) operand = @"0";
            if ([operand hasPrefix:@"-"])
                result = [operand substringFromIndex:1];
                result = [NSString stringWithFormat:@"-%@", operand];
        } else result = operation;
    return result;

The check for the single or two operand operation works analog to the previous task:

+ (BOOL)isTwoOperandOperation:(NSString *)operation
    NSSet *operators = [NSSet setWithObjects: @"+", @"*", @"-", @"/", nil];
    return [operators containsObject:operation];

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

Finally we implement our helper function to check for square brackets and remove or change them if necessary:

+ (NSString *)stripUnneccessaryParenthesis:(NSString *)string for:(NSString *)operation
    if (!string) return @"0"; // empty string equals 0
    if (![string hasPrefix:@"["]) return string; // nothing to do
    NSString *result = [string substringWithRange:NSMakeRange(1, [string length] - 2)];
    if ([operation isEqualToString:@"+"]) return result; 
    if ([operation isEqualToString:@"-"]) return result;
    if ([self isSingleOperandOperation:operation]) return result;
    return [NSString stringWithFormat:@"(%@)", result];

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


2 thoughts on “Assignment #2 Task #2”

Leave a Reply

Your email address will not be published.