Dear 4tH-ers!
I must excuse myself for not having written anything in the last six months. But there is IMHO a good reason for that. As you may know I'm a consultant in a non-programming computer science field, but sometimes I'm also hired to do some operational work.
This was a very stressful job, making long hours and having the responsibility for a small team. This wouldn't have been a problem a few decades ago, but now I'm in my early sixties and this one frankly took most of my energy - leaving very little left for other activities.
But that one is done and while enjoying the holidays, I took up some of the slack which was left.
One of the things was adding "ON ERROR GOTO" functionality to uBasic/4tH. I came to the conclusion that that syntax was not going to work for me, so I turned to Forth instead.
Here we have ['] MyWord CATCH. CATCH returns the exception thrown - translated to uBasic/4tH that means a function - x = TRY(_MyWord). And yes, you can add parameters as well, just like the related FUNC().
Unlike FUNC() you CANNOT return a value, because TRY() already returns the exception thrown. Of course, all stackpointers are preserved in case of an exception - and disregarded when no exceptions are thrown. Just like CATCH.
Of course, you have to be able to throw a user exception. For that I created RAISE(). RAISE() will take one parameter - but with one restriction. You cannot throw ANY exception, just user exceptions. You can retrieve the first user exception by issuing INFO("raise") - which is equivalent to RAISE(0). So you can throw any number of user exceptions, which will be returned intact by TRY().
Now, I've done quite some testing, but I decided the penultimate test would be the ANS Forth example given in Annex A. Since uBasic/4tH holds quite some Forthish stuff, it wasn't too difficult to implement:
---8<---
Proc _RetryIt ' call the routine
End
_RetryIt
Local (1)
Do
Push 1, 2 ' push two numbers on the stack
While Try(_DoIt) ' repeat until no exception
a@ = Pop() : a@ = Pop() ' drop items from the stack
Print "There was an exception" ' signal there was an exception
Loop
' no exception thrown, show character
Print "The character was ";Chr(Pop())
Return
_DoIt
Local (1)
a@ = Pop() : a@ = Pop() ' drop items from the stack
Return (Func (_CouldFail)) ' call CouldFail
_CouldFail
Local (1)
' return when "Q" is entered
If Set(a@, Peek(Ask ("Enter: "), 0)) = Ord ("Q") Then Return (a@)
Raise (1) ' raise user exception
Return (-1) ' this code is never reached
---8<---
And this is a sample run:
Enter: w
There was an exception
Enter: e
There was an exception
Enter: r
There was an exception
Enter: t
There was an exception
Enter: y
There was an exception
Enter: Q
The character was Q
0 OK, 0:61
Now, I know not all of you are very interested in uBasic/4tH, but I'll add the code to SVN after some more testing, so you may look at the Forth code yourself to satisfy your need for Forth code ;-)
It has been a bit restructured (refactoring is a thing), but I think the code has become even better. The whole invocation of the interpreter for TRY() and FUNC() has been isolated and
references to EXEC_GOTO and (POP) have been removed.
It worked out pretty much as I had imagined, the only thing I had forgotten all about was that EXEC_GOTO changed the program pointer, but once I figured that one out, it was a walk in the park. The implementation of RAISE() was pretty straight forward, only issuing the error message was a bit of a challenge.
So, this was my long overdue update. BTW, I have been making YouTube videos all this time. Take a look at this playlist, if you're interested:
Be seeing you,
Hans Bezemer