LOCAL ERROR and ON ERROR LOCAL

bbc micro/electron/atom/risc os coding queries and routines
Post Reply
User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Sat Nov 23, 2019 10:23 am

In Acorn's ARM BASIC V and VI the LOCAL ERROR and ON ERROR LOCAL statements are almost always used together as a pair:

Code: Select all

      LOCAL ERROR : ON ERROR LOCAL .....
This is such a common usage that in BBC BASIC for Windows and BBC BASIC for SDL 2.0 the ON ERROR LOCAL statement has the effect of both; LOCAL ERROR is still accepted, for compatibility, but does nothing. In the 18 years since BB4W was released I don't think anybody has ever remarked on this or expressed any concern about a loss of functionality.

So my question is: has anybody ever used either LOCAL ERROR or ON ERROR LOCAL in isolation, in ARM BASIC, and if so why?

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Mon Jan 06, 2020 4:49 pm

Can I claim some kind of prize for not receiving a single reply to (what I thought was) a sensible programming question? :shock:

User avatar
BigEd
Posts: 3342
Joined: Sun Jan 24, 2010 10:24 am
Location: West
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by BigEd » Mon Jan 06, 2020 6:16 pm

It's tempting to conclude that no-one (here) has used the facility...

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Mon Jan 06, 2020 6:47 pm

BigEd wrote:
Mon Jan 06, 2020 6:16 pm
It's tempting to conclude that no-one (here) has used the facility...
I wondered the same, but that seems hardly plausible. Perhaps rather than asking "has anybody ever used either LOCAL ERROR or ON ERROR LOCAL in isolation?" I should have asked "can anybody suggest a reason why one might want to use LOCAL ERROR or ON ERROR LOCAL in isolation?".

One of my favourite constructions is this BBC BASIC variant of Structured Exception Handling (SEH); so much nicer than ON ERROR GOTO:

Code: Select all

      ON ERROR LOCAL IF FALSE THEN
        REM 'TRY' clause
        REM Code which might result in an error
      ELSE
        REM 'CATCH' clause
        REM Code executed if an error occurred
      ENDIF : RESTORE ERROR
And then there's 'cascaded' error handling in a PROC or FN to ensure the stack is properly unwound:

Code: Select all

      DEF PROC_myproc
      ON ERROR LOCAL RESTORE ERROR : ERROR ERR, REPORT$
      REM Code which might result in an error
      ENDPROC
In BBC BASIC for Windows and BBC BASIC for SDL 2.0 (and I believe also recent versions of Matrix Brandy) replacing RESTORE ERROR with RESTORE LOCAL will also correctly restore parameters and local variables from the stack when it is unwound.

Both examples would need an initial LOCAL ERROR to work in Acorn's BASICs (hence my original enquiry).

User avatar
flaxcottage
Posts: 4197
Joined: Thu Dec 13, 2012 8:46 pm
Location: Derbyshire
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by flaxcottage » Mon Jan 06, 2020 7:55 pm

Sorry, Richard, I must have missed the original post. :?

I confess to using LOCAL ERROR when programming in ARM BASIC. I have not had a need to use it in BBCB4W.

I used the construct to provide local error trapping when running a handshake protocol between Raspberry Pi GPIO pins and a BBC Master user port. Apart from that I have never needed to use either construct.
- John

Image

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Mon Jan 06, 2020 8:02 pm

flaxcottage wrote:
Mon Jan 06, 2020 7:55 pm
I confess to using LOCAL ERROR when programming in ARM BASIC.
So can you give an example of how you might use LOCAL ERROR without a subsequent ON ERROR LOCAL? Following LOCAL ERROR, is error trapping effectively OFF, in other words is the default handler active? I've really never been sure how this works in Acorn's BASICs.

User avatar
jgharston
Posts: 4081
Joined: Thu Sep 24, 2009 12:22 pm
Location: Whitby/Sheffield
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by jgharston » Mon Jan 06, 2020 10:05 pm

I was going to post to this thread, but I was wanting to dig around my code to find an example. I didn't get the chance to, but I have memories of using them in isolation, but can't remember the exact details, which is why I was trying to track down some code.

On ARM BASIC,
LOCAL ERROR pushes the current error handler and the current error stack pointer.
ON ERROR LOCAL stores the current stack pointer as the current error stack pointer and sets this as the current error handler.
ON ERROR just sets this as the current error handler.
ENDPROC/=result/RESTORE ERROR pops the stacked values into the current error handler and error stack pointer

An error sets the stack pointer to the current error stack pointer then continues into the error handler.

That's slightly different from how I did it in PDP11 BASIC from first principles, when an error happens that's when the interpeter looks for the LOCAL token and resets or doesn't the stack pointer.

So, after LOCAL ERROR, the current error handler and stack have been pushed, but the current error handler and stack have not been changed. So, any error will use the parent's error handler. Semantically it makes sense for LOCAL ERROR and ON ERROR LOCAL to do different things, but it does look like almost all use cases will have them paired.

I think the practical upshot of LOCAL ERROR on it own, eg:
DEFPROCfoo(A%)
LOCAL ERROR
IF A%=0 THEN ERROR 100,"foo"
ENDPROC

PROCfoo(1) will stack the error handler, restore it, return to the caller
PROCfoo(0) will stack the error handler, generate an error, jump to the error handler.
If the current error handler is ON ERROR then the stack is reset and the error handler continues.
If the current error handler is ON ERROR LOCAL then the stack is reset to the outside ON ERROR LOCAL and that error handler is used.

And,
DEFPROCfoo(A%)
LOCAL ERROR
IF A%=0 THEN ERROR 100,"test"
RESTORE ERROR
IF A%=1 THEN ERROR 101,"bar"
ENDPROC

does the same, the outside error handler is called with the outside handler's stack if it has been saved.

In fact, it looks like the stack is reset to whatever the last ON ERROR LOCAL saved it as. It looks like:
ON ERROR LOCAL ...
PROC into...
ON ERROR ...

The second ON ERROR will be the error handler, but it will use the stack pointer saved by the ON ERROR LOCAL. That suggests to me that unexpected things will happen if you use a non-LOCAL error handler within a subroutine called by code with a LOCAL error handler.

It looks like LOCAL ERROR really has no function unless it is immediately paired with ON ERROR LOCAL. It looks like the semantics drove the implementation. It would make sense if ON ERROR LOCAL was coded the PDP11 way, but it isn't.

RESTORE ERROR has uses, for instance:
DEFPROCbar(A%)
LOCAL ERROR:ON ERROR LOCAL i will handle errors
do stuff
RESTORE ERROR
parent's handler deals with errors here
ENDPROC

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.32
(C) Copyright J.G.Harston 1989,2005-2020
>_

User avatar
jgharston
Posts: 4081
Joined: Thu Sep 24, 2009 12:22 pm
Location: Whitby/Sheffield
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by jgharston » Mon Jan 06, 2020 10:15 pm

Technical digression...

"It would make sense if ON ERROR LOCAL was coded the PDP11 way, but it isn't."

In PDP11 BBC BASIC:
LOCAL ERROR does that, it stacks the current error handler and recursion level.
RESTORE ERROR and ENDPROC/=result pop any error handler on the stack to the current error handler and recursion level.
ON ERROR sets the error handler to the next character position.
The error handler checks if the error handling code starts with LOCAL and if it is, it sets the stack to the current recursion level, if not it resets the stack.

ARM BASIC, however, implements two seperate error settings:
ON ERROR LOCAL stores the current recursion level in the error stack pointer, then stores the next character as the error handler.
ON ERROR just stores the next character as the error handler.
The error handler sets the current stack to the current error stack pointer, then continues. It assumes it's a local error handler because something has set the current error stack pointer to the correct point.

The LOCAL ERROR semantics makes sense if the PDP11 method is used, but not if the ARM method is used, as it's the ON ERROR LOCAL command that "saves" the current stack, not the LOCAL ERROR

It looks like possibly ARM BASIC's error handling was coded and worked, but within the expected and normal use cases, and at some point it became too late to tidy up the syntax.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.32
(C) Copyright J.G.Harston 1989,2005-2020
>_

User avatar
jgharston
Posts: 4081
Joined: Thu Sep 24, 2009 12:22 pm
Location: Whitby/Sheffield
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by jgharston » Mon Jan 06, 2020 10:19 pm

Richard Russell wrote:
Mon Jan 06, 2020 8:02 pm
So can you give an example of how you might use LOCAL ERROR without a subsequent ON ERROR LOCAL? Following LOCAL ERROR, is error trapping effectively OFF, in other words is the default handler active? I've really never been sure how this works in Acorn's BASICs.
Answering that specific question: no, the current error handler is active. So, the default is no ON ERROR has been executed, and the last ON ERROR if one has.

I can possibly see a use case for something like:
DEFPROCthing
LOCAL ERROR
ON ERROR LOCAL something
foo bar
ON ERROR LOCAL something else
foo bar
ON ERROR LOCAL something else again
foo bar
ENDPROC

If ON ERROR LOCAL stacks the current error handler, you'd have three error handlers stacked at the ENDPROC, so a use case is to allow multiple local error handlers and allowing the interpreter to more easily be coded for the ENDPROC/RESTORE ERROR to deal with them.

Code: Select all

$ bbcbasic
PDP11 BBC BASIC IV Version 0.32
(C) Copyright J.G.Harston 1989,2005-2020
>_

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Mon Jan 06, 2020 10:47 pm

jgharston wrote:
Mon Jan 06, 2020 10:05 pm
It looks like LOCAL ERROR really has no function unless it is immediately paired with ON ERROR LOCAL.
OK, that's quite satisfying because, as I stated, in BBC BASIC for Windows and BBC BASIC for SDL 2.0 LOCAL ERROR is a no-op and ON ERROR LOCAL does all the work!
RESTORE ERROR has uses
Not least in the implementation of SEH that I listed, which has ENDIF : RESTORE ERROR as the last line.

The absence of RESTORE LOCAL from Acorn's BASICs (as discussed recently in the Matrix Brandy thread) remains a mystery though, because it is without question really useful, ought to be almost trvially implemented in any BBC BASIC (since it activates code that must already exist for handling ENDPROC) and requires no new tokens. I think we concluded it was a rare example of Sophie missing something 'obvious'.
Answering that specific question: no, the current error handler is active. So, the default is no ON ERROR has been executed, and the last ON ERROR if one has.
Right, I should have guessed that because it's consistent with another difference between Acorn's BASICs and mine: in theirs LOCAL leaves the value of the variable(s) unchanged (which I don't like because it allows global state to leak into a PROC/FN unexpectedly) whereas mine zero the variable(s).
If ON ERROR LOCAL stacks the current error handler, you'd have three error handlers stacked at the ENDPROC
True (which is exactly what does happen in my BASICs) but the penalty is only a slightly increased stack usage. Generally anything unwound by ENDPROC can be present on the stack multiple times, all of which are unwound.

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Mon Jan 06, 2020 11:08 pm

jgharston wrote:
Mon Jan 06, 2020 10:15 pm
In PDP11 BBC BASIC ... The error handler checks if the error handling code starts with LOCAL and if it is, it sets the stack to the current recursion level, if not it resets the stack.
That wouldn't be possible in my BASICs, and I'm guessing not in Sophie's BASICs either, because there's no such thing as "the current recursion level". The only indicator that the stack is in use is the value of the stack pointer itself, and there's no easy way of determining 'recursion level' from 'stack pointer' (or vice versa) because the amount of stack used per recursion, loop etc. isn't fixed.

That's particularly true in my BBC BASIC interpreters that are coded in assembly language (Z80, 8086, 32-bit x86), in which BASIC's stack pointer is the (CPU/hardware) stack pointer rather than something independent (which of course it has to be in the versions coded in C). So saving the stack pointer at the ON ERROR LOCAL is the way it has to work.

User avatar
Richard Russell
Posts: 1658
Joined: Sun Feb 27, 2011 10:35 am
Location: Downham Market, Norfolk
Contact:

Re: LOCAL ERROR and ON ERROR LOCAL

Post by Richard Russell » Tue Jan 07, 2020 12:58 pm

jgharston wrote:
Mon Jan 06, 2020 10:05 pm
It would make sense if ON ERROR LOCAL was coded the PDP11 way, but it isn't.
I'm trying to get my head around your preferred "PDP11 way" but I'm not seeing it. Consider these two similar cases which differ only in the positioning of the ON ERROR LOCAL statement (after the FOR in one case, before it in the other):

Code: Select all

      DEF PROCtest1
      LOCAL I%
      LOCAL ERROR
      FOR I% = 1 TO 5
        ON ERROR LOCAL I% = I% + 1
        PRINT 1 / (I% - 3)
      NEXT
      ENDPROC
and

Code: Select all

      DEF PROCtest2
      LOCAL I%
      LOCAL ERROR
      ON ERROR LOCAL I% = I% + 1
      FOR I% = 1 TO 5
        PRINT 1 / (I% - 3)
      NEXT
      ENDPROC
Clearly these will behave differently: PROCtest1 will print four numbers and exit, PROCtest2 will enter an 'infinite loop' and print indefinitely (tested in both BBCSDL and ARM BASIC 5). But if PDP11 BBC BASIC doesn't record the current stack pointer in the ON ERROR LOCAL statement, how does it distinguish between these two cases?

Post Reply

Return to “programming”