2009-05-15 6 views
1

Hier ist der Deal: Ich versuche, als Lernerfahrung, ein C-Programm in C++ zu konvertieren. This program nimmt eine Textdatei und wendet Änderungen entsprechend den vom Benutzer eingegebenen Regeln an. Insbesondere wendet es Lautänderungen auf eine Reihe von Wörtern an, wobei Regeln verwendet werden, die wie "s1/s2/env" formatiert sind. s1 stellt die Zeichen dar, die geändert werden sollen, s2 gibt an, in was geändert werden soll, und env ist der Kontext, in dem die Änderung angewendet werden soll.Brauchen Sie Hilfe, eine C-Funktion zu verstehen

Es tut mir leid, dass ich dies nicht ausführlicher beschreibe, aber die Frage wäre zu lang, und die Website des Autors erklärt es bereits.

Die Funktion, die ich habe Probleme ist TryRule. Ich verstehe, dass es sehen soll, ob eine gegebene Regel auf eine gegebene Zeichenfolge zutrifft, aber ich habe Probleme, genau zu verstehen, wie es funktioniert. Die schlechte Erklärung der Parameter verwirrt mich: Zum Beispiel verstehe ich nicht, warum die Strings "s1" und "s2" zurückgegeben werden müssen oder was "i" bedeutet.

Dies ist der Code:

/* 
** TryRule 
** 
** See if a rule s1->s2/env applies at position i in the given word. 
** 
** If it does, we pass back the index where s1 was found in the 
** word, as well as s1 and s2, and return TRUE. 
** 
** Otherwise, we return FALSE, and pass garbage in the output variables. 
*/ 
int TryRule(char *word, int i, char *Rule, int *n, char **s1, char **s2, char *varRep) 
    { 
     int j, m, cont = 0; 
     int catLoc; 
     char *env; 
     int optional = FALSE; 
     *varRep = '\0'; 

     if (!Divide(Rule, s1, s2, &env) || !strchr(env, '_')) 
      return(FALSE); 

     for (j = 0, cont = TRUE; cont && j < strlen(env); j++) 
     { 
      switch(env[j]) 
      { 
       case '(': 
        optional = TRUE; 
        break; 

       case ')': 
        optional = FALSE; 
        break; 

       case '#': 
        cont = j ? (i == strlen(word)) : (i == 0); 
        break; 

       case '_': 
        cont = !strncmp(&word[i], *s1, strlen(*s1)); 
        if (cont) 
        { 
         *n = i; 
         i += strlen(*s1); 
        } 
        else 
        { 
         cont = TryCat(*s1, &word[i], &m, &catLoc); 
         if (cont && m) 
         { 
          int c; 
          *n = i; 
          i += m; 

          for (c = 0; c < nCat; c++) 
           if ((*s2)[0] == Cat[c][0] && catLoc < strlen(Cat[c])) 
            *varRep = Cat[c][catLoc]; 
         } 
         else if (cont) 
          cont = FALSE; 
        } 
        break; 

       default: 
        cont = TryCat(&env[j], &word[i], &m, &catLoc); 
        if (cont && !m) 
        { 
         /* no category applied */ 
         cont = i < strlen(word) && word[i] == env[j]; 
         m = 1; 
        } 
        if (cont) 
         i += m; 
        if (!cont && optional) 
         cont = TRUE; 
      } 
     } 
     if (cont && printRules) 
      printf(" %s->%s /%s applies to %s at %i\n", 
      *s1, *s2, env, word, *n); 

    return(cont); 
} 
+2

Diese Seite hat eine gute Code-Färbung - die Verwendung von Pastebin wird Sie nicht sehr beliebt machen. Formatieren und formulieren Sie Ihre Frage besser ist auch eine gute Möglichkeit, Antworten zu erhalten. – gnud

+1

Kopiert, um zu kommentieren: Bitte geben Sie das relevante Codebeispiel in den Beitrag ein und nicht als Link. Danke! –

+0

Nach den Informationen in Ihrer Frage wissen Sie, wofür die Parameter sind. Vielleicht sollten Sie sie umbenennen, damit sie darstellen, wofür sie eigentlich sind. s1 und s2 sind schreckliche Namen für Variablen. –

Antwort

2

Dieser Code ist schwer zu lesen. Ich habe mir die Originaldatei angeschaut und könnte tatsächlich bessere Variablennamen verwenden. Ich liebe besonders dieses Teil von einem der Funktionskommentare:

Ich kann die Herausforderung sehen. Ich stimme wmeyer zu den Variablen zu. Ich denke, ich verstehe Dinge, also werde ich versuchen, die Funktion in Pseudo-Code zu übersetzen.

Wort: Die Zeichenfolge wir bei
i suchen: Der Index im String sind wir bei
Regel sucht: Der Text der Regel (d„V/b/_“)
n: Eine Variable, die den Index in den String zurück wir das Spiel für die _ gefunden, ich glaube
s1: Gibt den ersten Teil der Regel aus Regel decodiert
s2 : der zweite Teil der Regel Returns Regel aus dekodiert
varRep: Gibt die in der Kategorie abgestimmt Charakter, wenn eine Kategorie abgestimmt, ich glaube,

int TryRule(char *word, int i, char *Rule, 
       int *n, char **s1, char **s2, char *varRep) { 
     Prepare a bunch of variables we''ll use later 
     Mark that we''re not working on an optional term 
     Set varRep''s first char to null, so it''s an empty string 

     if (We can parse the rule into it''s parts 
       OR there is no _ in the environment (which is required)) 
      return FALSE // Error, we can't run, the rule is screwy 

     for (each character, j, in env (the third part of the rule)) { 
      if (cont is TRUE) { 
       switch (the character we''re looking at, j) { 
        if the character is opening paren: 
         set optional to TRUE, marking it''s an optional character 
        if the character is closing paren: 
         set optional to FALSE, since we''re done with optional stuff 
        if the character is a hash mark (#): 
         // This is rather complicated looking, but it's not bad 
         // This uses a ? b : c, which means IF a THEN b ELSE c 
         // Remember i is the position in the word we are looking at 
         // Hash marks match the start or end of a word 
         // J is the character in the word 

         if (j >= 0) { 
          // We're not working on the first character in the rule 
          // so the # mark we found is to find the end of a word 

          if (i == the length of the word we''re looking at) { 
           // We've found the end of the word, so the rule matches 

           continue = true; // Keep going 
          } else { 
           // We're not at the end of a word, but we found a hash 
           // Rule doesn't match, so break out of the main loop by setting 
           //  continue to false 

           continue = false; 
          } 
         } else { 
          // OK, the hash mark is the first part of env, 
          // so it signifies the start of a word 

          continue = (i == 0); // Continue holds if we 
                // are matching the first 
                // character in *word or not 
         } 
        if the character is an _ (the match character): 
         // This gets complicated 

         continue = if word starting at character i ISN''T s1, the search string; 

         if (continue == TRUE) { 
          // There was no match, so we'll go look at the next word 
          n = the index of the word start that didn''t match // Not sure why 
          i = i (start index to look) + length of s1 (word we just matched) 
          // This means i now holds the index of the start of the next word 
         } else { 
          // TryCat sees if the character we're trying to match is a category 

          continue = s1 is a category in the program 
              && the category contains the character at word[i] 

          // If continue holds false, s1 was a category and we found no match 
          // If continue holds true, s1 either wasn't a category (so m = 0) 
          //  or s1 WAS a category, m contains 1, and catLoc holds which 
          //  character in the category definition was matched 

          if (we found a match of some sort 
            && s1 was a category (indicated by m == 1)) { 
           n = index of the character in the word we found a match 
           i = the index of the next character (m is always 1, so this is ugly) 

           for (each category defined) { 
            if (first character of s2 
              == the category''s name 
             && where in the category definition we matched 
               is less than the length of the category we''re on) { 
              varRep = the character matched in the category 
             } 
           } 

           // Now the above seems EXACTLY like the TryCat function. You'd 
           // think varRep would always hold the same value as catLoc. I 
           // believe this loop is so that later rules also get applied? 
          } else { 
           continue = FALSE; // Because we didn't match a letter or category 
          } 
         } 
        Any other character: 
         continue = the character we''re looking at is a category in the program 
             && the category contains the character at word[i] 

         if (there was a match AND it wasn''t a category (m == 0, just a letter)) { 
          m = 1; 
          continue if and only if there are characters left in the word 
           (i < strlen()) && the current character is at word[i] 
           (we matched a literal character, instead of a category) 
         } 

         if (continue) 
          i = i + m // Remember, M is always 1 or 0 
             // So this is basically IF continue THEN i++ END IF 
         if ((continue == FALSE) && (optional == TRUE)) 
          // We didn't find a match, but we're working on an optional part 
          // So continue anyway 
          continue = TRUE; 
       end switch 
      end if continue == true 
     } 
    } 

    if (continue && printRules) 
     print out a little debug statement showing what we matched 

    return continue; // At this point, if continue is false we can't keep matching 
} 

ich hoffe, das hilft. Möglicherweise müssen Sie es ein paar Mal lesen. Ich brauchte über 45 Minuten, um dies zu schreiben, fast ausschließlich, weil ich genau versuchte herauszufinden, was in einigen Fällen um TryCat herum passiert. Fügen Sie in ungefähr 5 Minuten hinzu, um ständig zu versuchen, die Tab-Taste zu drücken und meinen Cursor zum nächsten Feld zu schicken (dummes HTML-Textfeld).

Entschuldigung das ist so groß, Sie werden wahrscheinlich eine Reihe von horizontalen Scrollen machen müssen.

0

Da Sie von C zu C++ konvertieren Sie den Code werden Refactoring sollte besser lesbar als auch zu werden.

Ein großes Problem mit diesem Code ist, dass die Variablen schreckliche Namen haben und ich wette, sogar der ursprüngliche Schreiber der Routine müsste einige Zeit damit verbringen, sie zu analysieren.

Das Umbenennen der Variablen, um genauer zu sein, würde Ihnen eine größere Hand geben, zu verstehen, was der Code tut.

Werfen Sie einen Blick auf einige questions tagged under refactoring für einige Hilfe. Es gibt auch Refactoring by Martin Fowler

+1

Nun, Ärger ist, ich bekomme nicht, wofür die Variablen sind, also kann ich sie nicht umbenennen. – Javier

+0

@reyjavikvi Wie ich schon sagte, sollten Sie sich einige Refactoring-Techniken ansehen, um Ihnen auf Ihrem Weg zu helfen. Wie wmeyer sagte, müssen Sie vielleicht den ganzen Code studieren, um diese Routine zu verstehen. Das ist bei weitem nicht ideal, aber es könnte der Fall sein. –

0

Ich glaube, Sie brauchen die whole code, um dieses Fragment zu verstehen.

Es sieht aus wie "Wort", "i" und "Rule" sind Eingabevariablen, der Rest sind reine Ausgabevariablen.

"i" ist der aktuelle Index in "Wort", d. H. TryRule betrachtet nur "Wort" beginnend bei "Wort [i]".

In "s1" gibt die Funktion die linke Seite der Regel zurück, die angewendet wurde. In "s2" die rechte Seite dieser Regel.

In "n" gibt die Funktion die Position in "Wort" zurück, für die die Regel gilt.

Keine Ahnung was "varRep" ist.

+0

Also, was wäre der Unterschied zwischen n und ich? – Javier

+0

"i" ist eine Eingabe und weist TryRule an, bei word [i] zu beginnen. "n" ist eine Ausgabe und teilt der aufrufenden Funktion mit, dass "s1" (die linke Seite der Regel) bei word [n] gefunden wurde. Invariante: n> = i – wmeyer

Verwandte Themen