统计代码行和注释行

 1   //  parse_code_comment.hpp
  2  
  3   #pragma once
  4  
  5   #include  < map >
  6   #include  < fstream >
  7   #include  < utility >
  8  
  9  
 10   namespace  Comment
 11   {
 12  
 13   //  source file Line types
 14   enum  LineType { Blank  =   0 , Code  =   1 , CComment  =   2 , CppComment  =   3 ,
 15                            CCodeComment  =   4 , CppCodeComment  =   5  };
 16  
 17   //  source file line type in string literal style
 18   static  std:: string  LineArray[CppCodeComment  +   1U =
 19   " Blank line " " Code only " " C Comment " " C++ Comment " ,
 20      " Code and C Comment " " Code and C++ Comment "  };
 21  
 22   //  read all characters of a txt style file into buffer and figure out the number of
 23   //  code lines and the number of comment lines
 24   class  file_code_comment
 25   {
 26   public :
 27     typedef std::map < int , LineType > ::size_type size_type;
 28  
 29   public :
 30  
 31     file_code_comment( const  std:: string & );
 32  
 33      virtual   ~ file_code_comment();
 34  
 35     size_type size()  const ;
 36  
 37     std::pair < int int >  code_comment()  const ;
 38  
 39      //  list line number and type
 40      const  std::map < int , LineType >&  line_types()  const ;
 41  
 42   private :
 43  
 44      //  in case of comment marks in string literals
 45     size_type skip_double_quotes( const  std:: string & const  std:: string & , size_type)  const ;
 46  
 47     std::pair < LineType,  bool >  cppcode_comment( const  std:: string & , size_type, size_type)  const ;
 48  
 49     std::pair < LineType,  bool >  multicomment( const  std:: string & , size_type, size_type, size_type)  const ;
 50  
 51   //   [Blank]
 52   //   if(a == b) [Code]
 53   //    //   [CppComment]
 54   //   /*  */ [CComment]
 55   //   /*  [CComment]
 56   //   */ [CComment]
 57   //    */ [CComment]
 58   //   if(a == b) /*  */ [CCodeComment]
 59   //   if(a == b) /*  [CCodeComment]
 60   //   */ [CCodeComment]
 61   //    [CCodeComment]
 62   //  /*  */ if(a == b) [CCodeComment]
 63   //  if(a == b)  //   [CppCodeComment]
 64  
 65      //  deduce what line type is for a string literal
 66     std::pair < LineType,  bool >  line_type( const  std:: string & , size_type & const ;
 67  
 68      void  read_ccomment( const  std:: string & , std::ifstream & int & );
 69  
 70      //  Read source and figure out code lines, blank lines, comment lines
 71      void  read_file( const  std:: string & );
 72  
 73     size_type skip_leading_space( const  std:: string & , size_type  =   0 const ;
 74  
 75  
 76   private :
 77  
 78      void  initialize( const  std:: string & );
 79  
 80      static   const  std:: string  cppcmt;      //  C++ comment  //
 81      static   const  std:: string  ccmt_start;  //  C comment start /*
 82      static   const  std:: string  ccmt_end;    //  C comment end */
 83  
 84     std::map < int , LineType >  m_code_comment;  //  <line number, LineType>
 85   };
 86  
 87   file_code_comment::file_code_comment( const  std:: string &  file) :
 88     m_code_comment()
 89   {
 90     initialize(file);
 91   }
 92  
 93   file_code_comment:: ~ file_code_comment() { m_code_comment.clear(); }
 94  
 95   file_code_comment::size_type file_code_comment::
 96     skip_leading_space( const  std:: string &  str, size_type idx)  const
 97   {
 98      for (; idx  <  str.size()  &&  ( '   '   ==  str[idx]  ||   ' \t '   ==  str[idx]);  ++ idx);
 99      return  idx;
100   }
101  
102   file_code_comment::size_type file_code_comment::size()  const
103   {
104      return  m_code_comment.size();
105   }
106  
107   std::pair < int int >  file_code_comment::code_comment()  const
108   {
109      int  code  =   0 //  the number of code lines
110      int  cmt  =   0 ;   //  the number of comment lines
111      for (std::map < int , LineType > ::const_iterator cit(m_code_comment.begin());
112         cit  !=  m_code_comment.end();  ++ cit)
113        switch (cit -> second)
114       {
115          case  Code:  ++ code;  break ;
116          case  CComment:
117          case  CppComment:  ++ cmt;  break ;
118          case  CCodeComment:
119          case  CppCodeComment:  ++ code;  ++ cmt;  break ;
120          case  Blank:
121          default break ;
122       }
123      return  std::make_pair(code, cmt);
124   }
125  
126   //  list line number and type
127   const  std::map < int , LineType >&  file_code_comment::line_types()  const
128   {
129      return  m_code_comment;
130   }
131  
132   //  ignore comment marks in double quotes
133   //  "/*" "*/"
134   //  "  //  "
135   file_code_comment::size_type file_code_comment::skip_double_quotes
136     ( const  std:: string &  str,  const  std:: string &  cmt, size_type idx)  const
137   {
138      for (; idx  <  str.size();  ++ idx)
139     {
140       idx  =  str.find(cmt, idx);
141        if (str.size()  <  idx)
142       {
143         idx  =  str.size();
144          break ;
145       }
146       size_type ridx  =  str.find( ' " ' , idx);
147        if (str.size()  <  ridx)
148          break ;
149       size_type lidx  =  str.rfind( ' " ' , idx);
150        if (str.size()  <  lidx)
151          break ;
152        if (lidx  <  idx  &&  idx  <  ridx)
153         idx  =  ridx;
154        else
155          break ;
156     }
157      return  idx;
158   }
159  
160   //  many C style comment blocks in one single line match?
161   std::pair < LineType,  bool >  file_code_comment::cppcode_comment( const  std:: string &  str,
162                                                                size_type lidx,
163                                                                size_type idx)  const
164   {
165      if (lidx  ==  idx)
166        return  std::make_pair(CppComment,  false );
167      else
168     {
169       idx  =  str.size();
170        if (lidx  <  str.size())
171          return  std::make_pair(CppCodeComment,  false );
172        else
173          return  std::make_pair(Code,  false );
174     }
175   }
176  
177   //  /* */ while /* */  //  /*
178   //  /* ************** */ while {} /* ** */   //   
179   //  /* ******* */
180  
181   std::pair < LineType,  bool >  file_code_comment::multicomment( const  std:: string &  str,
182                                                                                              size_type eidx,
183                                                                                              size_type ridx,
184                                                                                              size_type idx)  const
185   {
186     size_type cnts  =   0 ;
187     size_type cnte  =   0 ;
188     LineType type  =  CComment;
189      if (idx  <  ridx)
190       type  =  CCodeComment;
191      bool  code_found  =   false ;
192      while (ridx  <  eidx)
193     {
194        ++ cnts;
195       ridx  =  skip_double_quotes(str, ccmt_end, ridx  +   2U );  //  +2 skip /*
196        if (ridx  <  eidx)
197       {
198         ridx  +=   2U //  +2 skip */
199         idx  =  ridx;
200          ++ cnte;
201         ridx  =  skip_double_quotes(str, ccmt_start, ridx);
202          if ( skip_leading_space(str, idx)  <  ridx)
203           code_found  =   true ;
204       }
205     }
206      if (code_found)
207       type  =  CCodeComment;
208      return  std::make_pair(type, cnte  <  cnts);
209   }
210  
211   //  deduce what line type is for a string literal
212   std::pair < LineType,  bool >  file_code_comment::line_type( const  std:: string &  str,
213                                                          size_type &  idx)  const
214   {
215     idx  =  skip_leading_space(str);
216      if (str.size()  ==  idx)
217        return  std::make_pair(Blank,  false );
218      else
219     {
220       size_type lidx  =  skip_double_quotes(str, cppcmt, idx);
221       size_type ridx  =  skip_double_quotes(str, ccmt_start, idx);
222        /*  Somettimes C comments and C++ comments (or Code) are mixed in a single line  */
223        if (lidx  <  ridx)       //  C++ comment first then CppComment or CppCodeComment
224          return  cppcode_comment(str, lidx, idx);
225        else   if (ridx  <  lidx)  //  C comment first then CComment or CCodeComment
226          return  multicomment(str, lidx, ridx, idx);
227        else   //  no comment
228          return  std::make_pair(Code,  false );
229     }
230   }
231  
232  
233   void  file_code_comment::read_ccomment( const  std:: string &  str, std::ifstream &  fin,
234                                          int &  line)
235   {
236     std:: string  tstr;
237      while (std::getline(fin, tstr))
238     {
239        ++ line;
240       size_type idx  =  skip_leading_space(tstr);
241        if (tstr.size()  ==  idx)
242       {
243         m_code_comment.insert(std::make_pair(line, Blank));
244       }
245        else
246       {
247         m_code_comment.insert(std::make_pair(line, CComment));
248          if (skip_double_quotes(tstr, ccmt_end,  0 <  tstr.size())  //  found */
249            break ;
250       }
251     }
252   }
253  
254   //  Read source and figure out code lines, blank lines, comment lines
255   void  file_code_comment::read_file( const  std:: string &  file)
256   {
257     std::ifstream fin(file.c_str());
258      if ( ! fin.is_open())
259     {
260       std::cerr  <<   " Failed to open file ' "   <<  file
261                  <<   " ' @ Comment::file_code_comment\n " ;
262        return ;
263     }
264     std:: string  str;
265     size_type idx  =   0 ;
266      int  line  =   0 ;
267      while (std::getline(fin, str))
268     {
269        ++ line;
270       std::pair < LineType,  bool >  tp  =  line_type(str, idx);
271       m_code_comment.insert(std::make_pair(line, tp.first));
272        switch (tp.first)
273       {
274          case  Blank:
275          case  Code:
276          case  CppComment:
277          case  CppCodeComment:  break ;
278          case  CComment:
279          case  CCodeComment:  if (tp.second)
280                                            read_ccomment(str, fin, line);
281                                           break ;
282          default break ;
283       }
284     }
285   }
286  
287   void  file_code_comment::initialize( const  std:: string &  file)
288   {
289     read_file(file);
290   }
291  
292   const  std:: string  file_code_comment::cppcmt( " // " );      //  C++ comment  //
293   const  std:: string  file_code_comment::ccmt_start( " /* " );  //  C comment start /*
294   const  std:: string  file_code_comment::ccmt_end( " */ " );    //  C Comment end */
295  
296   //  namespace Comment
297  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值