c++ - 需要帮助理解 C 函数

标签 c++ c

事情是这样的:作为一种学习经验,我正在尝试将 C 程序转换为 C++。 This program获取一个文本文件并根据用户输入的规则对其进行修改。具体来说,它使用格式为“s1/s2/env”的规则将声音更改应用于一组单词。 s1 表示要更改的字符,s2 表示要将其更改为什么,env 是应应用更改的上下文。

很抱歉我没有更深入地描述这个问题,但是这个问题太长了,作者的网站已经解释过了。

我遇到问题的函数是 TryRule。我知道它应该查看给定规则是否适用于给定字符串,但我无法准确理解它是如何做到的。参数解释的不好让我很困惑:比如,我不明白为什么要传回字符串“s1”和“s2”,或者“i”代表什么。

这是代码:

/*
**  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);
}

最佳答案

这段代码……很难读懂。我查看了原始文件,它确实可以使用一些更好的变量名。我特别喜欢其中一个功能评论中的这一部分:

/*
** (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 关于变量的观点。我想我明白了,所以我将尝试将函数转换为伪代码。

Word:我们正在查看的字符串
i:我们正在查看的字符串中的索引
规则:规则的文本(即“v/b/_”)
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
}

希望对您有所帮助。您可能需要多读几遍。我花了超过 45 分钟来写这篇文章,几乎完全是因为试图破译围绕 TryCat 的一些案例中到底发生了什么。添加大约 5 分钟,不断尝试按 Tab 键并将光标发送到下一个字段(愚蠢的 HTML 文本框)。

抱歉,这太大了,您可能需要进行大量水平滚动。

关于c++ - 需要帮助理解 C 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/871300/

相关文章:

c++ - 请提及一些差价合约资源

c - 分配值表而不更改变量名称或编写花哨的代码

c - 使用 MPI_Type_create_subarray 做二维循环分布的例子

c++ - 在调试器下运行时,AssignProcessToJobObject 失败并出现 "Access Denied"错误

c++ - 在 Assets 管理器中高效使用 c++11 shared_ptr

c++ - 创建双向本地/Unix 套接字

c++ - 曲面 segmentation 着色器没有输出?

c++ - 替换少量字节时如何在大字节数组上重新计算 CRC32

c - 如何将二维数组广播到所有进程,以便每个等级中的函数都可以访问它?

c++ - 粒子系统的点 Sprite