• Using Applesoft Internal Error Messages in a BASIC Error Handler

    From Bill Chatfield@21:1/5 to All on Wed Nov 29 10:31:27 2023
    I need an ONERR GOTO error handler to CLOSE files or return to TEXT mode or various other situations. In the error handler, I can get the error code with PEEK(222). Error codes are a waste of time because it just forces the user to look up what the error
    code means. That is often very hard to do, especially for retro computing. Computers are much better than humans at looking up error messages corresponding to error codes. A good user interface should never display an error code. It should always display
    the error message corresponding to the error code.

    I could write BASIC code in every BASIC program to convert the error code into and an error message. But that is silly when those messages are already in the Applesoft source code, which is here: https://github.com/cmosher01/Apple-II-Source/blob/master/
    src/system/applesoft/applesoft.m4

    I've copied the error table itself below. How can I use this from BASIC? There is an error subroutine called ERROR, but I don't think it does an RTS and I don't understand how it works. It would be nice if there was a standard subroutine in the Applesoft
    code that I could CALL to display the error message. But at least I could use the error table to get the messages. But I'm not sure how to do that either. Any ideas?

    ; --------------------------------
    ; --------------------------------
    ; ERROR MESSAGES
    ; --------------------------------
    ERROR_MESSAGES
    ERR_NOFOR = *-ERROR_MESSAGES
    LHASCII(`NEXT WITHOUT FOR')
    ERR_SYNTAX = *-ERROR_MESSAGES
    LHASCII(`SYNTAX')
    ERR_NOGOSUB = *-ERROR_MESSAGES
    LHASCII(`RETURN WITHOUT GOSUB')
    ERR_NODATA = *-ERROR_MESSAGES
    LHASCII(`OUT OF DATA')
    ERR_ILLQTY = *-ERROR_MESSAGES
    LHASCII(`ILLEGAL QUANTITY')
    ERR_OVERFLOW = *-ERROR_MESSAGES
    LHASCII(`OVERFLOW')
    ERR_MEMFULL = *-ERROR_MESSAGES
    LHASCII(`OUT OF MEMORY')
    ERR_UNDEFSTAT = *-ERROR_MESSAGES
    LOASCII(`UNDEF')
    ASM_DATA($27)
    LHASCII(`D STATEMENT')
    ERR_BADSUBS = *-ERROR_MESSAGES
    LHASCII(`BAD SUBSCRIPT')
    ERR_REDIMD = *-ERROR_MESSAGES
    LOASCII(`REDIM')
    ASM_DATA($27)
    LHASCII(`D ARRAY')
    ERR_ZERODIV = *-ERROR_MESSAGES
    LHASCII(`DIVISION BY ZERO')
    ERR_ILLDIR = *-ERROR_MESSAGES
    LHASCII(`ILLEGAL DIRECT')
    ERR_BADTYPE = *-ERROR_MESSAGES
    LHASCII(`TYPE MISMATCH')
    ERR_STRLONG = *-ERROR_MESSAGES
    LHASCII(`STRING TOO LONG')
    ERR_FRMCPX = *-ERROR_MESSAGES
    LHASCII(`FORMULA TOO COMPLEX')
    ERR_CANTCONT = *-ERROR_MESSAGES
    LOASCII(`CAN')
    ASM_DATA($27)
    LHASCII(`T CONTINUE')
    ERR_UNDEFFUNC = *-ERROR_MESSAGES
    LOASCII(`UNDEF')
    ASM_DATA($27)
    LHASCII(`D FUNCTION')
    ; --------------------------------

    QT_ERROR LOASCII(` ERROR')
    ASM_DATA($07,0)

    QT_IN LOASCII(` IN ')
    ASM_DATA(0)

    QT_BREAK ASM_DATA($0D)
    LOASCII(`BREAK')
    ASM_DATA($07,0)

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From fadden@21:1/5 to All on Wed Nov 29 22:23:56 2023
    The error code, passed in the X register, is just the index of the start of the error text (table at $d260). The error routine prints "?", then the error text, then "ERROR" and a bell (from $d350). If the code was running, it prints the line number,
    and does the Applesoft error handling.

    So for example, SYNTAX ERROR is error code 16. $d260 + 16 = $d270, which is the string "SYNTAX". The last letter has the high bit set (Dextral Character Inverted format, or DCI), which is how the code knows when to stop printing characters.

    Try this:

    100 BASE = 53856: REM $D260
    110 ERRCODE = 16: GOSUB 1000: REM SYNTAX ERROR
    120 ERRCODE = 53: GOSUB 1000: REM ILLEGAL QUANTITY
    130 END
    1000 PTR = BASE + ERRCODE
    1010 L = PEEK (PTR): IF L > = 128 THEN PRINT CHR$ (L - 128);: PRINT " ERROR": RETURN
    1020 PRINT CHR$ (L);:PTR = PTR + 1: GOTO 1010

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Jerry Penner@21:1/5 to Bill Chatfield on Thu Nov 30 11:00:24 2023
    Bill Chatfield <billchatfield1@gmail.com> writes:

    On Thursday, November 30, 2023 at 1:23:58 AM UTC-5, fadden wrote:
    The error code, passed in the X register, is just the index of the start of the error
    text (table at $d260). The error routine prints "?", then the error text, then "ERROR"
    and a bell (from $d350). If the code was running, it prints the line number, and does
    the Applesoft error handling.

    So for example, SYNTAX ERROR is error code 16. $d260 + 16 = $d270, which is the string
    "SYNTAX". The last letter has the high bit set (Dextral Character Inverted format, or
    DCI), which is how the code knows when to stop printing characters.

    Try this:

    100 BASE = 53856: REM $D260
    110 ERRCODE = 16: GOSUB 1000: REM SYNTAX ERROR
    120 ERRCODE = 53: GOSUB 1000: REM ILLEGAL QUANTITY
    130 END
    1000 PTR = BASE + ERRCODE
    1010 L = PEEK (PTR): IF L > = 128 THEN PRINT CHR$ (L - 128);: PRINT " ERROR": RETURN
    1020 PRINT CHR$ (L);:PTR = PTR + 1: GOTO 1010

    Wow, that makes a lot more sense in BASIC. I'm use to an ASCII code 0 terminator for
    strings, so setting the high bit is new to me. But it is more efficient because it saves
    one character. It's also more efficient than using a length byte at the beginning.

    Yeah, this is just what I was looking for. This is so much better than an IF/THEN for each
    error code in every BASIC program.

    I thought I was getting good at reading 6502 assembly, but the Applesoft source code is a
    little harder. I guess Bill Gates wrote it. Haha.

    Thank you so much for translating!


    Here's another way to see the errors:

    10 ONERR GOTO 1000
    20 REM make line 30 have your error of choice
    30 NEXT
    1000 PTR = 53856 + PEEK (222)
    1005 POKE 216,0
    1010 FOR X = 0 TO 1 STEP 0
    1020 C = PEEK (PTR): PTR = PTR + 1: X = C > = 128
    1030 PRINT CHR$ (C - 128 * (C > = 128));
    1040 NEXT
    1050 PRINT " ERROR IN LINE " PEEK (218) + PEEK (219) * 256


    Try different things for line 30:

    ]30 ASDF
    ]RUN

    SYNTAX ERROR IN LINE 30

    ]30 NEXT
    ]RUN

    NEXT WITHOUT FOR ERROR IN LINE 30

    ]30 X = 1 / 0
    ]RUN

    DIVISION BY ZERO ERROR IN LINE 30

    ]30 POKE 0,256
    ]RUN

    ILLEGAL QUANTITY ERROR IN LINE 30

    --
    --
    Jerry jerry+a2 at jpen.ca

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)
  • From Michael J. Mahon@21:1/5 to fadden on Wed Jan 17 07:19:40 2024
    fadden <fadden@fadden.com> wrote:
    The error code, passed in the X register, is just the index of the start
    of the error text (table at $d260). The error routine prints "?", then
    the error text, then "ERROR" and a bell (from $d350). If the code was running, it prints the line number, and does the Applesoft error handling.

    So for example, SYNTAX ERROR is error code 16. $d260 + 16 = $d270, which
    is the string "SYNTAX". The last letter has the high bit set (Dextral Character Inverted format, or DCI), which is how the code knows when to
    stop printing characters.

    Try this:

    100 BASE = 53856: REM $D260
    110 ERRCODE = 16: GOSUB 1000: REM SYNTAX ERROR
    120 ERRCODE = 53: GOSUB 1000: REM ILLEGAL QUANTITY
    130 END
    1000 PTR = BASE + ERRCODE
    1010 L = PEEK (PTR): IF L > = 128 THEN PRINT CHR$ (L - 128);: PRINT " ERROR": RETURN
    1020 PRINT CHR$ (L);:PTR = PTR + 1: GOTO 1010


    When writing the NadaNet ampersand extension for Applesoft, I needed a “standard” way to signal a data packet error. Since there is no easy way to extend the error message table, I chose to piggyback on an existing message
    by choosing an error number that points to the last word in the “OUT OF DATA” error, creating a “DATA” error message for NadaNet communication errors. ;-)

    --
    -michael - NadaNet 3.1 and AppleCrate II: http://michaeljmahon.com

    --- SoupGate-Win32 v1.05
    * Origin: fsxNet Usenet Gateway (21:1/5)