8-Bit Software

The BBC and Master Computer Public Domain Library

Back to 8BS Or Back to Disassembly


Page Last Altered:

8D04 Tokenise Line Number

Submitted by Steve Fewell

Routine:tokeniseLineNumber
Name: Tokenise Line Number
Starting Address: &8D04
Entry criteria: A contains the first digit of the line number.
Pointer (&37, &38) points to the address in the program of the first digit of the Program Line Number.
Exit: The line number in the Program Line is tokenised.
Carry flag is set if error occurred (Line number too large).

Description:
Store the 4 lowest bits (bits 0, 1, 2 & 3) of the first digit (in A) in location &3D.
Set X to zero (the upper digit of the 2-byte binary line number) Set Y to 1 (so the next character read will be the character after the first digit of the line number).

[&8D0C] Read next character from the (&37, &38) pointer.
If the next character is not a digit then go to &8D42 to store the line number token and exit.

Store the 4 lowest bits (bits 0, 1, 2 & 3) of the new digit on the stack.
Store X in location &3E.

Multiply the Line Number (in locations &3D (LSB) abd &3E (MSB) by 10, by:
   *1) Storing the value of location &3D and &3E.
   *2) Multiplying the Line Number value (in locations &3D-&3E) by 4
   *3) Adding the stored &3D and &3E value to the result from step *2).
   *4) Multiplying the Line Number value (in locations &3D-&3E [note: actually A at this stage] by 2.
If the Line Number MSB (&3E) becomes negative (or overflows) at any time during this multiply operation, the routine
will be exited with Carry set (as the line number is too large).

Next, retrieve the encoded next digit value from the Stack and add this digit to the Line Number (&3D-&3E).
This adds the digit to the binary line number.
If X (working copy of &3E) is negative then jump to &8D3F (exit with carry flag set), as the line number is too large.
Otherwise, jump back to &8D0C to process any further digits.

&8D42 Store Line Number Token & exit:

Decrement Y offset (so that Y points to the end of the ASCII Line Number on the command line).
Set A to #&8D (The Token for Line Number).
Call routine &8CEB to replace the ASCII Line Number currently present in the Program line with #&8D.

Next, Copy the program text pointer (&37, &38) to locations (&39 - &3A).
This is a pointer to the #&8D token value on the program line.
Increment Pointer (&37, &38) by 3 (to point to the location after the 3-byte tokenised line number.
by the 3-digit encoded line number value).

Copy program line text from location pointed to by (&39,&3A) to the (&37, &38) location (last byte first)
[routine &8CEB set Y to point to the end of the command line].
The first byte is correctly set to #&8D, so don't copy this byte.
This moves the command line text (after the program line number lcoation) along 3 bytes - to make space for the
tokenised line number.

Set Y to 3 (deal with the last byte of the tokenised line Number first).
Set A to X (the MSB of the Line Number).
OR A value with #&40 (01000000) to set bit 6 of the Byte, then store this result in the 3rd byte of the
tokenised line number (i.e. the 3rd byte after the #&8D token value).

Set A to &3D value (LSB of Line Number). AND this value with #&3F (00111111) to clear the top 2 bits of
the value and OR with #&40 (01000000) to set bit 6. Finally, store the result in the 2nd byte of the Tokenised
Line number (i.e. the 2nd byte after the #&8D token value).

Next, clear all but the top two bits of the &3D (LSB of Line Number) value.
AND the MSB of the Line Number with #&C0 (11000000) to clear all but the top 2 bits. Shift the top two bits
of the MSB Line Number value along 2 positions and set the top 2 bits to the top two bits of the &3D (LSB of Line
Number) value. EOR this result with #&54 (01010100).
Store the result as the 1st byte of the tokenised Line Number.

The resulting tokenised value contains 3 bytes which each contain an encoded value between &40 and &7F.
This ensures that tokenised Line Numbers cannot be confused with BASIC tokenised keyword values (which are all >= &80),
or with the quote character (").
This is important, otherwise BASIC might interpret the Line Number value as a String or as another BASIC keyword.


Examples:

Example1: Line Number = 10
[&8D04] A=&31. AND #&0F with A (1st digit), result=&01 (store in &3D).
[&8D14] A=&30. AND #&0F with A (2nd digit), result=&00. &3E & X = &00.
[&8D1E] Now: A=&02 and &3E=&00.
[&8D23] Now: A=&04 and &3E=&00.
[&8D27] Now: &3D and A = &05 [&8D2E] Now: A=&00, after addition, A=&00. &3D=&0A, A=&00.
[&8D39] Now: X=&00, A=&00 and &3D=&0A.

This 2-byte value is tokenised as follows:
(X = &00, &3D = &0A)
3rd byte of tokenised value = &40 (X (&00) OR &40).
2nd byte of tokenised value = &4A (A (&0A) OR &40).
1st byte of tokenised value = &54 (&00 EOR &54).

Example2: Line Number = 12345
[&8D04] A=&31. AND #&0F with A (1st digit), result=&01 (store in &3D).
[&8D14] A=&32. AND #&0F with A (2nd digit), result=&02. &3E & X = &00.
[&8D1E] Now: A=&02 and &3E=&00.
[&8D27] Now: A = &04, &3E = &00 and &3D = &05. [&8D2E] Now: A=&00, after addition, A=&00. &3D=&0A, A=&00.
[&8D39] Now: X=&00, A=&0C and &3D=&0C.
[&8D14] A=&33. AND #&0F with A (3rd digit), result=&03. &3E & X = &00.
[&8D1E] Now: A=&0C (= &18 after addition) and &3E=&00.
[&8D27] Now: A = &30, &3E = &00 and &3D = &3C. [&8D2E] Now: A=&00, after addition, A=&00. &3D=&78, A=&00.
[&8D39] Now: X=&00, &3D=&7B.
[&8D14] A=&34. AND #&0F with A (4th digit), result=&04. &3E & X = &00.
[&8D1E] Now: A=&7B (= &F6 after addition) and &3E=&00.
[&8D27] Now: A = &EC, &3E = &01 and &3D = &67. [&8D2E] Now: A=&00, after addition, A=&02. &3D=&CE, A=&04.
[&8D39] Now: X=&04 and &3D=&D2.
[&8D14] A=&35. AND #&0F with A (5th digit), result=&05. &3E & X = &04.
[&8D1E] Now: A=&D2 (= &A4 after addition) and &3E=&09.
[&8D27] Now: A = &48, &3E = &13 and &3D = &1A. [&8D2E] Now: A=&04, after addition, A=&18. &3D=&34, A=&30.
[&8D39] Now: X=&30 and &3D=&39.

This 2-byte value is tokenised as follows:
(X = &30, &3D = &39)
3rd byte of tokenised value = &70 (X (&40) OR &30).
2nd byte of tokenised value = &79 (A (&40) OR &39).
1st byte of tokenised value = &54 (&00 EOR &54).

Example3: Line Number = 333
[&8D04] A=&33. AND #&0F with A (1st digit), result=&03 (store in &3D).
[&8D14] A=&33. AND #&0F with A (2nd digit), result=&03. &3E & X = &00.
[&8D1E] Now: A=&06 and &3E=&00.
[&8D27] Now: A = &0C, &3E = &00 and &3D = &0F. [&8D2E] Now: A=&00, after addition, A=&00. &3D=&1E, A=&00.
[&8D39] Now: X=&00 and &3D=&21.
[&8D14] A=&33. AND #&0F with A (3rd digit), result=&03. &3E & X = &00.
[&8D1E] Now: A=&42 and &3E=&00.
[&8D27] Now: A = &84, &3E = &00 and &3D = &A5. [&8D2E] Now: A=&00, after addition, A=&00. &3D=&4A, A=&01.
[&8D39] Now: X=&01 and &3D=&4D.
This 2-byte value is tokenised as follows:
(X = &01, &3D = &4D)
3rd byte of tokenised value = &41 (X (&01) OR &40).
2nd byte of tokenised value = &4D (A (&0D) OR &40).
1st byte of tokenised value = &44 (&10 EOR &54) [(A (&01) AND &C0 => &00) ORA &3D (top 2 bits) = &40;
          divide by 4 = &10 EOR &54 ==> &44].


Disassembly for the Tokenise Line Number routine

8D04 ) 041 015 29 0F AND#&0F
8D06 = 133 061 85 3D STA &3D
8D08   162 000 A2 00 LDX#&00
8D0A   160 000 A0 00 LDY#&00
8D0C   200 C8 INY
8D0D 7 177 055 B1 37 LDA (&37),Y
8D0F   032 148 141 20 94 8D JSR &8D94 Check for numeric digit
8D12 . 144 046 90 2E BCC 46 --> &8D42 (no more numeric digits present)
8D14 ) 041 015 29 0F AND#&0F
8D16 H 072 48 PHA
8D17 > 134 062 86 3E STX &3E
8D19 = 165 061 A5 3D LDA &3D
8D1B   010 0A ASL A
8D1C &> 038 062 26 3E ROL &3E
8D1E 0 048 031 30 1F BMI 31 --> &8D3F
8D20   010 0A ASL A
8D21 &> 038 062 26 3E ROL &3E
8D23 0 048 026 30 1A BMI 26 --> &8D3F
8D25 e= 101 061 65 3D ADC &3D
8D27 = 133 061 85 3D STA &3D
8D29   138 8A TXA
8D2A e> 101 062 65 3E ADC &3E
8D2C = 006 061 06 3D ASL &3D
8D2E * 042 2A ROL A
8D2F 0 048 014 30 0E BMI 14 --> &8D3F
8D31   176 012 B0 0C BCS 12 --> &8D3F
8D33   170 AA TAX
8D34 h 104 68 PLA
8D35 e= 101 061 65 3D ADC &3D
8D37 = 133 061 85 3D STA &3D
8D39   144 209 90 D1 BCC -47 --> &8D0C
8D3B   232 E8 INX
8D3C   016 206 10 CE BPL -50 --> &8D0C
8D3E H 072 48 PHA
8D3F h 104 68 PLA
8D40 8 056 38 SEC
8D41 ` 096 60 RTS
8D42   136 88 DEY
8D43   169 141 A9 8D LDA#&8D
8D45   032 235 140 20 EB 8C JSR &8CEB Replace untokenised value with token
8D48 7 165 055 A5 37 LDA &37
8D4A 9 133 057 85 39 STA &39
8D4C 8 165 056 A5 38 LDA &38
8D4E : 133 058 85 3A STA &3A
8D50   032 162 141 20 A2 8D JSR &8DA2 Increment Pointer (&37, &38)
8D53   032 162 141 20 A2 8D JSR &8DA2 Increment Pointer (&37, &38)
8D56   032 162 141 20 A2 8D JSR &8DA2 Increment Pointer (&37, &38)
8D59 9 177 057 B1 39 LDA (&39),Y
8D5B 7 145 055 91 37 STA (&37),Y
8D5D   136 88 DEY
8D5E   208 249 D0 F9 BNE -7 --> &8D59
8D60   160 003 A0 03 LDY#&03
8D62   138 8A TXA
8D63 @ 009 064 09 40 ORA#&40
8D65 9 145 057 91 39 STA (&39),Y
8D67   136 88 DEY
8D68 = 165 061 A5 3D LDA &3D
8D6A )? 041 063 29 3F AND#&3F
8D6C @ 009 064 09 40 ORA#&40
8D6E 9 145 057 91 39 STA (&39),Y
8D70   136 88 DEY
8D71 ? 169 063 A9 3F LDA#&3F
8D73 = 020 061 14 3D TRB &3D
8D75   138 8A TXA
8D76 ) 041 192 29 C0 AND#&C0
8D78 J 074 4A LSR A
8D79 J 074 4A LSR A
8D7A = 005 061 05 3D ORA &3D
8D7C J 074 4A LSR A
8D7D J 074 4A LSR A
8D7E IT 073 084 49 54 EOR#&54
8D80 9 145 057 91 39 STA (&39),Y
8D82   024 18 CLC
8D83 ` 096 60 RTS

 


 Back to 8BS
Or