/*
 *                      ***************
 *                      * X R F 1 . C *
 *                      ***************
 *
 * Lexical processing for C xref'er. Sifts through C source code
 * and pulls out the identifiers. Recognizes reserved words and
 * disregards them. Returns non-zero integer (true) if an id was
 * successfully moved into 'idbuf', zero (false) if end-of-line
 * was reached. I took care to test the C compiler's reaction to
 * Formfeeds with respect to line numbers, and made sure the line
 * numbers assigned by xrf act the same.
 *
 * Version V1.3          9-May-80
 * Version V1.4		10-Jul-80 MM	Allow $ in identifiers, bummed code
 * Version V1.5		21-Jul-80 MM	Dropped newline from ctime()
 * Version V1.6		22-Jul-80 MM	'.' is not an alpha char.
 */

#include <stdio.h>
#include "xrf.h"

#define A 1             /* Alpha character */
#define C 2             /* Start of comment possibly */
#define L 3             /* Literal delimiter */
#define N 4             /* Numeric character */
#define Z 5             /* End of string */

#define NRW 28          /* # reserved words */

static int cmtflg = 0;	/* Comment flag */

static char ctype[] = {         /* Character action lookup */
                        Z,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
                        0,0,L,0,A,0,0,L,0,0,0,0,0,0,0,C,
                        N,N,N,N,N,N,N,N,N,N,0,0,0,0,0,0,
                        0,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
                        A,A,A,A,A,A,A,A,A,A,A,0,0,0,0,A,
                        0,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,
                        A,A,A,A,A,A,A,A,A,A,A,0,0,0,0,0
                      };

static char *reswrd[NRW] = {
                        "auto", "break", "case", "char",
                        "continue", "default", "do", "double",
                        "else", "entry", "extern", "float",
                        "for", "goto", "if", "int",
                        "long", "register", "return", "short",
                        "sizeof", "static", "struct", "switch",
                        "typedef", "union", "unsigned", "while"
                        };


/*
 * Scan off a non reserved identifier. Put it into 'idbuf'.
 * Returns +1 if successful, 0 if end-of-line was reached.
 *
 */

getid()                         /* Get an identifier into idbuf */

   {
   register char *p ;                   /* Fast scan pointer */
   register char *i ;                   /* Fast id buf pointer */
   register int c;                      /* Dispatch code */

   p = scanp;                           /* Init fast pointers */
   i = idbuf;

   while ((c = *p) != 0)                /* Scan till end of string */
      {

      if(c == '\014')                   /* If formfeed, */
         {
         c = *p = ' ';                  /* Convert to harmless blank */
         newpage();                     /* Force new page */
         }

      if (cmtflg)                       /* If comment flag is on */
         {
         while(*p && *p++ != '*');	/* Scan to '*' or end of string */
         if(*p == '/')                  /* If we found end of comment */
            cmtflg = 0;                 /* Turn off comment flag */
         continue;                      /* and recycle */
         }

      switch(ctype[c])			/* Dispatch on the type */
         {
         case A:                        /* Start of an identifier */
            i = idbuf;                  /* Reset the id buffer pointer */
            do
               if( i < &idbuf[NCPS] )   /* Copy into idbuf */
                  *i++ = *p++;
               else                     /* Unless it gets full */
                  p++;
            while( (c=ctype[*p]) == A || c == N ); /* While alphanumeric */

            while( i < &idbuf[NCPS] )   /* Pad idbuf with nulls */
               *i++ = '\0';
            if(nonres(idbuf))           /* If it's not a reserved word */
               {
               scanp = p;               /* Update the scan pointer */
               return (1);              /* Return with success */
               }
            break;                      /* End of identifier processing */

         case N:                        /* Scan by a number string */
            do p++; while( (c=ctype[*p]) == N || c == A );
            break;

         case L:                        /* Scan by a literal */
	    while (*++p != c && *p) {	/* Scan to the matching trailing */
		if (*p == '\\') p++;	/* Quote, ignoring backslash quoted */
	    }				/* Characters.  If not at the end */
	    if (*p) p++;		/* Of the line, skip to the char. */
            break;			/* Following the trailing quote */

         case C:
            if(*++p == '*')             /* Start a comment */
              cmtflg = 1;               /* by setting comment flag */
            break;

         default:                       /* Otherwise just scan it off */
            p++;
            break;
         }                              /* End of switch statement */

      }                         /* If we exit here, end-of line. */
   return(0);                   /* Return with failure indication */
   }



/*
 * Search for reserved word. Return true (1) if NOT reserved word.
 * Uses binary search.
 */

nonres( bufp )                  /* Test if not reserved word */
char *bufp;

   {
   register int low ;           /* Low pointer index */
   register int mid ;           /* Mid ... */
   register int hi  ;           /* hi ...  */

   int cond;                    /* Condition from strcmp */

   low = 0;
   hi  = NRW-1;

   while (low <= hi)
      {
      mid = (low + hi) / 2;
      if((cond = strcmp(bufp, reswrd[mid])) < 0)
         hi = mid - 1;
      else if (cond > 0)
         low = mid + 1;
      else
         return(0);             /* False, it IS reserved */
      }
   return(1);                   /* True, it's NOT reserved */
   }

