/*
 * cccc_tok.C
 * implementation of a token class for the cccc project
 *
 */

#include "cccc.h"
#include "cccc_tok.h"

/* static variables */
int ANTLRToken::RunningCount[tcLAST];
int ANTLRToken::PendingCount[tcLAST];
int ANTLRToken::RunningNesting;
int ANTLRToken::bCodeLine=0;
int ANTLRToken::numAllocated=0;
int toks_alloc1=0, toks_alloc2=0, toks_alloc3=0, toks_freed=0;

ANTLRToken currentLexerToken;

/* 
** Token objects are used to count the occurences of states which 
** our analyser is interested in within the text.  Any metric which
** can be reduced to lexical counting on the text can be recorded
** this way.
**
** This implementation counts the following features:
**   tokens
**   comment lines
**   lines containing at least one token of code
**  
** It also makes a lexical count for the following tokens, each of which
** is expected to increase McCabe's cyclomatic complexity (Vg) for the 
** section of code by one unit:
**  IF FOR WHILE SWITCH BREAK RETURN ? && ||
**
** Note that && and || create additional paths through the code due to C/C++ 
** short circuit evaluation of logical expressions.
**
** Also note the way SWITCH constructs are counted: the desired increment
** in Vg is equal to the number of cases provided for, including the 
** default case, whether or not an action is defined for it.  This is acheived
** by counting the SWITCH at the head of the construct as a surrogate for 
** the default case, and counting BREAKs as surrogates for the individual
** cases.  This approach yields the correct results provided that the
** coding style in use ensures the use of BREAK after all non-default
** cases, and forbids 'drop through' from one case to another other than
** in the case where two or more values of the switch variable require
** identical actions, and no executable code is defined between the 
** case gates (as in the switch statement in ANTLRToken::CountToken() below).
*/

/* default constructor */
ANTLRToken::ANTLRToken() : ANTLRCommonToken() { 
  SetCounts(); 
  toks_alloc1++;
}

/* 
** constructor used by makeToken below 
*/
ANTLRToken::ANTLRToken(ANTLRTokenType t, ANTLRChar *s) : 
   ANTLRCommonToken(t,s) {
  setType(t);
  setText(s);
  SetCounts();
  CountToken();
  toks_alloc2++;
}

/* copy constructor */
ANTLRToken::ANTLRToken(ANTLRToken& copyTok) {
  setType(copyTok.getType());
  setText(copyTok.getText());
  setLine(copyTok.getLine());
  toks_alloc3++;
  CopyCounts(copyTok);
}

/* 
** the virtual pseudo-constructor 
** This is required because the PCCTS support code does not know the
** exact nature of the token which will be created by the user's code, 
** and indeed does not forbid the user creating more than one kind of
** token, so long as ANTLRToken is defined and all token classes are
** subclassed from ANTLRAbstractToken
*/
ANTLRAbstractToken *ANTLRToken::makeToken(
  ANTLRTokenType tt, ANTLRChar *txt, int line
) {
  DbgMsg(
    LEXER,cerr, 
    "makeToken(tt=>" << tt << 
      ", txt=>" << txt << 
      ",line=>" << line << ")" << endl
  );
  ANTLRToken *new_t = new ANTLRToken(tt,txt);
  if(new_t==0) { 
    cerr << "Memory overflow in "
     "ANTLRToken::makeToken(" << tt << "," << txt << "," << line << ")" << endl;
    exit(2);
  }
  new_t->setLine(line);
  return new_t;
}

/* the destructor */
ANTLRToken::~ANTLRToken() {
  toks_freed++;
  DbgMsg(MEMORY,cerr,"freeing token " << getText()
	 << " on line " << getLine()
	 << " c1:" << toks_alloc1 << " c2:" << toks_alloc2 
	 << " c3:" << toks_alloc3 << " freed:" << toks_freed << endl);
}

/* the assignment operator */
ANTLRToken& ANTLRToken::operator=(ANTLRToken& copyTok) {
  setType(copyTok.getType());
  setText(copyTok.getText());
  setLine(copyTok.getLine());
  CopyCounts(copyTok);
  return *this;
}

/*
** as each token is created, it receives a copy of the current running
** counts of each of the lexical metrics.  The counts for an extent of code
** are obtained by looking at the first and last tokens and identifying
** the differences in their count values
*/
void ANTLRToken::SetCounts() {
  int i;
  for(i=0; i < (int) tcLAST; i++) {
    CurrentCount[i]=RunningCount[i];
  }
    CurrentNesting=RunningNesting;
}

/*
** used by the copy constructor
*/
void ANTLRToken::CopyCounts(ANTLRToken& copyTok) {
  int i;
  for(i=0; i < (int) tcLAST; i++) {
    CurrentCount[i]=copyTok.getCount(TokenCount(i));
  }
  CurrentNesting=copyTok.CurrentNesting;
}

/*
** ANTLRToken::CountToken performs counting of features which are traced
** back to individual tokens created up by the lexer, i.e. the token count 
** and McCabes VG.  Code lines and comment lines are both identified during
** the processing of text which the lexer will (usually) skip, so the code
** to increment these counts is in the relevant lexer rules in the file 
** cccc.g.m4
*/
void ANTLRToken::CountToken(){

  IncrementCount(tcTOKENS);

  // we have seen a non-skippable pattern => this line counts toward LOC  
  bCodeLine=1;

  // increment the running counts by the pending counts
  // the pending counts cover both this token and any skipped
  // patterns recognised since the last 'real' token
  for(int i=0; i<tcLAST; i++)
  {
    RunningCount[i]+=PendingCount[i];
    PendingCount[i]=0;
  }

  DbgMsg(COUNTER,cerr,*this);
}

char *ANTLRToken::getTokenTypeName() { return ""; }

/*
** structured output method for token objects
*/
ostream& operator << (ostream& out, ANTLRToken& t) {
  int i;

  out << "TOK: " << t.getTokenTypeName() << 
   " " << t.getText() <<
   " " << t.getLine();

  for(i=0; i<tcLAST; i++) {
    out << " " << t.getCount( TokenCount(i) );
  }

  out << " " << t.getNestingLevel();

  out << endl;
  return out;
}
 
  
 
