/* calc.pl -- Action Semantics and Prototype for simple calculator */ /* Action specification: [Acc,Op,Disp,Mem] --Action-->[Acc',Op',Disp',Mem'] */ /* declare digits */ digit(0). digit(1). digit(2). digit(3). digit(4). digit(5). digit(6). digit(7). digit(8). digit(9). mode(init). /* init at beginning of number, cont while accumulating number */ accumulator(0). memory(0). displayed(0). op(nop). /* [-,-,d1,-] --push(D)--> [-,-,D,-] if mode(init) */ push(D) :- digit(D), retract(mode(init)), retract(displayed(Disp)), assert(displayed(D)), assert(mode(cont)). /* [-,-,Disp,-] --push(D)--> [-,-,10*Disp+D,-] if mode(cont) */ push(D) :- digit(D), mode(cont), retract(displayed(Disp)), D1 is 10*Disp + D, assert(displayed(D1)). /* [a,op,d,m] --push(clear)--> [0,nop,0,0] */ push(clear) :- retract(accumulator(A)), retract(op(O)), retract(displayed(D)), retract(memory(M)), assert(accumulator(0)), assert(op(nop)), assert(displayed(0)), assert(memory(0)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(mem_rec)--> [a,op,m,m] */ push(mem_rec) :- memory(M), retract(displayed(D)), assert(displayed(M)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(plus)-->[op(a,d),plus,d,m] */ push(plus) :- retract(accumulator(A)), displayed(D), retract(op(O)), eval(O,A,D,R), assert(accumulator(R)), assert(op(plus)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(minus)--> [op(a,d,minus,d,m] */ push(minus) :- retract(accumulator(A)), displayed(D), retract(op(O)), eval(O,A,D,R), assert(accumulator(R)), assert(op(minus)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(times)--> [op(a,d),times,d,m] */ push(times) :- retract(accumulator(A)), displayed(D), retract(op(O)), eval(O,A,D,R), assert(accumulator(R)), assert(op(times)), retract(mode(Mode)), assert(mode(init)). eval(plus,A,B,R) :- R is A + B. eval(times,A,B,R) :- R is A * B. eval(minus,A,B,R) :- R is A - B. eval(nop,A,B,B). /* [a,op,d,m] --push(equal)--> [a,nop,op(a,d),m] */ push(equal) :- accumulator(A), retract(op(O)), retract(displayed(D)), assert(op(nop)), eval(O,A,D,R), assert(displayed(R)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(mem_plus)--> [a,nop,v,plus(m,v)] where v=op(a,d) */ push(mem_plus) :- accumulator(A), retract(op(O)), retract(displayed(D)), eval(O,A,D,R), assert(op(nop)), assert(displayed(R)), retract(memory(M)), eval(plus,M,R,S), assert(memory(S)), retract(mode(Mode)), assert(mode(init)). /* [a,op,d,m] --push(plus_minus)--> [a,op,-d,m] */ push(plus_minus) :- retract(displayed(D)), D1 is -D, assert(displayed(D1)), retract(mode(Mode)), assert(mode(init)). /* Calc reads button events and performs actions corresponding to the buttons that were pushed. Thus 'calc' provides an "animator" for the action specifications. Since most of the specification consists of the action clauses, we have what essentially amounts to an "executable specification" of our calculator. */ calc :- read(Button), push(Button), accumulator(A), write(A), write(','), op(O), write(O), write(','), displayed(D), write(D), write(','), memory(M), write(M), nl, calc.