import io import structures_lib type Stack= { push(_:T)->Void pop->T peek->T size->Number clear->Void contains(_:T)->Boolean isEmpty->Boolean iterator->Iterator asString->String} type Iterator = { reset->Void hasNext->Boolean next->T get->T} type StateType = { addDigit(_:Number)->Void doOp(_:String)->Void enter->Void clear->Void pop->Void exchange->Void} method new->StateType{State.new} // Class representing internal state of calculator. It is responsible // for keeping track of numbers entered and performing operations. class State.new{ // lacking graphics, this will be our "display" for results var display is readable:= io.output // stack of values on which to perform operations; will only contain Numbers var numStack:Stack is readable := structures_lib.newStack // list of digits added but not yet entered var digitsEntered:Stack is readable := structures_lib.newStack // number entered so far var currentNum:Number is readable := 0 method addRec(i:Iterator)->Number is confidential{ if(!i.hasNext) then {0} else{i.next + 10 * addRec(i)} } // User has "clicked" on a digit button // i.e. has entered a digit into input // @post updates current number and displays it in text field method addDigit(value:Number)->Void is public{ //reset current number, add value to list of digits added currentNum := 0 digitsEntered.push(value) var iter:Iterator := digitsEntered.iterator currentNum := addRec(iter) display.write("Display: {currentNum}\n") } // User has "clicked" on operator button // i.e. has entered an operator into input // @pre stack is not empty, enough values to perform // selected operation, and not dividing by 0 // @post performs selected operation method doOp(op:String)->Void is public{ enter //adds current # to stack var firstNum:Number := 0 //first num entered var secondNum:Number := 0 //second num entered var sign:String := op //operation sign entered var result:Number := 0 //result of operation //prints error message if fewer than two values // in stack if(numStack.size < 2) then{ clear display.write("Error: not enough values for this operation\n") } else{ //gets & removes top two values from stack secondNum := numStack.pop firstNum := numStack.pop //displays error message if user attempts to divide by 0 if((sign == "/") && (secondNum == 0)) then { clear display.write("Error: attempted to divide by zero\n") } else{ if(sign == "+") then {result := firstNum + secondNum} if(sign == "-") then {result := firstNum - secondNum} if(sign == "*") then {result := firstNum * secondNum} if(sign == "/") then {result := (firstNum / secondNum).truncate} } //add result to stack & display numStack.push(result) display.write("Display: {result}\n") } } // user has "clicked" enter button // i.e. user has entered "enter" // @pre list of digits entered not empty // @post add current number to stack method enter->Void is public{ if(!digitsEntered.isEmpty) then { numStack.push(currentNum) currentNum := 0 digitsEntered.clear} } // user has entered "clear" // @post clears stack method clear->Void is public{ numStack.clear display.write("Display: 0\n")} // user has entered "pop" // @pre stack is not empty // @post removes top value from stack method pop->Void is public{ enter if(numStack.isEmpty) then {display.write("Display: 0\n")} else{ numStack.pop if(numStack.isEmpty) then {display.write("Display: 0\n")} else{display.write("Display: {numStack.peek}\n") } } } // user has entered "exch" // @pre stack has at least two values // @post switches the top two values of stack method exchange->Void is public{ enter if(numStack.size >= 2) then{ var top:Number := numStack.pop var bottom:Number := numStack.pop numStack.push(top) numStack.push(bottom) display.write("Display: {numStack.peek}\n") } else{ clear display.write("Display: Error\n") } } }