2009-05-15 10 views
1

ここでは対処方法を学びます:私はC言語のプログラムをC++に変換しようとしています。 This programはテキストファイルを受け取り、ユーザーが入力した規則に従って変更を適用します。具体的には、 "s1/s2/env"のようなフォーマットの規則を使用して、一連の単語にサウンド変更を適用します。 s1は変更する文字を表し、s2は変更する文字を表し、envは変更を適用するコンテキストです。C関数を理解する助けが必要です

私はこれについて詳しくは説明しませんが、申し訳ありませんが、質問は長すぎるかもしれません。著者のサイトでは既に説明しています。

私が困っている機能はTryRuleです。与えられた文字列に与えられた規則が当てはまるかどうかを知るはずですが、どうしているのかを正確に理解できません。パラメータの貧弱な説明は私を混乱させます。たとえば、文字列 "s1"と "s2"を返す必要があるかどうか、または "i"が何を表すのか分かりません。

これはコードです:あなたはあなたにも読みやすくなるようにコードをリファクタリングする必要がありますC++にCから変換されていることを考えると

/* 
** 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

このサイトでは、コードの色分けがよくなっています。ペーストビンを使用しても人気がありません。あなたの質問の書式を整えて公式化することも、答えを得る良い方法です。 – gnud

+1

コメントにコピー:リンクではなく、関連する最小コードサンプルを投稿に含めてください。 ありがとう! –

+0

あなたの質問の情報によれば、パラメータが何のためのものなのか知っているので、実際に何を表すかを表すように名前を変更するべきでしょう。 s1とs2は変数のひどい名前です。 –

答えて

2

このコードは読みにくいです。私は元のファイルを見て、実際にはより良い変数名を使用することができます。私は特に、この部分を機能のコメントから愛しています。

/* 
** (Stuff I removed) 
** 
** Warning: For now, we don't have a way to handle digraphs. 
** 
** We also return TRUE if (<- It really just stops here!) 
*/ 

私は挑戦を見ることができます。私は変数に関するwmeyerに同意します。私は物事を理解していると思うので、私は関数を疑似コードに変換しようとします。

ワード:文字列のインデックスは、我々は
ルールを見ている:私たちは私
見ている文字列ルールのテキスト(すなわち、
n:_の一致が見つかった文字列にインデックスを返す変数
s1:ルール
s2からデコードされたルールの最初の部分を返します。 :ルールの第二部を返し、ルール
varRepのうちのデコードは:カテゴリが一致した場合、私はこのことができます願ってい

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 
} 

を考えて、カテゴリにマッチした文字を返します。あなたはそれを数回読む必要があるかもしれません。 TryCatのいくつかのケースで何が起こっているのかを正確に解読しようとしたため、これを書くのに45分以上かかりました。約5分で、Tabキーを押してカーソルを次のフィールド(愚かなHTMLテキストボックス)に送るようにしています。

申し訳ありませんが、これは非常に大きいので、おそらく水平スクロールの束を行う必要があります。

0

このコードの主な問題点は、変数にひどい名前が付いていることです。ルーチンの元の作家であっても、分析に時間を費やす必要があります。

より正確に変数の名前を変更するだけで、コードが何をしているかを理解することができます。

いくつかのヘルプについては、questions tagged under refactoringをご覧ください。 Refactoring by Martin Fowler

+1

まあ、問題は変数が何であるのか分からないから、名前を変更できないということです。 – Javier

+0

@reyjavikvi私が言ったように、あなたのやり方であなたを助けるリファクタリング技術を調べたいと思うかもしれません。 wmeyerは、そのルーチンを理解するためにコード全体を調べる必要があるかもしれないと言いました。それはどこにも理想に近いところですが、それは事実かもしれません。 –

0

私はこの断片を理解するためにwhole codeが必要だと思います。

"word"、 "i"、 "Rule"は入力変数で、残りは純粋な出力変数です。

"i"は "word"内の現在のインデックスです。つまり、TryRuleは "word [i]"から始まる "word"のみを検索します。

"s1"では、関数は適用されたルールの左側を返します。 "s2"では、そのルールの右側です。

"n"では、関数はルールが適用される "word"内の位置を返します。

"varRep"とは何も分かりません。

+0

したがって、nとiの違いは何ですか? – Javier

+0

"i"は入力であり、tryRuleにword [i]で始まるように指示します。 "n"は出力であり、ワード[n]で "s1"(ルールの左側)が見つかったことを呼び出し関数に通知します。 不変式:n> = i – wmeyer

関連する問題