Refuse a branch to a line the program did not number
GOTO 100 in a script written without line numbers finds the hundredth line and branches there. Silent, plausible and wrong: the test for it loops forever printing the second line when the check is removed. akbasic_runtime_check_targets() is a fourth prescan beside the label, DATA and TYPE ones, run on every entry into MODE_RUN -- the earliest the check can be made and the only place all four ways a program arrives pass through. A target naming an empty line is still allowed, for the same reason RENUMBER leaves one alone, and a fully numbered program is unaffected, which is every program that existed before this. It shares RENUMBER's walk rather than repeating it. renumber.c grows an akbasic_TargetWalk -- a self pointer and a visit function -- and rewrite_line() takes one. RENUMBER's visitor substitutes the number a line moved to; the check's substitutes the number unchanged and raises. One walk, so the two cannot disagree about what a branch target is. The check points environment->lineno at the line being walked so the "? N :" prefix names the offending line. The other three prescans do not and report whichever line the loader stopped on; TODO.md section 5 item 64 records it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
20
tests/language/statements/unnumbered.bas
Normal file
20
tests/language/statements/unnumbered.bas
Normal file
@@ -0,0 +1,20 @@
|
||||
REM A whole program with no line numbers at all, read through RUNSTREAM.
|
||||
REM Blank lines cost nothing, and every branch is by LABEL.
|
||||
|
||||
PRINT "START"
|
||||
|
||||
FOR I# = 1 TO 3
|
||||
PRINT I# * I#
|
||||
NEXT I#
|
||||
|
||||
GOSUB GREET
|
||||
GOTO FINISH
|
||||
|
||||
PRINT "NOT REACHED"
|
||||
|
||||
LABEL GREET
|
||||
PRINT "HELLO"
|
||||
RETURN
|
||||
|
||||
LABEL FINISH
|
||||
PRINT "END"
|
||||
Reference in New Issue
Block a user