/*
 * A scanner to identify and output location information for "useful" parts
 * of C or C++ source text, of of source text that has a similar style.
 *
 * Currently we look for comments (both C and C++ styles) and function names.
 *
 * Some of this code is based on examples from the GNU "Flex" manual by
 * G. T. Nicol.
 *
 * Dave Clemans, June 1993
 */

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

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

char *buffer         = NULL;
int buffer_size      = 0;

int inBody           = 0;
int inClass          = 0;

long lineNumber      = 1;
long charNumber      = 0;
long savedLineNumber = 0;
long savedCharNumber = 0;
long funcStartLine   = 0;
long funcStartChar   = 0;

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

extern void *realloc();

%}

%x COMMENT
%x STRING

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

name [a-zA-Z_:~.][-a-zA-Z_$0-9:~>.]*

%%

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

"//"[^\n]*\n         {
      printf("comment %d.%d %d.%d\n",lineNumber,charNumber,
         lineNumber,charNumber+yyleng);
      lineNumber += 1;
      charNumber = 0;
                     }

"/*"                 {
      BEGIN(COMMENT);
      savedLineNumber = lineNumber;
      savedCharNumber = charNumber;
      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;
      printf("comment %d.%d %d.%d\n",savedLineNumber,savedCharNumber,
         lineNumber,charNumber);
      BEGIN(INITIAL);
                     }

\'.\'                {
      charNumber += yyleng;
      funcStartLine = 0;
                     }

\\\"                 {
      charNumber += yyleng;
      funcStartLine = 0;
                     }

\"                   {
      buffer = malloc(1);
      buffer_size = 1;
      strcpy(buffer,"");
      BEGIN(STRING);
      savedLineNumber = lineNumber;
      savedCharNumber = charNumber;
      charNumber += yyleng;
      funcStartLine = 0;
                     }

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

<STRING><<EOF>>      {
      yyerror("EOF in string");
      free(buffer);
      BEGIN(INITIAL);
                     }

<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>\"           {
      free(buffer);
      charNumber += yyleng;
      /* printf("string %d.%d %d.%d\n",savedLineNumber,savedCharNumber,
         lineNumber,charNumber); */
      BEGIN(INITIAL);
                     }

case                 |
char                 |
do                   |
double               |
extern               |
float                |
for                  |
if                   |
inline               |
int                  |
long                 |
private              |
protected            |
public               |
return               |
short                |
sizeof               |
static               |
switch               |
unsigned             |
void                 |
while                {
      charNumber += yyleng;
      funcStartLine = 0;
                     }

class                |
struct               {
      inClass++;
      charNumber += yyleng;
      funcStartLine = 0;
                     }

operator[ 	]+{name} |
operator[ 	]+[^ 	]/[ 	]*\( |
{name}::operator[ 	]+{name} |
{name}::operator[ 	]+[^ 	]/[ 	]*\( |
{name}               {
      funcStartLine = lineNumber;
      funcStartChar = charNumber;
      savedLineNumber = lineNumber;
      charNumber += yyleng;
      savedCharNumber = charNumber;
                     }

;                    {
      if (inBody == 0)
         if (inClass > 0)
            inClass--;
      charNumber += yyleng;
      funcStartLine = 0;
                     }

\{                   {
      inBody++;
      charNumber += yyleng;
      funcStartLine = 0;
                     }

\}                   {
      inBody--;
      if (inBody == 0)
         inClass = 0;
      charNumber += yyleng;
      funcStartLine = 0;
                     }

"("                  {
      if (inBody == 0 || (inClass && inBody == 1)) {
         if (funcStartLine != 0) {
            printf("functionName %d.%d %d.%d\n",funcStartLine,funcStartChar,
               savedLineNumber,savedCharNumber);
         }
      }
      charNumber += yyleng;
      funcStartLine = 0;
                     }

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

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

"["                  |
"]"                  |
"="                  |
"/"                  |
"*"                  |
"%"                  |
"^"                  |
"<"                  |
">"                  |
"-"                  |
")"                  |
"&"                  |
"|"                  |
"?"                  |
","                  |
"!"                  |
"+"                  {
      charNumber += yyleng;
      funcStartLine = 0;
                     }

.                    {
      charNumber += yyleng;
      funcStartLine = 0;
                     }

%%

void main(argc,argv)
int argc;
char *argv[];
{
   yylex();

   exit(0);
}
