Shop OBEX P1 Docs P2 Docs Learn Events
Spin question about CASE statement — Parallax Forums

Spin question about CASE statement

pjrpjr Posts: 14
edited 2012-10-24 20:28 in Propeller 1
Can i use a CASE test for matching complete strings ?

Comments

  • doggiedocdoggiedoc Posts: 2,243
    edited 2012-10-24 06:58
    I would assume you could using a variable assignment and/or constant. Perhaps the STRCOMP command would be helpful?
  • Mike GreenMike Green Posts: 23,101
    edited 2012-10-24 07:03
    No, not really

    The CASE statement takes a single 32-bit value and compares it to other 32-bit values. A string is represented by the address of the first byte of a block of bytes containing the string terminated with a zero byte. Comparing addresses doesn't do what you want. String literals are not combined by the Spin compiler, so, when you write STRING("something") and later write STRING("something"), you get two different addresses and two copies of the string in your object program.

    One solution to this is to have a dictionary and always look up strings that are entered by the program's user. FemtoBasic does this using a dictionary of keywords. You can see the routine involved in FemtoBasic.spin (tokenize) which scans through an input line, substituting a byte containing the number of the keyword + 128 for the characters of the keyword. It also recognizes the string quote (") so it doesn't try to lookup keywords in the string. The dictionary is near the beginning of the program.
  • pjrpjr Posts: 14
    edited 2012-10-24 09:14
    Thanks for the info. I was assuming something like this was happening.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-10-24 10:26
    For special purpose, remember that you can pack a 4-character string into one long, for example,
    "/cmd"
    That can be long-aligned with other 4-byte strings and then used as longs in case statements, for example for a command parser. Note that those strings are low-endian, so the "/" above is in the least significant byte.
  • pjrpjr Posts: 14
    edited 2012-10-24 10:30
    That would fit for me as I'm parsing 3-char strings. How do you pack them into longs ?
  • Mike GreenMike Green Posts: 23,101
    edited 2012-10-24 10:37
    aLong := (aChar[2] << 16) + (aChar[1] << 8) + aChar[0] ' where the string is in the 3 character byte array "aChar"

    Given a 3 character string in the array aChar, you could also have
    PRI makePackedString( aStringAddress )
       repeat 3
          result := (result << 8) + byte[aStringAddress++]
    
    Then you'd call makePackedString(@aChar) and the returned value would be the 3 characters in a single long.

    You could also supply a literal, so you could write: makePackedString(string("foo"))
  • doggiedocdoggiedoc Posts: 2,243
    edited 2012-10-24 11:00
    Handy tips Mike and Tracey! Thanks for info.

    Paul
  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2012-10-24 11:52
    You can also use a hash function to create 32-bit signatures for strings of any length. The following example was created based upon the FNV Hash:
    CON
    
      _clkmode      = xtal1 + pll16x
      _xinfreq      = 5_000_000
    
      FNV_PRIME     = 16777619
      FNV_OFFSET    = 2166136261
    
    OBJ
    
      pst   :       "Parallax Serial Terminal"
    
    PUB start | addr
    
      pst.start(9600)
      addr := @testing
      repeat
        pst.str(addr)
        pst.char(" ")
        pst.dec(hash(addr))
        pst.char(13)
        addr += strsize(addr) + 1
      while byte[addr]  
    
    PUB hash(str_addr) | ch
    
      result := FNV_OFFSET
      repeat while (ch := byte[str_addr++])
        result := (result * FNV_PRIME) ^ ch
    
    DAT
    
    testing       byte      "Testing 123.", 0
    fourscore     byte      "Fourscore and seven years ago.", 0
    uc_prop       byte      "The Propeller is a really cool chip.", 0
    lc_prop       byte      "The propeller is a really cool chip.", 0
                  byte      0
    

    For use with case statements, the target strings would all be pre-hashed and the results stored. Then the input string would be hashed and that result used in the case statement to compare with the pre-hashed values.

    Obviously, hashing is a many-to-one mapping, so it's possible to have two strings return the same hash value. But the likelihood of that, given a finite set of strings, is vanishingly small.

    -Phil
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-10-24 13:44
    You can do like Mike says at run-time, or at compile time in a CON block with = for a predefined command set. Or pack them in DATa statements:
    DAT
      dummy long  0    ' to assure long alignment
      leftmove byte "/lmv"
      rightmove byte "/rmv"
      getdegC byte "/g*C"
      setpin  byte "/spn"
    
    etc. Then when commands come in over whatever channel, look for the start character, e.g., the "/", and use the type of code Mike suggested to parse the incoming command into a long, low endian. Then use CASE to compare that with the predefined command names and take the appropriate actions.
    CASE myValue
       leftmove : 
       rightmove :
       getdegC :  
       yadayada
    
  • cavelambcavelamb Posts: 720
    edited 2012-10-24 20:28
    Then use CASE to compare that with the predefined command names and take the appropriate actions.
    CASE myValue
       leftmove : 
       rightmove :
       getdegC :  
       yadayada
    


    I can follow this - i think.


    I love it when you guys talk dirty.
Sign In or Register to comment.