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

select input(0); select output(0)
      prompt("eval:")
again:val=eval
      if val=int(val) then write(int(val),0) { imp77 perms missing} {%else print(val,0,4)}
      newline
      ->again

endofprogram