Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- typedef struct {
- unsigned int n;
- long long *st;
- } stack;
- void push(stack *st, long long);
- long long pop(stack *s);
- unsigned int heightOf(stack *s);
- unsigned int isEmpty(stack *s);
- unsigned int isFull(stack *s, unsigned int);
- /* Dinamically allocated stack (the vector). */
- stack getStack(unsigned int);
- /* Free allocated memory of stack (the vector). */
- void freeStack(stack *);
- /* Template for evaluated reverse polish expression. */
- typedef struct {
- char *expr;
- long long value;
- } polish_expr;
- /* Polish calculator (reverse polish notation)
- * [INPUT] : String
- * [OUTPUT] : Reverse polish expression
- * & the result of evaluating the expression.
- */
- /* calculator(): sets up storage for the calculator_body, and calls _body.
- * Afterwards frees the previously allocated memory and returns
- * the result received from calling _body.
- */
- polish_expr calculator(char *);
- /* calculator_body(): returns the evaluated expression and the result as polish_expr.
- * Handles bad input, arity errors, ignores white space. In case of error,
- * returns NULL for the expression, and 0 for the value.
- */
- polish_expr calculator_body(char *, stack *, char *, char *); /* Returns heap memory! (.expr) */
- /* Print arity error message for the given operator (%c). */
- void err_op_arity(char);
- /* Template for parsed tokens. */
- typedef struct {
- char type;
- unsigned long long value;
- } data;
- #define NATURAL_NUMBER 'N'
- #define LETTER 'L'
- /* Returns a struct *data* with value and type of string contents.
- * If !NATURAL_NUMBER && !LETTER returns (negative number) as value and for type 0.
- */
- data parse_token(char *);
- /* BEIGN: Error codes. */
- #define SUCCESS 0
- #define INPUT_ERR 1
- #define DOMAIN_ERR 2
- /* END_OF: Error codes. */
- /* Used for signaling errors. (ex: strtol_ sets errno_ to DOMAIN_ERR if conversion failed. */
- int errno_ = 0; // Error codes are the ones defined above.
- /* Converts a string to number.
- * Returns -1 if conversion failed (&& sets errno_ = DOMAIN_ERR).
- */
- long long strtol_(const char *number);
- /* Takes a stack, a binary function, and a symbol (of the operator)
- * used for error checking and printing.
- */
- int stackOperate(stack *, long long (*)(long long, long long), char );
- /* Binary operators */
- long long add (long long termL, long long termR);
- long long substract (long long termL, long long termR);
- long long multiply (long long termL, long long termR);
- long long divide (long long termL, long long termR); // errno_ = (termR = 0) ? DOMAIN_ERR : 0
- long long mod (long long termL, long long termR); // same as above
- /* If malloc returns NULL, exit with code (-1). */
- void *ec_malloc(unsigned int);
- /* If realloc returns NULL, exit with code (-1). */
- void *ec_realloc(void *, unsigned int);
- /* Get a line (*string) (del: EOF, '\n') from stdin.
- * !! Retuns heap memory. The caller is responsible
- * for deallocating it !!
- */
- char *cin_getline();
- /* Start calculator */
- int init()
- {
- char *string;
- /* Get a line (string) from stdin. */
- string = cin_getline();
- /* Pass string to calculator. */
- polish_expr expr = calculator(string);
- /* If string was not a valid expression, terminate. */
- if (NULL == expr.expr) {
- free(string);
- return -1;
- }
- /* Print the evaluated expresion and the result. */
- printf("\n%s = %lld\n", expr.expr, expr.value);
- /* Free memory */
- free(expr.expr);
- free(string);
- return 0;
- }
- int main()
- {
- return init();
- }
- polish_expr calculator(char *string)
- {
- unsigned long input_size = strlen(string) + 1; /* + 1 to account for '\0'. */
- /* The polish expr. */
- polish_expr result;
- /* Used by _body for storing operands. */
- stack s = getStack(input_size);
- /* Used by _body for storing tokens of *string. */
- char *token = (char *) ec_malloc(input_size + 1); /* + 1 for '\0'. */
- /* Setup storage for the evaluated expression. */
- char *expr = (char *) ec_malloc(strlen(string) + 2); /* + 1 for '\0'; + 1 due to trailing [space]. */
- // Get result (and the evaluade expression)
- result = calculator_body(string, &s, token, expr);
- /* Free memory */
- freeStack(&s);
- free(token);
- return result;
- }
- polish_expr calculator_body(char *string, stack *st, char *token, char *expr)
- {
- /* Init. needed for strncat to work (no segfaults). */
- expr[0] = '\0';
- polish_expr result = { NULL, 0 };
- /* Used for storing parsed token. */
- data input;
- /* Statistic used for validation of *expr
- * and error reporting.
- */
- char last_operation = 0;
- unsigned int err = 0;
- unsigned int index = 0, j;
- /* While there's more of the string to process. */
- while (
- string[index] && !err
- )
- {
- /* Skip white space. */
- while (string[index] && strchr(" \t\n", string[index])) {
- index++;
- }
- /* Get token. */
- j = 0;
- while ( string[index] && !strchr(" \t\n", string[index]) ) {
- token[j++] = string[index++];
- }
- token[j] = '\0';
- /* GOT token! */
- /* Get data from token. */
- input = parse_token(token);
- /* If it's a natural number, push it on the stack. */
- if (input.type == NATURAL_NUMBER) {
- push(st, input.value);
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- }
- else if (input.type == LETTER) {
- /* Operate */
- switch (input.value) {
- case '+':
- if (SUCCESS != stackOperate(st, add, input.value))
- err++;
- last_operation = (char) input.value;
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- break;
- case '-':
- if (SUCCESS != stackOperate(st, substract, input.value))
- err++;
- last_operation = (char) input.value;
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- break;
- case '*':
- if (SUCCESS != stackOperate(st, multiply, input.value))
- err++;
- last_operation = (char) input.value;
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- break;
- case '/':
- if (SUCCESS != stackOperate(st, divide, input.value))
- err++;
- last_operation = (char) input.value;
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- break;
- case '%':
- if (SUCCESS != stackOperate(st, mod, input.value))
- err++;
- last_operation = (char) input.value;
- /* Forming of expr. */
- strncat(expr, token, strlen(token));
- strncat(expr, " ", 1);
- break;
- default:
- printf("\n[Error] Undefined operator: \"%s\"\n", token);
- err++;
- }
- }
- else if (*token) {
- /* If token is !natural_number, !letter and !empty : bad input! */
- printf("\n[Error] Bad input: \"%s\"\n", token);
- err++;
- }
- }
- /* If there were operands, but no operation(s). */
- if (!err && !last_operation && !isEmpty(st)) {
- printf("\n[Error] Please provide an operation.\n");
- err++;
- }
- /* If too many operands were given. */
- if (!err && last_operation && heightOf(st) > 1) {
- err_op_arity(last_operation);
- err++;
- }
- /* If err OR if input was null, show USAGE message. */
- if (err || !last_operation) {
- printf("Usage: a b [+-*/] | long a, b.\n");
- free(expr);
- return result;
- }
- /* Remove trailing [space]. */
- expr[strlen(expr)] = '\0';
- result.expr = expr;
- result.value = pop(st);
- return result;
- }
- data parse_token(char *token)
- {
- data d = { 0, 0 };
- long long value = 0;
- char type = '0';
- /* Convert token to long. */
- if ((value = strtol_(token)) >= 0) {
- type = NATURAL_NUMBER;
- }
- /* We're dealing with non-numbers then. */
- else if (strlen(token) == 1) {
- type = LETTER;
- value = *token;
- }
- /* Else not a number nor single letter. */
- d.value = (unsigned long long) value;
- d.type = type;
- return d;
- }
- int stackOperate(stack *s, long long (*operator)(long long, long long), char symbol)
- {
- if (heightOf(s) < 2) {
- err_op_arity(symbol);
- return -1;
- }
- long long termL, termR, result;
- termR = pop(s);
- termL = pop(s);
- if ( (symbol == '/' || symbol == '%') && !termR ) {
- printf("\n[Error] Ilegal operation; trying to %c by 0: \"%lld %lld %c\".\n", symbol, termL, termR, symbol);
- return DOMAIN_ERR;
- }
- result = (*operator)(termL, termR);
- push(s, result);
- return SUCCESS;
- }
- void err_op_arity(char op)
- {
- printf("\n[Error] The \"%c\" operator takes two operands: \"a b %c\" | long a, b.\n", op, op);
- }
- stack getStack(unsigned int size)
- {
- stack temp;
- temp.n = 0;
- temp.st = (long long *) ec_malloc(sizeof(long long) * size);
- return temp;
- }
- void freeStack(stack *s)
- {
- free(s->st);
- }
- void push(stack *s, long long elem)
- {
- s->st[s->n++] = elem;
- }
- long long pop(stack *s)
- {
- return s->st[s->n-- - 1]; // -1 due to 0 .. n-1 indexing
- }
- unsigned int heightOf(stack *s)
- {
- return s->n;
- }
- unsigned int isEmpty(stack *s)
- {
- return 0 == heightOf(s);
- }
- unsigned int isFull(stack *s, unsigned int size)
- {
- return heightOf(s) >= size;
- }
- /* =================================================
- * Numbers.
- * =================================================
- */
- long long strtol_(const char *string)
- {
- long long number = 0;
- int sign = 1; /* Assume positive number. */
- /* Used for iterating over string. */
- unsigned int i = 0;
- /* Skip inital white space. */
- while ( strchr(" \n\t", string[i]) ) {
- i++;
- }
- /* Check for sign. */
- if (string[i] == '-') {
- sign = -1;
- i++;
- }
- else if (string[i] == '+') {
- i++;
- }
- /* If input string is null OR if input string contains only a sign (+ or -). */
- if (!string[i]) {
- errno_ = DOMAIN_ERR;
- return -1;
- }
- while (string[i]) {
- /* If string[i] is a digit. */
- if (string[i] >= '0' && string[i] <= '9') {
- number = number * 10 + (string[i++] - '0');
- }
- else if ( strchr(" \n\t", string[i]) ) {
- /* Ignore white space after the number. */
- while ( strchr(" \n\t", string[i]) ) {
- i++;
- }
- if (string[i]) {
- /* A number has no white space. */
- errno_ = DOMAIN_ERR;
- return -1;
- }
- }
- /* string[i] is not a digit. */
- else {
- errno_ = DOMAIN_ERR;
- return -1;
- }
- }
- return sign * number;
- }
- long long add(long long termL, long long termR)
- {
- return termL + termR;
- }
- long long substract(long long termL, long long termR)
- {
- return termL - termR;
- }
- long long multiply(long long termL, long long termR)
- {
- return termL * termR;
- }
- long long divide(long long termL, long long termR)
- {
- /* Call out attempt to divide by 0. */
- if (termR == 0) {
- errno_ = DOMAIN_ERR;
- return errno_;
- }
- return termL / termR;
- }
- long long mod(long long termL, long long termR)
- {
- /* Call out attempt to mod by 0. */
- if (termR == 0) {
- errno_ = DOMAIN_ERR;
- return errno_;
- }
- return termL % termR;
- }
- char *cin_getline()
- {
- char *string;
- /* i - used for *iterating* over the block s points to. */
- unsigned int i = 0, size = 100;
- /* Allocate memory for string */
- string = (char *)ec_malloc(size);
- for (
- int c;
- /* *While* c != EOF ^ '\n'. */
- EOF != (c = getchar()) && '\n' != c;
- /* *Insert* c into string. */
- *(string + i) = c, i++
- )
- {
- /* Resize string to fit the current chr ^ more chrs. */
- if (i >= size) {
- string = (char *)ec_realloc(string, (size += 30));
- }
- }
- /* Discard unused memory (also needed *if* i == size). */
- string = (char *)ec_realloc(string, i + 1);
- /* End string. */
- *(string + i) = '\0';
- return string;
- }
- void *ec_malloc(unsigned int size)
- {
- return ec_realloc(NULL, size);
- }
- void *ec_realloc(void *ptr, unsigned int size)
- {
- void *new_ptr;
- new_ptr = realloc(ptr, size);
- if (!new_ptr) {
- printf("[Error] ec_realloc(): realloc() returned NULL.");
- exit(-1);
- }
- return new_ptr;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement