Skip to content

Instantly share code, notes, and snippets.

@sam97
Last active November 21, 2016 06:46
/r/dailyprogrammer Challenge #291 (Intermediate)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
void print_help();
void push(char **, int *, char *);
char *pop(char **, int *);
char *operate(char *, char *, char *);
int is_oper(char *);
double fact(char *);
// String handling stuff.
// char *strdup(char *);
char *ftoa(double);
int is_num(char *);
void printf_f(char *);
int main(int argc, char const *argv[])
{
int i, top = 0;
char *stack[argc], *op1, *op2, *res;
if(argc == 1) {
print_help();
return 0;
}
op1 = op2 = NULL;
for(i = 0; i < argc-1; ++i) {
if(top == argc) {
fprintf(stderr, "[!] Stack overflow.\n");
print_help();
exit(EXIT_FAILURE);
}
if(is_oper(argv[i+1])) { // Check for operator.
op2 = pop(&stack, &top);
if(argv[i+1][0] != '!') // Factorial is unary, others are binary.
op1 = pop(&stack, &top);
else
op1 = NULL;
res = operate(argv[i+1], op1, op2);
push(&stack, &top, res);
free(op1);
free(op2);
}
else if(is_num(argv[i+1])) { // Check for operand.
push(&stack, &top, argv[i+1]);
}
else { // Error.
fprintf(stderr, "[-] Invalid input.\n");
print_help();
exit(EXIT_FAILURE);
}
}
printf_f(stack[0]);
free(stack[0]);
return 0;
}
// Stack functions start...
char *operate(char *oper, char *op1, char *op2) {
// Apply operand to operators.
char *res;
float fres;
switch(oper[0]) {
case '+':
res = ftoa(atof(op1) + atof(op2));
break;
case '-':
res = ftoa(atof(op1) - atof(op2));
break;
case '*':
case 'x':
res = ftoa(atof(op1) * atof(op2));
break;
case '%':
res = ftoa((int)(atof(op1)) % (int)(atof(op2)));
break;
case '^':
res = ftoa(pow(atof(op1), atof(op2)));
break;
case '!':
res = ftoa(fact(op2));
break;
case '/':
fres = atof(op1) / atof(op2);
if(oper[1] == '/') // For the '//' operator...
fres = (int)fres;
res = ftoa(fres);
// else res = ftoa((int)(atof(op1) / atof(op2)));
break;
}
return res;
}
char *pop(char **stack, int *top) {
*top -= 1;
if(*top < 0) {
fprintf(stderr, "[!] Stack underflow.\n");
print_help();
exit(EXIT_FAILURE);
}
return stack[*top];
}
void push(char **stack, int *top, char *data) {
char *elem;
elem = strdup(data);
stack[(*top)++] = elem;
}
// ...Stack functions end.
// String-handling functions start...
char *ftoa(double d) {
// Return string from a double.
char *f;
f = (char *) malloc(32 * sizeof(char));
if(f == NULL) {
fprintf(stderr, "Malloc failed.\n");
exit(EXIT_FAILURE);
}
sprintf(f, "%f", d);
return f;
}
int is_oper(char *arg) {
// Check if arg is an operator.
switch(arg[0]) {
case '+':
case '-':
case '*':
case 'x':
case '%':
case '^':
case '!':
if(arg[1] == '\0')
return 1;
break;
case '/':
if(arg[1] == '\0' || (arg[1] == '/' && arg[2] == '\0'))
return 1;
break;
default:
break;
}
return 0;
}
int is_num(char *str) {
// Check if str is a valid number, int or float.
int dots = 0; // Keep track of number of dots in str.
for(; *str; str++) {
if(!isdigit(*str)){
if(*str == '.'){
// ++dots;
if(++dots > 1)
return 0;
}
else
return 0;
}
}
return 1;
}
void printf_f(char *str) {
// Print float(as a string) upto the last signifant digit only.
int i = 0, pos;
while(str[i] != '.' && str[i] != '\0')
++i;
if(str[i] == '\0') { // Print the integer.
printf("%s\n", str);
return;
}
pos = i-1; // Stop before dot.
++i;
while(str[i] != '\0') {
if(str[i] > '0') // If significant digit found after dot...
pos = i; // ...set it as the furthest point to print to.
++i;
}
str[pos + 1] = '\0';
printf("%s\n", str);
}
// char *strdup(char *str) {
// // Implementation of 'strdup', since some systems may not have it.
// unsigned int len;
// char *dup;
// len = strlen(str) + 1;
// dup = (char *) malloc(len * sizeof(char));
// memcpy(dup, str, len * sizeof(char));
// return dup;
// }
// ...String handling functions end.
double fact(char *str) {
// Get factorial of str.
int n = atoi(str);
double res;
for(res = 1.0; n > 1; --n)
res *= n;
return res;
}
void print_help() {
printf("Help:\n");
printf("Reverse Polish Notation Calculator\n");
printf("Provide space-delimited RPN.\n");
printf("Supported operators are:\n");
printf("\t+\t - addition\n"
"\t-\t - subtraction\n"
"\t*, x\t - multiplication\n"
"\t/\t - division (floating point, e.g. 3/2=1.5, not 3/2=1)\n"
"\t//\t - integer division (e.g. 3/2=1)\n"
"\t%%\t - modulus, or \"remainder\" division (e.g. 14%%3=2 and 21%%7=0)\n"
"\t^\t - power (two carats '^^' for Windows systems.)\n"
"\t!\t - factorial (unary operator)\n");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment