<!DOCTYPE html>
<html>

<head>
  <meta charset="utf-8" />
  <title></title>
  <link rel="stylesheet" href="style.css" />
  <script data-require="jquery" data-semver="2.0.3" src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
  <script src="script.js"></script>
</head>

<body>
  <h2>Javascript RPN (Reverse Polish Notation) with Shunting Yard implementation by Paul Lan</h2>
  <h3>Input your Expression here:</h3>
  <input id="expression_input" value="( a || b ) && ( c &&  ( d || e) )" placeholder="Support &&, ||, (, ) " size="50" />
  <div>
    <h3>Parsed output</h3>
    <div id="output"></div>
  </div>
  <p />
  <hr />
  <h3>Reference: </h3>
  <ol>
  <li> RPN: 
  <a href="http://en.wikipedia.org/wiki/Reverse_Polish_notation">http://en.wikipedia.org/wiki/Reverse_Polish_notation</a></li>
  <li> Shunting Yard: 
    <a href="http://en.wikipedia.org/wiki/Shunting-yard_algorithm">http://en.wikipedia.org/wiki/Shunting-yard_algorithm</a>
  </li>
</body>


</html>
// Add your javascript here
var FIELDSPLITER = ':'; // forRPN: N;
var FIELDSPLITERPattern = /:/; // forRPN: N;
var AND = '&&'; // forRPN: Y; priority: 2
var ANDForReg = '\\&\\&'; // forRPN: Y; priority: 2
var OR = '||'; // forRPN: Y; priority: 3
var ORForReg = '\\|\\|'; // forRPN: Y; priority: 3
var LEFTPS = '('; // forRPN: Y; priority: Left parenthesis
var LEFTPSForReg = '\\('; // forRPN: Y; priority: Left parenthesis
var RIGHTPS = ')'; // forRPN: Y; priority: right parenthesis
var RIGHTPSForReg = '\\)'; // forRPN: Y; priority: right parenthesis
var fieldListPatternStr = '[^' + AND + OR + LEFTPS + RIGHTPS + ']+'; // valid field pattern

var splitterList = [OR, AND, LEFTPS, RIGHTPS];
var splitterListRegExp = [ORForReg, ANDForReg, LEFTPSForReg, RIGHTPSForReg];
var splitterListPattern = new RegExp(splitterListRegExp.join('|') + '|' + fieldListPatternStr, 'g');
var fieldListRegExp = new RegExp(fieldListPatternStr, 'g');
var operatorListPattern = new RegExp(splitterListRegExp.join('|'));
var RPNPriorityGroup = {};
RPNPriorityGroup[OR] = 3;
RPNPriorityGroup[AND] = 2;
var ANDORPattern = new RegExp(ANDForReg + '|' + ORForReg);


var makeRPN = function(inputValue) {

  if (!inputValue) {
    return false;

  }

  var inputRPN = [];

  inputRPN = inputValue.match(splitterListPattern);
  var tmpStackRPN = [];
  var outputRPN = [];

  // there are some unpaired parenthesis in the input
  var isUnPairedPs = false;
  var utils = {
    pushToOutput: function(item) {
      outputRPN.push(item);
    },
    topOfTmpStack: function() {
      return tmpStackRPN[tmpStackRPN.length - 1]
    },
    popItemOfStackToOutputRPNUntilLeftPs: function(indexOfItemInInputRPN) {
      var item;
      while ((item = tmpStackRPN.pop()) !== LEFTPS) {
        utils.pushToOutput(item);

      }

      if (typeof item === 'undefined' && !tmpStackRPN.length && (indexOfItemInInputRPN === inputRPN.length - 1)) {
        // un pair parenthesis
        isUnPairedPs = true;

      }


    },
    popAllItemOfStack: function() {

      var item;


      while (item = tmpStackRPN.pop()) {
        if (item === LEFTPS) {
          isUnPairedPs = true;

        } else {
          utils.pushToOutput(item);
        }

      }


    }
  };
  var top;
  for (var i = 0, element; i < inputRPN.length; i++) {
    element = inputRPN[i].trim();
    if (operatorListPattern.test(element)) {
      // all operators

      if (element === LEFTPS) {
        // left parenthesis
        tmpStackRPN.push(element);


      } else if (element === RIGHTPS) {
        // right parenthesis
        utils.popItemOfStackToOutputRPNUntilLeftPs(i);


      } else {
        // if the input operator priority is <= outputUtil.top()
        top = utils.topOfTmpStack();

        // for operator with priority (not parenthesis)
        if (top && (top != LEFTPS) && RPNPriorityGroup[element] <= RPNPriorityGroup[top]) {
          utils.pushToOutput(tmpStackRPN.pop());
          tmpStackRPN.push(element);
        } else {
          tmpStackRPN.push(element);


        }
      }
    } else {
      // text
      // remove empty string
      if (element !== '') {
        utils.pushToOutput(element);
      }
    }
  }

  // pop out the rest stacked operator
  utils.popAllItemOfStack();

  return !isUnPairedPs && outputRPN || false;
}


$(function() {
  
  var $input = $('#expression_input');
  var parseIt = function() {

    $('#output').html(makeRPN($input.val()));

    // debugger;


  };
  $input.keyup(parseIt);
  parseIt();
});
/* Put your css in here */

h2 {
  color: blue;
}
#output {
  letter-spacing: 3px;
}