<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<link rel="stylesheet" href="main.css">
    <script src="https://code.jquery.com/jquery-2.2.2.min.js" integrity="sha256-36cp2Co+/62rEAAYHLmRCPIych47CvdM+uTBJwSzWjI=" crossorigin="anonymous"></script>
	<script src="common.js"></script>
    <script src="infix.js"></script>
    <script src="postfix.js"></script>
    <script src="main.js"></script>
</head>
<body>
	<h1>Infix to Postfix - Calculator</h1>
	<div>
        <div>
            #a = <input type="text" value="1,2,3,4,5" id="variable_a" /><br/>
            #b = <input type="text" value="300, 200" id="variable_b" /><br/>
            <input type="text" value="5+2*$sum(1,2,3) + 2 + $sum($avg(#b), #a, 7)" id="expression" />
            <button type="button" id="btnCalc">Calculate</button>
        </div>
        <div class="hide">
            Postfix expression: <span id="spanPostfix"></span>
        </div>
        <div>
            <h3>Result:</h3>
            <span id="spanResult"></span>
        </div>
        <div>
            <h3>Example:</h3>
            <span id="example1"></span>
        </div>
	</div>
</body>
</html>
Infix to Postfix converter and Postfix calculator

See more about the project on my http://www.ivansivak.net/blog/simple-math-evaluator-infix-to-postfix-converter-and-calculator-reverse-polish-notation
var Common = (function(){
    
	var tokenType = { operand: 1, operator: 2, leftPar: 3, rightPar: 4, variable: 5, func: 6 , not: 7, comparator: 8, comma: 9, wall:10},
        operators = ['+', '-', '*', '/' ];
    
    var determineToken = function (char) {
        if (~operators.indexOf(char)) return tokenType.operator;
        if (char[0] == '$') return tokenType.func;
        if (char[0] == '#') return tokenType.variable;
        if (char[0] == '|') return tokenType.wall;
        if (char == '<' || char == '>' || char == '<=' || char == '>=') return tokenType.comparator;
        
        switch (char) {
            case '(':
                return tokenType.leftPar;
            case ')':
                return tokenType.rightPar;
            case '!':
                return tokenType.not;
            case ',':
                return tokenType.comma;
            default:
                return tokenType.operand;
        }
    };
    
    var trimSpaces = function (str) {
        return str.replace(/\s+/g, '');
    };
    
    var isAlphaNumeric = function (str) {
      return /^[a-z0-9]+$/i.test(str);
    };
    
    var tokenize = function (str) {
        var num = '',
            res = [],
            leftParseStack = [];
        
        for (var i = 0; i < str.length; i++){
          console.log(str[i] + ':' + Common.determineToken(str[i]));
            switch (Common.determineToken(str[i])) {
                case Common.tokenType.func:
                  num += (str[i]);
                  while(isAlphaNumeric(str[i+1]) && i< str.length){
                    i++;
                    num += (str[i]);
                  }
                  if (str[i+1] == '(') {
                    i++;
                    num += (str[i]);
                  } else {
                    //invalid expression, missing ( for function
                  }
                  res.push(num);
                  leftParseStack.push(Common.tokenType.func);
                  num = '';
                  break;
                case Common.tokenType.variable:
                  num += (str[i]);
                  while(isAlphaNumeric(str[i+1]) && i< str.length){
                    i++;
                    num += (str[i]);
                  }
                  res.push(num);
                  num = '';
                  break;
                case Common.tokenType.comparator:
                  if ($.isNumeric(num)) res.push(parseFloat(num));
                  num = (str[i]);
                  if(str[i+1]=='='){
                    i++;
                    num += (str[i]);
                  }
                  res.push(num);
                  num = '';
                  break;
                case Common.tokenType.operand:
                    num += $.trim(str[i]);
                    break;
                case Common.tokenType.operator:
                    if ($.isNumeric(num)) res.push(parseFloat(num));
                    res.push(str[i]);
                    num = '';
                    break;
                case Common.tokenType.comma:
                    if ($.isNumeric(num)) res.push(parseFloat(num));
                    num = '';
                    res.push(str[i]);
                    break;
                case Common.tokenType.leftPar:
                    if ($.isNumeric(num)) res.push(parseFloat(num));
                    res.push(str[i]);
                    num = '';
                    leftParseStack.push(Common.tokenType.leftPar);
                    break;
                case Common.tokenType.rightPar:
                  if (Common.tokenType.func == leftParseStack.pop()){
                      if ($.isNumeric(num)) res.push(parseFloat(num));
                      res.push('|');
                      num = '';
                    } else {
                      if ($.isNumeric(num)) res.push(parseFloat(num));
                      res.push(str[i]);
                      num = '';
                    }
                    break;
            }
        }
        if (num != '') res.push(num);
        return res;
    }
    
    return {
        tokenType: tokenType,
        determineToken: determineToken,
        trimSpaces: trimSpaces,
        tokenize: tokenize
    }
})();
/**
 * Examples:
 * ============================================
 * 2*3-4/5 = 23*45/-
 * 5+3*2 = 5 3 2*+
 * 10 + 3 * 5 / (16 - 4) = 10 3 5 * 16 4 - / +
 * 2 * 5 + 3 - 2 * (8 / (4 / 2)) + (3 * 3) = 2 5 * 3 + 2 8 4 2 / / * - 3 3 * + 
 */

var Infix = (function() {
  var postfix,
    stack;

  var precedence = function(operator) {
    switch (operator) {
      case '*':
      case '/':
        return 4;
      case '+':
      case '-':
      case '>':
      case '<':
        return 3;
      case ',':
        return 5;
      case '(':
        return 2;
      case '!':
        return 6;
      default:
        if (operator[0] == '$') {
          return 2;
        }
        if (operator[0] == '#') {
          //return 4;
        }
    }
  };

  var processOperand = function(char) {
    postfix += char + ' ';
  };

  var processOperator = function(char) {
    while (stack.length > 0 &&
      (precedence(stack[stack.length - 1]) >= precedence(char))) {
      postfix += stack.pop() + ' ';
    }
    stack.push(char);
  };

  var processLeftPar = function(char) {
    stack.push(char);
  };

  var processRightPar = function(char) {
    var j = stack.length - 1,
      ce;
    while (true && stack.length > 0) {
      ce = stack.pop();
      if (ce == '(') break;
      postfix += ce + ' ';
    }
  };
  
  var processWall = function(char) {
    var j = stack.length - 1,
      ce;
    while (true) {
      ce = stack.pop();
      if (ce.length > 1 && ce[ce.length-1] == '('){
        postfix += ce + ' ';
        break;
      }
      postfix += ce + ' ';
      if (stack.length ==0) break;
    }
  };

  var processFunc = function(char) {
    postfix += '|' + ' ';
    stack.push(char);
  };

  var processComma = function(char) {
    var j = stack.length - 1,
      ce;
    while (true) {
      ce = stack.pop();
      if (ce.length > 1 && ce[ce.length-1] == '('){
        ce = stack.push(ce);
        break;
      }
      postfix += ce + ' ';
      if (stack.length ==0) break;
    }
  };


  var processToken = function(char) {
    var type = Common.determineToken(char);
    
    switch (type) {
      case Common.tokenType.operand:
        processOperand(char);
        break;
      case Common.tokenType.operator:
        processOperator(char);
        break;
      case Common.tokenType.leftPar:
        processLeftPar(char);
        break;
      case Common.tokenType.rightPar:
        processRightPar(char);
        break;
      case Common.tokenType.func:
        processFunc(char);
        break;
      case Common.tokenType.not:
        processOperator(char);
        break;
      case Common.tokenType.variable:
        processOperator(char);
        break;
      case Common.tokenType.comparator:
        processOperator(char);
        break;
      case Common.tokenType.wall:
        processWall(char);
        break;
      case Common.tokenType.comma:
        processComma(char);
        break;
    }
  };

  var start = function(infix) {
    var tokens = Common.tokenize(infix);
    console.log(tokens);
    for (var i = 0; i < tokens.length; i++) {
      processToken(tokens[i]);
      console.log(stack);
      console.log(postfix);
    }
    return postfix;
  };

  var toPostfix = function(infix) {
    postfix = '';
    stack = [];
    stack.push('(');
    return start(infix + ')');
  };

  return {
    toPostfix: toPostfix
  }

})();
//fork from http://www.ivansivak.net/blog/simple-math-evaluator-infix-to-postfix-converter-and-calculator-reverse-polish-notation
//add support to function operator, variable operation, comparator

$(document).ready(function () {
    $('#btnCalc').click(function () {
        var infix = $('#expression').val(),
            
            postfix = Infix.toPostfix(infix);
            
        $('#spanPostfix').text(postfix).parent().fadeIn();
        $('#spanResult').text(Postfix.calc(postfix));
        
        
    });
    var example = ['$avg(#a)', '1>2', '$sum(#a)>6', '$sum(#a)', '$avg(#b)+$sum(#a)'];
    var exampleTxt = '';
    for (var i =0 ; i <example.length ; i++){
      $('#example1').append(
        '<p>' + example[i] + ' = ' + Postfix.calc(Infix.toPostfix(example[i]))) +'</p>'
      ;
    }
      
    //$('#example2').text(Postfix.calc(Infix.toPostfix('2>1')));
    //$('#example3').text(Postfix.calc(Infix.toPostfix()));
    //$('#example4').text(Postfix.calc(Infix.toPostfix()));
    //$('#example5').text(Postfix.calc(Infix.toPostfix()));
});
#spanResult{
    font-size: 16px;
    font-weight: bold;
    color: rgb(teal);
}
.hide{
    display: none;
}
input[type="text"]{
    width: 250px;    
}
var Postfix = (function () {
    var stack = [];
    
    var processOperand = function (char) {
        stack.push(parseFloat(char));
    };

    var sumOf = function (hashTag){
      return 100; //testing
    };

    var valueOf = function (hashTag){
      if (hashTag == '#a'){
        return 11; //testing
      } else {
        return 0;
      }
    };
    
    var div100 = function (value){
      return value / 100;
    };

    var processFunc = function (char) {
      var temp = [];
      while (true){
        var right = stack.pop();
        if (right[right.length-1] == '|') break;
        temp.push(right);
      }
      if (char == '$sum('){
        var result = 0;
        for (var i=0;i<temp.length;i++){
          result+=temp[i];
        }
        stack.push(result);
      }
      if (char == '$avg('){
        var result = 0;
        for (var i=0;i<temp.length;i++){
          result+=temp[i];
        }
        stack.push(result/temp.length);
      }
    };


    var processVariable = function (char) {
        switch (char) {
            case '#a':
                var var_a = $('#variable_a').val();
                var_a.split(',').forEach(function (va) {
                  stack.push(parseFloat(va));
                });
                break;
            case '#b':
                var var_b = $('#variable_b').val();
                var_b.split(',').forEach(function (va) {
                  stack.push(parseFloat(va));
                });
                break;

        }
    };


    var processUnionOperator = function (char) {
        var right = (stack.pop());

        switch (char) {
            case '!':
                stack.push(right==1?0:1);
                break;
            case '$sumOf':
                stack.push(sumOf(right));
                break;
            case '$valueOf':
                stack.push(valueOf(right));
                break;
            case '$div100':
                stack.push(div100(right));
                break;
        }
    };

    var processWall = function (char) {
      stack.push(char);
    };

    var processOperator = function (char) {
        var right = (stack.pop()),
            left = (stack.pop());
            
        switch (char) {
            case '+':
                stack.push(left + right);
                break;
            case '-':
                stack.push(left - right);
                break;
            case '*':
                stack.push(left * right);
                break;
            case '/':
                stack.push(left / right);
                break;
            case '>':
                stack.push(left > right ? 1:0);
                break;
            case '>':
                stack.push(left >= right ? 1:0);
                break;
            case '<':
                stack.push(right > left ? 1:0);
                break;
            case '<=':
                stack.push(right >= left ? 1:0);
                break;
            case '=':
                stack.push(right = left ? 1:0);
                break;
            case '!=':
                stack.push(right != left ? 1:0);
                break;
        }
    };
    
    var processToken = function (char) {
      console.log('processToken' + char);
        var type = Common.determineToken(char);

        switch (type) {
            case Common.tokenType.operand:
                processOperand(char);
                break;
            case Common.tokenType.operator:
            case Common.tokenType.comparator:
                processOperator(char);
                break;
            case Common.tokenType.func:
                processFunc(char);
                break;
            case Common.tokenType.variable:
                processVariable(char);
                break;
            case Common.tokenType.not:
                processUnionOperator(char);
                break;
            case Common.tokenType.wall:
                processWall(char);
                break;
        }
    };
    
    var calc = function (postfix) {
        var tokens;
        
        stack = [];
        tokens = postfix.split(' ');
        tokens.splice(tokens.length - 1, 1);
        while(tokens.length>0){
          processToken(tokens.shift());
        }
        /*for (var i = 0; i < tokens.length; i++) {
            processToken(tokens[i]);
        }*/
        
        return stack.pop();
    };
    
    return {
        calc: calc
    }
})();