Last active
November 21, 2016 06:46
/r/dailyprogrammer Challenge #291 (Intermediate)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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