#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"); }