0

I'm trying to implement a simple Revrse Polish Notation calculator in Angular.js and so far the code can handle single-digit calculations like

2 3 +

How can I modify it to handle inputs with more than one digit, such as:

122 233 +

Its an idea that occurred to me after participating in this discussion). I suspect that I may have to use onkeypress and parseInt and/or parseFloat but am unsure. I look forward to your thoughts. Thank you.

JavaScript:

var calcApp = angular.module('calcApp', []);

calcApp.controller('calcCtrl', function ($scope) {

    $scope.leftOperand = "";
    $scope.operator = "";
    $scope.rightOperand = "";
    $scope.answer = "";


    $scope.setOperand = function (operandEntered) {
        ($scope.leftOperand)
        ? $scope.rightOperand += operandEntered + " "
        : $scope.leftOperand += operandEntered + " ";
 console.log($scope.leftOperand,$scope.rightOperand);
    };



    $scope.setOperator = function (operatorEntered) {
        $scope.operator = operatorEntered;
    };

    $scope.getAnswer = function () {
        var result = $scope.leftOperand + $scope.operator + $scope.rightOperand;
        var answer = eval(result);

        if (answer % 1 !== 0){   // % 1 to identify floats
            $scope.answer = answer.toFixed(2);
        }
        else {$scope.answer = answer;}

        $scope.leftOperand = $scope.answer;
        $scope.operator = "";
        $scope.rightOperand = "";
    };

    $scope.setClear = function (a) {
          $scope.leftOperand = "";
          $scope.operator = "";
          $scope.rightOperand = "";
          $scope.answer = "";

    };


});
slevy1
  • 3,797
  • 2
  • 27
  • 33
  • This question is way too broad. Are you asking about syntax parsing or are you asking someone to give you advice on a more complicated app? If you're looking for advice, StackOverflow is the wrong place. – Soviut Jun 10 '17 at 23:21
  • Essentially, I'm asking for how can one write code so that the input values are greater than one digit operands. I did this myself years ago in C in a Windows environment, so I know it can be done. – slevy1 Jun 10 '17 at 23:24
  • You should really have made an attempt at it so you have some code to show. Questions like these get closed all the time for being too broad, opinion-based or just "write my code for me". You could really improve your answer by showing your attempt as an actual formatted code block in your question. – Soviut Jun 10 '17 at 23:31
  • 1
    parse the input as a string, easier than tracking which click belongs to which number – Dale Jun 10 '17 at 23:31
  • @Dale, nice suggestion -- I'll check it out. – slevy1 Jun 10 '17 at 23:42

2 Answers2

3

Your 2nd example already strays from your (A B Operator) syntax. If you're planning to keep it consistent to make parsing easier it should be

122 (233 41234 +) +

As with any programming language, you'll need to start doing some extra parsing work to address the fact that you can no longer simply split on spaces. If you did, you'll wind up with

['122', '(233', '41234', '+)', '+']

Explaining how to parse your own domain-specific language (DSL) is beyond the scope of this answer. Suffice to say you may want to look into tokenizers to make the job easier.

Finally, this type of nested syntax can be handled with recursion. Meaning you take your parsed values and search the "tree" for branches. If you find a branch, follow it, if it has a branch, follow that, etc. Continue following branches until you find the deepest nodes. Calculate them, then return their values up a level. Keep doing this recursively and eventually you'll get back to the top-most level and have a single value left from all those child calculations. It's this value that you return to the user.

In terms of when you should do this, you could perform this action every time the user clicks a button, or only do it when they click the "calculate" button on your calculator. That's up to you.

Soviut
  • 88,194
  • 49
  • 192
  • 260
0

This was really much easier than I expected and did not need onkeypress, ParseInt or ParseFloat. Here's what ultimately worked:

var calcApp = angular.module("calcApp", []);

calcApp.controller("calcCtrl", function($scope) {
  $scope.leftOperand = "";
  $scope.operator = "";
  $scope.rightOperand = "";
  $scope.answer = "";

  var left = false; // flags
  var right = false;

  $scope.setOperand = function(operandEntered) {
    if (left == false && operandEntered >= 0 && operandEntered <= 9) {
      $scope.leftOperand += operandEntered;
      if (operandEntered == "") {
        left = true;
      }
    } else if (right == false) {
      $scope.rightOperand += operandEntered;
    }
  };

  $scope.setOperator = function(operatorEntered) {
    if (left == true && $scope.rightOperand) {
      $scope.operator = operatorEntered;
      right = true;
    }
    else if($scope.rightOperand=="")
    {
        left = true; // end of leftOperand input
    }
  };

  $scope.getAnswer = function() {
    var result = $scope.leftOperand + $scope.operator + $scope.rightOperand;
    var answer = eval(result);

    if (answer % 1 !== 0) {
      // % 1 to identify floats
      $scope.answer = answer.toFixed(2);
    } else {
      $scope.answer = answer;
    }

    $scope.leftOperand = $scope.answer;
    $scope.operator = "";
    $scope.rightOperand = "";
  };

  $scope.setClear = function() {
    $scope.leftOperand = "";
    $scope.operator = "";
    $scope.rightOperand = "";
    $scope.answer = "";
    left = false;
    right = false;
  };
});
#answerScreen {
  background-color: lightgray;
  border: 3px inset white;
  font: 23px Arial, Helvetica;
  font-weight: bold;
  height: 34px;
  padding-left: 3px;
  width: 215px;
}

button {
  border-radius: 10px;
  border-color: pink;
  font-weight: bold;
  height: 2em;
  width: 2em;
}

#rpn {
  text-align: center;
}

.calcButtonsrow {
  padding: 4px;
}

#calcButtonsBox {
  border-style: groove;
}

#clear {
  background-color: #FFAAAA;
}

body {
  padding-top: 7vh;
}

#space {
  background-color: #cff;
  text-align: center;
  padding: 0;
}

.overflow-hidden {
  overflow: hidden;
}

#plusSign,
#multiplySign,
#minusSign,
#divideBySign {
  border-radius: 10px;
  font-weight: bold;
  height: 2em;
  width: 2em;
}

#plusSign:hover,
#multiplySign:hover,
#minusSign:hover,
#equalSign:hover,
#divideBySign:hover {
  background-color: #ff9;
  color: black;
}

#equalSign {
  color: #FA6800;
}

#modalCalcButt {
  height: 150px !important;
  width: 150px !important;
}

#OpenSource {
  font-weight: bold;
}
<html lang="en-us" ng-app="calcApp" class="full-height">

<head>
  <title></title>
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>


<body>
  <div class="theCalculator" ng-controller="calcCtrl">
    <div class="calcButtonsrow" id="1stLine">
      <div id="answerScreen">
        <span>{{leftOperand}}</span>
        <span>{{rightOperand}}</span>
        <span>{{operator}}</span>
        <span>{{clear}}</span>
      </div>
    </div>
    <div><span>RPN Calculator - Usage: </span><span id="OpenSource">Number(s) {Sp} Number(s) {operator} {=}</span></div>
    <div class="calcButtonsrow" id="2ndLine">
      <button class="number" id="7" ng-click="setOperand('7')">7</button>
      <button class="number" id="8" ng-click="setOperand('8')">8</button>
      <button class="number" id="9" ng-click="setOperand('9')">9</button>
      <button id="divideBySign" ng-click="setOperator('/')" class=" operator">/</button>
    </div>
    <div class="calcButtonsrow" id="3rdLine">
      <button class="number" id="4" ng-click="setOperand('4')">4</button>
      <button class="number" id="5" ng-click="setOperand('5')">5</button>
      <button class="number" id="6" ng-click="setOperand('6')">6</button>
      <button id="multiplySign" ng-click="setOperator('*')" class=" operator">*</button>
    </div>
    <div class="calcButtonsrow" id="4thLine">
      <button class="number" id="1" ng-click="setOperand('1')">1</button>
      <button class="number" id="2" ng-click="setOperand('2')">2</button>
      <button class="number" id="3" ng-click="setOperand('3')">3</button>
      <button id="minusSign" ng-click="setOperator('-')" class=" operator">-</button>

    </div>
    <div class="calcButtonsrow" id="5thLine">
      <button id="clear" ng-click="setClear('C')">C</button>
      <button class="number" id="0" ng-click="setOperand('0')">0</button>
      <button id="equalSign" ng-click="getAnswer('=')" ng-disabled="!leftOperand || !rightOperand || !operator">=</button>
      <button id="plusSign" ng-click="setOperator('+')" class="operator">+</button>
      <button id="space" ng-click="setOperand('')" class="operator">Sp</button>
    </div>
  </div>


  <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js">
  </script>

</body>

</html>

The solution hinges on setting two flags for the operands. Initially they are false. Upon the user striking the space button which ironically is set to an empty string, the left flag is set to true to signal the end of the input for the left operand. The right operand's end of input is marked by the user clicking an operator button. The code is also forgiving in case the user clicks an operator instead of the "Sp" button, in which case the end of input for the left operand is marked by setting the left flag. Note, if the user picks the wrong operator, the code allows for easily choosing a different one.

slevy1
  • 3,797
  • 2
  • 27
  • 33