Thread: calculator parsing

  1. #1
    Registered User dharh's Avatar
    Join Date
    Jan 2002
    Posts
    51

    calculator parsing

    I wrote up a simple calculator program that can take command line arguments through its own prompt. Im using an fgets(str, COLS, stdin); to make the input a string, then I parse the input into a 2d array so that the 2d array. It ends up looking something like this:

    Code:
    Enter command. (example: /help)
    :1.2*3.456-7+8^2+2
    
    Unparsed:
    str[0]:1
    str[1]:.
    str[2]:2
    str[3]:*
    str[4]:3
    str[5]:.
    str[6]:4
    str[7]:5
    str[8]:6
    str[9]:-
    str[10]:7
    str[11]:+
    str[12]:8
    str[13]:^
    str[14]:2
    str[15]:+
    str[16]:2
    str[17]:
    
    Parsed:
    pStr[0][0]=1
    pStr[0][1]=.
    pStr[0][2]=2
    pStr[1][0]=*
    pStr[2][0]=3
    pStr[2][1]=.
    pStr[2][2]=4
    pStr[2][3]=5
    pStr[2][4]=6
    pStr[3][0]=-
    pStr[4][0]=7
    pStr[5][0]=+
    pStr[6][0]=8
    pStr[7][0]=^
    pStr[8][0]=2
    pStr[9][0]=+
    pStr[10][0]=2
    
    Total 63.147200
    Anyway, after its parsed I pass through a couple loops.

    Code:
      size = 0;
      while(pStr[size][0] != '\0') {
        size++;
      }
    
      i = size-1;
      j = 0;
      doneBefore = 0;
      total = 0;
      while(i >= 0) {
        ch = pStr[i-1][0];
    
        if(ch == '^') {
          if(doneBefore) {
            total = doCalc(atof(pStr[i-2]), ch, total);
            doneBefore = 1;
          }
          else {
            total = doCalc(atof(pStr[i-2]), ch, atof(pStr[i]));
            doneBefore = 1;
          }
        }
        else {
          if(doneBefore) {
            snprintf(tempStr[j], COLS, "%f", total);
            snprintf(tempStr[j+1], COLS, "%c", ch);
            strncpy(tempStr[j+2], pStr[i-2], COLS);
            doneBefore = 0;
          }
          else {
            strcpy(tempStr[j], pStr[i]);
            snprintf(tempStr[j+1], COLS, "%c", ch);
            strncpy(tempStr[j+2], pStr[i-2], COLS);
            doneBefore = 0;
          }
          j = j + 2;
        }
        i = i - 2;
      }
      tempStr[j-1][0] = '\0';
    
        /* el reverso */
        i = 0;
        size = j-2;
        while(size >= 0) {
          strncpy(tempStr2[i], tempStr[size], COLS);
          i++;
          size--;
        }
        tempStr2[i][0] = '\0';
    
      i = 0;
      j = 0;
      doneBefore = 0;
      total = 0;
      while(tempStr2[i][0] != '\0') {
        ch = tempStr2[i+1][0];
    
        if(ch == '*' || ch == '/' || ch == '%') {
          if(doneBefore) {
            total = doCalc(atof(tempStr2[i+2]), ch, total);
            doneBefore = 1;
          }
          else {
            total = doCalc(atof(tempStr2[i+2]), ch, atof(tempStr2[i]));
            doneBefore = 1;
          }
        }
        else {
          if(doneBefore) {
            snprintf(tempStr3[j], COLS, "%f", total);
            snprintf(tempStr3[j+1], COLS, "%c", ch);
            strncpy(tempStr3[j+2], tempStr2[i-2], COLS);
            doneBefore = 0;
          }
          else {
            strncpy(tempStr3[j], tempStr2[i], COLS);
            snprintf(tempStr3[j+1], COLS, "%c", ch);
            strncpy(tempStr3[j+2], tempStr2[i-2], COLS);
            doneBefore = 0;
          }
          j = j + 2;
        }
        i = i + 2;
      }
    
    
      total = atof(tempStr3[0]);
    
      i = 0;
      while(tempStr3[i+1][0] != '\0') {
        ch = tempStr3[i+1][0];
    
        total = doCalc(total, ch, atof(tempStr3[i+2]));
        
        i = i + 2;
      }
    
      printf("Total %f\n", total);
    Im pretty sure theres better ways I can do this. Such as a tree, I could build during the parse proccess, this would possibly help me to implement paren overiding order of operations.

    Any ideas how I could do a tree parse, im still not exactly sure how it would work. Or other ideas to shorten my code.

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    A parse tree is an option worth considering, you can search www.google.com for algorithms and source.

    My preference would be a stack though, push the expression onto the stack until you get to an operator, then evaluate the expression. Save that evaluation and then push and pop the stack as necessary until you've evaluated all of the expressions and you have your result.

    Natuarally it's not quite that simple, you have to consider operator precedence and parens if you want a good parser, something that can handle expressions such as

    (26 + (18 / (37 - 5)) * 2)

    without choking and still returning the correct answer. Parens are very nice for setting up the stack, but you can't guarantee that they'll be there. Just some food for thought

    -Prelude
    My best code is written with the delete key.

Popular pages Recent additions subscribe to a feed