String Comparison Confusion

A forum for users of EhBASIC (Enhanced BASIC), a portable BASIC interpreter for 6502 microcomputers written by Lee Davison.
Post Reply
JenniferDigital
Posts: 92
Joined: 25 May 2015

String Comparison Confusion

Post by JenniferDigital »

Hello!

I was minding my own business writing a little basic program when I stumbled on some odd behaviour. I figured it may be a bug but I can't seem to find it in the EhBASIC source.

Code: Select all

p$="*"
DIM q$(1)
q$(1)="*"
PRINT p$=q$(1)
 0
PRINT q$(1)=p$
 -1
So, if I have a string on the left hand side it evaluates with false being true and true being false but if I have a string array on the left hand side, it evaluates correctly. The same appears true for <> :?

Am I going mad?
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: String Comparison Confusion

Post by Klaus2m5 »

Actually ?p$=p$ fails already. a=p$=p$:?a results in 1.89739E-16. It fails only in direct mode. If you put your statements into numbered program lines the results are correct in run mode.
6502 sources on GitHub: https://github.com/Klaus2m5
JenniferDigital
Posts: 92
Joined: 25 May 2015

Re: String Comparison Confusion

Post by JenniferDigital »

Interesting clue, though I am by no means clear on how EhBASIC evaluates the expression. I've been attempting to follow LAB_EVEX, but maybe I'm barking up the wrong tree.
User avatar
GaBuZoMeu
Posts: 660
Joined: 01 Mar 2017
Location: North-Germany

Re: String Comparison Confusion

Post by GaBuZoMeu »

Strange behavior indeed. I also test it and getting the same results. In programmed mode I got:

Code: Select all

100 P$="*"
110 DIM Q$(2)
120 Q$(1) = "*"
130 V$="+"
140 PRINTP$,Q$(1),V$
150 PRINT"P$=Q$(1) ",P$=Q$(1)
160 X=P$=Q$(1)
170 PRINTX,NOT(NOT(X))
180 PRINT"V$=Q$(1) ",V$=Q$(1)
190 X=V$=Q$(1)
200 PRINTX,NOT(NOT(X))
210 PRINT"Q$(1)=P$ ",Q$(1)=P$
220 X=Q$(1)=P$
230 PRINTX,NOT(NOT(X))
240 PRINT"Q$(1)=V$ ",Q$(1)=V$
250 X=Q$(1)=V$
260 PRINTX,NOT(NOT(X))

Ready
RUN
*             *             +
P$=Q$(1)      -1
-1            -1
V$=Q$(1)       0
 1.93215E-16   0
Q$(1)=P$      -1
-1            -1
Q$(1)=V$       0
 1.93215E-16   0

Ready
1,932E-16 isn't much but even EhBasic2.22 says:

Code: Select all

?X=0
 0

Ready
?NOT(NOT(X))=0
-1

Ready
:o
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: String Comparison Confusion

Post by Klaus2m5 »

The string compare is at LAB_1CAE. At LAB_1CE6 the strings are actually compared if they have the same length. FAC1_1 and FAC2_2 is used to hold the indirect pointer to the strings being compared. FAC2_2 was pointing to an invalid location in direct mode. Earlier in the code the string descriptor is pulled

Code: Select all

      LDA   FAC2_2            ; get descriptor pointer low byte
      LDY   FAC2_3            ; get descriptor pointer high byte
      JSR   LAB_22BA          ; pop (YA) descriptor off stack or from top of string space
                              ; returns with A = length, X=pointer low byte,
                              ; Y=pointer high byte
      STX   FAC2_2            ; save string pointer low byte
      STY   FAC2_3            ; save string pointer high byte
In memory the pointer to the string descriptor is off by +$100. So I went back to LAB_EVEX to see where FAC2_2 is loaded. After some more single stepping I found it is pushed onto the stack from FAC1 and then restored to FAC2. When it is pushed to the stack via LAB_1B5B FAC1 is rounded which causes the high address to be incremented by 1 if FAC1_r is > $7f. FAC1_r is not cleared when FAC1 actually contains a memory pointer. Actually it is never cleared and so I am not so sure wether it could also go wrong in run mode.

Code: Select all

; push sign, round FAC1 and put on stack

LAB_1B5B
      PLA                     ; get return addr low byte
      STA   ut1_pl            ; save it
      INC   ut1_pl            ; increment it (was ret-1 pushed? yes!)
                              ; note! no check is made on the high byte! if the calling
                              ; routine assembles to a page edge then this all goes
                              ; horribly wrong !!!
      PLA                     ; get return addr high byte
      STA   ut1_ph            ; save it
      LDA   FAC1_s            ; get FAC1 sign (b7)
      PHA                     ; push sign

; round FAC1 and put on stack

LAB_1B66
      JSR   LAB_27BA          ; round FAC1
      LDA   FAC1_3            ; get FAC1 mantissa3
      PHA                     ; push on stack
      LDA   FAC1_2            ; get FAC1 mantissa2
      PHA                     ; push on stack
      LDA   FAC1_1            ; get FAC1 mantissa1
      PHA                     ; push on stack
      LDA   FAC1_e            ; get FAC1 exponent
      PHA                     ; push on stack
      JMP   (ut1_pl)          ; return, sort of
Either FAC1_r must be cleared when FAC1 is used as a memory pointer or LAB_27BA should check wether the data type is string or number (without breaking something else of course).
6502 sources on GitHub: https://github.com/Klaus2m5
User avatar
GaBuZoMeu
Posts: 660
Joined: 01 Mar 2017
Location: North-Germany

Re: String Comparison Confusion

Post by GaBuZoMeu »

Thank you Klaus.

Do you have any idea why the floating point accumulators are used during string compare??? Is it a space issue?
JenniferDigital
Posts: 92
Joined: 25 May 2015

Re: String Comparison Confusion

Post by JenniferDigital »

It really confuses me when a name isn't meaningful. I'd like to know why too please?
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: String Comparison Confusion

Post by Klaus2m5 »

While strings are saved from top of memory down in EhBASIC the pointers to the strings are saved like normal variables from the end of the program upwards. So when variables or strings are referenced the mechanism is at first identical and a variable or pointer will be loaded to the floating point accumulator. Up to this point there is no need for extra code and extra zero page locations.

Only when an operation is to be executed the extra steps are taken to reference the string location. For example a "+" operation will just use the loaded arguments and add them if they are variables. If they are strings they need to be concatenated which is a completely different operation. Only then the strings are actually copied to free space in the string area. An error will occur if the data type (string or variable) is not identical on both sides of the "+".

Of course this is not an exact description of what is happening but a simplified view of how it actually works.
6502 sources on GitHub: https://github.com/Klaus2m5
User avatar
GaBuZoMeu
Posts: 660
Joined: 01 Mar 2017
Location: North-Germany

Re: String Comparison Confusion

Post by GaBuZoMeu »

Ah, yes, I forget that Basic defaults to work with floats. And EhBasic does not use the % operator for integers - although it sometimes appears to distinguish between float and integer - at least it appears to me due to the speed it has compared to M$.
User avatar
barrym95838
Posts: 2056
Joined: 30 Jun 2013
Location: Sacramento, CA, USA

Re: String Comparison Confusion

Post by barrym95838 »

GaBuZoMeu wrote:
... at least it appears to me due to the speed it has compared to M$.
I am by no stretch of the imagination an expert on either version, but the sources appear to me to do things in a superficially similar manner. Have you or anyone else had a chance to do any execution speed comparisons between them? OSI was the 32-bit float version, and therefore the most appropriate for the comparison.

Mike B.
User avatar
GaBuZoMeu
Posts: 660
Joined: 01 Mar 2017
Location: North-Germany

Re: String Comparison Confusion

Post by GaBuZoMeu »

This entry was a response to the previous post. As it was quite a bit OT I moved it to viewtopic.php?f=1&t=5198

Arne
Last edited by GaBuZoMeu on Tue Jul 03, 2018 4:39 pm, edited 3 times in total.
User avatar
BigEd
Posts: 11463
Joined: 11 Dec 2008
Location: England
Contact:

Re: String Comparison Confusion

Post by BigEd »

> P.S.: Sorry - this is quite a bit OT.

But a great table of benchmark results!
Chromatix
Posts: 1462
Joined: 21 May 2018

Re: String Comparison Confusion

Post by Chromatix »

(moved to new thread: viewtopic.php?f=1&t=5198&p=61006)
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: String Comparison Confusion

Post by Klaus2m5 »

I have created 2 patches. They haven't been tested to the full extend and so I can't be sure that they don't break anything else for now!

Patch to fix the string compare of equal strings in direct mode returning FALSE:

Code: Select all


; variable name set-up
; get (var), return value in FAC_1 and $ flag

LAB_1C18
      JSR   LAB_GVAR          ; get (var) address
      STA   FAC1_2            ; save address low byte in FAC1 mantissa2
      STY   FAC1_3            ; save address high byte in FAC1 mantissa3
      LDX   Dtypef            ; get data type flag, $FF=string, $00=numeric
      BMI   LAB_1C25          ; if string then return (does RTS)

LAB_1C24
      JMP   LAB_UFAC          ; unpack memory (AY) into FAC1

LAB_1C25
; *** begin patch  string pointer high byte trashed when moved to stack
; *** add
      LSR   FAC1_r            ; clear bit 7 (<$80) = do not round up
; *** end patch 
      RTS

Patch to fix FALSE value stored to a variable after string compare is not exactly zero:

Code: Select all


; perform LET

LAB_LET
      JSR   LAB_GVAR          ; get var address
      STA   Lvarpl            ; save var address low byte
      STY   Lvarph            ; save var address high byte
      LDA   #TK_EQUAL         ; get = token
      JSR   LAB_SCCA          ; scan for CHR$(A), else do syntax error then warm start
      LDA   Dtypef            ; get data type flag, $FF=string, $00=numeric
      PHA                     ; push data type flag
      JSR   LAB_EVEX          ; evaluate expression
      PLA                     ; pop data type flag
      ROL                     ; set carry if type = string
; *** begin patch  result of a string compare stores string pointer to variable
;                  but should store FAC1 (true/false value)
; *** replace
;      JSR   LAB_CKTM          ; type match check, set C for string
;      BNE   LAB_17D5          ; branch if string
; *** with
      JSR   LAB_CKTM          ; type match check, keep C (expected type)
      BCS   LAB_17D5          ; branch if string
; *** end patch

      JMP   LAB_PFAC          ; pack FAC1 into variable (Lvarpl) and return

; string LET

LAB_17D5
The patches above will eventually make it into my patched version of EhBASIC and my list of bugs supplied with the original version of EhBASIC. Now I am ready to have breakfast. :D
6502 sources on GitHub: https://github.com/Klaus2m5
User avatar
GaBuZoMeu
Posts: 660
Joined: 01 Mar 2017
Location: North-Germany

Re: String Comparison Confusion

Post by GaBuZoMeu »

I need to revive some old tools. This may take some time. But then I could apply these patches and verify them as well.

Brilliant work, Klaus 8)
Post Reply