' Tiny RPN calculator, 2019, 2022 Hans Bezemer
' This is mainly a demo for the NAME() and LINE() functions

' Valid commands:
'   ., +, /, mod, -, *, drop, over, swap, negate, exit, quit,
'   depth, free

' NOTE: Exhausting the stack will terminate the program!

' E.g.
'   23 45 + over . .
'   67 dup * .

e = info ("nil")                       ' store error value in e

do                                     ' do forever
  a = ask ("Ok ")                      ' get a line of commands
  for x = 0 to len (a) - 1             ' process until end of line
    for y = x to len (a) - 1           ' skip any leading spaces
      while peek (a, y) = ord(" ")
    next

    t = dup ("")                       ' start with an empty token

    for z = y to len (a) - 1           ' start after leading spaces
      until peek (a, z) = ord(" ")     ' until we find another space
      t = join (t, char (peek (a, z))) ' add character to token
    next

    if val (t) > e then                ' if this is a number
      push val (t)                     ' push its value
    else                               ' if it isn't a number, it SHOULD be
      l = FUNC(_Interpret (t))         ' convert it to a line number
      if line (l) then                 ' if it's a valid line number
        gosub l                        ' it's a command, so call it
      else                             ' otherwise show a message
        print show (t);"?"
      endif
    endif

    x = z                              ' get a new token after this
  next                                 ' get a whole new line of commands
loop
end

_Interpret                             ' this one converts commands not
  Param (1)                            ' legal as names for labels

  If comp(a@, ".") = 0 return (name("print"))
  If comp(a@, "+") = 0 return (name("add"))
  If comp(a@, "/") = 0 return (name("div"))
  If comp(a@, "*") = 0 return (name("mul"))
  If comp(a@, "-") = 0 return (name("min"))
return (name(a@))

_exit end                              ' like BYE, exits the program
_quit end                              ' below: ., DUP, NEGATE, +, -, /, MOD,
_depth push used () : return           '        *, DROP, OVER, SWAP, DEPTH,
_free push free (0) : return           '      FREE
_dup param (1) : push a@, a@ : return
_negate param (1) : push -a@ : return
_mod param (2) : push (a@ % b@) : return
_drop param (1) : return
_over param (2) : push a@, b@, a@ : return
_swap param (2) : push b@, a@ : return
                                       ' these ones need name conversion
_print param (1) : print a@ : return
_add param (2) : push (a@ + b@) : return
_div param (2) : push (a@ / b@) : return
_mul param (2) : push (a@ * b@) : return
_min param (2) : push (a@ - b@) : return

