/*
 * A scanner, along with a "large" set of heuristics, that examines C & C++
 * files to try to find all declarations and definitions of objects.
 * It outputs TCL "code" by a browser to build its database of the code.
 *
 * Some of this code is based on examples from the GNU "Flex" manual by
 * G. T. Nicol.
 *
 * Dave Clemans, June 1993
 * dave_clemans@mentorg.com
 */

%{
#include <stdio.h>
#include <ctype.h>

#define isodigit(x)  ((x) >= '0' && (x) <= '7')
#define hextoint(x)  (isdigit((x)) ? (x) - '0' : ((x) - 'A') + 10)

static char *buffer         = NULL;
static int buffer_size      = 0;
static char *ptr,*bptr;

static char *currentFile    = NULL;
static long parenNest       = 0;
static long braceNest       = 0;
static long lineNumber      = 1;
static long charNumber      = 0;
static long savedLineNumber = 0;
static long savedCharNumber = 0;

#define  TKB_DEC_NUMBER    256
#define  TKB_OCT_NUMBER    257
#define  TKB_HEX_NUMBER    258
#define  TKB_FLOAT_NUMBER  259
#define  TKB_STRING_CONST  260
#define  TKB_CHAR_CONST    261
#define  TKB_IDENT         262
#define  TKB_CLASS         263
#define  TKB_WORD          264
#define  TKB_ANDAND        265
#define  TKB_OROR          266
#define  TKB_EQUALEQUAL    267
#define  TKB_NOTEQUAL      268
#define  TKB_COLONCOLON    269
#define  TKB_TYPE          270
#define  TKB_VISIBILITY    271
#define  TKB_LANGUAGE      272
#define  TKB_OPERATOR      273
#define  TKB_STATIC        274
#define  TKB_EXTERN        275
#define  TKB_LSHIFT        276
#define  TKB_RSHIFT        277
#define  TKB_INCR          278
#define  TKB_DECR          279
#define  TKB_PLUSEQUAL     280
#define  TKB_MINUSEQUAL    281
#define  TKB_STAREQUAL     282
#define  TKB_SLASHEQUAL    283
#define  TKB_MODEQUAL      284
#define  TKB_ANDEQUAL      285
#define  TKB_OREQUAL       286
#define  TKB_COMPEQUAL     287
#define  TKB_XOREQUAL      288
#define  TKB_LSHIFTEQUAL   289
#define  TKB_RSHIFTEQUAL   290
#define  TKB_NEWDEL        291
#define  TKB_LESSEREQUAL   292
#define  TKB_GREATEREQUAL  293
#define  TKB_ENUM          294
#define  TKB_ARROW         295

void yyerror(message)
char *message;
{
#ifdef   DEBUGGING
   /* silently swallow error messages unless debugging */
   fprintf(stderr,"\nError: %s\n",message);
#endif
}

extern void *realloc();

#undef   yywrap

%}

%x COMMENT
%x STRING
%x PREPROCESSOR

hex (x|X)[0-9a-fA-F]{1,2}
oct [0-7]{1,3}

name [a-zA-Z_][a-zA-Z_$0-9]*
dec_num [0-9]+
oct_num 0[0-7]+
hex_num 0[xX][0-9a-fA-F]+

%%

^#[ 	]*{dec_num}[ 	]+\"[^"]*\"\n |
^#[ 	]*line[ 	]+{dec_num}[ 	]+\"[^"]*\"\n {
      for (ptr = yytext; ptr < &yytext[yyleng]; ptr++)
         if (isdigit(*ptr))
            break;
      lineNumber = atol(ptr);
      while (isdigit(*ptr) && ptr < &yytext[yyleng])
         ptr++;
      for (; ptr < &yytext[yyleng]; ptr++)
         if (*ptr == '"')
            break;
      if (*ptr == '"')
         ptr++;
      bptr = ptr;
      for (; ptr < &yytext[yyleng]; ptr++)
         if (*ptr == '"')
            break;
      if (currentFile != NULL)
         free(currentFile);
      currentFile = (char *)malloc(ptr - bptr + 1);
      strncpy(currentFile,bptr,ptr - bptr);
      currentFile[ptr - bptr] = '\0';
                     }

^#                   {
      charNumber += yyleng;
      BEGIN(PREPROCESSOR);
                     }

<PREPROCESSOR>\\\n   {
      charNumber = 0;
      lineNumber += 1;
                     }

<PREPROCESSOR>\n     {
      charNumber = 0;
      lineNumber += 1;
      BEGIN(INITIAL);
                     }

<PREPROCESSOR>.      {
      charNumber += yyleng;
                     }

"//"[^\n]*\n         {
      lineNumber += 1;
      charNumber = 0;
                     }

"/*"                 {
      BEGIN(COMMENT);
      charNumber += yyleng;
                     }

<COMMENT>[^*\n]*     {
      charNumber += yyleng;
                     }

<COMMENT>[^*\n]*\n   {
      lineNumber += 1;
      charNumber = 0;
                     }

<COMMENT>"*"+[^*/\n]* {
      charNumber += yyleng;
                     }

<COMMENT>"*"+[^*/\n]*\n {
      lineNumber += 1;
      charNumber = 0;
                     }

<COMMENT><<EOF>>     {
      yyerror("EOF in comment");
                     }

<COMMENT>"*"+"/"     {
      charNumber += yyleng;
      BEGIN(INITIAL);
                     }

\'.\'                |
\'..\'               {
      charNumber += yyleng;
      return TKB_CHAR_CONST;
                     }

\\\"                 {
      charNumber += yyleng;
                     }

\"                   {
      if (buffer != NULL)
         free(buffer);
      buffer = malloc(1);
      buffer_size = 1;
      strcpy(buffer,"");
      BEGIN(STRING);
      savedLineNumber = lineNumber;
      savedCharNumber = charNumber;
      charNumber += yyleng;
                     }

<STRING>\n           {
      yyerror("Unterminated string");
      lineNumber += 1;
      charNumber = 0;
      BEGIN(INITIAL);
      return TKB_STRING_CONST;
                     }

<STRING><<EOF>>      {
      yyerror("EOF in string");
      BEGIN(INITIAL);
      return TKB_STRING_CONST;
                     }

<STRING>[^\\\n"]     {
      buffer_size += yyleng;
      buffer = realloc(buffer,buffer_size+1);
      strcat(buffer,yytext);
      charNumber += yyleng;
                     }

<STRING>\\\n         {
      lineNumber += 1;
      charNumber = 0;
                     }

<STRING>\\{hex}      {
      int temp = 0;
      int loop = 0;
      int foo;
      for (loop = yyleng-2; loop>0; loop--) {
         temp <<= 4;
         foo = toupper(yytext[yyleng-loop]);
         temp += hextoint(foo);
      }
      buffer = realloc(buffer,buffer_size+1);
      buffer[buffer_size-1] = temp;
      buffer[buffer_size] = '\0';
      buffer_size += 1;
      charNumber += yyleng;
                     }

<STRING>\\{oct}      {
      int temp = 0;
      int loop = 0;
      for (loop = yyleng-2; loop>0; loop--) {
         temp <<= 3;
         temp += (yytext[yyleng-loop] - '0');
      }
      buffer = realloc(buffer,buffer_size+1);
      buffer[buffer_size-1] = temp;
      buffer[buffer_size] = '\0';
      buffer_size += 1;
      charNumber += yyleng;
                     }

<STRING>\\[^\n]      {
      buffer = realloc(buffer,buffer_size+1);
      switch (yytext[yyleng-1]) {
         case 'b':
            buffer[buffer_size-1] = '\b';
            break;
         case 't':
            buffer[buffer_size-1] = '\t';
            break;
         case 'n':
            buffer[buffer_size-1] = '\n';
            break;
         case 'v':
            buffer[buffer_size-1] = '\v';
            break;
         case 'f':
            buffer[buffer_size-1] = '\f';
            break;
         case 'r':
            buffer[buffer_size=1] = '\r';
            break;
         default:
            buffer[buffer_size-1] = yytext[yyleng-1];
            break;
      }
      buffer[buffer_size] = '\0';
      buffer_size += 1;
      charNumber += yyleng;
                     }

<STRING>\"           {
      charNumber += yyleng;
      BEGIN(INITIAL);
      return TKB_STRING_CONST;
                     }

class                |
struct               {
      charNumber += yyleng;
      return TKB_CLASS;
                     }

char                 |
const                |
double               |
float                |
inline               |
int                  |
long                 |
short                |
signed               |
typedef              |
unsigned             |
virtual              |
void                 |
volatile             {
      charNumber += yyleng;
      return TKB_TYPE;
                     }

enum                 {
      charNumber += yyleng;
      return TKB_ENUM;
                     }

extern[ 	]*\"C\" |
extern[ 	]*\"C++\" {
      charNumber += yyleng;
      return TKB_LANGUAGE;
                     }

extern               {
      charNumber += yyleng;
      return TKB_EXTERN;
                     }

static               {
      charNumber += yyleng;
      return TKB_STATIC;
                     }

private              |
protected            |
public               {
      charNumber += yyleng;
      return TKB_VISIBILITY;
                     }

operator[ 	]*[^(]+ |
operator[ 	]*"("[^)]*")" {
      charNumber += yyleng;
      return TKB_OPERATOR;
                     }

new                  |
delete               {
      charNumber += yyleng;
      return TKB_NEWDEL;
                     }

break                |
case                 |
default              |
do                   |
entry                |
for                  |
friend               |
if                   |
return               |
sizeof               |
switch               |
while                {
      charNumber += yyleng;
      return TKB_WORD;
                     }

" "*                 |
"	"*           {
      charNumber += yyleng;
                     }

\n                   {
      lineNumber += 1;
      charNumber = 0;
                     }

{name}               {
      savedLineNumber = lineNumber;
      savedCharNumber = charNumber;
      charNumber += yyleng;
      return TKB_IDENT;
                     }

[0-9]*\.[0-9]+[eE][0-9]+ |
[0-9]*\.[0-9]+       |
[0-9]+[eE][0-9]+     {
      charNumber += yyleng;
      return TKB_FLOAT_NUMBER;
                     }

{dec_num}            {
      charNumber += yyleng;
      return TKB_DEC_NUMBER;
                     }

{oct_num}            {
      charNumber += yyleng;
      return TKB_OCT_NUMBER;
                     }

{hex_num}            {
      charNumber += yyleng;
      return TKB_HEX_NUMBER;
                     }

"+="                 {
      charNumber += yyleng;
      return TKB_PLUSEQUAL;
                     }

"-="                 {
      charNumber += yyleng;
      return TKB_MINUSEQUAL;
                     }

"*="                 {
      charNumber += yyleng;
      return TKB_STAREQUAL;
                     }

"/="                 {
      charNumber += yyleng;
      return TKB_SLASHEQUAL;
                     }

"%="                 {
      charNumber += yyleng;
      return TKB_MODEQUAL;
                     }

"&="                 {
      charNumber += yyleng;
      return TKB_ANDEQUAL;
                     }

"|="                 {
      charNumber += yyleng;
      return TKB_OREQUAL;
                     }

"~="                 {
      charNumber += yyleng;
      return TKB_COMPEQUAL;
                     }

"<<="                {
      charNumber += yyleng;
      return TKB_LSHIFTEQUAL;
                     }

">>="                {
      charNumber += yyleng;
      return TKB_RSHIFTEQUAL;
                     }

"^="                 {
      charNumber += yyleng;
      return TKB_XOREQUAL;
                     }

">="                 {
      charNumber += yyleng;
      return TKB_GREATEREQUAL;
                     }

"<="                 {
      charNumber += yyleng;
      return TKB_LESSEREQUAL;
                     }

"&&"                 {
      charNumber += yyleng;
      return TKB_ANDAND;
                     }

"||"                 {
      charNumber += yyleng;
      return TKB_OROR;
                     }

"=="                 {
      charNumber += yyleng;
      return TKB_EQUALEQUAL;
                     }

"!="                 {
      charNumber += yyleng;
      return TKB_NOTEQUAL;
                     }

"::"                 {
      charNumber += yyleng;
      return TKB_COLONCOLON;
                     }

"<<"                 {
      charNumber += yyleng;
      return TKB_LSHIFT;
                     }

">>"                 {
      charNumber += yyleng;
      return TKB_RSHIFT;
                     }

"--"                 {
      charNumber += yyleng;
      return TKB_DECR;
                     }

"++"                 {
      charNumber += yyleng;
      return TKB_INCR;
                     }

"->"                 {
      charNumber += yyleng;
      return TKB_ARROW;
                     }

"("                  {
      parenNest++;
      charNumber += yyleng;
      return yytext[0];
                     }

")"                  {
      parenNest--;
      charNumber += yyleng;
      return yytext[0];
                     }

"{"                  {
      braceNest++;
      charNumber += yyleng;
      return yytext[0];
                     }

"}"                  {
      braceNest--;
      charNumber += yyleng;
      return yytext[0];
                     }

"["                  |
"]"                  |
"="                  |
"/"                  |
"*"                  |
"+"                  |
"%"                  |
"^"                  |
"<"                  |
">"                  |
"-"                  |
"|"                  |
"&"                  |
"|"                  |
"?"                  |
","                  |
"!"                  |
"+"                  |
"~"                  |
"."                  |
":"                  |
";"                  {
      charNumber += yyleng;
      return yytext[0];
                     }

.                    {
      charNumber += yyleng;
                     }

%%

static void declObject();
static void declFunction();
static void declFile();
static void declClass();

static char *currentClass = NULL;

/*
 * Gen up a printable version of a token
 */
static char *token(tokenType)
int tokenType;
{
   static char tokenBuf[2048];
   int len;
   char *ptr,*mptr;

   if (tokenType == TKB_STRING_CONST) {
      len = yyleng;
      if (len > sizeof(tokenBuf)-3)
         len = sizeof(tokenBuf)-3;
      strncpy(&tokenBuf[1],yytext,len);
      tokenBuf[0] = '\\';
      tokenBuf[len+1] = '\\';
      tokenBuf[len+2] = '\0';
   } else if (tokenType == '[' || tokenType == ']') {
      tokenBuf[0] = '\\';
      tokenBuf[1] = tokenType;
      tokenBuf[2] = '\0';
   } else {
      len = yyleng;
      if (len > sizeof(tokenBuf)-1)
         len = sizeof(tokenBuf)-1;
      strncpy(tokenBuf,yytext,len);
      tokenBuf[len] = '\0';
   }
   ptr = tokenBuf;
   while ((ptr = (char *)strchr(ptr,'$')) != NULL) {
      for (mptr = ptr; *mptr; mptr++)
         /* do nothing */;
      while (mptr >= ptr) {
         mptr[1] = mptr[0];
         mptr--;
      }
      *ptr++ = '\\';
      ptr++;
   }
   for (ptr = tokenBuf; *ptr; ptr++)
      if (*ptr == '\n')
         *ptr = ' ';
   return tokenBuf;
}

static int gargc;
static char **gargv;
static int gargi;

struct staticFuncs
{
   char  *funcName;
   struct staticFuncs *next;
};
static struct staticFuncs *staticFuncList = NULL;

int yywrap()
{
   struct staticFuncs *sptr,*sbptr;

   for (sptr = staticFuncList; sptr != NULL; ) {
      sbptr = sptr;
      sptr = sptr->next;
      free(sbptr->funcName);
      free(sbptr);
   }
   staticFuncList = NULL;

   gargi++;
   if (gargi < gargc) {
      if (freopen(gargv[gargi],"r",stdin) != stdin) {
         fprintf(stderr,"browser: unable to open file %s\n",gargv[gargi]);
         return 1;
      }
      lineNumber = 1;
      charNumber = 0;
      printf("# Processing %s...\n",gargv[gargi]);
      if (currentFile != NULL)
         free(currentFile);
      currentFile = (char *)malloc(strlen(gargv[gargi])+1);
      strcpy(currentFile,gargv[gargi]);
      return 0;
   }
   return 1;
}

/*
 * Main program
 * parse files and figure out what they declare/define
 */
main(argc,argv)
int argc;
char *argv[];
{
   gargc = argc;
   gargv = argv;
   gargi = 1;
   if (argc > 1) {
      if (freopen(argv[1],"r",stdin) != stdin) {
         fprintf(stderr,"browser: unable to open file %s\n",argv[1]);
         exit(-1);
      }
      if (currentFile != NULL)
         free(currentFile);
      currentFile = (char *)malloc(strlen(argv[1])+1);
      strcpy(currentFile,argv[1]);
      lineNumber = 1;
      charNumber = 0;
      printf("# Processing %s...\n",argv[1]);
      declFile();
   } else {
      if (currentFile != NULL)
         free(currentFile);
      currentFile = (char *)malloc(2);
      strcpy(currentFile,"-");
      lineNumber = 1;
      charNumber = 0;
      printf("# Processing stdin...\n");
      declFile();
   }

   exit(0);
}

/*
 * Parse in the scope of a file
 */
static void declFile()
{
   long rc;
   long lineNo;
   char *name;
   char *subname;
   char *ptr;

   name = NULL;
   subname = NULL;
   while (rc = yylex()) {
      switch (rc) {
         case TKB_EXTERN:
            declObject(rc,currentFile,1,0,0);
            break;
         case TKB_STATIC:
            declObject(rc,currentFile,2,0,0);
            break;
         case TKB_TYPE:
         case TKB_ENUM:
         case TKB_IDENT:
            declObject(rc,currentFile,0,0,0);
            break;
         case TKB_CLASS:
            rc = yylex();
            if (name != NULL)
               free(name);
            ptr = token(rc);
            name = (char *)malloc(strlen(ptr)+1);
            strcpy(name,ptr);
            lineNo = lineNumber;
            rc = yylex();
            switch (rc) {
               case ':':
                  rc = yylex();
                  if (subname != NULL)
                     free(subname);
                  subname = NULL;
                  if (rc == TKB_VISIBILITY)
                     rc = yylex();
                  while (rc && rc == TKB_IDENT) {
                     ptr = token(rc);
                     if (subname == NULL) {
                        subname = (char *)malloc(strlen(ptr)+1);
                        strcpy(subname,ptr);
                     } else {
                        subname = (char *)realloc(subname,strlen(subname)+
                           strlen(ptr)+2);
                        strcat(subname,",");
                        strcat(subname,ptr);
                     }
                     rc = yylex();
                     if (rc == ',')
                        rc = yylex();
                  }
                  if (subname == NULL)
                     printf("tkbCdef %s %s:%d\n",name,currentFile,lineNo);
                  else printf("tkbSubCdef %s %s %s:%d\n",name,subname,currentFile,
                     lineNo);
                  while (rc && rc != '{')
                     rc = yylex();
                  if (currentClass != NULL)
                     free(currentClass);
                  currentClass = (char *)malloc(strlen(name)+1);
                  strcpy(currentClass,name);
                  declClass(rc,name);
                  break;
               case ';':
                  printf("tkbCdecl %s %s:%d\n",name,currentFile,lineNo);
                  break;
               case '{':
                  printf("tkbCdef %s %s:%d\n",name,currentFile,lineNo);
                  if (currentClass != NULL)
                     free(currentClass);
                  currentClass = (char *)malloc(strlen(name)+1);
                  strcpy(currentClass,name);
                  declClass(rc,name);
                  break;
               default:
                  break;
            }
            break;
         default:
            break;
      }
   }
   if (name != NULL)
      free(name);
   if (subname != NULL)
      free(subname);
}

/*
 * Parse an individual object declaration
 */
static void declObject(rc,scopeName,scopeType,inFunc,inClass)
int rc;
char *scopeName;
int scopeType;
int inFunc;
int inClass;
{
   int oldrc,inFuncParms,inBrackets,lastNameToken,inParens;
   int funcDecl;
   long lineNo;
   char *name;
   char *fulldecl;
   char *ptr;
   char *pad;
   int inEnum;
   int inBraces;
   char *scope;
   struct staticFuncs *sptr;
   int restart;

   lineNo = lineNumber;
   inFuncParms = 0;
   inBrackets = 0;
   lastNameToken = 0;
   inParens = 0;
   funcDecl = 0;
   inEnum = 0;
   inBraces = 0;
   oldrc = 0;
   name = NULL;
   fulldecl = NULL;
   restart = 1;
   while (restart) {
      while (rc != 0) {
         if (rc == TKB_ENUM)
            inEnum = 1;
         if (rc == TKB_STATIC)
            scopeType = 2;
         ptr = token(rc);
         if (isalnum(*ptr) || *ptr == '_' || *ptr == '*' || *ptr == '&' ||
            *ptr == '~') {
            if (fulldecl != NULL && (isalnum(*ptr) || *ptr == '_' ||
               *ptr == '~') &&
               (isalnum(fulldecl[strlen(fulldecl)-1]) ||
               fulldecl[strlen(fulldecl)-1] == '_'))
               pad = " ";
            else if (*ptr == '&')
               pad = " ";
            else if (*ptr == '*' && oldrc != '*')
               pad = " ";
            else pad = "";
         } else pad = "";
         if (!inBrackets && rc != TKB_STATIC && rc != TKB_EXTERN &&
            (rc != TKB_TYPE || strcmp(ptr,"inline") != 0)) {
            if (fulldecl != NULL) {
               fulldecl = (char *)realloc(fulldecl,strlen(fulldecl)+strlen(pad)+
                  strlen(ptr)+1);
               strcat(fulldecl,pad);
               strcat(fulldecl,ptr);
            } else {
               fulldecl = (char *)malloc(strlen(ptr)+1);
               strcpy(fulldecl,ptr);
            }
         }
         if ((rc == TKB_IDENT || rc == TKB_OPERATOR || rc == TKB_COLONCOLON ||
            rc == '~') && !inFuncParms && !funcDecl && !inBrackets) {
            if (rc == TKB_IDENT && lastNameToken == TKB_IDENT) {
               free(name);
               name = NULL;
            } else if (rc == TKB_OPERATOR && lastNameToken == TKB_IDENT) {
               free(name);
               name = NULL;
            }
            if (name != NULL) {
               name = (char *)realloc(name,strlen(name)+strlen(pad)+strlen(ptr)+1);
               strcat(name,pad);
               strcat(name,ptr);
            } else {
               name = (char *)malloc(strlen(ptr)+1);
               strcpy(name,ptr);
            }
            lastNameToken = rc;
         } else if (!inFuncParms && !funcDecl && rc != '(' && !inBrackets &&
            rc != '[' && rc != ']') {
            if (!(inEnum && inBraces)) {
               if (name != NULL)
                  free(name);
               name = NULL;
            }
         }
         if (rc == '[')
            inBrackets++;
         if (inFuncParms > 0 && rc == ')') {
            inFuncParms--;
         }
         if (inFunc && oldrc == 0 && rc == TKB_IDENT) {
            rc = yylex();
            if (rc != '*' && rc != '&' && rc != TKB_IDENT) {
               while (rc && rc != ';')
                  rc = yylex();
               if (name != NULL)
                  free(name);
               if (fulldecl != NULL)
                  free(fulldecl);
               return;
            }
            oldrc = TKB_IDENT;
         } else {
            oldrc = rc;
            rc = yylex();
         }
         if (oldrc == '(' && rc != '(' && rc != '*' && rc != '&' &&
            inParens == 0) {
            inFuncParms++;
            funcDecl = 1;
         }
         if (rc == ']')
            inBrackets--;
         if (rc == '{')
            inBraces++;
         if (rc == '}')
            inBraces--;
         if (inEnum && inBraces > 0) {
            if (rc == '=')
               while (rc && rc != ',' && rc != '}')
                  rc = yylex();
            if (rc == '}')
               inBraces--;
         }
         if (rc == ';' && inEnum)
            inEnum = 0;
         if (funcDecl && inFuncParms == 0 && rc != ';') {
            while (rc && rc != '{')
               rc = yylex();
         }
         if (rc == ':' || (rc == '=' && !inFuncParms) ||
            (rc == ',' && !inEnum && !inFuncParms) ||
            rc == ';' || (rc == '{' && !inEnum))
            break;
      }
      if (name == NULL || fulldecl == NULL) {
         if (name != NULL) {
   /*         printf("*err: name=%s\n",name); */
            free(name);
         }
         if (fulldecl != NULL) {
   /*         printf("*err: fulldecl=%s\n",fulldecl); */
            free(fulldecl);
         }
         return;
      }
   
      if (funcDecl) {
         if (rc != ';' && rc != ',')
            while (rc && rc != '{')
               rc = yylex();
         if (scopeType == 2) {
            sptr = (struct staticFuncs *)malloc(sizeof(*sptr));
            sptr->funcName = (char *)malloc(strlen(name)+1);
            strcpy(sptr->funcName,name);
            sptr->next = staticFuncList;
            staticFuncList = sptr;
         } else {
            for (sptr = staticFuncList; sptr != NULL; sptr = sptr->next) {
               if (strcmp(sptr->funcName,name) == 0) {
                  scopeType = 2;
                  break;
               }
            }
         }
         if (!inClass) {
            char *fptr;
            if (scopeType != 2)
               scope = "global";
            else scope = "local";
            fptr = (char *)strchr(name,':');
            if (fptr != NULL && fptr != name && fptr[1] == ':') {
               if (rc == '{') {
                  printf("tkbMbrFuncDefn %s \"%s\" \"%s\" %s:%d\n",scope,name,
                     fulldecl,currentFile,lineNo);
                  declFunction(rc,name,inClass);
               } else {
                  printf("tkbMbrFuncDecl %s \"%s\" \"%s\" %s:%d\n",scope,name,
                     fulldecl,currentFile,lineNo);
               }
            } else {
               if (rc == '{') {
                  printf("tkbFuncDefn %s \"%s\" \"%s\" %s:%d\n",scope,name,fulldecl,
                     currentFile,lineNo);
                  declFunction(rc,name,inClass);
               } else {
                  printf("tkbFuncDecl %s \"%s\" \"%s\" %s:%d\n",scope,name,fulldecl,
                     currentFile,lineNo);
               }
            }
         } else {
            if (scopeType == 2)
               scope = "class";
            else scope = "instance";
            if (rc == '{') {
               printf("tkbMbrFuncDefn %s:%s \"%s\" \"%s\" %s:%d\n",scope,currentClass,
                  name,fulldecl,currentFile,lineNo);
               declFunction(rc,name,inClass);
            } else {
               printf("tkbMbrFuncDecl %s:%s \"%s\" \"%s\" %s:%d\n",scope,currentClass,
                  name,fulldecl,currentFile,lineNo);
            }
         }
      } else {
         if (rc != ';' && rc != ',')
            while (rc && rc != ';')
               rc = yylex();
         if (inClass) {
            if (inFunc) {
               char *cname;
               char *result = (char *)strchr(scopeName,':');
               if (result == NULL) {
                  cname = (char *)malloc(strlen(currentClass)+strlen(scopeName)+3);
                  sprintf(cname,"%s::%s",currentClass,scopeName);
               } else {
                  cname = (char *)malloc(strlen(scopeName)+1);
                  strcpy(cname,scopeName);
               }
               if (scopeType == 2)
                  scope = "function";
               else scope = "call";
               if (scopeType != 1) {
                  printf("tkbObjDefn %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,cname,
                     name,fulldecl,currentFile,lineNo);
               } else {
                  printf("tkbObjDecl %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,cname,
                     name,fulldecl,currentFile,lineNo);
               }
               free(cname);
            } else {
               if (scopeType == 2)
                  scope = "class";
               else scope = "instance";
               printf("tkbMbrObjDefn %s %s %s \"%s\" %s:%d\n",scope,currentClass,
                  name,fulldecl,currentFile,lineNo);
            }
         } else if (inFunc) {
            char *cname;
            char *result = (char *)strchr(scopeName,':');
            if (result == NULL) {
               cname = (char *)malloc(strlen(name)+1);
               strcpy(cname,name);
            } else {
               result = (char *)strchr(name,':');
               if (result != NULL) {
                  cname = (char *)malloc(strlen(name)+1);
                  strcpy(cname,name);
               } else {
                  cname = (char *)malloc(strlen(scopeName)+strlen(name)+3);
                  strcpy(cname,scopeName);
                  result = (char *)strchr(cname,':');
                  strcpy(cname,&result[2]);
                  strcat(cname,"::");
                  strcat(cname,name);
               }
            }
            if (scopeType == 2)
               scope = "function";
            else scope = "call";
            if (scopeType != 1) {
               printf("tkbObjDefn %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,scopeName,
                  cname,fulldecl,currentFile,lineNo);
            } else {
               printf("tkbObjDecl %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,scopeName,
                  cname,fulldecl,currentFile,lineNo);
            }
            free(cname);
         } else {
            char *fptr;
            if (scopeType != 1)
               scope = "global";
            else scope = "local";
            fptr = (char *)strchr(name,':');
            if (fptr != NULL && fptr[1] == ':') {
               if (scopeType != 1) {
                  printf("tkbMbrObjDefn %s %s %s \"%s\" %s:%d\n",scope,currentFile,
                     name,fulldecl,currentFile,lineNo);
               } else {
                  printf("tkbMbrObjDecl %s %s %s \"%s\" %s:%d\n",scope,currentFile,
                     name,fulldecl,currentFile,lineNo);
               }
            } else {
               if (scopeType != 1) {
                  printf("tkbObjDefn %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,
                     currentFile,name,fulldecl,currentFile,lineNo);
               } else {
                  printf("tkbObjDecl %s \"%s\" \"%s\" \"%s\" %s:%d\n",scope,
                     currentFile,name,fulldecl,currentFile,lineNo);
               }
            }
         }
      }
      restart = 0;
      if (rc == ',') {
         for (ptr = fulldecl; *ptr; ptr++)
            /* do nothing */;
         while (ptr > fulldecl && *ptr != ' ')
            ptr--;
         *ptr = '\0';
         free(name);
         name = NULL;
         restart = 1;
         rc = yylex();
      }
   }
   free(name);
   free(fulldecl);
}

/*
 * Parse in the scope of a function
 */
static void declFunction(rc,fName,inClass)
int rc;
char *fName;
int inClass;
{
   int nest,parenNest,innerNest;
   char *funcName;

   funcName = (char *)malloc(strlen(fName)+1);
   strcpy(funcName,fName);
   nest = braceNest-1;
   while (rc && braceNest > nest) {
      switch(rc) {
         case TKB_EXTERN:
            declObject(rc,funcName,1,1,inClass);
            break;
         case TKB_STATIC:
            declObject(rc,funcName,2,1,inClass);
            break;
         case TKB_TYPE:
         case TKB_ENUM:
         case TKB_IDENT:
            declObject(rc,funcName,0,1,inClass);
            break;
         case '{':
            break;
         default:
            if (strcmp("for",token(rc)) == 0) {
               while (rc && rc != '(')
                  rc = yylex();
               parenNest = 1;
               while (rc && parenNest > 0) {
                  rc = yylex();
                  if (rc == '(')
                     parenNest++;
                  if (rc == ')')
                     parenNest--;
               }
            }
            while (rc && rc != ';' && rc != '{')
               rc = yylex();
            break;
      }
      rc = yylex();
   }
   free(funcName);
}

/*
 * Parse in the scope of a class
 */
static void declClass(rc,cName)
int rc;
char *cName;
{
   int nest;
   char *className;

   className = (char *)malloc(strlen(cName)+1);
   strcpy(className,cName);
   nest = braceNest-1;
   while (rc && braceNest > nest) {
      switch(rc) {
         case TKB_EXTERN:
            declObject(rc,className,1,0,1);
            break;
         case TKB_STATIC:
            declObject(rc,className,2,0,1);
            break;
         case TKB_TYPE:
         case TKB_ENUM:
         case TKB_IDENT:
         case TKB_OPERATOR:
         case '~':
            declObject(rc,className,0,0,1);
            break;
         case TKB_VISIBILITY:
            rc = yylex();
            break;
         case '{':
            break;
         default:
            while (rc && rc != ';')
               rc = yylex();
            break;
      }
      rc = yylex();
   }
   free(className);
}
