Advertisement
kaenan

Polish postfix

Nov 12th, 2017
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.37 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <string.h>
  3. #include <stdio.h>
  4.  
  5.  
  6. typedef struct {
  7.     unsigned int n;
  8.     long long *st;
  9. } stack;
  10.  
  11. void push(stack *st, long long);
  12. long long pop(stack *s);
  13.  
  14. unsigned int heightOf(stack *s);
  15.  
  16. unsigned int isEmpty(stack *s);
  17. unsigned int isFull(stack *s, unsigned int);
  18.  
  19. /* Dinamically allocated stack (the vector). */
  20. stack getStack(unsigned int);
  21. /* Free allocated memory of stack (the vector). */
  22. void freeStack(stack *);
  23.  
  24.  
  25.  
  26.  
  27. /* Template for evaluated reverse polish expression. */
  28. typedef struct {
  29.     char *expr;
  30.     long long value;
  31. } polish_expr;
  32.  
  33. /* Polish calculator (reverse polish notation)
  34.  * [INPUT]  : String
  35.  * [OUTPUT] : Reverse polish expression
  36.  *          & the result of evaluating the expression.
  37. */
  38.  
  39. /* calculator(): sets up storage for the calculator_body, and calls _body.
  40.  * Afterwards frees the previously allocated memory and returns
  41.  * the result received from calling _body.
  42.  */
  43. polish_expr calculator(char *);
  44.  
  45. /* calculator_body(): returns the evaluated expression and the result as polish_expr.
  46.  * Handles bad input, arity errors, ignores white space. In case of error,
  47.  * returns NULL for the expression, and 0 for the value.
  48.  */
  49. polish_expr calculator_body(char *, stack *, char *, char *);  /* Returns heap memory! (.expr) */
  50.  
  51.  
  52.  
  53. /* Print arity error message for the given operator (%c). */
  54. void err_op_arity(char);
  55.  
  56.  
  57. /* Template for parsed tokens. */
  58. typedef struct {
  59.     char type;
  60.     unsigned long long value;
  61. } data;
  62.  
  63. #define NATURAL_NUMBER  'N'
  64. #define LETTER          'L'
  65. /* Returns a struct *data* with value and type of string contents.
  66.  * If !NATURAL_NUMBER && !LETTER returns (negative number) as value and for type 0.
  67. */
  68. data parse_token(char *);
  69.  
  70.  
  71.  
  72.  
  73. /* BEIGN:  Error codes. */
  74. #define SUCCESS         0
  75. #define INPUT_ERR       1
  76. #define DOMAIN_ERR      2
  77. /* END_OF: Error codes. */
  78.  
  79. /* Used for signaling errors. (ex: strtol_ sets errno_ to DOMAIN_ERR if conversion failed. */
  80. int errno_ = 0;  // Error codes are the ones defined above.
  81.  
  82. /* Converts a string to number.
  83.  * Returns -1 if conversion failed (&& sets errno_ = DOMAIN_ERR).
  84.  */
  85. long long strtol_(const char *number);
  86.  
  87.  
  88. /* Takes a stack, a binary function, and a symbol (of the operator)
  89.  * used for error checking and printing.
  90.  */
  91. int stackOperate(stack *, long long (*)(long long, long long), char );
  92.  
  93.  
  94. /* Binary operators */
  95. long long add        (long long termL, long long termR);
  96. long long substract  (long long termL, long long termR);
  97. long long multiply   (long long termL, long long termR);
  98. long long divide     (long long termL, long long termR); // errno_ = (termR = 0) ?  DOMAIN_ERR : 0
  99. long long mod        (long long termL, long long termR); // same as above
  100.  
  101.  
  102.  
  103. /* If malloc returns NULL, exit with code (-1). */
  104. void *ec_malloc(unsigned int);
  105.  
  106. /* If realloc returns NULL, exit with code (-1). */
  107. void *ec_realloc(void *, unsigned int);
  108.  
  109. /* Get a line (*string) (del: EOF, '\n') from stdin.
  110.  * !! Retuns heap memory. The caller is responsible
  111.  *    for deallocating it !!
  112.  */
  113. char *cin_getline();
  114.  
  115.  
  116.  
  117. /* Start calculator */
  118. int init()
  119. {
  120.     char *string;
  121.  
  122.     /* Get a line (string) from stdin. */
  123.     string = cin_getline();
  124.  
  125.  
  126.     /* Pass string to calculator. */
  127.     polish_expr expr = calculator(string);
  128.  
  129.     /* If string was not a valid expression, terminate. */
  130.     if (NULL == expr.expr) {
  131.         free(string);
  132.  
  133.         return -1;
  134.     }
  135.  
  136.     /* Print the evaluated expresion and the result. */
  137.     printf("\n%s = %lld\n", expr.expr, expr.value);
  138.  
  139.  
  140.     /* Free memory */
  141.     free(expr.expr);
  142.     free(string);
  143.  
  144.     return 0;
  145. }
  146.  
  147.  
  148. int main()
  149. {
  150.     return init();
  151. }
  152.  
  153.  
  154. polish_expr calculator(char *string)
  155. {
  156.     unsigned long input_size = strlen(string) + 1;           /* + 1 to account for '\0'. */
  157.  
  158.     /* The polish expr. */
  159.     polish_expr result;
  160.  
  161.     /* Used by _body for storing operands. */
  162.     stack s = getStack(input_size);
  163.  
  164.     /* Used by _body for storing tokens of *string. */
  165.     char *token = (char *) ec_malloc(input_size + 1);        /* + 1 for '\0'. */
  166.  
  167.     /* Setup storage for the evaluated expression. */
  168.     char *expr = (char *) ec_malloc(strlen(string) + 2);     /* + 1 for '\0'; + 1 due to trailing [space]. */
  169.  
  170.  
  171.     // Get result (and the evaluade expression)
  172.     result = calculator_body(string, &s, token, expr);
  173.  
  174.  
  175.     /* Free memory */
  176.     freeStack(&s);
  177.     free(token);
  178.  
  179.     return result;
  180. }
  181.  
  182. polish_expr calculator_body(char *string, stack *st, char *token, char *expr)
  183. {
  184.     /* Init. needed for strncat to work (no segfaults). */
  185.     expr[0] = '\0';
  186.  
  187.     polish_expr result = { NULL, 0 };
  188.  
  189.  
  190.     /* Used for storing parsed token. */
  191.     data input;
  192.  
  193.     /* Statistic used for validation of *expr
  194.      * and error reporting.
  195.      */
  196.     char last_operation = 0;
  197.     unsigned int err = 0;
  198.  
  199.  
  200.     unsigned int index = 0, j;
  201.  
  202.     /* While there's more of the string to process. */
  203.     while (
  204.            string[index] && !err
  205.            )
  206.     {
  207.  
  208.         /* Skip white space. */
  209.         while (string[index] && strchr(" \t\n", string[index])) {
  210.             index++;
  211.         }
  212.  
  213.  
  214.         /* Get token. */
  215.         j = 0;
  216.         while ( string[index] && !strchr(" \t\n", string[index]) ) {
  217.             token[j++] = string[index++];
  218.         }
  219.         token[j] = '\0';
  220.         /* GOT token! */
  221.  
  222.  
  223.  
  224.         /* Get data from token. */
  225.         input = parse_token(token);
  226.  
  227.  
  228.         /* If it's a natural number, push it on the stack. */
  229.         if (input.type == NATURAL_NUMBER) {
  230.             push(st, input.value);
  231.  
  232.  
  233.             /* Forming of expr. */
  234.             strncat(expr, token, strlen(token));
  235.             strncat(expr, " ", 1);
  236.         }
  237.  
  238.         else if (input.type == LETTER) {
  239.             /* Operate */
  240.  
  241.             switch (input.value) {
  242.  
  243.             case '+':
  244.                 if (SUCCESS != stackOperate(st, add, input.value))
  245.                     err++;
  246.  
  247.                 last_operation = (char) input.value;
  248.  
  249.  
  250.                 /* Forming of expr. */
  251.                 strncat(expr, token, strlen(token));
  252.                 strncat(expr, " ", 1);
  253.                 break;
  254.  
  255.  
  256.             case '-':
  257.                 if (SUCCESS != stackOperate(st, substract, input.value))
  258.                     err++;
  259.  
  260.                 last_operation = (char) input.value;
  261.  
  262.  
  263.                 /* Forming of expr. */
  264.                 strncat(expr, token, strlen(token));
  265.                 strncat(expr, " ", 1);
  266.                 break;
  267.  
  268.  
  269.             case '*':
  270.                 if (SUCCESS != stackOperate(st, multiply, input.value))
  271.                     err++;
  272.  
  273.                 last_operation = (char) input.value;
  274.  
  275.  
  276.                 /* Forming of expr. */
  277.                 strncat(expr, token, strlen(token));
  278.                 strncat(expr, " ", 1);
  279.                 break;
  280.  
  281.  
  282.             case '/':
  283.                 if (SUCCESS != stackOperate(st, divide, input.value))
  284.                     err++;
  285.  
  286.                 last_operation = (char) input.value;
  287.  
  288.  
  289.                 /* Forming of expr. */
  290.                 strncat(expr, token, strlen(token));
  291.                 strncat(expr, " ", 1);
  292.                 break;
  293.  
  294.  
  295.             case '%':
  296.                 if (SUCCESS != stackOperate(st, mod, input.value))
  297.                     err++;
  298.  
  299.                 last_operation = (char) input.value;
  300.  
  301.  
  302.                 /* Forming of expr. */
  303.                 strncat(expr, token, strlen(token));
  304.                 strncat(expr, " ", 1);
  305.                 break;
  306.  
  307.             default:
  308.                 printf("\n[Error] Undefined operator: \"%s\"\n", token);
  309.                 err++;
  310.             }
  311.         }
  312.  
  313.         else if (*token) {
  314.             /* If token is !natural_number, !letter and !empty : bad input! */
  315.  
  316.             printf("\n[Error] Bad input: \"%s\"\n", token);
  317.             err++;
  318.         }
  319.     }
  320.  
  321.  
  322.     /* If there were operands, but no operation(s). */
  323.     if (!err && !last_operation && !isEmpty(st)) {
  324.         printf("\n[Error] Please provide an operation.\n");
  325.         err++;
  326.     }
  327.  
  328.     /* If too many operands were given. */
  329.     if (!err && last_operation && heightOf(st) > 1) {
  330.         err_op_arity(last_operation);
  331.         err++;
  332.     }
  333.  
  334.     /* If err OR if input was null, show USAGE message. */
  335.     if (err || !last_operation) {
  336.         printf("Usage: a b [+-*/] | long a, b.\n");
  337.  
  338.         free(expr);
  339.  
  340.         return result;
  341.     }
  342.  
  343.  
  344.     /* Remove trailing [space]. */
  345.     expr[strlen(expr)] = '\0';
  346.  
  347.     result.expr = expr;
  348.     result.value =  pop(st);
  349.  
  350.     return result;
  351. }
  352.  
  353.  
  354. data parse_token(char *token)
  355. {
  356.     data d = { 0, 0 };
  357.  
  358.     long long value = 0;
  359.     char type = '0';
  360.  
  361.     /* Convert token to long. */
  362.     if ((value = strtol_(token)) >= 0) {
  363.         type = NATURAL_NUMBER;
  364.     }
  365.  
  366.     /* We're dealing with non-numbers then. */
  367.     else if (strlen(token) == 1) {
  368.         type = LETTER;
  369.         value = *token;
  370.     }
  371.     /* Else not a number nor single letter. */
  372.  
  373.  
  374.     d.value = (unsigned long long) value;
  375.     d.type = type;
  376.  
  377.     return d;
  378. }
  379.  
  380.  
  381. int stackOperate(stack *s, long long (*operator)(long long, long long), char symbol)
  382. {
  383.  
  384.     if (heightOf(s) < 2) {
  385.         err_op_arity(symbol);
  386.  
  387.         return -1;
  388.     }
  389.  
  390.     long long termL, termR, result;
  391.  
  392.     termR = pop(s);
  393.     termL = pop(s);
  394.  
  395.     if ( (symbol == '/' || symbol == '%') && !termR ) {
  396.         printf("\n[Error] Ilegal operation; trying to %c by 0: \"%lld %lld %c\".\n", symbol, termL, termR, symbol);
  397.  
  398.         return DOMAIN_ERR;
  399.     }
  400.  
  401.     result = (*operator)(termL, termR);
  402.     push(s, result);
  403.  
  404.     return SUCCESS;
  405.  
  406. }
  407.  
  408. void err_op_arity(char op)
  409. {
  410.     printf("\n[Error] The \"%c\" operator takes two operands: \"a b %c\" | long a, b.\n", op, op);
  411. }
  412.  
  413.  
  414. stack getStack(unsigned int size)
  415. {
  416.     stack temp;
  417.     temp.n = 0;
  418.     temp.st = (long long *) ec_malloc(sizeof(long long) * size);
  419.  
  420.     return temp;
  421. }
  422. void freeStack(stack *s)
  423. {
  424.     free(s->st);
  425. }
  426.  
  427.  
  428. void push(stack *s, long long elem)
  429. {
  430.     s->st[s->n++] = elem;
  431. }
  432.  
  433. long long pop(stack *s)
  434. {
  435.     return s->st[s->n-- - 1]; // -1 due to 0 .. n-1 indexing
  436. }
  437.  
  438. unsigned int heightOf(stack *s)
  439. {
  440.     return s->n;
  441. }
  442.  
  443. unsigned int isEmpty(stack *s)
  444. {
  445.     return 0 == heightOf(s);
  446. }
  447.  
  448. unsigned int isFull(stack *s, unsigned int size)
  449. {
  450.     return heightOf(s) >= size;
  451. }
  452.  
  453.  
  454. /* =================================================
  455.  * Numbers.
  456.  * =================================================
  457.  */
  458. long long strtol_(const char *string)
  459. {
  460.     long long number = 0;
  461.     int sign = 1;  /* Assume positive number. */
  462.  
  463.                    /* Used for iterating over string. */
  464.     unsigned int i = 0;
  465.  
  466.     /* Skip inital white space. */
  467.     while ( strchr(" \n\t",  string[i]) ) {
  468.         i++;
  469.     }
  470.  
  471.     /* Check for sign. */
  472.     if (string[i] == '-') {
  473.         sign = -1;
  474.         i++;
  475.     }
  476.     else if (string[i] == '+') {
  477.         i++;
  478.     }
  479.  
  480.     /* If input string is null OR if input string contains only a sign (+ or -). */
  481.     if (!string[i]) {
  482.         errno_ = DOMAIN_ERR;
  483.         return -1;
  484.     }
  485.  
  486.  
  487.     while (string[i]) {
  488.  
  489.         /* If string[i] is a digit. */
  490.         if (string[i] >= '0' && string[i] <= '9') {
  491.             number = number * 10 + (string[i++] - '0');
  492.         }
  493.  
  494.         else if ( strchr(" \n\t",  string[i]) ) {
  495.  
  496.             /* Ignore white space after the number. */
  497.             while ( strchr(" \n\t",  string[i]) ) {
  498.                 i++;
  499.             }
  500.             if (string[i]) {
  501.                 /* A number has no white space. */
  502.                 errno_ = DOMAIN_ERR;
  503.                 return -1;
  504.             }
  505.         }
  506.  
  507.         /* string[i] is not a digit. */
  508.         else {
  509.             errno_ = DOMAIN_ERR;
  510.             return -1;
  511.         }
  512.     }
  513.  
  514.     return sign * number;
  515. }
  516.  
  517.  
  518. long long add(long long termL, long long termR)
  519. {
  520.     return termL + termR;
  521. }
  522.  
  523. long long substract(long long termL, long long termR)
  524. {
  525.     return termL - termR;
  526. }
  527.  
  528. long long multiply(long long termL, long long termR)
  529. {
  530.     return termL * termR;
  531. }
  532.  
  533. long long divide(long long termL, long long termR)
  534. {
  535.     /* Call out attempt to divide by 0. */
  536.     if (termR == 0) {
  537.         errno_ = DOMAIN_ERR;
  538.  
  539.         return errno_;
  540.     }
  541.  
  542.     return termL / termR;
  543. }
  544.  
  545. long long mod(long long termL, long long termR)
  546. {
  547.     /* Call out attempt to mod by 0. */
  548.     if (termR == 0) {
  549.         errno_ = DOMAIN_ERR;
  550.  
  551.         return errno_;
  552.     }
  553.  
  554.     return termL % termR;
  555. }
  556.  
  557.  
  558. char *cin_getline()
  559. {
  560.     char *string;
  561.  
  562.     /* i - used for *iterating* over the block s points to. */
  563.     unsigned int i = 0, size = 100;
  564.  
  565.     /* Allocate memory for string */
  566.     string = (char *)ec_malloc(size);
  567.  
  568.     for (
  569.         int c;
  570.         /* *While* c != EOF ^ '\n'. */
  571.         EOF != (c = getchar()) && '\n' != c;
  572.         /* *Insert* c into string. */
  573.         *(string + i) = c, i++
  574.         )
  575.     {
  576.         /* Resize string to fit the current chr ^ more chrs. */
  577.         if (i >= size) {
  578.             string = (char *)ec_realloc(string, (size += 30));
  579.         }
  580.     }
  581.  
  582.     /* Discard unused memory (also needed *if* i == size). */
  583.     string = (char *)ec_realloc(string, i + 1);
  584.  
  585.     /* End string. */
  586.     *(string + i) = '\0';
  587.  
  588.     return string;
  589. }
  590.  
  591.  
  592. void *ec_malloc(unsigned int size)
  593. {
  594.     return ec_realloc(NULL, size);
  595. }
  596.  
  597. void *ec_realloc(void *ptr, unsigned int size)
  598. {
  599.     void *new_ptr;
  600.  
  601.     new_ptr = realloc(ptr, size);
  602.  
  603.     if (!new_ptr) {
  604.         printf("[Error] ec_realloc(): realloc() returned NULL.");
  605.         exit(-1);
  606.     }
  607.  
  608.     return new_ptr;
  609. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement