%begin
%realfn eval    {evaluate sub-expression}
%routinespec pushopd(%real val)
%routinespec pushop(%integer op)
%realfnspec popopd
%integerfnspec popop
%realfnspec nextopd
%integerfnspec nextop
%routinespec operate
%constinteger plus=1,minus=2,times=3,divide=4,exp=5,assign=6,end=7,space=' '
%constintegerarray prec(plus:assign)=1,1,2,2,3,0
%realarray opds(0:4)    {operand stack}
%integerarray ops(0:3)    {operator stack}
%ownrealarray vars('a':'z')=0(*)
%ownintegerarray vara('a':'z')=0(*)
%integer op,opdsp,opsp,var
  opdsp=0 ; opsp=0    {init stack pointers}
  pushopd(nextopd)    {first operand}
  %cycle    {for each operator}
    op=nextop
    %if op=end %then %exit
    operate %while opsp>0 %and prec(ops(opsp))>=prec(op)
    %if op=assign %then %start
      read symbol(var)
      %unless 'a'<=var<='z' %or 'A'<=var<='Z' %then print symbol(var) %c
        %and print string(" variable") %and %signal 15
      %if 'A'<=var<='Z' %then var=var-'A'+'a'
      vars(var)=opds(opdsp)
      vara(var)=1    {assigned}
      %continue
    %finish
    pushop(op)
    pushopd(nextopd)
  %repeat
  operate %while opsp>0
  %result=popopd
!
%routine pushopd(%real val)
  opdsp=opdsp+1
  opds(opdsp)=val
%end
!
%routine pushop(%integer op)
  opsp=opsp+1
  ops(opsp)=op
%end
!
%realfn popopd
%real val
  val=opds(opdsp)
  opdsp=opdsp-1
  %result=val
%end
!
%integerfn popop
%integer op
  op=ops(opsp)
  opsp=opsp-1
  %result=op
%end
!
%realfn nextopd
%integer var
%real opd
  skip symbol %while next symbol=space %or next symbol=nl
  %if '0'<=next symbol<='9' %or next symbol='-' %or next symbol='.' %c
     %then read(opd) %and %result=opd
  %if next symbol='(' %then skip symbol %and %result=eval
  %if 'a'<=next symbol<='z' %or 'A'<=next symbol<='Z' %then %start
    read symbol(var)
    %if 'A'<=var<='Z' %then var=var-'A'+'a'
    %if vara(var)=0 %then print symbol(var) %and %c
      print string(" unassigned") %and %signal 15
    %result=vars(var)
  %finish
  read symbol(var)
  print symbol(var)
  print string(" operand")
  %signal 15
%end
!
%integerfn nextop
%integer sym
  skip symbol %while next symbol=space
  read symbol(sym)
  %if sym='+' %then %result=plus
  %if sym='-' %then %result=minus
  %if sym='*' %then %result=times
  %if sym='/' %then %result=divide
  %if sym='^' %then %result=exp
  %if sym=':' %then %result=assign
  %if sym=')' %or sym=nl %then %result=end
  print symbol(sym)
  print string(" operator")
  %signal 15
%end
!
%routine operate
%real opd1,opd2
%switch opn(plus:exp)
  opd2=popopd
  opd1=popopd
  ->opn(popop)
opn(plus):pushopd(opd1+opd2) ; %return
opn(minus):pushopd(opd1-opd2) ; %return
opn(times):pushopd(opd1*opd2) ; %return
opn(divide):%if opd2=0 %then print string("divide by zero") %and %signal 15
            pushopd(opd1/opd2) ; %return
opn(exp):pushopd(opd1^int(opd2))
%end
!
%end  {of eval}
%real val

  %on %event 9,15 %start    {to trap everything}
{*} %stop %if Event_Event = 9
    print string("?
")
   ->again ; %finish

      prompt("eval:")
again:val=eval
      %if val=int(val) %then write(int(val),0) %else print(val,0,4)
      newline
      ->again

%endofprogram
