C语言实现注释转换

主题思路

将c语言的注释风格 转换 为 C++的风格需要遇到如下问题 :

//1.一般情况
int num = 0;
/int i = 0; /// 2.换行问题/ * int i = 0; * / int i = 0; / * int i = 0; * /int j = 0; // 3.匹配问题/ * int i = 0; / * xxxxx * /// 4.多行注释问题/ int i = 0; int j = 0; int k = 0; / int k = 0; // 5.连续注释问题/ * // * /// 6.连续的* /问题/ * ///7.C++注释问题// / * xxxxxxxxxxxxxxx * /说明不是简单的将/ * * /变成//就可可以了,从上面我们可以在遍历input.c可以发现4中状态遇到C语言状态,c ++状态,无状态(没有注释的状态),结束状态(遍历完成的状态)。可以把问题看成四种状态的来回。

## CommentConvert.h

#include
#include
#include
void DoCommentConvert(FILE *fpIn, FILE *fpOut);//注释处理函数
void DoNUL_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理无状态的函数
void DoC_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理C语言状态的函数
void DoCPP_STATE(FILE *fpIn, FILE *fpOut, enum State *state);//处理C++状态的函数

enum State
{
    NUL_STATE,
    C_STATE,
    CPP_STATE,
    END_STATE,
};

CommentConvert.c

    void DoCommentConvert(FILE *fpIn, FILE *fpOut)
{
    enum State state = NUL_STATE;//初始化为无状态
    while (state != END_STATE)//当结束状态的时候跳出
    {
        switch (state)//选择状态
        {
        case NUL_STATE:DoNUL_STATE(fpIn, fpOut, &state);
            break;
        case C_STATE:DoC_STATE(fpIn, fpOut, &state);
            break;
        case CPP_STATE:DoCPP_STATE(fpIn, fpOut, &state);
            break;
        }
    }
}

DoCommentConvert()设定了初始化的的无状态。通过一个while循环将状态来回转换。

void DoNUL_STATE(FILE *fpIn, FILE *fpOut, enum State *state)
{
    int first = fgetc(fpIn);
    switch(first)
    { 
    case'/':
    { 
        int second = fgetc(fpIn);; 
        switch(second)
        { 
        case'*':
        { 
            fputc('/',fpOut); 
            的fputc( '/',fpOut); 
            * state = C_STATE; 
            打破; 
        } 
        case'/':
        { 
            fputc(first,fpOut); 
            的fputc(第二,fpOut);               * state = CPP_STATE;                打破;             }           default:            {               putc(first,fpOut);              putc将(第二,fpOut);                打破;             }           }           打破;











    } 
    情况下EOF:
        *状态= END_STATE; 
        打破; 
    默认值:
        的fputc(第一,fpOut); 打破; 
    } 
} 

进入无状态函数。将文件指针所指向的字符通过龟etc(fpin)赋值给一个整形第一。通过开关语句判断这个第一是不是* / 。如果不是,那么看看是不是文件的数据流结束了EOF,如果再不是那么这个肯定是一个字符,只需要将它输入到output.c文件里。接下来如果是 / ,还需要判断接下来的一个字符second是号,还是 / *。如果是,那么可已确定是/ 组合,是C语言风格。需要将两个/写入到output.c中。将状态改为C_STATE即C语言状态如果是/ ,那么可以确定是//组合,是C ++风格。只需要将第一和第二直接写入到输出中。将状态改为CPP_STATE即C ++状态 void DoC_STATE(FILE fpIn,FILE * fpOut,enum State * state)

{ 
    int first = fgetc(fpIn); 
    switch(first)
    { 
    case'*':
    { 
        int second = fgetc(fpIn); 
        switch(second)
        { 
        case'/':
        { 
            * state = NUL_STATE; 
            int third = fgetc(fpIn); 
            if(third!='\ n')
            { 
                ungetc(third,fpIn); 
                fputc('\ n',fpOut); 
            } 
            else 
            { 
                ungetc(third,fpIn); 
            } 
            打破; 
        } 
        case'*':
        { 
            ungetc(second,fpIn); 
            fputc(第二,fpOut); 
            打破;
        }
        default:
            fputc(first, fpOut);
            fputc(second, fpOut);
            break;
        }
        break;
    }
    case '\n':
    {
        fputc(first, fpOut);
        fputc('/', fpOut);
        fputc('/', fpOut);
        break;
    }
    default:
        fputc(first, fpOut);
        break;
    }
}

转到C语言后继续获取字符,由于C语言注释还有一个结束标志 */。接下来的字符还需要一一判断。

如果fisrt 是一个 * 号时,需要进一步判断second是一个什么字符。

如果 second 是一个 / 还需要进行第三次判断。

如果 third 是一个 \n 说明 需要换行了。写入一个/n字符。

如果 third 是一个 其他字符,那么就不用管,这时C语言注释已经结束了。需要将注释状态改为无状态 State = NUL_STATE

如过第二放是继续写入 不是C语言的结束标志。如果首先是一个换行符就将换行符写入到output.c后,再加入两个//。如果first是一个非注释符的字符,就直接写入到这个output.c里去 .void DoCPP_STATE(FILE fpIn,FILE * fpOut,enum State * state) { int ch = fgetc(fpIn); switch(ch) { case’\ n’: { fputc(ch,fpOut); * state = NUL_STATE; 打破; } 情况下EOF: { *状态= END_STATE; 打破; } default: { fputc(ch,fpOut); 打破; } } }

这个函数是用来处理C++状态,由于是C++状态相当于不改变什么东西。需要关心的是换行问题和结束问题。 其他的东西照写不误。

如果是 \n ,那么需要注意的是换行后还是C++状态吗?,显然不是了换行后可能遇到C语言状态,也可能是无状态 。但是 无状态能够进一步判断是否进入了 C语言状态。

BlackTech.h void _Work(const char * dir,const char * findname,const char * dst){char DocumentName [200]; char DocumentNameCopy [200]; int size = strlen(dir) - 4; //将现有的名字后四位剪掉,原因是后四位是通配符.strcpy(DocumentName,dir); DocumentName [size + 1] =’\ 0’; //复制操作完成后给其后面补一个\ 0原因是剪掉后四位把\ 0剪没了strcat(DocumentName,findname); size = strlen(dst)-1; 的strcpy(DocumentNameCopy,DST); DocumentNameCopy [size + 1] =’\’; DocumentNameCopy [size + 2] =’\’; DocumentNameCopy [size + 3] =’\ 0’; //对复制版文件夹名字进行操作并加入通配符strcat(DocumentNameCopy,findname); FILE * fpIn = fopen((const char *)DocumentName,“rb”); //二进制输入流可以遍历任何文件 if(fpIn == NULL) { perror(“

        系统( “暂停”); 
        出口(EXIT_FAILURE); 
    } 
    FILE * fpOut = fopen((const char *)DocumentNameCopy,“wb”); 
    if(fpOut == NULL)
    { 
        fclose(fpIn); 
        perror(“fpOut打开文件失败!\ n”); 
        系统( “暂停”); 
        出口(EXIT_FAILURE); 
    } 
    DoCommentConvert(fpIn,fpOut); 
    //转换完成文件关闭
    FCLOSE(fpIn); 
    FCLOSE(fpOut); 
} 
空隙MakeNewDocument(字符* DocumentNameOld,字符* DocumentNewName)//创建一个同名的复制版文件夹
{ 
    INT大小= 0; 
    strcpy(DocumentNewName,DocumentNameOld); 
    size = strlen(DocumentNewName);
    DocumentNewName[size - 5] = '\0';
    strcat(DocumentNewName, "复制版");
    _mkdir(DocumentNewName);//创建文件夹
}
void listFiles(const char *dir,char *DocumentNameCopy)
{
    char DocumentNew[200];//创建一个新的文件夹名字
    char DocumentName1[200];//用于文件名字的复制
    char DocumentName2[200];//用于文件遍历的名字
    char FinshMessage[100] = "done!_";
    intptr_t handle;
    struct _finddata_t findData;
    strcpy(DocumentNew, dir);//当前文件夹的名字拷贝给新文件夹
    strcat(DocumentNew, "\\\\*.*");//给新文件夹的名字后面加上通配符后缀
    strcat(DocumentNameCopy, "\\\\*.*");//给新文件夹的名字增添上通配符
    handle = _findfirst(DocumentNew, &findData);//比对文件夹的名字和数据,将其返回一个句柄
    MakeNewDocument(DocumentNameCopy, DocumentName1);//将拷贝的名字 添加上“复制版”得到 DocumentName1
    strcpy(DocumentName2, DocumentName1);//将获得的名字防在DocumentName2里 用于接下来的遍历
    if (handle == -1)//如果句柄返回失败就终止程序
    {
        printf("Failed to find first file!\n");
        system("pause");
        return;
    }
    do
    {
        char tmp_name[200];
        strcpy(tmp_name, findData.name);
        if (findData.attrib & _A_SUBDIR)
        {

            if (strcmp(findData.name, ".") == 0 || strcmp(findData.name, "..") == 0)
                //遍历文件夹里的文件 如果是子文件夹 就跳过
            {
                continue;
            }
            strcat(DocumentName2, "\\\\");
            strcat(DocumentName2, findData.name);
            strcpy(DocumentNew, dir);
            strcat(DocumentNew, "\\\\");
            //调整文件夹的名字,使其能够对应fpin的读取个格式
            strcat(DocumentNew, findData.name);
            listFiles(DocumentNew,DocumentName2);
            //遇到文件夹的时候进行递归操作
            strcpy(DocumentNew, dir);
            strcat(DocumentNew, "\\\\*.*");
            //当上一个函数完成后,也就是说文件夹遍历完毕,添加好通配符,为下一个文件夹做准备
        }
        else
        {
            _Work(DocumentNew, tmp_name, DocumentName1);
            //当读取到的不是文件夹后,对其惊喜注释转换操作
        }
    } while (_findnext(handle, &findData) == 0);
    //一个文件夹 遍历完成
    strcat(FinshMessage, dir);
    strcat(FinshMessage,“\ n”); 
    的printf(FinshMessage); 
    _findclose(手柄); 
    返回; 
} 

这个黑科技写的很烂,主要是对这个递归不熟悉。但是神奇的是这个程序能跑。能够遍历以下文件夹里的所有文件,包括了文件的嵌套。另外附赠一个链接,我就是看这个博客才学会遍历文件夹。

https://img-blog.csdn.net/20180825145503853?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hfU3Ryb25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 )![ 这里写图片描述] (https://img-blog.csdn.net/20180825145512828?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L0hfU3Ryb25n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 )

你可能感兴趣的:(c语言学习)