注释转换(c注释->c++注释)

前言:本篇文章介绍了一个基于各类文件操作函数的一个小项目“注释转换”,功能是将C风格的注释装换成C++风格的注释,当然对于C++风格的注释装换C风格的注释原理是一样的。本篇博文里所用到的一些文件操作函数在我的上一篇博文(输入/输出函数总结)里有详细介绍。

项目介绍

本项目基于一个状态机的思想,每次处理完成之后通过状态的装换继续处理后边的内容。另外,利用各类的文件操作函数,实现将将C风格的注释装换成C++风格的注释的一个简单功能。大概如下图:
这里写图片描述

什么是状态机?

一个极度确切的描述是它是一个有向图形,由一组节点和一组相应的转移函数组成。状态机通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转移函数的控制范围内,其中函数的范围是节点的一个子集。函数返回“下一个”(也许是同一个)节点。这些节点中至少有一个必须是终态。当到达终态, 状态机停止。(百度摘抄)

在本项目中,会用到四种状态,既空状态(正常代码区)、c注释状态(c风格注释区)、c++注释状态(c++风格注释区)、文件结束状态(EOF),下面是四种状态的装换图:
这里写图片描述

因为c注释区里的内容不可能包括文件结束标志,所以c注释状态不可能存在与文件结束状态之间的转换。

一些测试用例


    // 1.一般情况
    int num = 0;
    /* int i = 0; */

    // 2.换行问题
    /* int i = 0; */int j = 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++注释问题
    // /*xxxxxxxxxxxx*/

参考代码

CommentCovert.h


    #ifndef __COMMENTCOVERT_H__
    #define __COMMENTCOVERT_H__

    enum status
    {
        END_STATUS,
        NUL_STATUS,
        C_STATUS,
        CPP_STAUS
    };
    #include<stdio.h>
    #include<stdlib.h>
    #pragma warning(disable:4996)

    void CommentCovert(FILE *pfIn, FILE *pfOut);
    void DoNulStaus(FILE *pfIn, FILE *pfOut, enum status *ps);
    void DoCStaus(FILE *pfIn, FILE *pfOut, enum status *ps);
    void DoCppStaus(FILE *pfIn, FILE *pfOut, enum status *ps);


    #endif //__COMMENTCOVERT_H__

CommentCovert.c


    //为了方便理解,下面的代码存在向原状态装换的过程,这是不必要的,已经注释掉。
    #include"CommentCovert.h"

    //正常代码处理
    void DoNulStaus(FILE *pfIn, FILE *pfOut, enum status *ps)
    {
        int first = fgetc(pfIn);
        switch (first)
        {
        case '/':
        {
                    int second = fgetc(pfIn);
                    switch (second)
                    {
                    case'*':
                    {
                               fputc('/', pfOut);
                               fputc('/', pfOut);
                               *ps = C_STATUS;
                    }
                        break;
                    case'/':
                    {
                               fputc(first, pfOut);
                               fputc(second, pfOut);
                               *ps = CPP_STAUS;
                    }
                        break;
                    default:
                    {
                               fputc(first, pfOut);
                               fputc(second, pfOut);
                               /**ps = NUL_STATUS;*/
                    }
                        break;
                    }
        }
            break;
        case EOF:
        {
                    fputc(first, pfIn);
                    *ps = END_STATUS;
        }
            break;
        default:
        {
                   fputc(first, pfOut);
                   /**ps = NUL_STATUS;*/
        }
            break;
        }
    }
    //c风格代码注释区处理
    void DoCStaus(FILE *pfIn, FILE *pfOut, enum status *ps)
    {
        int first = fgetc(pfIn);
        switch (first)
        {
        case'*':
        {
                   int second = fgetc(pfIn);
                   switch (second)
                   {
                   case'/':
                   {
                              int third = fgetc(pfIn);
                              if (third != '\n')
                              {
                                  fseek(pfIn, -1, SEEK_CUR);
                                  //如果third不是'\n',那个字符已经被读走,应该把那个字符还回去在放一个'\n'
                                  fputc('\n', pfOut);
                              }
                              else
                              {
                                  fputc(third, pfOut);
                              }
                              *ps = NUL_STATUS;
                   }
                       break;
                   case'*':
                   {
                              fputc(first, pfOut);
                              fseek(pfIn, -1, SEEK_CUR);
                              /**ps = C_STATUS;*/
                              //把fp指针移动到离文件当前位置-1字节处,回退1个字符
                              //因为第二个字符如果是*要和/一起判断是否是C语言注释风格结束
                   }
                       break;
                   default:
                   {
                              fputc(first, pfOut);
                              fputc(second, pfOut);
                              /**ps = C_STATUS;*/
                   }
                       break;
                   }
        }
            break;
        case'\n':
        {
                    fputc(first, pfOut);
                    fputc('/', pfOut);
                    fputc('/', pfOut);
                    /**ps = C_STATUS;*/
        }
            break;
        default:
        {
                   fputc(first, pfOut);
                   /**ps = C_STATUS;*/
        }
            break;
        }
    }
    //c++风格代码注释区处理
    void DoCppStaus(FILE *pfIn, FILE *pfOut, enum status *ps)
    {
        int first = fgetc(pfIn);
        switch (first)
        {
        case'\n':
        {
                    fputc(first, pfOut);
                    *ps = NUL_STATUS;
        }
            break;
        case EOF:
            fputc(first, pfOut);
            *ps = END_STATUS;
            break;
        default:
            fputc(first,pfOut);
            /**ps = CPP_STAUS;*/
            break;
        }
    }
fseek的简单理解

    SEEK_SET: 文件开头
    SEEK_CUR: 当前位置
    SEEK_END: 文件结尾
    其中SEEK_SET,SEEK_CUR和SEEK_END依次为012
    例如:
    fseek(fp,100L,0);把stream指针移动到离文件开头100字节处;
    fseek(fp,100L,1);把stream指针移动到离文件当前位置100字节处;
    fseek(fp,-100L,2);把stream指针退回到离文件结尾100字节处。

test.c


        #include"CommentCovert.h"

    void CommentCovert(FILE *pfIn, FILE *pfOut)
    {
        enum status status = NUL_STATUS;
        while (status != END_STATUS)
        {
            switch (status)
            {
            case NUL_STATUS:
                DoNulStaus(pfIn, pfOut, &status);
                break;
            case C_STATUS:
                DoCStaus(pfIn, pfOut, &status);
                break;
            case CPP_STAUS:
                DoCppStaus(pfIn, pfOut, &status);
                break;
            default:
                break;
            }
        }
    }
    int main()
    {
        FILE *pfIn = NULL;
        FILE *pfOut = NULL;
        pfIn = fopen("input.c", "r");
        if (pfIn == NULL)
        {
            perror("use file to read");
            exit(EXIT_FAILURE);
        }
        pfOut = fopen("output.c", "w");
        if (pfOut == NULL)
        {
            perror("use file to write");
            fclose(pfIn);
            pfIn = NULL;
            exit(EXIT_FAILURE);
        }
        //注释转换
        CommentCovert(pfIn, pfOut);

        fclose(pfIn);
        pfIn = NULL;
        fclose(pfOut);
        pfOut = NULL;

        return 0;
    }

源代码:CommentCovert

猜你喜欢

转载自blog.csdn.net/hansionz/article/details/80884173