Logo Search packages:      
Sourcecode: cccc version File versions

cccc_utl.cc

// 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;
  }
}









Generated by  Doxygen 1.6.0   Back to index