MastaC729

CMPSC 122 HW 4 evaluate.cpp

Mar 3rd, 2015
337
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.86 KB | None | 0 0
  1. // Simple Expression Evaluation
  2. // This program will evaluate simple arithmetic expressions
  3. // represented as a linked-list of tokens.  Keyboard input
  4. // will be accepted into a string, which will be converted
  5. // into that linked list.
  6. //
  7. // If the first symbol in the input string is an operator,
  8. // then the value of the previous expression will be taken
  9. // as an implicit first operand.
  10. //
  11. // The expressions may consist of the following:
  12. // -- integer values (which may have multiple digits)
  13. // -- simple arithmetic operators ( +, -, *, /, % )
  14. // -- matched parentheses for grouping
  15.  
  16. // This implementation consists of a set of mutually-recursive
  17. // functions. which will track the structure of the expression.
  18. //
  19. // A sum expression is the sum or difference of one or more products.
  20. // A product expression is the product or quotient of one or more factors.
  21. // A factor may be a number or a parenthesized sum expression.
  22.  
  23. #include <iostream>
  24. using namespace std;
  25. #include "tokenlist.h"
  26. #include "vartree.h"
  27.  
  28. // Conversion to postfix function
  29. void convertToPostfix(TokenList &, TokenList &);
  30. void postFixVar(ListIterator &, TokenList &, TokenList&, TokenList &);
  31. void postFixSum(ListIterator &, TokenList &, TokenList&, TokenList &);
  32. void postFixProduct(ListIterator &, TokenList &, TokenList&, TokenList &);
  33. void postFixFactor(ListIterator &, TokenList &, TokenList&, TokenList &);
  34.  
  35. int evaluatePostfix(TokenList &, VarTree &);
  36.  
  37. // Evaluate
  38. // Begins to tokenize the string, and then recursively evaluates it.
  39. int evaluate(const char expr[], VarTree &vars) {
  40.     TokenList list = TokenList(expr);                   // Conversion from character array to TokenList
  41.     int value = 0;                                      // Result of artithmetic expression
  42.  
  43.     cout << "Expression: " << (list) << endl;
  44.  
  45.     TokenList listPostfix = TokenList();
  46.     convertToPostfix(list, listPostfix);        // Conversion to postfix
  47.    
  48.     cout << "Expression in postfix: " << (listPostfix) << endl;
  49.    
  50.     value = evaluatePostfix(listPostfix, vars);
  51.  
  52.     return value;
  53. }
  54.  
  55. // ConvertToPostfix
  56. // Converts the infix TokenList to postfix
  57. void convertToPostfix(TokenList &t, TokenList &listPostFix) {
  58.    
  59.     ListIterator iter = t.begin();
  60.     TokenList operStack = TokenList();
  61.  
  62.     postFixVar(iter, t, listPostFix, operStack);
  63. }
  64.  
  65. // postFixVar
  66. // Handles assignment operators ('=') and variables (e.g. Five, Twenty, etc.)
  67. void postFixVar(ListIterator &iter, TokenList &t, TokenList &listPostFix, TokenList &operStack)
  68. {
  69.     Token equalsToken = Token('='); // Equals token to be added at the end
  70.     Token *varToken;                // Token being tested
  71.     string text;                    // Variable name
  72.     bool equalsCheck = false;       // Check for an equals
  73.  
  74.     varToken = &iter.token();               // Tests the token
  75.     text = varToken->tokenText();           // Find the token's text
  76.  
  77.     if (varToken->tokenChar() == '=') {     // If the token is an equals
  78.         equalsCheck = true;                 // The equals will be added after evaluation of the rest of the expression
  79.         iter.advance();                     // Go past the equals
  80.         varToken = &iter.token();           // And save the assumed variable
  81.     }
  82.     else if (text != "+" || text != "-" || text != "*" || text != "/" || text != "%" || text != "(" || text != ")" && !iter.currentIsInteger())     // If the token is a variable and not a number
  83.     {
  84.         if (listPostFix.empty())                                // If the list is empty
  85.             listPostFix.push_back(iter.token());                // Add the variable to the head of the list
  86.         else
  87.             listPostFix.push_front(iter.token());               // Add the variable to the tail of the list
  88.         iter.advance();                                         // And get past it
  89.     }
  90.  
  91.     if (iter != t.end()) {                                      // If the iterator is not at the end
  92.         postFixSum(iter, t, listPostFix, operStack);                // Continue with the rest of the expression
  93.  
  94.         if (equalsCheck) {                                          // If there was an equals somewhere in the expression
  95.             if (listPostFix.empty())                                // If the list is empty
  96.                 listPostFix.push_back(equalsToken);                 // Add the equals to the head of the list
  97.             else
  98.                 listPostFix.push_front(equalsToken);                // Add the equals to the tail of the list
  99.         }
  100.     }
  101. }
  102.  
  103. // postFixSum
  104. // Evaluates a sum expression: the sum or difference of one or more products
  105. // Also deals with negative integers
  106. void postFixSum(ListIterator &iter, TokenList &t, TokenList &listPostFix, TokenList &operStack)
  107. {
  108.     char oper = 0;          // possible operation
  109.     char operTest = 0;      // Check of precedence
  110.     Token operStackToken;   // Token popped off of stack
  111.  
  112.     if (iter.tokenChar() == '-')                            // if negative
  113.     {
  114.         iter.advance();                                     // go past the negative sign
  115.         if (listPostFix.empty()) {                          // If the postfix list is empty
  116.             listPostFix.push_back(-iter.integerValue());    // Save the negative integer as the head of the list
  117.         }
  118.         else {
  119.             listPostFix.push_front(-iter.integerValue());   // Otherise append it to the tail
  120.         }
  121.         iter.advance();
  122.         postFixProduct(iter, t, listPostFix, operStack);    // Keep going through the list
  123.     }
  124.     else
  125.         postFixProduct(iter, t, listPostFix, operStack);
  126.  
  127.     oper = iter.tokenChar();
  128.     while (oper == '+' || oper == '-' && iter != t.end())
  129.     {
  130.         if (operStack.empty()) {                                // If the stack is empty
  131.             operStack.push_back(iter.tokenChar());              // Add the operator to the front
  132.         }
  133.         else {
  134.             ListIterator stackIter = operStack.begin();         // Look at the previous operator
  135.             operTest = stackIter.tokenChar();
  136.             if (operTest == '+' || operTest == '-') {           // If the previous token was of equal precedence (+ or -)
  137.                 operStackToken = operStack.pop_front();         // Pop off that operator
  138.                 listPostFix.push_front(operStackToken);         // And push it onto the postfix stack
  139.             }
  140.             else if (operTest == '*' || operTest == '/' || operTest == '%') {
  141.                 operStackToken = operStack.pop_front();
  142.                 listPostFix.push_front(operStackToken);
  143.             }
  144.             operStack.push_back(iter.tokenChar());              // Add the operator to the front
  145.         }
  146.  
  147.         iter.advance();     // get past the operator
  148.         postFixProduct(iter, t, listPostFix, operStack);
  149.  
  150.         oper = iter.tokenChar();
  151.     }
  152.     while (!operStack.empty()) {
  153.         operStackToken = operStack.first();
  154.         if (operStackToken.tokenChar() == '(') {
  155.             operStackToken = operStack.pop_front();
  156.         }
  157.         else {
  158.             operStackToken = operStack.pop_front();
  159.             listPostFix.push_front(operStackToken);
  160.         }
  161.     }
  162. }
  163.  
  164.  
  165. // postFixProduct
  166. // Processes *, /, and %, making sure that it takes precedence over + and -
  167. void postFixProduct(ListIterator &iter, TokenList &t, TokenList &listPostFix, TokenList &operStack)
  168. {
  169.     char oper = 0;          // possible operation
  170.     char operTest = 0;      // Check of precedence
  171.     Token operStackToken;   // Token popped off of stack
  172.  
  173.     postFixFactor(iter, t, listPostFix, operStack);
  174.     oper = iter.tokenChar();
  175.     while (oper == '*' || oper == '/' || oper == '%' && iter != t.end())
  176.     {
  177.         if (operStack.empty()) {                                // If the stack is empty
  178.             operStack.push_back(iter.tokenChar());              // Add the operator to the front
  179.         }
  180.         else {
  181.             ListIterator stackIter = operStack.begin();
  182.             operTest = stackIter.tokenChar();
  183.             if (operTest == '+' || operTest == '-') {           // If the top of the stack is of lower precedence
  184.                 operStack.push_back(iter.tokenChar());          // Push the higher precedence operator on top
  185.             }
  186.             else if (operTest == '(') {                         // If there is a parenthesis already on the stack
  187.                 operStack.push_back(iter.tokenChar());          // Push the value on
  188.             }
  189.             else {                                              // If the top of the stack is also a *,/, or %
  190.                 operStackToken = operStack.pop_front();         // Pop off that operator
  191.                 listPostFix.push_front(operStackToken);         // And push it onto the postfix stack
  192.             }
  193.         }
  194.         iter.advance(); // get past the operator
  195.         postFixFactor(iter, t, listPostFix, operStack);
  196.         oper = iter.tokenChar();
  197.     }
  198. }
  199.  
  200. // postFixFactor
  201. // Processes numbers or parenthsized expressions
  202. // Pre-condition: the current place in iter is either a number or a parenthesis
  203. void postFixFactor(ListIterator &iter, TokenList &t, TokenList &listPostFix, TokenList &operStack)
  204. {
  205.     if (iter.currentIsInteger() && iter != t.end())
  206.     {
  207.         if (listPostFix.empty()) {
  208.             listPostFix.push_back(iter.integerValue());
  209.         }
  210.         else {
  211.             listPostFix.push_front(iter.integerValue());
  212.         }
  213.         iter.advance();     // get past the digit
  214.     }
  215.     else
  216.     {
  217.         operStack.push_back(iter.tokenChar());
  218.         iter.advance();     // go past assumed (
  219.         postFixVar(iter, t, listPostFix, operStack);
  220.         iter.advance();     // go past assumed )
  221.     }
  222. }
  223.  
  224. // EvaluatePostfix
  225. // Evaluates a TokenList converted to postfix notation
  226. // Precondtion: the TokenList is already converted to postfix
  227. int evaluatePostfix(TokenList &t, VarTree &vars) {
  228.  
  229.     ListIterator iter = t.begin();      // Used to traverse the postfix expression
  230.     TokenList evalStack = TokenList();  // Used in the calculation of the expression
  231.     int tokenType = 0;                  // Used to determine if the token is a variable, an equals, an operator, or a number
  232.     Token evalToken;                    // Temporary save of the token, later on convers to an integer
  233.     string varToken;                    // Temporary save of a variable
  234.     string varToken2;                   // Temporary save of a second variable
  235.  
  236.     int number1;        // Operand 1
  237.     int number2;        // Operand 2
  238.     int number3;        // Result of number 1 +,-,*,/,% 2, or a number being saved into a variable
  239.     char oper;          // Operator being performed on number1 and number2
  240.  
  241.     while (iter != t.end()) {
  242.         oper = iter.tokenChar();
  243.         switch (oper) {     // Cannot possibly be a space or any parenthesis, since these were previously taken out
  244.         case '+':
  245.         case '-':
  246.         case '/':
  247.         case '*':
  248.         case '%':
  249.             tokenType = 1;      // A 1 indicates an operator
  250.             break;
  251.         case '=':               // A 3 indicates an assignment operator
  252.             tokenType = 3;
  253.             break;
  254.         default:                // A 2 (number), a 4 (part of a variable name), or a 0 (unknown token type)
  255.             if (iter.currentIsInteger()) {
  256.                 tokenType = 2;  // A 2 indicates a number
  257.             }
  258.             else
  259.                 tokenType = 4;  // A 4 (part of a variable name)
  260.         }
  261.         switch (tokenType) {
  262.         case 1:         // An operator, assumed to follow two integers
  263.             oper = iter.tokenChar();
  264.             evalToken = evalStack.pop_front();
  265.             if (evalToken.isInteger())                          // If the eval token is a number
  266.                 number2 = evalToken.integerValue();             // Save the number of that token
  267.             else                                                // Otherwise if the token is a variable
  268.                 number2 = vars.lookup(evalToken.tokenText());   // Lookup the value of that variable (nonexisting variable will be assigned a 0 automatically)
  269.             evalToken = evalStack.pop_front();
  270.             if (evalToken.isInteger())                          // If the eval token is a number
  271.                 number1 = evalToken.integerValue();             // Save the number of that token
  272.             else                                                // Otherwise if the token is a variable
  273.                 number1 = vars.lookup(evalToken.tokenText());   // Lookup the value of that variable (nonexisting variable will be assigned a 0 automatically)
  274.             switch (oper) {
  275.                 case '+':
  276.                     number3 = number1 + number2;
  277.                     break;
  278.                 case '-':
  279.                     number3 = number1 - number2;
  280.                     break;
  281.                 case '*':
  282.                     number3 = number1 * number2;
  283.                     break;
  284.                 case '/':
  285.                     number3 = number1 / number2;
  286.                     break;
  287.                 case '%':
  288.                     number3 = number1 % number2;
  289.                     break;
  290.             }
  291.             evalStack.push_back(number3);
  292.             break;
  293.         case 3:     // An equals, assumed to be at the end of the postfix expression (or in a separate area that used to have parenthesis)
  294.             evalToken = evalStack.pop_front();              // Pop off the first token
  295.             if (evalToken.isInteger()) {                    // If the first token is a number
  296.                 number3 = evalToken.integerValue();             // Save that number
  297.                 evalToken = evalStack.pop_front();              // Pop off the next token
  298.                 if (evalToken.isInteger())                      // If it is a number (which it can't be, here for robustness)
  299.                     number3 = evalToken.integerValue();             // Save that number
  300.                 else                                            // If it is a variable
  301.                     varToken = evalToken.tokenText();               // Save the name of that variable
  302.                 vars.assign(varToken, number3);                 // Assign the number to the variable
  303.             }
  304.             else {                                          // If it is a variable
  305.                 varToken = evalToken.tokenText();               // Save the name of that variable
  306.                 evalToken = evalStack.pop_front();              // Pop off the next token
  307.                 if (evalToken.isInteger()) {                    // If it is a number
  308.                     number3 = evalToken.integerValue();             // Save that number
  309.                     vars.assign(varToken, number3);                 // Assign the number to the variable
  310.                 }
  311.                 else {                                          // If it is a variable (A variable being assigned to another variable)
  312.                     varToken2 = evalToken.tokenText();              // Save the name of the LH variable
  313.                     number3 = vars.lookup(varToken);                // Find the value of the RH variable
  314.                     vars.assign(varToken2, number3);                // Assign the value of the RH variable to the LH variable
  315.                 }
  316.             }
  317.             break;
  318.         case 2:     // A number
  319.             evalStack.push_back(iter.integerValue());   // Push it on the stack
  320.             break;
  321.         case 4:     // A variable
  322.             evalToken = iter.token();                   // Save the token
  323.             varToken = evalToken.tokenText();           // Save the variable
  324.             evalStack.push_back(varToken);              // And push it on the stack
  325.             break;
  326.         }
  327.         iter.advance();
  328.     }
  329.     return number3;
  330. }
Advertisement
Add Comment
Please, Sign In to add comment