CCCC - C and C++ Code Counter  9999-git
CCCC Development version (post-3.1.4)
cccc_utl.cc
Go to the documentation of this file.
1 /*
2  CCCC - C and C++ Code Counter
3  Copyright (C) 1994-2005 Tim Littlefair (tim_littlefair@hotmail.com)
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19 // cccc_utl.cc
20 
21 // implementation of enumerations and utility classes for CCCC
22 // includes the Parse_Utility class which is a helper to centralise
23 // error recovery and recording facilities across the three parsers
24 #include "cccc.h"
25 
26 #include "cccc_itm.h"
27 #include "cccc_utl.h"
28 #include "cccc_db.h"
29 #include "cccc_tok.h"
30 #include "AParser.h"
31 #include "ATokPtr.h"
32 
33 #define DEBUG_EXTENT_STREAMS 1
34 
35 #include <cassert>
36 #include <iomanip>
37 using std::ios;
38 //using std::trunc;
39 using std::ends;
40 using std::setw;
41 using std::setiosflags;
42 using std::resetiosflags;
43 
44 
45 #define FS "@"
46 #define RS "\n"
47 
52 
55 
56 // insertion and extraction functions intended to support enumerations
57 void insert_enum(ostream& os, int e)
58 {
59  os << (char) e;
60 }
61 
62 void extract_enum(istream& is, int& e)
63 {
64  e=0;
65  is >> (char&) e;
66 }
67 
68 
69 ostream& operator<<(ostream& os, AugmentedBool ab) {
70  insert_enum(os,ab);
71  return os;
72 }
73 
74 istream& operator>>(istream& is, AugmentedBool& ab) {
75  extract_enum(is,(int&)ab);
76  return is;
77 }
78 
79 ostream& operator<<(ostream& os, Visibility v) {
80  insert_enum(os,v);
81  return os;
82 }
83 
84 istream& operator>>(istream& is, Visibility& v) {
85  extract_enum(is,(int&)v);
86  return is;
87 }
88 
89 ostream& operator<<(ostream& os, UseType ut) {
90  insert_enum(os,ut);
91  return os;
92 }
93 
94 istream& operator>>(istream& is, UseType& ut) {
95  extract_enum(is,(int&)ut);
96  return is;
97 }
98 
100 {
101  static string retval;
102  retval="";
103  int i;
104  for(i=1; i<=n; i++)
105  {
106  if(parser->LT(i) != NULL)
107  {
108  retval=retval+parser->LT(i)->getText();
109  retval=retval+" ";
110  }
111  }
112  return retval;
113 }
114 
115 void ParseUtility::resynchronize(int initial_nesting,
116  SetWordType *resync_token_class,
117  ANTLRTokenPtr& resync_token)
118 {
119  // the interface for resynchronisation is as follows:
120  // the caller supplies a nesting level at which the resynchronisation must
121  // occur, and a token class containing all of the tokens which can
122  // be accepted to delimit the resynchronisation
123  // this function will scan until it finds that it is at the correct level and
124  // the next token of lookahead is in the resynchronisation set
125  // it will then accept as many tokens from the resynchronisation set as
126  // are available, consolidating the text of the tokens accepted
127  // as the text associated with the last token
128  string resync_text="...";
129 
130  string string1=parser->LT(1)->getText();
131  int line1=parser->LT(1)->getLine();
132  string string2;
133  int line2=0;
134 
135  int resynchronising=1;
136  while(resynchronising)
137  {
138  parser->consumeUntil(resync_token_class);
139  if(
140  (MY_TOK(parser->LT(1))->getNestingLevel() > initial_nesting) &&
141  (parser->LT(2) != NULL)
142  )
143  {
144  parser->consume();
145  }
146  else
147  {
148  // we are ready to resynchronise
149  resynchronising=0;
150  string2=parser->LT(1)->getText();
151  line2=parser->LT(1)->getLine();
152  }
153  }
154 
155  // we now consume a succession of tokens from the resynchronisation token
156  // class until we come across a token which is not in the set, or the
157  // nesting level changes
158  resync_token=parser->LT(1);
159  while(
160  parser->set_el(parser->LT(1)->getType(),resync_token_class) &&
161  ( MY_TOK(parser->LT(1))->getNestingLevel() == initial_nesting)
162  )
163  {
164  string2=parser->LT(1)->getText();
165  line2=parser->LT(1)->getLine();
166 
167  resync_text+=parser->LT(1)->getText();
168  resync_text+=" ";
169  resync_token=parser->LT(1);
170  resync_token->setText(resync_text.c_str());
171  parser->consume();
172  }
173 
174  cerr << "Unrecognized section from "
175  << string1.c_str() << " on line " << line1 << " to "
176  << string2.c_str() << " on line " << line2 << endl
177  << "=====ignored section begins=====" << endl
178  << resync_text.c_str() << endl
179  << "===== ignored section ends =====" << endl;
180 }
181 
182 
184 {
185  // This is designed as a serial-singleton class (e.g. many
186  // instances may exist over time but no more than one at a
187  // time).
188  // For the lifetime of an instance, the static member theCurrentInstance
189  // points to it. When no instance exists, this pointer is null.
190  assert(theCurrentInstance==NULL);
191  theCurrentInstance=this;
192 
193  trace_depth=0;
194  stack_depth=0;
195  this->parser=(ANTLR_Assisted_Parser*)parser;
196 
197 }
198 
200 {
201  theCurrentInstance=NULL;
202 }
203 
204 // This utility function is used to create
205 // a composite scope name from a qualifier scope
206 // and a relative name.
207 string ParseUtility::scopeCombine(const string& baseScope, const string& name)
208 {
209  // I am presently (as at 3.pre44) experimenting with
210  // how I handle scopes. The present code has a policy
211  // of discarding scope information altogether and defining
212  // modules based solely on the final component of the
213  // fully qualified name.
214  // This variable may become a parameter to control policy in this
215  // area.
216  bool bIgnoreScope=true;
217  string retval;
218  if(bIgnoreScope)
219  {
220  retval=name;
221  }
222  else if(baseScope.size()>0 && name.size()>0)
223  {
224  retval=baseScope+"::"+name;
225  }
226  else
227  {
228  retval=baseScope+name;
229  }
230 
231  return retval;
232 }
233 
234 ParseStore::ParseStore(const string& filename)
235 : theFilename(filename)
236 , pendingLexicalCounts(static_cast<int>(tcLAST),0)
237 , flag(static_cast<int>(psfLAST)+1,'?')
238 {
239  // This is designed as a serial-singleton class (e.g. many
240  // instances may exist over time but no more than one at a
241  // time).
242  // For the lifetime of an instance, the static member theCurrentInstance
243  // points to it. When no instance exists, this pointer is null.
244  assert(theCurrentInstance==NULL);
245  theCurrentInstance=this;
246  flag[psfLAST]='\0';
247 }
248 
250 {
251  // If the current object came from the default constructor
252  // it is the primary singleton instance and we wish to
253  // set the static pointer to itself back to null. Otherwise,
254  // it was a cached copy, and we don't really care.
255  if(theCurrentInstance==this)
256  {
257  theCurrentInstance=NULL;
258  }
259 }
260 
261 int ParseStore::get_flag(PSFlag psf) const {
262  return int(flag[psf]);
263 }
264 
265 void ParseStore::set_flag(PSFlag psf, int value) {
266  flag[psf]=value;
267 }
268 
270  MAKE_STRSTREAM(ofstr);
271  ofstr << value;
272  flag[psfVISIBILITY]=(ofstr.str())[0];
273  RELEASE_STRSTREAM(ofstr);
274 }
275 
277 {
278  return static_cast<Visibility>(flag[psfVISIBILITY]);
279 }
280 
282 {
283  return theFilename;
284 }
285 
286 void
288 insert_extent(CCCC_Item& os, int startLine, int endLine,
289  const string& description, const string& flags,
290  UseType ut, bool allocate_lexcounts)
291 {
292  os.Insert(theFilename);
293  os.Insert(startLine);
294  os.Insert(description);
295  os.Insert(flags);
296  int i;
297  int lexical_counts_for_this_extent[tcLAST];
298  for(i=0; i<tcLAST; i++)
299  {
300  lexical_counts_for_this_extent[i]=0;
301  }
302 
303  if(allocate_lexcounts==true)
304  {
305  LineLexicalCountMatrix::iterator extentStartIter =
306  lineLexicalCounts.lower_bound(startLine);
307  LineLexicalCountMatrix::iterator extentEndIter =
308  lineLexicalCounts.upper_bound(endLine-1);
309  LineLexicalCountMatrix::iterator llcmIter;
310  for(llcmIter=extentStartIter;
311  llcmIter!=extentEndIter;
312  ++llcmIter)
313  {
314  // This record relates to a line within the current
315  // extent.
316  for(i=0; i<tcLAST; i++)
317  {
318  lexical_counts_for_this_extent[i]+=(*llcmIter).second[i];
319  }
320  }
321  // The lexical occurrences mentioned in the records processed
322  // above are now been accounted for in the database, so we
323  // purge these records. This has the effect of allowing
324  // accurate accounting on nested extents (i.e. the outer
325  // extent will only be reported as containing lines which
326  // are not already listed in the inner extent).
327  lineLexicalCounts.erase(extentStartIter,extentEndIter);
328 
329  ostringstream lexcount_str;
330 
331  lexcount_str << "LOC:" << lexical_counts_for_this_extent[tcCODELINES]
332  << " COM:" << lexical_counts_for_this_extent[tcCOMLINES]
333  << " MVG:" << lexical_counts_for_this_extent[tcMCCABES_VG]
334  << ends;
335 
336  os.Insert(lexcount_str.str().c_str());
337 
338  }
339  else
340  {
341  os.Insert("*");
342  }
343  os.Insert((char)flag[psfVISIBILITY]);
344  os.Insert((char)ut);
345 }
346 
347 
348 
349 void ParseStore::record_module_extent(int startLine, int endLine,
350  const string& moduleName,
351  const string& moduleType,
352  const string& description,
353  UseType ut)
354 {
355  // See the lengthy comment in record_userel_extent about
356  // why we are filtering for empty module names.
357  if(moduleName.size()>0)
358  {
359  CCCC_Item module_line;
360  module_line.Insert(moduleName);
361  module_line.Insert(moduleType);
362  insert_extent(module_line,startLine,endLine,
363  description,flags(),ut,true);
364  prj->add_module(module_line);
365  }
366 }
367 
368 void ParseStore::record_function_extent(int startLine, int endLine,
369  const string& returnType,
370  const string& moduleName,
371  const string& memberName,
372  const string& paramList,
373  const string& description,
374  Visibility visibility,
375  UseType ut)
376 {
377  // We require every call to this function to specify a member
378  // function name and a parameter list.
379  if(memberName.size()>0)
380  {
381  // If the moduleName is an empty string, we remap this to the
382  // string "anonymous". This implies that we treat all
383  // C-style functions as belonging to a single module.
384  string mappedModuleName = moduleName;
385  if(mappedModuleName.size()==0)
386  {
387  mappedModuleName = "anonymous";
388  }
389 
390  CCCC_Item function_line;
391  function_line.Insert(mappedModuleName);
392  function_line.Insert(memberName);
393  function_line.Insert(returnType);
394  function_line.Insert(paramList);
395 
396  string baseFlags=flags();
397  baseFlags[psfVISIBILITY]=visibility;
398 
399  insert_extent(function_line,startLine,endLine,
400  description,baseFlags,ut,true);
401  prj->add_member(function_line);
402  }
403 }
404 
405 void ParseStore::record_userel_extent(int startLine, int endLine,
406  const string& clientName,
407  const string& memberName,
408  const string& serverName,
409  const string& description,
410  Visibility visibility,
411  UseType ut)
412 {
413  CCCC_Item userel_line;
414 
415  // This function should not be invoked unless the clientName
416  // and serverName are non-empty strings, however it appears
417  // that in test case prn16.java the parser does execute the
418  // actions of the 'implementsClause' rule, even though there
419  // is no 'implements' keyword outside comments in the program
420  // text.
421  // I don't understand this, but as a workaround, I filter at
422  // this point and ensure that if either clientName or serverName
423  // is empty, no action is taken.
424  if(clientName.size()>0 && serverName.size()>0)
425  {
426  userel_line.Insert(clientName);
427  userel_line.Insert(memberName);
428  userel_line.Insert(serverName);
429 
430  // for data member definitions, we record lexical data for the
431  // extent,
432  // for inheritance and parameter relationships we do not
433  bool record_lexcounts=false;
434  switch(ut)
435  {
436  case utHASBYVAL:
437  case utHASBYREF:
438  record_lexcounts=true;
439  break;
440  default:
441  record_lexcounts=false;
442  }
443 
444  string baseFlags=flags();
445  baseFlags[psfVISIBILITY]=visibility;
446  insert_extent(userel_line,startLine,endLine,
447  description,baseFlags,ut,record_lexcounts);
448  prj->add_userel(userel_line);
449  }
450 }
451 
452 void ParseStore::record_other_extent(int startLine, int endLine,
453  const string& description)
454 {
455  CCCC_Item rejext_line;
456  insert_extent(rejext_line,startLine,endLine,description,flags(),utREJECTED,true);
457  prj->add_rejected_extent(rejext_line);
458 }
459 
460 static void toktrace(ANTLRAbstractToken *tok)
461 {
462  // at the LHS we put out information about the current token
463  if(tok != NULL)
464  {
465  DbgMsg(PARSER,cerr,
466  std::setw(6) << tok->getLine()
467  << std::setw(4) << (int)tok->getType()
468  << std::setiosflags(ios::left)
469  << std::resetiosflags(ios::right)
470  << std::setw(20) << tok->getText()
471  );
472  }
473  else
474  {
475  DbgMsg(PARSER,cerr,std::setw(30)<<"");
476  }
477 }
478 
479 enum InOrOut { IO_IN, IO_OUT };
480 
481 static void rectrace(const char *rulename,
482  const char *dir_indic,
483  int guessing,
484  ANTLRAbstractToken *tok)
485 {
486  static int trace_depth=0;
487  if(guessing)
488  {
489  DbgMsg(PARSER,cerr,
490  setw(trace_depth*4+1) << "" << dir_indic
491  << "?" << rulename << endl);
492  }
493  else
494  {
495  trace_depth=((ANTLRToken*) tok)->getNestingLevel();
496  DbgMsg(PARSER,cerr,
497  setw(trace_depth*4)<< "" << dir_indic << rulename << endl);
498  }
499 }
500 
502  const char *rulename, int guessing,
503  ANTLRAbstractToken *tok)
504 {
505  if(guessing == 0)
506  {
507  stack_tokentext[stack_depth]=tok->getText();
508  stack_tokenline[stack_depth]=tok->getLine();
509  stack_rules[stack_depth]=rulename;
510  stack_depth++;
511  }
512 
513  // first put out the token details
514  toktrace(tok);
515 
516  // then the indented recognition trace
517  rectrace(rulename,"-> ",guessing,tok);
518 }
519 
520 void ParseUtility::traceout(const char *rulename,
521  int guessing,
522  ANTLRAbstractToken *tok)
523 {
524  if(guessing == 0)
525  {
526  stack_depth--;
527  // some error checking...
528  if(stack_depth<0)
529  {
530  cerr << "ParseUtility::traceout negative stack depth - "
531  << "exiting from rule " << rulename
532  << " at " << tok->getText() << " on line " << tok->getLine()
533  << endl;
534  }
535  else if(rulename!=stack_rules[stack_depth])
536  {
537  cerr << "ParseStore::traceout rule name mismatch - "
538  << rulename << "!=" << stack_rules[stack_depth] << endl;
539  }
543  }
544  // first put out the token details
545  toktrace(tok);
546  rectrace(rulename,"<- ",guessing,tok);
547 }
548 
550  _ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset,
551  ANTLRTokenType etok, int k)
552 {
553  string filename=ParseStore::currentInstance()->filename();
554  if(tok != NULL)
555  {
556  cerr << filename << '(' << tok->getLine() << "):"
557  << " syntax error at token " << tok->getText() << endl;
558  }
559  else
560  {
561  cerr << filename << "(0): syntax error at null token" << endl;
562  }
563 
564 #if 1
565  // The logic in the other half of this #if section
566  // generated too much noise for some people's taste.
567  // It's only really useful to myself (TJL) or anyone
568  // else with a taste for debugging cccc.g/java.g etc.
569  int i=stack_depth-1;
570  cerr << filename << '(' << stack_tokenline[i]
571  << "): trying to match " << stack_rules[i]
572  << " at '" << stack_tokentext[i] << "'"
573  << endl;
574 #else
575  cerr << "Parser context:" << endl;
576  for(int i=stack_depth-1; i>=0; i--)
577  {
578  cerr << filename << '(' << stack_tokenline[i]
579  << "): trying to match " << stack_rules[i]
580  << " at '" << stack_tokentext[i] << "'"
581  << endl;
582  }
583  cerr << endl;
584 #endif
585 }
586 
587 void ParseStore::endOfLine(int line)
588 {
589  // We only do the processing below if the line which has just
590  // ended contained at least one non-skippable token
591  // The flag which tells us whether this is true is set in the
592  // token constructor
594  {
596  LineLexicalCountMatrix::value_type
597  vt(line,LexicalCountArray(static_cast<int>(tcLAST),0));
598 
599  for(int i=0; i<tcLAST; i++)
600  {
601  vt.second[i]=pendingLexicalCounts[i];
603  }
604  lineLexicalCounts.insert(vt);
605 
606  // reset the flat for next time
607  ANTLRToken::bCodeLine=false;
608  }
609 }
610 
611 
612 
613 
614 
615 
616 
617 
istream & operator>>(istream &is, AugmentedBool &ab)
Definition: cccc_utl.cc:74
static void rectrace(const char *rulename, const char *dir_indic, int guessing, ANTLRAbstractToken *tok)
Definition: cccc_utl.cc:481
void insert_enum(ostream &os, int e)
Definition: cccc_utl.cc:57
std::vector< int > LexicalCountArray
Definition: cccc_utl.h:275
#define MY_TOK(t)
Definition: cccc_tok.h:86
bool Insert(const string &s)
Definition: cccc_itm.cc:31
static int stack_depth
Definition: cccc_utl.h:176
static void toktrace(ANTLRAbstractToken *tok)
Definition: cccc_utl.cc:460
LineLexicalCountMatrix lineLexicalCounts
Definition: cccc_utl.h:279
LexicalCountArray pendingLexicalCounts
Definition: cccc_utl.h:276
InOrOut
Definition: cccc_utl.cc:479
string scopeCombine(const string &baseScope, const string &name)
Definition: cccc_utl.cc:207
void extract_enum(istream &is, int &e)
Definition: cccc_utl.cc:62
void add_rejected_extent(CCCC_Item &rejected_data_line)
Definition: cccc_prj.cc:145
ParseUtility(ANTLRParser *parser)
Definition: cccc_utl.cc:183
CCCC_Project * prj
Definition: ccccmain.cc:49
ANTLR_Assisted_Parser * parser
Definition: cccc_utl.h:174
void resynchronize(int initial_nesting, SetWordType *resync_token_class, ANTLRTokenPtr &resync_token)
Definition: cccc_utl.cc:115
void record_module_extent(int startLine, int endLine, const string &moduleName, const string &moduleType, const string &description, UseType ut)
Definition: cccc_utl.cc:349
void endOfLine(int line)
Definition: cccc_utl.cc:587
Visibility
Definition: cccc_utl.h:52
void add_module(CCCC_Item &module_data_line)
Definition: cccc_prj.cc:56
UseType
Definition: cccc_utl.h:65
void traceout(const char *rulename, int guessing, ANTLRAbstractToken *tok)
Definition: cccc_utl.cc:520
static int bCodeLine
Definition: cccc_tok.h:65
static string stack_rules[MAX_STACK_DEPTH]
Definition: cccc_utl.h:179
int get_flag(PSFlag) const
Definition: cccc_utl.cc:261
string name(int level) const
Definition: cccc_prj.cc:412
static ParseStore * currentInstance()
Definition: cccc_utl.h:269
ostream & operator<<(ostream &os, AugmentedBool ab)
Definition: cccc_utl.cc:69
string lookahead_text(int n)
Definition: cccc_utl.cc:99
void set_flag(PSFlag, int)
Definition: cccc_utl.cc:265
void add_member(CCCC_Item &member_data_line)
Definition: cccc_prj.cc:88
CharArray flag
Definition: cccc_utl.h:282
string filename()
Definition: cccc_utl.cc:281
void insert_extent(CCCC_Item &, int, int, const string &, const string &, UseType, bool allocate_lexcounts)
Definition: cccc_utl.cc:288
Definition: cccc.h:45
#define RELEASE_STRSTREAM(X)
Definition: cccc.h:69
int trace_depth
Definition: cccc_utl.h:175
char * flags()
Definition: cccc_utl.h:261
static ParseUtility * theCurrentInstance
Definition: cccc_utl.h:172
ParseStore(const string &filename)
Definition: cccc_utl.cc:234
void tracein(const char *rulename, int guessing, ANTLRAbstractToken *tok)
Definition: cccc_utl.cc:501
void record_other_extent(int startLine, int endLine, const string &description)
Definition: cccc_utl.cc:452
void record_function_extent(int startLine, int endLine, const string &returnType, const string &moduleName, const string &memberName, const string &paramList, const string &description, Visibility visibility, UseType ut)
Definition: cccc_utl.cc:368
void record_userel_extent(int startLine, int endLine, const string &clientName, const string &memberName, const string &serverName, const string &description, Visibility visibility, UseType ut)
Definition: cccc_utl.cc:405
PSFlag
Definition: cccc_utl.h:98
#define MAKE_STRSTREAM(X)
Definition: cccc.h:67
void add_userel(CCCC_Item &use_data_line)
Definition: cccc_prj.cc:125
#define DbgMsg(DF, OS, X)
Definition: cccc.h:51
static int stack_tokenline[MAX_STACK_DEPTH]
Definition: cccc_utl.h:178
static ParseStore * theCurrentInstance
Definition: cccc_utl.h:271
Visibility get_visibility()
Definition: cccc_utl.cc:276
static string stack_tokentext[MAX_STACK_DEPTH]
Definition: cccc_utl.h:177
void syn(_ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset, ANTLRTokenType etok, int k)
Definition: cccc_utl.cc:549
string theFilename
Definition: cccc_utl.h:273
AugmentedBool
Definition: cccc_utl.h:59
string flags
Definition: cccc_rec.h:46
ANTLRTokenType
Definition: cccc_tok.h:37
#define MAX_STACK_DEPTH
Definition: cccc_utl.h:105