# My C program has turned into a monster

1. Feb 19, 2015

### Jamin2112

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

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. Feb 19, 2015

### 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.

3. Feb 20, 2015

### Jamin2112

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;

4. Feb 20, 2015

### Jamin2112

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
5. Feb 21, 2015

### ScottSalley

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. Feb 21, 2015

### Jamin2112

Standard libraries are for chumps. My mottos are:

• Always reinvent the wheel
• Micro-optimization is the greatest good

7. Feb 21, 2015

### Staff: Mentor

Unfortunately the real world doesn't like wheel inventors unless the wheel is vastly superior to what is in use now.

8. Feb 22, 2015

### ellipsis

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. Feb 23, 2015

### Jamin2112

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. Feb 23, 2015

### ellipsis

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