Re: REM <SHIFT+L>

From: Stephen Judd (judd_at_merle.acns.nwu.edu)
Date: 1998-09-22 00:00:18

Hola,

> > Can anyone tell me why the REM <SHIFT+L> trick works.  I'm sure you know

Yup!

> > The only investigation I've done is to look at the REM routine at 43323,
> > but I saw nothing in the following opcodes that represents a shifted L.

As others have said, it is LIST -- specifically QPLOP, which prints
tokens -- which causes the problem, albeit indirectly.

Ethan wrote:
> Back in the PET days, we used to poke odd tokens into REM statements to keep
> our BASIC programs unlistable.  I think what you will find if you dump hex
> for your line 20, is that the token following the REM token is out of bounds
> and the lookup routine in LIST errors out when asked to translate that token
> back into a printable word.  IIRC, we used to poke a 204 into a REM to screw
> things up on a PET with BASIC 2.0 ROMs.  The table is larger for BASIC 4.0,
> so it was a different value there.

Shift-L is character code $CC -- 204 decimal, as Ethan says above.  In 
BASIC, tokens are indicated by having the high bit set.  The highest token
is "go" (so that "go to" works), which has token value $CB.  Although
you might be thinking "ah, larger than the largest token", note that
shift-M shift-N etc. list just fine; the problem only occurs with
shift-L, and the reason is quite interesting.

Keywords are printed by searching forwards through the keyword table:

:LOOP1   DEX              ;Traverse the keyword table
	 BEQ :PLOOP
:LOOP2   INY              ;read a keyword
	 LDA RESLST,Y
	 BPL :LOOP2
	 BMI :LOOP1
:PLOOP   INY              ;Print out the keyword
	 LDA RESLST,Y
	 BMI LISTENT1     ;Exit if on last char
	 JSR HAB47        ;Print char, AND #$FF
	 BNE :PLOOP

The last char of each keyword has the high bit set; the above code
just counts .X characters that have the high bit set.  Note that
absolute addressing is used, though, so that the size of the text
in RESLST can't be larger than 256 bytes total.  

It turns out that there are 255 text bytes in the table -- token
$CC begins at RESLST+255, the last byte of the table, which has
a value of zero.  So what happens is that $AB47, which prints the
character in .A, is called with .A=0.  AB47 is part of the PRINT
command used with the CMD command.  And what _it_ does is call
$E10C, which calls $FFD2 and branches to an error if the carry is
set.  But send a zero to $FFD2 and he sets the carry flag on exit, 
causing $E10C to branch to the error routine.

So it's all because the first character of "token" $CB is CHR$(0),
which causes an error in the print routine.

Why doesn't a line like 

10 PRINT shift-L

work?  Because the tokenizer discards all bytes larger than 127,
except for REM.  You can also see why shift-M, shift-N etc. work --
in the QPLOP code, .Y just wraps back around to zero, and those
higher "tokens" just correspond to tokens $81, $82, etc. ($80 gets
skipped -- it would be token $CB if it weren't for the zero).

The one thing I'm not sure of is why the check for carry set is made
in $E10C -- I'll try to look it up when I get home.

-Steve
-
This message was sent through the cbm-hackers mailing list.
To unsubscribe: echo unsubscribe | mail cbm-hackers-request@dot.tcm.hut.fi.

Archive generated by hypermail 2.1.1.