删除源文件中的注释

周翼翼 发布于 2011/04/29 23:39
阅读 679
收藏 1

http://www.oschina.net/bbs/thread/18227里提到删除源文件中注释的问题,我想,既然所有的支持源代码高亮的编辑器和编译器都可以识别出注释,那就一定有办法能删除源文件中的注释.最近新开了编译原理的课,刚上到词法分析一节,有点小思路,就写了一个小程序,试试能不能正确删除注释.请看下图

这是我全部的思路,大家可以从图中看出.

以下是我写的代码,我初步试了一下,基本还行,已知的三个问题是:

1.这里针对window下的文件,apple和unix要做一点修改,详见代码

2.对于只有注释的行,删除后会留下空行

3.由于每次只读一个字节,IO的次数会比较多,理论上IO太多会影响效率,但是c++的IO是用stream方式做的,我对stream到底怎么实现的不太清楚,会影响效率到什么程度还不知道.不过考虑到源文件不般不会太大,这不是主要要考虑的问题.请大家将注意力集中在逻辑部分.

/*这个小程序的目的是删除输入源文件中所以用//和/** /注释掉的内容,并将注释内容写入一个doc文件*/

//test comment

#include<string>

#include<fstream>

#include <stdio.h>

const int Normal = 0;

const int String = 1;

const int AlmostComment = 2;

const int AlmostNormal = 3;

const int SigleLineComment = 4;

const int MultiLineComment = 5;

 

bool deleteComments(std::string& inputFileName,

                    std::string& outputFileName,

                    std::string& docFileName)

{

    std::ifstream inFile = std::ifstream(inputFileName.c_str(),std::ios:🇮🇳:ios::binary);

    std::ofstream outFile = std::ofstream(outputFileName.c_str(),std::ios::out|std::ios::binary);

    std::ofstream docFile = std::ofstream(docFileName.c_str(),std::ios::out|std::ios::binary);

    if(!inFile.is_open() || !outFile.is_open() || !docFile.is_open() )  return false;

    char c[1];

    int status = Normal;

    while(true)

    {

        inFile.read(c,1);

        if(inFile.gcount() == 0) break;

        switch(status)

        {

        case Normal:

            if(c[0]=='/')  status  = AlmostComment;

            if(c[0]=='"') status  = String;

            if(c[0]!='/') outFile.write(c,1);

            break;

        case String:

            if(c[0]=='"') status = Normal;

            outFile.write(c,1);

            break;

        case AlmostComment:

            if(c[0]=='/') status = SigleLineComment;

            else if(c[0]=='*') status = MultiLineComment;

            else  status = Normal;

            if(c[0]!='/' && c[0]!='*') outFile.write(c,1);

            break;

        case AlmostNormal:

            if(c[0]=='/') status = Normal;

            else if(c[0]=='*') status = AlmostNormal;

            else status = MultiLineComment;

            if(c[0]!='/' && c[0]!='*')outFile.write(c,1);

            break;

        case SigleLineComment:

//这里的按windows的行结束符处理,apple与unix请适当更改

            if(c[0]=='\r')

            {

                outFile.write(c,1);

                inFile.read(c,1);

                outFile.write(c,1);

                status = Normal;

            }

            else docFile.write(c,1);

            break;

        case MultiLineComment:

            if(c[0]=='*') status = AlmostNormal;

            docFile.write(c,1);

            break;

        }

    }

    inFile.close();

    outFile.close();

    docFile.close();

    return true;

}

 

int main(int argc,char** argv)

{

    if(argc<4)

    {

        printf("Usage:%s inputFileName outputFileName docFileName\n",argv[0]);

        exit(1);

    }

    std::string inputFileName(argv[1]);

    std::string outputFileName(argv[2]);

    std::string docFileName(argv[3]);

    if(deleteComments(inputFileName,outputFileName,docFileName))

        printf("操作成功 %s -> %s %s",inputFileName.c_str(),outputFileName.c_str(),docFileName.c_str());

    return 0;

}

这个程序完全没有用到正则表达式,或者说是很原始的方式在用.我想,大家不必往正则表达式那方面想,那会相当烦.

实际上这是一个非常非常小型的一个词法分析器之类的东西.

请大家帮找找bug.

加载中
0
ddatsh
ddatsh

BEANSOFT就写了个删除注释的

有源码

0
周翼翼
周翼翼

引用来自#2楼“dd”的帖子

BEANSOFT就写了个删除注释的

有源码

求详情.网址什么的.可以去学习一下.

0
ddatsh
ddatsh

搜他BLOG

0
李渊
李渊

用正则可以么?

0
鞋底两万里
鞋底两万里

有注释不是挺好!何必呢?

0
ddatsh
ddatsh

只是技术讨论

0
周翼翼
周翼翼

引用来自#5楼“李渊”的帖子

用正则可以么?

应该会很复杂.你可以看开始提到那个帖子里,那里有一个正则的.

0
cheristorm
cheristorm
求教,为什么要加上 ” 的考虑情况。还有前四种状态:Normal,String,AlmostComment,AlmostNormal的具体分析情况楼主能再说的细一些吗?
0
周翼翼
周翼翼

引用来自“cheristorm”的答案

求教,为什么要加上 ” 的考虑情况。还有前四种状态:Normal,String,AlmostComment,AlmostNormal的具体分析情况楼主能再说的细一些吗?
这么老的帖子,你都翻了出来~~
加上双引号是因为字符串内的/* //这类不能算注释,是正常内容.
Normal是正常状态,String是字符状态,AlmostComment是正常状态下输入了/号,而AlmostNormal是多行注释态下输出了一个*号,这时候再输出一个/号,就回到正常态,所以是差不多正常态.你看图,那是一个有限状态机之类的东西,根据当前的状态和当前的输入字符,做不同的动作.图是关键.
0
cheristorm
cheristorm

三个月前也不算太老嘛~非常感谢,周老师~我正在写一个对比代码相似度的软件里面的预处理模块需要一个删除注释的功能。你的思路很严密也很清晰,这回我明白了。你也谈到了一个个读入可能影响效率,那么有没有可能一个字符串一个字符串读入……

状态机貌似最开始是单片机还是硬件方面的理论。今后再用状态机的方法是否依然用这样的图及Switch格式即可?

返回顶部
顶部