Skip to content

Commit

Permalink
feat: infix notation stack based calculator
Browse files Browse the repository at this point in the history
  • Loading branch information
declaudefrancois committed Aug 7, 2023
1 parent b105380 commit a0b8d46
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 127 deletions.
29 changes: 23 additions & 6 deletions declaudefrancois/README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,27 @@
# Stack based Calculator.

Simple stack based calculator, takes as inputs arithmetic operations described
in [infix](https://en.wikipedia.org/wiki/Infix_notation) notation and output the
result.

## TODO:
## How to use

1- Compile the program
```bash
gcc *.c -o scp -lm
```

2- Excecute the program and describe your operation.
```
./scp
(SCP): (12 + 4) * (1 + 8 * 6)
```

- [x] Suppport simple operations (e.g: -12.2 + 5 - 6)
- [ ] Support of arithmetic operation ( negative and positive number).
- [ ] Support of more operator such as power.
- [ ] Operator precedence.
- [ ] Handle parentheses operator.
3- Press ENTER to get your result.
```bash
(SCP): 784
```

## TODO:
- [ ] Free allocated memory.
- [ ] Handle errors.
124 changes: 66 additions & 58 deletions declaudefrancois/calculator.c
Original file line number Diff line number Diff line change
@@ -1,98 +1,107 @@
#include <ctype.h>
#include <math.h>
#include "num_stack.h"
#include "op_stack.h"
#include "calculator.h"


/**
* calculate - Takes a operation description string as
* input and returns the result if the operation
* is valid.
* @op: A char pointer containing a 'string' description of
* the operation to perform.
*
* Return: Float, the result of the operation.
* Return: Int, the result of the operation.
*/
float calculate(char *op)
int calculate(char *op)
{
char *next;
float res;
char operator;
int oplen, n;
num_stack_t *nstack;
op_stack_t *opstack, *cur_op;
char cur;

next = strtok(op, " ");
res = 0.0;
operator = '\0';
/**
* TODO: evaluate the result using stacks DSA.
*/
while (next != NULL)
oplen = strlen(op);
nstack = create_num_stack();
opstack = create_op_stack();
for (int i = 0; op[i] != '\0'; i++)
{
if (strlen(next) == 1 && isOperator(next[0]))
{
operator = next[0];
}
else if (isFloat(next))
cur = op[i];
if (isdigit(cur))
{
if (res == 0.0)
res = strtof(next, NULL);
else if (operator != '\0')
n = 0;
while (isdigit(cur))
{
res = evaluate(res, strtof(next, NULL), operator);
n = n * 10 + (cur - '0');
i++;
if (i < oplen)
cur = op[i];
else
break;
}
i--;
push_num(&nstack, n);
}
else if (cur == '(')
push_op(&opstack, cur);
else if (cur == ')')
{
while (opstack != NULL && opstack->op != '(')
push_num(&nstack, evaluate(&nstack, &opstack));
pop_op(&opstack);
}
else if (isOperator(cur))
{
while (opstack &&
precedence(cur) <= precedence(opstack->op))
push_num(&nstack, evaluate(&nstack, &opstack));
push_op(&opstack, cur);
}
else
exit(0);
next = strtok(NULL, " ");
}

return (res);
while (opstack && isOperator(opstack->op))
push_num(&nstack, evaluate(&nstack, &opstack));
return (nstack->n);
}


/**
* evaluate - evaluates the result of operator
* applied on a and b.
* @a: the first number
* @b: the second number
* @c: the operator symbol
* @nstack: the operand stack.
* @opstack: the operator stack.
* Return: The result.
*/
float evaluate(float a, float b, char c)
int evaluate(num_stack_t **nstack, op_stack_t **opstack)
{
int a, b;
op_stack_t *op;

switch (c)
a = pop_num(nstack)->n;
b = pop_num(nstack)->n;
op = pop_op(opstack);
switch (op->op)
{
case '+':
return (a + b);
case '-':
return (a - b);
return (b - a);
case '*':
return (a * b);
case '^':
return pow(b, a);
case '/':
return (a / b);
if (a == 0)
{
printf("Division by 0\n");
exit(1);
}
return (b / a);
}

printf("Operator '%c' not supported.\n", c);
exit(0);
exit(1);
}

/**
* isFloat - Checks if an string is a valid
* representation of a float number.
* @op: The string to check.
*
* Return: 1 if valid otherwise 0.
*/
char isFloat(char *op)
{
int opSize;

opSize = strlen(op);
for (int i = 0; i < opSize; i++)
{
if (!isOperator(op[0]) && op[i] != '.' &&
(op[i] < '0' || op[i] > '9'))
return (0);
}

return (1);
}

/**
* precedence - Returns the precendente of an
Expand All @@ -111,8 +120,7 @@ char precedence(char op)
case '*':
case '/':
return (2);
case '(':
case ')':
case '^':
return (3);
default:
return (-1);
Expand All @@ -130,7 +138,7 @@ char isOperator(char op)
{
if (op == '-' || op == '+' ||
op == '/' || op == '*' ||
op == '(' || op == ')')
op == '*' || op == '^')
return (1);
return (0);
}
12 changes: 4 additions & 8 deletions declaudefrancois/calculator.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,13 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "op_stack.h"
#include "num_stack.h"

#define INPUT_BUFF_SIZE 200

float calculate(char *op);
char isValid(char *op);
int calculate(char *op);
char precedence(char op);
char isOperator(char op);
char isValid(char *op);
char isFloat(char *op);
char precedence(char op);
char isOperator(char op);
float evaluate(float a, float b, char c);

int evaluate(num_stack_t **nstack, op_stack_t **opstack);
#endif /* CALC_H */
2 changes: 1 addition & 1 deletion declaudefrancois/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ int main(int ac, char **av)
if (strcmp(op, "QUIT") == 0)
break;

printf("(SCP): %f\n", calculate(op));
printf("(SCP): %d\n", calculate(op));
} while (input != NULL);

free(input);
Expand Down
63 changes: 63 additions & 0 deletions declaudefrancois/num_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <stdlib.h>
#include <stdio.h>
#include "num_stack.h"


/**
* create_num_stack - Create a new stack of operands.
* Return: A pointer to the top of the stack.
*/
num_stack_t *create_num_stack()
{
num_stack_t *stack;

stack = malloc(sizeof(*stack));
if (stack == NULL)
{
printf("Malloc failed");
exit(1);
}

return (stack);
}


/**
* push_num - Pushed an item to the top of the num_stack.
* @top: A double poitner to the current top of the num_stack.
* @n: the vlaue of the item to push on the num_stack.
*/
void push_num(num_stack_t **top, int n)
{
num_stack_t *item;

item = malloc(sizeof(*item));
if (item == NULL)
{
printf("Malloc failed");
exit(1);
}

item->next = *top;
item->n = n;
*top = item;
}


/**
* pop_num - pop the top of the num_stack.
* @top: A double pointer to the top of the num_stack.
*
* Return: Return A pointer to the new top of
* the num_stack.
*/
num_stack_t *pop_num(num_stack_t **top)
{
num_stack_t *item;

item = *top;
if (*top && (*top)->next)
*top = (*top)->next;

return (item);
}
23 changes: 23 additions & 0 deletions declaudefrancois/num_stack.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef NUM_STACK_H
#define NUM_STACK_H


/**
* struct num_stack_s - operand stack.
* @n: int, the value of an operand.
* @next: points to the next element of the num_stack.
*
* Description: Stack dsa for holding the operand of
* the calculator.
*/
typedef struct num_stack_s
{
int n;
struct num_stack_s *next;
} num_stack_t;

num_stack_t *pop_num(num_stack_t **);
void push_num(num_stack_t **, int);
num_stack_t *create_num_stack();

#endif /* NUM_STACK_H */
63 changes: 63 additions & 0 deletions declaudefrancois/op_stack.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
#include <stdlib.h>
#include <stdio.h>
#include "op_stack.h"


/**
* create_op_stack - Create a new stack of operands.
* Return: A pointer to the top of the stack.
*/
op_stack_t *create_op_stack()
{
op_stack_t *stack;

stack = malloc(sizeof(*stack));
if (stack == NULL)
{
printf("Malloc failed");
exit(1);
}

return (stack);
}


/**
* push_op - Pushed an item to the top of the stack.
* @top: A double poitner to the current top of the stack.
* @op: the value of the item to push on the stack.
*/
void push_op(op_stack_t **top, char op)
{
op_stack_t *item;

item = malloc(sizeof(*item));
if (item == NULL)
{
printf("Malloc failed");
exit(1);
}

item->next = *top;
item->op = op;
*top = item;
}


/**
* pop_op - pop the top of the stack.
* @top: A double pointer to the top of the stack.
*
* Return: Return A pointer to the new top of
* the stack.
*/
op_stack_t *pop_op(op_stack_t **top)
{
op_stack_t *item;

item = *top;
if (*top && (*top)->next)
*top = (*top)->next;

return (item);
}
Loading

0 comments on commit a0b8d46

Please sign in to comment.