Parsing a string (snippet, issues)

Posted by Zeno on Sun 25 Mar 2007 07:32 PM — 9 posts, 30,589 views.

USA #0
Long story short, I'm installing this snippet:
http://auricmud.com/snippets/FUSS_Variables.html

The parse_setvar function does not work correctly.

With this prog:
say Hello $n... $n?

It produces the output:
Quote:
Mob says 'Hello .. Zeno?'


So any token except the last(?) one is lost. In the parse_setvar function then, 'results' is being parsed wrong.

Does anyone see the problem? I'm still looking into it.
USA #1
Well, without really having studied the system in detail, it looks like it's expecting something after the $n. When it sees a period two after the $, it goes into variable parsing mode and doesn't put back the $\[xyz]. However when it doesn't see a period two after $\[xyz], it puts back the $\[xyz].

That is probably why you're seeing this issue. If you try something like "say $n hello $n... $n $n $n" you will probably get four times your name.
USA #2
It's looking for a . after $n, but it shouldn't expect it. The . will not always be there.
USA #3
Well, yes, but that's what it's doing nonetheless:


      x+=2; // skip over the identifier and go straight into whats next...
      if (cmnd[x] != '.' || cmnd[x] == '\0') //  not a period, so this isnt a pointer, just a variable.
      {
       add_letter( results, cmnd[x-2]); // Put this piece back
       add_letter( results, cmnd[x-1]); // Put this piece back
       add_letter( results, cmnd[x]); // Put this piece back
       if ( cmnd[x] == '\0')
         return results;
       continue; // and keep going.
      }


If it sees the pattern $.[^.], it puts that back into the result text, therefore not expecting a period.

However if it sees the pattern $.\., it goes into parsing mode.

In parsing mode we have:

      else  // Ok, they used the right syntax, lets fight out what our 'word' is.
      {
         char word[MAX_INPUT_LENGTH];;
         word[0] = '\0';
         x++;
         while ( isalpha(cmnd[x]) && cmnd[x] != '\0')  // Lets find the next single word.
         {
            add_letter( word, cmnd[x]);
            x++;
         }


In your case, this is where it stops. It skipped over the $n., and is now trying to build up the word. The first thing it sees is another ., so it stops that while loop. The word string is therefore empty.

Now all of the ifchecks after that only add to the result string if they find a word they were expecting.

To fix this problem it would probably suffice to have a case where word is empty; in that case you would put into the result string whatever was period the period, in addition to the period.

Basically what we have here is a case of lexical parsing ambiguity.
USA #4
*nod*
Do you see anything wrong with this fix? It appears to be working.

      else  // Ok, they used the right syntax, lets fight out what our 'word' is.
      {
         char word[MAX_INPUT_LENGTH];;
         word[0] = '\0';
         int origX=x-2;

         x++;
         while ( isalpha(cmnd[x]) && cmnd[x] != '\0')  // Lets find the next single word.
         {
            add_letter( word, cmnd[x]);
            x++;
         }
        if ( word[0] != '\0' )
        {
           // If we get here, we assume we now have the word.
         if (chkchar != NULL)  // Begin looking for possible character matches.
         { 
             if (!str_cmp( word, "name"))     
             {
                 if (IS_NPC(chkchar))
                   strcat( results, format( "%s", chkchar->short_descr) );
                 else
                   strcat( results, format( "%s", chkchar->name ));
             }
             if (!str_cmp( word, "sex"))
             {           
                 if (chkchar->sex == 2)
                   strcat( results, format( "%s", "female" ));
                 else
                   strcat( results, format( "%s", "male" ));
             }
             if (!str_cmp( word, "class"))
             {
                 strcat( results, format( "%s", npc_class[chkchar->class] ));
             }
             if (!str_cmp( word, "race"))
             {              
                 strcat( results, get_race(chkchar) );
             }
             if (!str_cmp( word, "level"))
             {
                 strcat( results, format( "%d", chkchar->level) );
             }

             // add your own char checks at this point
         }
         if (chkobj != NULL)  // Then do objects.
         {
             if (!str_cmp( word, "level"))
             {
                 strcat( results, format( "%d", chkobj->level) );
             }
             // add your own obj checks at this point
         }
        }
        else
        {
          //no word
          while ( origX < x )
          {
            add_letter( results, cmnd[origX]);
            origX++;
          }
        }     
         if (cmnd[x] == '\0')           
          return results;
         else
          add_letter( results, cmnd[x]);
      }              
    }
  }           
  return results;
}            
USA #5
That looks reasonable to me, yes. Although I think the best check is to just test it and see what happens. :-)
USA #6
hey zeno, the whole snippet is broken as it is, if you want i can email you my copy and you can fix it with that. my version is different as i went away from the only 5 variables per char/mob/obj thing, but it should be sufficient in helping you fix it.
#7
I recently installed a similar snippet (a few weeks ago) and I can't remember the details properly, but ie, 'mpechoat $n Moo!' would become 'mpechoat Moo!'. I fixed it up and i've just replicated what you've done above with no problems. It was the 'Scripting System' available on MudBytes. Try:

http://www.mudbytes.net/index.php?a=files&s=displayfile&fid=740&d=/&f=progvariables.txt

Sorry mate. I'm happy to email you my code too though, if you want. :P
USA #8
umm volk that is my snippet that i posted if you could tell me what was wrong with it i will be happy to fix it as that did not happen in my system. i will be updating it soon for the updated code i have so i'd like to make sure its 100% before i repost it.