File: cccc_utl.cc

package info (click to toggle)
cccc 3.pre81-2
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 3,820 kB
  • ctags: 4,972
  • sloc: ansic: 33,244; cpp: 10,691; java: 618; makefile: 165; sh: 11
file content (569 lines) | stat: -rw-r--r-- 14,725 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
// cccc_utl.cc

// implementation of enumerations and utility classes for CCCC
// includes the Parse_Utility class which is a helper to centralise
// error recovery and recording facilities across the three parsers
#include "cccc.h"

#include "cccc_itm.h"
#include "cccc_utl.h"
#include "cccc_db.h"
#include "cccc_ast.h"
#include "cccc_tok.h"
#include "AParser.h"
#include "ATokPtr.h"

#define DEBUG_EXTENT_STREAMS 1

#include <cassert>
#include <iomanip>
using std::ios;
//using std::trunc;
using std::ends;
using std::setw;
using std::setiosflags;
using std::resetiosflags;


#define FS "@"
#define RS "\n"

string ParseUtility::stack_rules[MAX_STACK_DEPTH];
int         ParseUtility::stack_tokenline[MAX_STACK_DEPTH];
string ParseUtility::stack_tokentext[MAX_STACK_DEPTH];
int         ParseUtility::stack_depth;

ParseUtility* ParseUtility::theCurrentInstance=NULL;
ParseStore* ParseStore::theCurrentInstance=NULL;

// insertion and extraction functions intended to support enumerations
void insert_enum(ostream& os, int e) 
{ 
  os << (char) e;
}

void extract_enum(istream& is, int& e) 
{
  e=0;
  is >> (char&) e;
}


ostream& operator<<(ostream& os, AugmentedBool ab) {
  insert_enum(os,ab);
  return os;
}

istream& operator>>(istream& is, AugmentedBool& ab) {
  extract_enum(is,(int&)ab);
  return is;
}

ostream& operator<<(ostream& os, Visibility v) {
  insert_enum(os,v);
  return os;
}

istream& operator>>(istream& is, Visibility& v) {
  extract_enum(is,(int&)v);
  return is;
}

ostream& operator<<(ostream& os, UseType ut) {
  insert_enum(os,ut);
  return os;
}

istream& operator>>(istream& is, UseType& ut) {
  extract_enum(is,(int&)ut);
  return is;
}

string ParseUtility::lookahead_text(int n)
{
  static string retval;
  retval="";
  int i;
  for(i=1; i<=n; i++)
    {
      if(parser->LT(i) != NULL)
	{
	  retval=retval+parser->LT(i)->getText();
	  retval=retval+" ";
	}
    }
  return retval;
}

void ParseUtility::resynchronize(int initial_nesting, 
				 SetWordType *resync_token_class, 
				 ANTLRTokenPtr& resync_token)
{
  // the interface for resynchronisation is as follows:
  // the caller supplies a nesting level at which the resynchronisation must 
  // occur, and a token class containing all of the tokens which can 
  // be accepted to delimit the resynchronisation
  // this function will scan until it finds that it is at the correct level and
  // the next token of lookahead is in the resynchronisation set
  // it will then accept as many tokens from the resynchronisation set as
  // are available, consolidating the text of the tokens accepted
  // as the text associated with the last token
  string resync_text="...";

  string string1=parser->LT(1)->getText();
  int line1=parser->LT(1)->getLine();
  string string2;
  int line2=0;

  int resynchronising=1;
  while(resynchronising)
    {
      parser->consumeUntil(resync_token_class);
      if( 
	 (MY_TOK(parser->LT(1))->getNestingLevel() > initial_nesting) &&
	 (parser->LT(2) != NULL)
	 )
	{
	  parser->consume();
	}
      else
	{
	  // we are ready to resynchronise
	  resynchronising=0;
	  string2=parser->LT(1)->getText();
	  line2=parser->LT(1)->getLine();
	}
    }

  // we now consume a succession of tokens from the resynchronisation token
  // class until we come across a token which is not in the set, or the
  // nesting level changes
  resync_token=parser->LT(1);
  while(
	parser->set_el(parser->LT(1)->getType(),resync_token_class) &&
	( MY_TOK(parser->LT(1))->getNestingLevel() == initial_nesting) 
	)
    {
      string2=parser->LT(1)->getText();
      line2=parser->LT(1)->getLine();
 
      resync_text+=parser->LT(1)->getText();
      resync_text+=" ";
      resync_token=parser->LT(1);
      resync_token->setText(resync_text.c_str());
      parser->consume();
    }

  cerr << "Unrecognized section from " 
       << string1.c_str() << " on line " << line1 << " to " 
       << string2.c_str() << " on line " << line2 << endl
       << "=====ignored section begins=====" << endl
       << resync_text.c_str() << endl
       << "===== ignored section ends =====" << endl;
}


ParseUtility::ParseUtility(ANTLRParser *parser)
{
  // This is designed as a serial-singleton class (e.g. many 
  // instances may exist over time but no more than one at a
  // time).
  // For the lifetime of an instance, the static member theCurrentInstance
  // points to it. When no instance exists, this pointer is null.
  assert(theCurrentInstance==NULL);
  theCurrentInstance=this;

  trace_depth=0;
  stack_depth=0;
  this->parser=(ANTLR_Assisted_Parser*)parser;

}

ParseUtility::~ParseUtility()
{
  theCurrentInstance=NULL;
}

// This utility function is used to create
// a composite scope name from a qualifier scope
// and a relative name.
string ParseUtility::scopeCombine(const string& baseScope, const string& name)
{
	// I am presently (as at 3.pre44) experimenting with
	// how I handle scopes.  The present code has a policy
	// of discarding scope information altogether and defining
	// modules based solely on the final component of the 
	// fully qualified name.
	// This variable may become a parameter to control policy in this
	// area.
	bool bIgnoreScope=true;
	string retval;
	if(bIgnoreScope)
	{
		retval=name;
	}
	else if(baseScope.size()>0 && name.size()>0)
	{
		retval=baseScope+"::"+name;
	}
	else
	{
		retval=baseScope+name;
	}
	
  return retval;
}

ParseStore::ParseStore(const string& filename)
: theFilename(filename)
, pendingLexicalCounts(static_cast<int>(tcLAST),0)
, flag(static_cast<int>(psfLAST)+1,'?')
{
  // This is designed as a serial-singleton class (e.g. many 
  // instances may exist over time but no more than one at a
  // time).
  // For the lifetime of an instance, the static member theCurrentInstance
  // points to it. When no instance exists, this pointer is null.
  assert(theCurrentInstance==NULL);
  theCurrentInstance=this;
  flag[psfLAST]='\0';
}

ParseStore::~ParseStore()
{
  // If the current object came from the default constructor
  // it is the primary singleton instance and we wish to 
  // set the static pointer to itself back to null.  Otherwise,
  // it was a cached copy, and we don't really care.
  if(theCurrentInstance==this)
    {
      theCurrentInstance=NULL;
    }
}

int ParseStore::get_flag(PSFlag psf) const {
  return int(flag[psf]); 
}

void ParseStore::set_flag(PSFlag psf, int value) { 
  flag[psf]=value;
}

void ParseStore::set_flag(Visibility value) { 
  MAKE_STRSTREAM(ofstr);
  ofstr << value;
  flag[psfVISIBILITY]=(ofstr.str())[0];
  RELEASE_STRSTREAM(ofstr);
}

Visibility ParseStore::get_visibility()
{
  return static_cast<Visibility>(flag[psfVISIBILITY]);
}
  
string ParseStore::filename() 
{ 
  return theFilename; 
}

void 
ParseStore::
insert_extent(CCCC_Item& os, int startLine, int endLine,
	      const string& description, const string& flags,
	      UseType ut, bool allocate_lexcounts) 
{
  os.Insert(theFilename);
  os.Insert(startLine);
  os.Insert(description);
  os.Insert(flags);
  int i;
  int lexical_counts_for_this_extent[tcLAST];
  for(i=0; i<tcLAST; i++)
    {
      lexical_counts_for_this_extent[i]=0;
    }

  if(allocate_lexcounts==true)
    {
      LineLexicalCountMatrix::iterator extentStartIter =
	lineLexicalCounts.lower_bound(startLine); 
      LineLexicalCountMatrix::iterator extentEndIter =
	lineLexicalCounts.upper_bound(endLine-1); 
      LineLexicalCountMatrix::iterator llcmIter;
      for(llcmIter=extentStartIter;
	  llcmIter!=extentEndIter; 
	  ++llcmIter)
	{
	  // This record relates to a line within the current
	  // extent.
	  for(i=0; i<tcLAST; i++)
	    {	
	      lexical_counts_for_this_extent[i]+=(*llcmIter).second[i];
	    }
	}
      // The lexical occurrences mentioned in the records processed 
      // above are now been accounted for in the database, so we
      // purge these records.  This has the effect of allowing
      // accurate accounting on nested extents (i.e. the outer
      // extent will only be reported as containing lines which 
      // are not already listed in the inner extent).
      lineLexicalCounts.erase(extentStartIter,extentEndIter);

      char lexcount_buf[1024];
      ostrstream lexcount_str(lexcount_buf,1023);

      lexcount_str << "LOC:" << lexical_counts_for_this_extent[tcCODELINES]
		   << " COM:" << lexical_counts_for_this_extent[tcCOMLINES]
		   << " MVG:" << lexical_counts_for_this_extent[tcMCCABES_VG]
		   << ends;

      os.Insert(lexcount_str.str());

    }
  else
    {
      os.Insert("*");
    }
  os.Insert((char)flag[psfVISIBILITY]);
  os.Insert((char)ut);
}


  
void ParseStore::record_module_extent(int startLine, int endLine, 
				      const string& moduleName, 
				      const string& moduleType,
				      const string& description,
				      UseType ut)
{
  CCCC_Item module_line;
  module_line.Insert(moduleName);
  module_line.Insert(moduleType);
  insert_extent(module_line,startLine,endLine,
		description,flags(),ut,true);
  prj->add_module(module_line);
}

void ParseStore::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)
{
  CCCC_Item function_line;
  function_line.Insert(moduleName);
  function_line.Insert(memberName);
  function_line.Insert(returnType);
  function_line.Insert(paramList);

  string baseFlags=flags();
  baseFlags[psfVISIBILITY]=visibility;

  insert_extent(function_line,startLine,endLine,
		description,baseFlags,ut,true);
  prj->add_member(function_line);
}

void ParseStore::record_userel_extent(int startLine, int endLine,
				      const string& clientName, 
				      const string& memberName,
				      const string& serverName,
				      const string& description,
				      Visibility visibility,
				      UseType ut)
{
  CCCC_Item userel_line;
  userel_line.Insert(clientName);
  userel_line.Insert(memberName);
  userel_line.Insert(serverName);

  // for data member definitions, we record lexical data for the
  // extent,
  // for inheritance and parameter relationships we do not
  bool record_lexcounts=false;
  switch(ut)
    {
    case utHASBYVAL:
    case utHASBYREF:
      record_lexcounts=true;
      break;
    default:
      record_lexcounts=false;
    }

  string baseFlags=flags();
  baseFlags[psfVISIBILITY]=visibility;
  insert_extent(userel_line,startLine,endLine,
		description,baseFlags,ut,record_lexcounts);
  prj->add_userel(userel_line);
}

void ParseStore::record_other_extent(int startLine, int endLine, 
					  const string& description)
{
  CCCC_Item rejext_line;
  insert_extent(rejext_line,startLine,endLine,description,flags(),utREJECTED,true);
  prj->add_rejected_extent(rejext_line);
}

static void toktrace(ANTLRAbstractToken *tok)
{
  // at the LHS we put out information about the current token
  if(tok != NULL)
    {
      DbgMsg(PARSER,cerr,
	     std::setw(6) << tok->getLine() 
	     << std::setw(4) << (int)tok->getType()
	     << std::setiosflags(ios::left) 
	     << std::resetiosflags(ios::right) 
	     << std::setw(20) << tok->getText()
	     );
    }
  else
    {
      DbgMsg(PARSER,cerr,std::setw(30)<<"");
    }
}

enum InOrOut { IO_IN, IO_OUT };

static void rectrace(const char *rulename, 
		     const char *dir_indic, 
		     int guessing, 
		     ANTLRAbstractToken *tok)
{
  static int trace_depth=0;
  if(guessing)
    {
      DbgMsg(PARSER,cerr,
	     setw(trace_depth*4+1) << "" << dir_indic 
	     << "?" << rulename << endl);
    }
  else
    {
      trace_depth=((ANTLRToken*) tok)->getNestingLevel();
      DbgMsg(PARSER,cerr,
	     setw(trace_depth*4)<< "" << dir_indic << rulename << endl);
    }
}

void ParseUtility::tracein(
			   const char *rulename, int guessing, 
			   ANTLRAbstractToken *tok)
{
  if(guessing == 0)
    {
      stack_tokentext[stack_depth]=tok->getText();
      stack_tokenline[stack_depth]=tok->getLine();
      stack_rules[stack_depth]=rulename;
      stack_depth++;
    }

  // first put out the token details
  toktrace(tok);
  
  // then the indented recognition trace
  rectrace(rulename,"-> ",guessing,tok);
}

void ParseUtility::traceout(const char *rulename, 
			    int guessing, 
			    ANTLRAbstractToken *tok)
{
  if(guessing == 0)
    {
      stack_depth--;
      // some error checking...
      if(stack_depth<0)
	{
	  cerr << "ParseUtility::traceout negative stack depth - "
	       << "exiting from rule " << rulename 
	       << " at " << tok->getText() << " on line " << tok->getLine() 
	       << endl;
	}
      else if(rulename!=stack_rules[stack_depth])
	{
	  cerr << "ParseStore::traceout rule name mismatch - "
	       << rulename << "!=" << stack_rules[stack_depth] << endl;
	}
      stack_tokentext[stack_depth]="";
      stack_tokenline[stack_depth]=0;
      stack_rules[stack_depth]="";
    }
  // first put out the token details
  toktrace(tok);
  rectrace(rulename,"<- ",guessing,tok);
}
  
void ParseUtility::syn(
  _ANTLRTokenPtr tok, ANTLRChar *egroup, SetWordType *eset,
  ANTLRTokenType etok, int k) 
{
  string filename=ParseStore::currentInstance()->filename();
  if(tok != NULL)
    {
      cerr << filename << '(' << tok->getLine() << "):" 
	   << " syntax error at token " << tok->getText() << endl;
    }
  else
    {
      cerr << filename << "(0): syntax error at null token" << endl;
    }

#if 1
	  // The logic in the other half of this #if section
	  // generated too much noise for some people's taste.
	  // It's only really useful to myself (TJL) or anyone
	  // else with a taste for debugging cccc.g/java.g etc.
	  int i=stack_depth-1;
      cerr << filename << '(' << stack_tokenline[i] 
	   << "): trying to match " << stack_rules[i]
	   << " at '" << stack_tokentext[i] << "'"
	   << endl;
#else
  cerr << "Parser context:" << endl;
  for(int i=stack_depth-1; i>=0; i--)
    {
      cerr << filename << '(' << stack_tokenline[i] 
	   << "): trying to match " << stack_rules[i]
	   << " at '" << stack_tokentext[i] << "'"
	   << endl;
    }	
  cerr << endl;
#endif
}	

void ParseStore::endOfLine(int line)
{
  // We only do the processing below if the line which has just
  // ended contained at least one non-skippable token
  // The flag which tells us whether this is true is set in the 
  // token constructor
  if(ANTLRToken::bCodeLine)
  {
	pendingLexicalCounts[tcCODELINES]++;
    LineLexicalCountMatrix::value_type 
      vt(line,LexicalCountArray(static_cast<int>(tcLAST),0));

    for(int i=0; i<tcLAST; i++)
      {
	vt.second[i]=pendingLexicalCounts[i];
	pendingLexicalCounts[i]=0;
      }
    lineLexicalCounts.insert(vt);

	// reset the flat for next time
	ANTLRToken::bCodeLine=false;
  }
}