Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

My C program has turned into a monster

  1. Feb 19, 2015 #1
    I started making a program with the following prompt (For privacy purposes, I'm posting it as an image).

    2vwxrh1.jpg

    Yes, it's a useless program; I'm making it for fun.

    I started out with what I thought were some nice implementations of helper functions:

    Code (Text):

    int index_of (char * str, char c)

    {

    /* Returns the index of the first instance of

      character c in the character array str. If

      none is found, returns -1.

    */

        int i = 0;

        while (str != '\0')

        {

            if (*str == c)

            {

                break;

            }

            else

            {

                ++str;

                ++i;

            }

        }

        return str == '\0' ? -1 : i;

    }







    int parse_int (char * cp, int * i)

    {

    /*  cp: Pointer to a character array that is a base-10 string representation of an integer

        i: Pointer to an integer which will store the output of the parsing of cp



        Returns the number of characters parsed.



    */

        int n = 0;

        *i = 0;

        while (cp!= '\0')

        {

            char c = *cp;

            if (c >= '0' && c <= '9')

            {

                n = n * 10 + (c - '0');

            }

            else

            {

                break;

            }

           

            ++cp;

        }

       

        return n;

    }



    int bin_op (int a, char oper, int b)

    {

    /* Returns

       

        a oper b



      where oper is defined as in the specs.

         

    */

        int c;

        switch (oper)

        {

            case '|':

                c = a | b; break;

            case '*':

                c = a & b; break;

            case '^':

                c = a & b; break;

            default: /* Never happens */

                ;

        }

        return c;

    }
     
    After that it went all downhill ....... I realized I'm doing something wrong after I go halfway through writing my master function.

    Code (Text):

    int parse_input (char ** args, int args_len, int * output, char * err)

    {

    /*       args: Command-line parameters

        args_len: Number of command-line parameters

          output: Evaluation of the equation

              err: Error message

    */

        if (args_len < 2)

        {

            str_cpy("No equation provided.", err);

            return -1;

        }

        char * pcc = args[1]; /* Pointer to curent character */

        char cc = *pcc; /* Current character */

        char * plo = NULL; /* Pointer to last operator */

        int nnrp = 0; /* Net number of right parantheses */

        while (cc != '\0')

        {

            if (cc >= '0' && cc <= '9') /* If current character is a digit */

            {

                int pi = 0; /* Parameter index */

                pcc += parse_int(pcc, &pi);

                if (pi > (args_len - 2))

                {

                    sprintf(err, "Index %d is out-of-bounds", pi);

                    return -1;

                }

                int pv; /* Value at parameter pn */

                if (parse_int(args[pi], &pv) > 0)

                {

                    if (plo == NULL)

                    {

                        *output = pv;

                    }

                    else

                    {

                        *output = bin_op(*output, *plo, pv);

                    }

                }

                else

                {

                    sprintf(err, "Parameter %d is not an integer", pv);

                    return -1;

                }

               

            }

            elseif (index_of(ops, cc) > -1) /* If current character is an operator */

            {

                if (pcc == args[1]) /* If the current character is the first character */

                {

                    sprintf(err, "Expression cannot begin with %c", cc);

                    return -1;

                }

                elseif (pcc == (args[1] + sizeof(args[1])/sizeof(char *))) /* If the current character is the final character */

                {

                    sprintf(err, "Expression cannot end with %c", cc);

                    return -1;

                }

                else if ((*(pcc - 1)) < '0') && (*(pcc - 1) > '9')) /* If the previous character is not a digit */

                {

                    sprintf(err, "Operator %c must be preceded by a digit, cannot be preceded by %c", cc, *(pcc - 1)));

                    return -1;

                }

                else/* The current character is an operator preceded by a digit */

                {

                    *plo = cc;

                }

            }

            else if (cc == '(')

            {

                if (pcc == (args[1] + sizeof(args[1])/sizeof(char *))) /* If the current character is the final character */

                {

                    sprintf(err, "Expression cannot end with %c", cc);

                    return -1;

                }

                else if (

                {

                   

                }

                else

                {

                    ++nnrp;

                }

            }

            else if (cc == ')')

            {

              // ...

                --nnrp;

            }

            ++pcc;

        }

     

    Anyways, can someone please criticize me in the most condescending way possible; and if you're feeling nice, maybe give me an outline of how to better approach this problem?
     
  2. jcsd
  3. Feb 19, 2015 #2

    jedishrfu

    Staff: Mentor

    Well if I were writing such a program and wanted to use the same characters you chose for logic operators then I'd have the program run and provide a prompt. The problem is that * and other characters may be processed by the command shell you're using and so wouldn't t be passed to your program at all.

    Next I would allow for infix notation so you don't need to write the expression followed by the data.
    In a sense you're writing a command line calculator program where users could enter 0001+1000 and the program would respond 1001.

    what you need to write is a line parser that breaks up things into tokens and then processes them using a data stack and an operator stack that is if you want to support parentheses.
     
  4. Feb 20, 2015 #3
    True.

    The whole point of the problem is to implement a calculator that uses postfix notation.

    I don't see why I can't do what I'm trying to do, which is an algorithm like

    Code (Text):

    parse_equation:

       Have an integer k that will be the result.  

       For each character character c in a string S {

          if c is a digit, run a parse_int routine that reads a string beginning at c into an int i and meanwhile increments c. Afterwards, update k by k=k$i where $ is the last operator; if there is no last operator, then i is the first int parsed, so set k=i;

          if c is an operator, store that as the last operator.

          if c is a right-facing parenthesis, increment c until reaching the parenthesis that closes it. Run parse_int on the string inside the parenthesis and $ the result to k, where, again, $ is the last operator

        }

        Return k;

     
     
  5. Feb 20, 2015 #4
    Here's a better look at what I have so far. Remove the * in https://github.com/j**a***m******k***in/**cs**L**o**g**ic [Broken]
     
    Last edited by a moderator: May 7, 2017
  6. Feb 21, 2015 #5
    I'll try to be as 'condescending' as possible.

    As I took the prisoner downstairs, I said "You should leverage the standard C library. Your function index_of is very similar to strchr. The function parse_int is very similar to atoi. The rest of the code doesn't seem unreasonable for a hand written parser."

    Get it? prisoner = con. downstairs = descending. I love Tom Swifty's.
     
  7. Feb 21, 2015 #6
    Standard libraries are for chumps. My mottos are:

    • Always reinvent the wheel
    • Micro-optimization is the greatest good
    • Cleverness over readability
     
  8. Feb 21, 2015 #7

    jedishrfu

    Staff: Mentor

    Unfortunately the real world doesn't like wheel inventors unless the wheel is vastly superior to what is in use now.
     
  9. Feb 22, 2015 #8
    If you want to do this cleanly (i.e. without a monstrous program), take a look at the shunting-yard algorithm. This allows you to convert infix notation logical expressions to reverse polish notation, which is much more efficient to parse (using a stack data structure). The conversion and execution thereby only takes two passes through, which results in O(n) asymptotic complexity.

    To clarify: You are taking in an expression is infix (as in 2+5), yes? Because postfix (aka reverse polish notation) does not have parentheses.
     
  10. Feb 23, 2015 #9
    That will be my next implementation.

    Just finished writing my first implementation: htt ps:/ /gi th ub.com /jam ki n/c sLo gic
     
  11. Feb 23, 2015 #10
    That's good. Also, you might want to note the difference between "logical" and "bitwise" operations. Logical operations perform on boolean values, while bitwise operations perform on sets of booleans (numbers).

    I took a look at the repo, by the way.
     
    Last edited: Feb 23, 2015
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook