My C program has turned into a monster

  • #1
986
9
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:
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:
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?
 

Answers and Replies

  • #2
12,031
5,691
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.
 
  • #3
986
9
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.
True.

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.
The whole point of the problem is to implement a calculator that uses postfix notation.

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.
I don't see why I can't do what I'm trying to do, which is an algorithm like

Code:
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;
 
  • #4
986
9
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:
  • #5
21
10
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.
 
  • #6
986
9
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.
Standard libraries are for chumps. My mottos are:

  • Always reinvent the wheel
  • Micro-optimization is the greatest good
  • Cleverness over readability
 
  • Like
Likes ellipsis and jedishrfu
  • #7
12,031
5,691
Unfortunately the real world doesn't like wheel inventors unless the wheel is vastly superior to what is in use now.
 
  • #8
158
23
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.
 
  • #9
986
9
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.
That will be my next implementation.

Just finished writing my first implementation: htt ps:/ /gi th ub.com /jam ki n/c sLo gic
 
  • #10
158
23
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:

Related Threads on My C program has turned into a monster

  • Last Post
Replies
6
Views
2K
Replies
2
Views
1K
Replies
25
Views
2K
  • Last Post
Replies
10
Views
4K
Replies
3
Views
2K
  • Last Post
Replies
16
Views
6K
Replies
4
Views
2K
Top