Wednesday, January 30, 2013

Forth for Enlightenment, part ten of ten, local variables and loop exit


If you've been following this blog for a while, then you'll recall that i described a series of programs for a 1986 calculator, the HP-28c. There aren't any forward links in the series, though you can follow them easily enough in the blog's automatically generated links on the right side. They're more or less all together. Until now. I've decided to revisit the calculator, the language, and the descriptions.
Now that i think of it, there's an easy way to get access to all the previous articles in this series. Ten parts were planned, and labeled here zero through nine. Here are the links.
zero Count
one Factorial
two Logic problem pt 0
three Logic problem pt 1
four GCD
five Backwords pt 0
six Backwords pt 1
seven Backwords pt 2
eight Backwords pt 3
nine Primes
There are two features of the RPL language as implemented on the HP-28c that i really wanted, but didn't seem to be include. One is local variables. It turns out that RPL has local variables. And, they're documented in the manual. Worse, i'd written programs when the calculator was much younger that used them. There are a couple pages in the manual that describe it. Unfortunately, there aren't any examples of how to use them, but a little experimentation shows how they work. Above the "U" key, there's a right arrow. It's an operator that takes arguments to its left and right. To the right, you give it the new variable names. This list ends when a new block "«"(as a single character) is encountered. For each of the variables, that number of arguments are taken off the stack (to the left). A function with a local variable might look like this.


«
 1 2 → a b «
  a b 2 * +
 »
» 'FNAB' STO

This assigns 1 to 'a', 2 to 'b', recalls 'b' (2), multiplies it by 2, and adds 'a' (1). So 5 ends up on the stack. At the close of the block '«', the variables 'a' and 'b' vanish. You can assign new values to 'a' and 'b' at will in your program using 'STO'. Unfortunately, 'STO+' doesn't work with local variables. No idea why not. One can create a function that takes arguments on the stack, and has local variables like this:


«
 1 2 → a b c d «
  a b 2 * + c 3 * + d 4 * +
 «
« 'FNABCD' STO

This assigns two arguments from the stack to 'b', then 'a', then assigns 1 to 'c', and 2 to 'd'. So, if you call this function using 7 8 FNABCD, you get 'a' set to 7, 'b' set to 8, with an answer of 35.
The other feature that i'd like is some way to exit a loop early. The manuals extol the advantages of not having a functional GO TO. In my humble opinion, RPL (and Forth and Lisp) are not that easy to read. Perhaps GO TO would make it impossible. Or perhaps we should consider these read only languages. It is very likely that implementing an abusable GO TO would slow down these languages. And yet, it's common that you need to search a list for something, and you'd like to be able to stop searching when you've found it. You can use a WHILE loop, since there's a condition you can use to exit. But what do you do with a FOR loop? After all, the FOR loop creates a local variable, which gets automatically cleaned up when you're done with it. It's handy. Well, here's how you do it. You set the loop variable to the end value. This code puts A on the stack each loop. Run it, and 1 2 3 4 5 are on the stack. The number 6 doesn't go on the stack because when A is 5, it gets set to 10. The IF statement needs to be placed just before the NEXT. You can't use it to magically exit the loop from somewhere in the middle.


«
 1 10 FOR A
  A
  IF A 5 == THEN
   10 'A' STO
  END
 NEXT
« 'E' STO

The HP-28c has a printer, which prints to thermal paper. One way to save a program is to print it to the printer, then xerox the output. What happens is that the thermal paper fades with time. Making a copy can give you a high contrast print for longer. One thing that would be better is if you could print your program, but have another computer capture the output and store it to disk. Then you could make a CD, which would last quite a long time. However, the HP-28c has several non-ascii (non-standard) characters. You'd have to make sure that you also documented these. It turns out that the protocol that the HP-28c uses to talk to the printer is pretty straight forward. So building an IR receiver and capturing the data isn't that hard. I haven't done it yet. And this still leaves getting a program back into the calculator. The HP-28c does not have any kind of network input. The printer only accepts input. The HP-28c only emits output. If there's no printer, or it misses something or falls behind, well, too bad. And, i've discovered that you don't really know how to enter a program until you've entered it and made it work. So, once you have your killer application written, you need to copy it somewhere, delete it, and enter it from your notes. There's no way around this. Doing it sooner (when you still know the program) has the advantage that if you make a mistake, you probably still know enough about it to fix it. Doing it later than sooner has the advantage that if you can do it then, it's more likely anyone can.