Thread: need help on Calculator program in C

  1. #1
    Registered User
    Join Date
    Jan 2005
    Posts
    1

    Exclamation need help on Calculator program in C

    i need help on how to get the answer of an equation entered by the user. For example:

    user enters:
    10*2+3/5*912-6/5)= ?

    i accepted the equation as string but i dont know how to get the answer, implementing the MDAS rule and all. i already converted the numbers in the string to integer using atoi() but i dont know what's next and what to do with all the operators....

    I need help badly. Thanks!!!

  2. #2
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    The hard part is operator precedence. For that it's much much easier to convert the expression to postfix and then use a stack based evaluation to solve it. Once you have the tokens in postfix form, it's a trivial affair to solve the equation. For example, here's a postfix calculator with a lot of functionality:
    Code:
    #include <ctype.h>
    #include <math.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define UNARY  0  /* Offset into actions for unary words */
    #define BINARY 6  /* Offset into actions for binary words */
    #define ACLEN  17 /* Total number of actions */
    #define UNLEN  6  /* Total number of unary words */
    #define BILEN  11 /* Total number of binary words */
    
    static const char *actions[] = {
      ".", "sqrt", "sq", "not", "abs", "log",
      "+", "-",    "*",  "/",   "mod", "pow",
      "<", "=",    ">",  "and", "or",
    };
    
    static long int stack[1024]; /* 1024 should be MORE than enough */
    static int top = 0;
    
    static void eval ( void );
    static void gather ( void );
    static void process ( const char *action );
    static void do_unary ( const char *action );
    static void do_binary ( const char *action );
    static void die ( const char *msg );
    
    static int is_valid ( const char *action, size_t offset, size_t limit );
    
    int main ( void )
    {
      while ( 1 )
        eval();
    }
    
    void eval ( void )
    {
      gather();
      puts ( " ok" );
    }
    
    void gather ( void )
    {
      char buffer[BUFSIZ];
      char *action;
      char *end;
    
      if ( fgets ( buffer, sizeof buffer, stdin ) == NULL )
        die ( "Input error" );
    
      for ( action = strtok ( buffer, " \t\n" );
        action != NULL; action = strtok ( NULL, " \t\n" ) )
      {
        long int number;
    
        /* Process a number or an action */
        number = strtol ( action, &end, 0 );
        if ( end > action )
          stack[top++] = number;
        else if ( is_valid ( action, 0, ACLEN ) )
          process ( action );
        else if ( strcmp ( action, "bye" ) == 0 )
          exit ( EXIT_SUCCESS );
        else
          die ( "Input error" );
      }
    }
    
    void process ( const char *action )
    {
      if ( is_valid ( action, UNARY, UNLEN ) )
        do_unary ( action );
      else if ( is_valid ( action, BINARY, BILEN ) )
        do_binary ( action );
    }
    
    void do_unary ( const char *action )
    {
      long int result = 0;
      long int a;
    
      if ( top == 0 )
        die ( "Stack underflow" );
      a = stack[--top];
    
      if ( strcmp ( action, "." ) == 0 ) {
        printf ( "%ld ", a );
        fflush ( stdout );
        return;
      }
      else if ( strcmp ( action, "not" ) == 0 )
        result = !a;
      else if ( strcmp ( action, "sqrt" ) == 0 )
        result = (long int)sqrt ( a );
      else if ( strcmp ( action, "sq" ) == 0 )
        result = a * a;
      else if ( strcmp ( action, "abs" ) == 0 )
        result = abs ( a );
      else if ( strcmp ( action, "log" ) == 0 )
        result = (long int)log ( a );
      else
        die ( "Invalid format" );
    
      stack[top++] = result;
    }
    
    void do_binary ( const char *action )
    {
      long int result = 0;
      long int a, b;
    
      if ( top < 2 )
        die ( "Stack underflow" );
      b = stack[--top];
      a = stack[--top];
    
      if ( action[0] == '+' )
        result = a + b;
      else if ( action[0] == '-' )
        result = a - b;
      else if ( action[0] == '*' )
        result = a * b;
      else if ( action[0] == '/' ) {
        if ( b == 0 )
          die ( "Division by zero" );
        result = a / b;
      }
      else if ( strcmp ( action, "mod" ) == 0 ) {
        if ( b == 0 )
          die ( "Division by zero" );
        result = a % b;
      }
      else if ( strcmp ( action, "pow" ) == 0 )
        result = (long int)pow ( a, b );
      else if ( action[0] == '<' )
        result = a < b;
      else if ( action[0] == '=' )
        result = a == b;
      else if ( action[0] == '>' )
        result = a > b;
      else if ( strcmp ( action, "and" ) == 0 )
        result = a && b;
      else if ( strcmp ( action, "or" ) == 0 )
        result = a || b;
      else
        die ( "Invalid format" );
    
      stack[top++] = result;
    }
    
    int is_valid ( const char *action, size_t offset, size_t limit )
    {
      size_t i;
    
      for ( i = offset; i < limit + offset; i++ ) {
        if ( strcmp ( action, actions[i] ) == 0 )
          return 1;
      }
    
      return 0;
    }
    
    void die ( const char *msg )
    {
      fprintf ( stderr, "%s\n", msg );
      exit ( EXIT_FAILURE );
    }
    It's very short, but very powerful. That's because all of the parsing work is done by the stack, not the program logic.
    My best code is written with the delete key.

  3. #3
    UT2004 Addict Kleid-0's Avatar
    Join Date
    Dec 2004
    Posts
    656
    Hey Prelude, I have two questions about the code above.
    1) Why are the global variables static? Aren't global variables always static?
    2) How would you make an answer output? It does the calculations, I just don't know what the result are lol :(

  4. #4
    Registered User Scribbler's Avatar
    Join Date
    Sep 2004
    Location
    Aurora CO
    Posts
    266
    Quote Originally Posted by Kleid-0
    1) Why are the global variables static? Aren't global variables always static?
    Static gives them internal linkage, which will make them available only to functions within that file. So if you have multiple files in the program, only the file in which they are declared static will be able to reference them.

  5. #5
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >1) Why are the global variables static? Aren't global variables always static?
    Global variables and functions are have external linkage by default. Unless you have a need for external linkage, internal is far better. You do that by qualifying a global name as static.

    >2) How would you make an answer output?
    The period (.) operator will print the current top of the stack.
    My best code is written with the delete key.

  6. #6
    UT2004 Addict Kleid-0's Avatar
    Join Date
    Dec 2004
    Posts
    656
    Quote Originally Posted by Prelude
    The period (.) operator will print the current top of the stack. :)
    I'm trying to read the code correctly, but I'm doing something wrong. I run the program and '.' doesn't like me :(
    Code:
    kleid@Shiva:~/Programming/Laboratory$ ./a.out
    3*4*5
     ok
    .
    3  ok
    .
    Stack underflow
    :( the answer says 3, but I need 60 :(

  7. #7
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    Code:
    3*4*5
     ok
    .
    3  ok
    .
    Stack underflow
    Eew. Remember that this is a postfix calculator, and the binary operators require two numbers to be present on the stack. So your example should be:
    Code:
    3 4 5 * *
      ok
    .
    60 ok
    Of course, you should stop there because now the stack is empty and trying to print the top value will result in an error message. Alternatively, you could do this:
    Code:
    3 4 * 5 *
      ok
    .
    60 ok
    Because the result of the previous operation is left on the top of the stack until an operator removes it. You can even put it all on one line if you want:
    Code:
    3 4 * 5 * .
    60 ok
    My best code is written with the delete key.

  8. #8
    UT2004 Addict Kleid-0's Avatar
    Join Date
    Dec 2004
    Posts
    656
    Code:
    kleid@Shiva:~/Programming/Laboratory$ ./a.out
    23 45 * 3 .
    3  ok
    23 45 * 56 * .
    57960  ok
    23 67 *
     ok
    .
    1541  ok
    23 67 / .
    0  ok
    109 44 + .
    153  ok
    100 34 * 23 * 2 / .
    39100  ok
    I gotcha. That's a different way at looking at how a calculator can work, I like it, nice job :)

  9. #9
    Registered User Bajanine's Avatar
    Join Date
    Dec 2001
    Location
    The most peaks over 10,000 feet!
    Posts
    396
    Thanks Prelude for posting that code!

    I have been toying around with the idea of writing a RPN calculator program and I am sure I will learn tons just by examining your code.
    Favorite Quote:

    >For that reason someone invented C++.
    BLASPHEMY! Begone from my C board, you foul lover of objects, before the gods of C cast you into the void as punishment for your weakness! There is no penance for saying such things in my presence. You are henceforth excommunicated. Never return to this house, filthy heretic!



Popular pages Recent additions subscribe to a feed