PLACE
spec
solutions
Objective-C

RPN Calculator in Objective-C

The following implementation differs from plain C not so much by distinctive features of the Objective-C language per se as by using the Foundation library. Objective-C is an object-oriented C, but there are not classes and objects in this program other than the classes from the library and the objects instantiated from them.

The implementation is stack-based. An input line is read a character at a time and stored in line, which is an instance of NSMutableData – the class representing a dynamically sized byte container. Sending mutableBytes to line provides us with a pointer p to the actual character sequence in line, so that we can parse it. Parsing proper, i.e. splitting into tokens and finding out what each one is is carried out by the C library functions strtok, strtod, strlen, and strchr. As soon as a token is properly identified, the corresponding action takes place, eventually leading to an increase or a decrease of the stack.

The stack's role is played by stk of class NSMutableArray – a dynamically sized array of objects, which in our case are numbers, namely NSNumbers. For stack maintenance purposes, the program makes use of several methods of NSMutableArray with names saying enough about their function: count, addObject, lastObject, removeLastObject, and removeAllObjects.

Note how numbers are pushed onto the stack by sending addObject to it. First of all, we have to create an object of type NSNumber. The class NSNumber is a generalisation and an object wrapper of the different C numeric types. By sending numberWithDouble:x to it we wrap the x of type double in an NSNumber. Since that class inherits from NSValue, the wrapping object is also an NSValue. The latter is, in general, an object wrapper for arbitrary C and Objective-C data items. So, ultimately, we have to accomodate x within an NSValue in order to be able to store it in a collection, which in this case is an NSMutableArray.

When popping a number off the stack, we have to unwrap it from the corresponding object which we take out from stk, so we send doubleValue to that object.

Because of the automated management of the two arrays line and stk, the resulting program is smaller and cleaner than one of a like kind we would have written in plain C. It is a bit annoying that there is no similar advantage with respect to parsing.

#include <stdio.h>
#include <string.h>
#import <Foundation/NSData.h>
#import <Foundation/NSValue.h>
#import <Foundation/NSArray.h>

int main() {
  int c,err;
  double x,y;
  char *p,*q;
  NSMutableData *line = [NSMutableData new];
  NSMutableArray *stk = [NSMutableArray new];
#define POP(z) z = [[stk lastObject] doubleValue]; \
                   [stk removeLastObject]
  while ((c=getchar())!=EOF) {
    if (c=='\n') c = 0;
    [line appendBytes:(void*)&c length:1];
    if (c) continue;
    [stk removeAllObjects];
    p = [line mutableBytes];
    err = 0;
    while (NULL!=(q=strtok(p," \t"))) {
      x = strtod(q,&p);  err = *p;
      p = NULL;
      if (err) {
        err = q[1] || NULL==strchr("+-*/",*q) || 2>[stk count];
        if (err) break;
        POP(y); POP(x);
        switch (*q) {
          case '+': x += y; break;
          case '-': x -= y; break;
          case '*': x *= y; break;
          case '/': x /= y;
        }
      }
      [stk addObject:[NSNumber numberWithDouble:x]];
    }
    if (err || 1<[stk count]) puts("error");
    else if ([stk count]) {POP(x); printf("%f\n",x);}
    [line setLength:0];
  }
  return 0;
}

boykobbatgmaildotcom