Argentum_02

condition_parser.cpp

Apr 9th, 2019
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.18 KB | None | 0 0
  1. #include "condition_parser.h"
  2. #include "token.h"
  3. #include "date.h"
  4.  
  5. #include <map>
  6. using namespace std;
  7.  
  8. template <class It> shared_ptr<Node> ParseComparison(It& current, It end) {
  9.   if (current == end) {
  10.     throw logic_error("Expected column name: date or event");
  11.   }
  12.  
  13.   Token& column = *current;
  14.   if (column.type != TokenType::COLUMN) {
  15.     throw logic_error("Expected column name: date or event");
  16.   }
  17.   ++current;
  18.  
  19.   if (current == end) {
  20.     throw logic_error("Expected comparison operation");
  21.   }
  22.  
  23.   Token& op = *current;
  24.   if (op.type != TokenType::COMPARE_OP) {
  25.     throw logic_error("Expected comparison operation");
  26.   }
  27.   ++current;
  28.  
  29.   if (current == end) {
  30.     throw logic_error("Expected right value of comparison");
  31.   }
  32.  
  33.   Comparison cmp;
  34.   if (op.value == "<") {
  35.     cmp = Comparison::Less;
  36.   } else if (op.value == "<=") {
  37.     cmp = Comparison::LessOrEqual;
  38.   } else if (op.value == ">") {
  39.     cmp = Comparison::Greater;
  40.   } else if (op.value == ">=") {
  41.     cmp = Comparison::GreaterOrEqual;
  42.   } else if (op.value == "==") {
  43.     cmp = Comparison::Equal;
  44.   } else if (op.value == "!=") {
  45.     cmp = Comparison::NotEqual;
  46.   } else {
  47.     throw logic_error("Unknown comparison token: " + op.value);
  48.   }
  49.  
  50.   const string& value = current->value;
  51.   ++current;
  52.  
  53.   if (column.value == "date") {
  54.     istringstream is(value);
  55.     return make_shared<DateComparisonNode>(cmp, ParseDate(is));
  56.   } else {
  57.     return make_shared<EventComparisonNode>(cmp, value);
  58.   }
  59. }
  60.  
  61. template <class It>
  62. shared_ptr<Node> ParseExpression(It& current, It end, unsigned precedence) {
  63.   if (current == end) {
  64.     return shared_ptr<Node>();
  65.   }
  66.  
  67.   shared_ptr<Node> left;
  68.  
  69.   if (current->type == TokenType::PAREN_LEFT) {
  70.     ++current; // consume '('
  71.     left = ParseExpression(current, end, 0u);
  72.     if (current == end || current->type != TokenType::PAREN_RIGHT) {
  73.       throw logic_error("Missing right paren");
  74.     }
  75.     ++current; // consume ')'
  76.   } else {
  77.     left = ParseComparison(current, end);
  78.   }
  79.  
  80.   const map<LogicalOperation, unsigned> precedences = {
  81.       {LogicalOperation::Or, 1}, {LogicalOperation::And, 2}
  82.   };
  83.  
  84.   while (current != end && current->type != TokenType::PAREN_RIGHT) {
  85.     if (current->type != TokenType::LOGICAL_OP) {
  86.       throw logic_error("Expected logic operation");
  87.     }
  88.  
  89.     const auto logical_operation = current->value == "AND" ? LogicalOperation::And
  90.                                                            : LogicalOperation::Or;
  91.     const auto current_precedence = precedences.at(logical_operation);
  92.     if (current_precedence <= precedence) {
  93.       break;
  94.     }
  95.  
  96.     ++current; // consume op
  97.  
  98.     left = make_shared<LogicalOperationNode>(
  99.         logical_operation, left, ParseExpression(current, end, current_precedence)
  100.     );
  101.   }
  102.  
  103.   return left;
  104. }
  105.  
  106. shared_ptr<Node> ParseCondition(istream& is) {
  107.   auto tokens = Tokenize(is);
  108.   auto current = tokens.begin();
  109.   auto top_node = ParseExpression(current, tokens.end(), 0u);
  110.  
  111.   if (!top_node) {
  112.     top_node = make_shared<EmptyNode>();
  113.   }
  114.  
  115.   if (current != tokens.end()) {
  116.     throw logic_error("Unexpected tokens after condition");
  117.   }
  118.  
  119.   return top_node;
  120. }
Add Comment
Please, Sign In to add comment