dykstrom / basic-mode

Emacs major mode for editing BASIC code
GNU General Public License v3.0
7 stars 10 forks source link

basic-find-jumps doesn't find all target lines for renumbering #29

Closed hackerb9 closed 1 year ago

hackerb9 commented 1 year ago

Issue #26 lists multiple ways in which line numbers can be referred to in a BASIC program. It appears basic-renumber does not yet take some of those into account. In particular, it is missing:

For completeness, it may make sense to handle

Note that one reason to not bother being complete is that ranges do not necessarily refer to existing lines. For example, Microsoft's BASIC for the TRS-80 Model 100 allows 10 EDIT 10 - 99 which loads up all the lines between 10 and 99, inclusive, in a text editor.

I don't think any version of BASIC allows RENUM in a program, but theoretically it is possible.

dykstrom commented 1 year ago

How is ERL used? Is it always used like this?

10 IF ERL = 200 GOTO 9999

Or does it makes sense to write

10 IF ERL <> 200 GOTO 9999

Or even

10 IF ERL = 200 OR ERL = 300 GOTO 9999
hackerb9 commented 1 year ago

I don't know what you'll find in the wild, but it makes sense to me to use ERL to check if an error occurred in a particular section of the program.

10 IF ERL >= 200 AND ERL < 300 GOTO 9999

The IBM BASIC 3.0 manual I have (May 1984) specifies that RENUM only works if ERL is used in a constrained way. Specifically,

If you do test ERL in an IF–THEN, be sure to put the line number on the right side of the relational operator, like this: ```BASIC IF ERL = line number THEN ... ``` The number must be on the right side of the operator to be renumbered by RENUM.

The use of the term "relational operator" implies to me that < , >, and <> are allowed. However, I have not had a chance to test this on my IBM 5155 as the CRT has gone bad. However, I did try it with Rob Hagerman's PC-BASIC and it did work the way IBM documented it.

10 IF ERL >= 200 AND ERL < 300 GOTO 9999       ' This gets renumbered correctly
20 IF 200 <= ERL AND ERL < 300 GOTO 9999       ' This fails: "200" is not changed

Note: Running RENUM in PC-BASIC will refuse to renumber anything if it can tell it will mangle the results. For example, the above example won't make any changes unless lines 200, 300, and 9999 exist in the program. While it is reasonable to test ERL against non-existent line numbers, RENUM gives an error, which is preferable to making a mistake. Perhaps this should be a feature request for basic-mode. Either that, or handle the situation correctly by creating virtual line numbers for non-existent lines. (I can describe more if this is something that you think is a good idea.)

Also, when the documentation says the number must be on the right-hand side, it means a literal integer. If someone tries to RENUM a test like IF ERL >= 4*100, PC-BASIC will complain, "Undefined lines 4 and 100". In contrast, the left-hand side is never changed: RENUM of IF ERL - 200 = 0 will preserve the "200".

dykstrom commented 1 year ago

I will add support for the other relational operators as well. Checking if all referenced line numbers (jump-locations as they are called in the code) and stop with an error if any of them does not exist should probably be a feature request as you write. I think it would be better to check and stop than to create new line numbers.

hackerb9 commented 1 year ago

I will add support for the other relational operators as well.

Thanks.

I think it would be better to check and stop than to create new line numbers.

Agreed. I think stopping is completely fine since that was good enough when these languages were in common use.

By the way, by "virtual" line numbers, I meant that basic-renumber would act like the jump target line exists just during the renumbering so that no other line gets assigned to its position; it wouldn't actually create new line numbers.

hackerb9 commented 1 year ago

Earlier I said,

I don't think any version of BASIC allows RENUM in a program, but theoretically it is possible.

I just noticed that one of my official manuals for IBM BASIC actually shows this as the example of RENUM usage:

10 RENUM 1000, 10

I still don't think that was ever valid but thought you'd get a chuckle out of it.

dykstrom commented 1 year ago

It would be an interesting way to write a self-modifying program. :)