Shop OBEX P1 Docs P2 Docs Learn Events
Strange method behavior, it will work locally, but not as an object — Parallax Forums

Strange method behavior, it will work locally, but not as an object

turbosupraturbosupra Posts: 1,088
edited 2011-10-21 12:04 in Propeller 1
I'm using Kye's strings method and when I send the following I'm getting strange behavior and was hoping someone could shed some light as to why. I tried to make this as simple as possible, but if it is confusing, I'll be happy to post my entire code, please let me know.

Whenever I send a string that has 2 or more characters in front of the delimiterPositionForName (in this case an equals sign) it will work

So 01=mot or 44=mot

But anytime I run it as an object and it is a single digit, it will not find the delimiter and returns a -1.
                      [b]DOESN'T WORK[/b]
    OBJ
pst : "Parallax Serial Terminal"
strings : "Strings"
com : "serialCom"

    l_variableReversed := "3=mot"
    b_delimiter[0] := "="
    b_delimiter[1] := 0

    l_returnTemp := strings.StrPos(l_variableReversed, @b_delimiter, 0)

    l_returnTemp is -1 (or it cannot find it)

when I run it locally
                      [b]DOES WORK[/b]
    OBJ
pst : "Parallax Serial Terminal"
strings : "Strings"
com : "serialCom"

    l_variableReversed := "3=mot"
    b_delimiter[0] := "="
    b_delimiter[1] := 0

    l_returnTemp := StrPos(l_variableReversed, @b_delimiter, 0)

    l_returnTemp is 1

Does anyone have any theories as to why? Thanks for reading.


This code below always works locally or as a method because there are at least 2 characters in front of the delimiter, in this case "31".
                      [b]ALWAYS WORKS[/b]
    OBJ
pst : "Parallax Serial Terminal"
strings : "Strings"
com : "serialCom"

    l_variableReversed := "31=mot" (or anything that is more than 1 digit)
    b_delimiter[0] := "="
    b_delimiter[1] := 0
    
    l_returnTemp := strings.StrPos(l_variableReversed, @b_delimiter, 0) OR  l_returnTemp := StrPos(l_variableReversed, @b_delimiter, 0)

Comments

  • kuronekokuroneko Posts: 3,623
    edited 2011-10-21 06:54
    The only string object with that method I could find in the OBEX is from Brandon Nimon and it works as advertised.
    OBJ
      strings : "Strings"
    
    VAR
      long  l_variableReversed
      byte  b_delimiter[2]
      
    PUB null
    
      l_variableReversed := [COLOR="#FFA500"]string([/COLOR]"3=mot"[COLOR="#FFA500"])[/COLOR]
      b_delimiter[0] := "="
      b_delimiter[1] := 0
    
      dira[16..23]~~
      outa[16..23] := strings.[COLOR="#0000FF"]StrPos[/COLOR](l_variableReversed, @b_delimiter, 0)
    
      waitpne(0, 0, 0)
    
    I don't know how you get away with l_variableReversed := "3=mot" (doesn't compile) but the code above works for me and returns 1.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-21 06:59
    The assignment l_variableReversed := "j_mot" is not legal. I don't know why the compiler let it pass. You can have single characters between quotes and the compiler will use the numeric value of the single character which isn't what you want here. The proper form is

    l_variableReversed := string("31=mot")

    This sets l_variableReversed to the address of the first byte of the string which is what you want here. The string is stored as a byte array with a zero byte appended to it to mark the end.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-10-21 07:09
    Hi Kuroneko,

    Thanks for the reply that was a typo, I apologize for that. Since I was trying to simply my code, I missed that when typing.

    The work firewall is blocking me from uploading the method object.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-10-21 07:18
    Hi Mike,

    So why if I call this method as an attached object and strAddr (in the method below) starts with a single numeric value before the delimiter, will the method fail ... but if strAddr starts with 2 or more numeric values, will the method succeed?

    Then when I call it locally, it works with a single digit?

    I can post my entire code, just not as an attached set of files, if that helps.

    PUB StrPos (strAddr, searchAddr, offset) | size, searchsize
    {{Returns location of first occurrence of search in str, returns -1 if search is not found.
    NOTE: counting starts at 0. 0 can be returned if search is found at first character of str.
    Faster than strstr if just searching for a string inside another str.
    StrPos("ABCDEFGHIJK","GH",0)
    Output: 6
    }}
      size := strsize(strAddr) + 1
      searchsize := strsize(searchAddr) 
      REPEAT UNTIL (offset + searchsize > size)
        IF (strcomp(StrParse(strAddr, offset++, searchsize), searchAddr))           ' if string search found
          RETURN offset - 1                                                         ' return byte location
      RETURN -1
    
    
    
    PUB StrParse (strAddr, start, count)
    {{Returns part of a string for count bytes starting from start byte.
    This is a faster and simpler version of SubStr.
    NOTE: forward counting starts at 0.
    example: char-position 01234567890
    string:                ABCDEFGHIJK
    SubParse("ABCDEFGHIJK",4,1)
    Output: "E"
    }}
      'bytefill(@ostr, 0, count)
      count <#= constant(STR_MAX_LENGTH - 1)
      bytemove(@ostr, strAddr + start, count)                                       ' just move the selected section
    
      ostr[count] := 0                                                              ' terminate string
      RETURN @ostr
    
    
    
    Mike Green wrote: »
    The assignment l_variableReversed := "j_mot" is not legal. I don't know why the compiler let it pass. You can have single characters between quotes and the compiler will use the numeric value of the single character which isn't what you want here. The proper form is

    l_variableReversed := string("31=mot")

    This sets l_variableReversed to the address of the first byte of the string which is what you want here. The string is stored as a byte array with a zero byte appended to it to mark the end.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-10-21 07:30
    Ok,

    I believe this indicates what the problem is, although I'm not 100% sure yet what it is.

    I'm getting "3=mot" as a return value from another method. It is a variable that is set to a long (l_variableReversed ). In my example I hard coded it to simplify how long the code was and to try and make it easier to understand (which is where the typo came from). When I hard coded it like your example, it did indeed work.

    The difference is between

    (long) l_variableReversed := string("3=mot")

    and (long) l_variableReversed := method return value, which I believe is a "long"

    Can anyone expand upon this and tell me if I'm onto something or not? If this is indeed the issue, how can I correct it?


    kuroneko wrote: »
    The only string object with that method I could find in the OBEX is from Brandon Nimon and it works as advertised.
    OBJ
      strings : "Strings"
    
    VAR
      long  l_variableReversed
      byte  b_delimiter[2]
      
    PUB null
    
      l_variableReversed := [COLOR="#FFA500"]string([/COLOR]"3=mot"[COLOR="#FFA500"])[/COLOR]
      b_delimiter[0] := "="
      b_delimiter[1] := 0
    
      dira[16..23]~~
      outa[16..23] := strings.[COLOR="#020FC0"]StrPos[/COLOR](l_variableReversed, @b_delimiter, 0)
    
      waitpne(0, 0, 0)
    
    I don't know how you get away with l_variableReversed := "3=mot" (doesn't compile) but the code above works for me and returns 1.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-21 07:46
    Where's ostr?

    When you use the Strings object, ostr is allocated in the storage area for the object. When you use the StrParse method locally, you have to provide that and it has to be big enough to hold the largest possible result string.
  • turbosupraturbosupra Posts: 1,088
    edited 2011-10-21 08:03
    I have the same values in both files, whether I run it locally or as an attached object. Would you like the whole code in text format?

    Also, can you explain the programmatic difference between these two? Is there a "toString" method, so I could say l_variableReversed := l_variableReversed.ToString or something like that?

    (long) l_variableReversed := string("3=mot")

    and (long) l_variableReversed := method return value, which I believe is a "long"
    CON
        STR_MAX_LENGTH = 128  
    
    
    VAR
        BYTE ostr[STR_MAX_LENGTH]
        BYTE ostr2[STR_MAX_LENGTH]                            ' used for StrReplace only
    
    

    Mike Green wrote: »
    Where's ostr?

    When you use the Strings object, ostr is allocated in the storage area for the object. When you use the StrParse method locally, you have to provide that and it has to be big enough to hold the largest possible result string.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-21 09:47
    I guess I'm still confused about what you're trying to do, what you're starting with, and what the "strange behavior" is.

    Spin does not really have string values. It has 32-bit signed integers that are called longs. There are 16-bit variables (words) and 8-bit variables (bytes) as well as arrays of all of these. No automatic sign extension is done when fetching values from storage units smaller than 32-bits. String constants are stored as byte arrays with a zero byte as a terminator and the address of the first byte is what is used as the string "value". Various library routines that use string values (like the String object) use the same convention. Method parameters, results, and local variables are all longs.

    Spin does allow single quoted characters in expressions and the value of that quoted character is the numeric value of the character in the ASCII character set. StrPos expects its first two parameters to be strings, in other words, the addresses of characters stored in byte arrays in memory. You would call StrPos as follows:

    outa[16..23] := strings.StrPos(string("3=mot"), string("="), 0)

    If you declare

    var byte l_stringReversed[10], delimiter[3]
    var long l_variableReversed

    you could then write (in some method)

    l_variableReversed := @l_stringReversed ' get the address of the string value
    bytemove(l_variableReversed, string("3=mot"), 6) ' initialize the string value
    bytemove(@delimiter, string("="), 2) ' initialize the delimiter value

    dira[ 16..23 ]~~
    outa[ 16..23 ] := StrPos( l_variableReversed, @delimiter, 0 )
  • turbosupraturbosupra Posts: 1,088
    edited 2011-10-21 10:58
    Mike Green wrote: »
    I guess I'm still confused about what you're trying to do, what you're starting with, and what the "strange behavior" is.

    Hi Mike,

    Thanks for the reply. The strange behavior is that when I use the StrPos (and StrParse) methods locally, they will work regardless of how many characters/bytes precede the delimiter in the StrPos method.

    When I use the StrPos method by attaching it inside of the Strings object (Strings.StrPos)
    OBJ
        strings : "Strings"
    

    it will only work if the character/byte count is 2 or more, that precede the delimiter in the Strings.StrPos method.

    Mike Green wrote: »
    Spin does not really have string values. It has 32-bit signed integers that are called longs. There are 16-bit variables (words) and 8-bit variables (bytes) as well as arrays of all of these. No automatic sign extension is done when fetching values from storage units smaller than 32-bits. String constants are stored as byte arrays with a zero byte as a terminator and the address of the first byte is what is used as the string "value". Various library routines that use string values (like the String object) use the same convention. Method parameters, results, and local variables are all longs.

    If I understand this correctly, if a string is "This is a string", the variable would be stringName[128] and the string method would want the memory address of the first "T". After that, it would read each concurrent byte, until it arrived at a byte with all zeros, 00000000 and that is how it determines the length of the string byte array and where it ends, correct?

    Mike Green wrote: »
    Spin does allow single quoted characters in expressions and the value of that quoted character is the numeric value of the character in the ASCII character set.

    This is because it stores it as a single byte, followed by a byte terminator of 00000000 ?

    Mike Green wrote: »
    StrPos expects its first two parameters to be strings, in other words, the addresses of characters stored in byte arrays in memory. You would call StrPos as follows:

    outa[16..23] := strings.StrPos(string("3=mot"), string("="), 0)

    If you declare

    var byte l_stringReversed[10], delimiter[3]
    var long l_variableReversed

    you could then write (in some method)

    l_variableReversed := @l_stringReversed ' get the address of the string value
    bytemove(l_variableReversed, string("3=mot"), 6) ' initialize the string value
    bytemove(@delimiter, string("="), 2) ' initialize the delimiter value

    dira[ 16..23 ]~~
    outa[ 16..23 ] := StrPos( l_variableReversed, @delimiter, 0 )

    I will have to try this code. Would you mind if I emailed you my code, so you could see the changing behavior?
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-21 12:04
    "Spin does not really have string values ..." Yes, you're correct except that the length of the array allocated is the number of characters in the string plus 1.

    "Spin does allow single quoted ..." No, the constant value is actually encoded in the Spin interpretive instructions since there's an instruction that does a push immediate value for 8-bit values. There's no byte terminator since this really isn't considered a string, just a single character value.
Sign In or Register to comment.