%{
/*
 *   Copyright (C) 1988-2006 Lucent Technologies Inc. and others.
 *   All Rights Reserved.
 */

/*	cscope - interactive C symbol cross-reference
 *
 *	Java symbol scanner
 */

/* #include "global.h" -- prepended to lex.yy.c by make */

/* the line counting has been moved from character reading for speed */
/* comments are discarded */
static	int 	comment();
static 	int	sourceinput();	/* Can't use input() - generated by flex */
static	int	noncommentinput();
static	int	msdosgetc();
#define YY_INPUT(buf,result,max_size) \
	{ \
		int c = sourceinput(); \
		result = (c == LEXEOF) ? YY_NULL : (buf[0] = c, 1); \
	}

/* keyword text for fast testing of keywords in the scanner */
extern	char	classtext[];
extern	char	interfacetext[];

int	jfirst;	/* buffer index for first char of symbol */
int	jlast;	/* buffer index for last char of symbol */
int	jlineno;/* symbol line number */
int	jmyylineno = 1;

static	BOOL	arraydimension;		/* inside array dimension declaration */
static	int	braces;			/* unmatched left brace count */
static	int	classtoken;		/* class token */
static	BOOL	classdef;		/* class definition */
static	int	classbraces;		/* class brace count */
static	BOOL	fcndef;			/* function definition */
static	BOOL	globalscope;		/* file global scope (outside functions) */
static	BOOL	initializer;		/* data initializer */
static	int	initializerbraces;	/* data initializer outer brace count */
static	BOOL	lex;			/* lex file */
static	BOOL	localdef;		/* function/block local definition */
static	int	parens;			/* unmatched left parenthesis count */
static	BOOL	ppdefine;		/* preprocessor define statement */
static	BOOL	rules;			/* lex/yacc rules */
static	int	token;			/* token found */

static	void	multicharconstant();
%}
identifier	[a-zA-Z_\$][a-zA-Z_0-9\$]*
number		\.?[0-9][.0-9a-fA-FlLuUxX]*
%x JAVA
%a 12000
%o 18000
%p 5000
%%
\{		{	/* count unmatched left braces for fcn def detection */
			++braces;
			if (classdef == YES && fcndef == NO) {
				classbraces++;
			}
			
			/* mark an untagged class token so its beginning
			   can be found */
			if (classtoken) {
				jlast = jfirst;
				jsavesymbol(classtoken);
				classtoken = '\0';
			}
			goto more;
			/* NOTREACHED */
		}
\}		{
			/* could be the last enum member initializer */
			if (braces == initializerbraces) {
				initializerbraces = -1;
				initializer = NO;
			}
			if (--braces <= 0) {
		endstate:
				braces = 0;
			}
			/* if the end of a class */
			if (classdef == YES && braces == classbraces-1) {
				if (classbraces > 0) classbraces--;
				if (classbraces == 0) classdef = NO;
				globalscope = YES;
				jlast = jfirst;
				yymore();
				return(FCNEND);
			}
			/* if the end of a function */
			if ((braces == 0 || braces == classbraces && classdef == YES) &&
			    fcndef == YES) {
				fcndef = NO;
				if (classdef == NO) {
					globalscope = YES;
				}
				jlast = jfirst;
				yymore();
				return(FCNEND);
			}
			goto more;
			/* NOTREACHED */
		}
\(		{	/* count unmatched left parentheses */
			++parens;
			goto more;
			/* NOTREACHED */
		}
\)		{
			if (--parens <= 0) {
				parens = 0;
			}
			goto more;
			/* NOTREACHED */
		}
=		{	/* if a global definition initializer */
			if ((globalscope == YES || localdef == YES)) {
				initializerbraces = braces;
				initializer = YES;
			}
			goto more;
			/* NOTREACHED */
		}
\,		{
			if (braces == initializerbraces) {
				initializerbraces = -1;
				initializer = NO;
			}
			goto more;
			/* NOTREACHED */
		}
;		{
			localdef = NO;
			initializer = NO;
			goto more;
			/* NOTREACHED */
		}
<JAVA>final[ \t]+(boolean|char|byte|short|int|long|float|double)[ \t]+{identifier}	{
				
			/* constant definition */
			ppdefine = YES;
			token = DEFINE;
			REJECT;
			/* NOTREACHED */
		}
<JAVA>(class|interface)[ \t]+{identifier}[ \t\n\ra-zA-Z0-9_\$():]*\{	{	/* class definition */
			classdef = YES;
			classtoken = 'c';

			/* Fix reject messing up jfirst */
			if (jlast < jfirst) jfirst = 0;
				
			REJECT;
			/* NOTREACHED */
		}
{identifier}/[ \t\n\r]*\([ \t\n\ra-zA-Z0-9_\$*&[\]=,.]*\)[ \t\n\r()]*[:a-zA-Z_\$#{]	{
			
			/* warning: "if (...)" must not overflow yytext, so the content
			   of function argument definitions is restricted, in particular
			   parentheses are not allowed */

			/* if a function definition */
			if (braces == 0 && rules == NO ||
			    braces == classbraces && classdef == YES) {
				if (classdef == NO) {
					fcndef = YES;
					token = FCNDEF;
				}
				globalscope = NO;
				goto iflongline;
			}
			goto iffcncall;
			/* NOTREACHED */
		}
{identifier}/[ \t]*\(	{
			/* if a function call */
		iffcncall:
			if ((fcndef == YES || ppdefine == YES || rules == YES) &&
			    (localdef == NO || initializer == YES)) {
				token = FCNCALL;
				goto iflongline;
			}
			token = IDENT;
			goto iflongline;
			/* NOTREACHED */
		}
(\+\+|--)[ \t]*{identifier}	{	/* prefix increment or decrement */
			token = ASSIGNMENT;
		findident:
			jfirst = yyleng - 1;
			while (isalnum(yytext[jfirst]) || 
			       yytext[jfirst] == '_' ||
			       yytext[jfirst] == '$') {
				--jfirst;
			}
			++jfirst;
			goto iflongline;
			/* NOTREACHED */
		}
{identifier}/[ \t]*(\+\+|--)	{	/* postfix increment or decrement */
			token = ASSIGNMENT;
			goto iflongline;
			/* NOTREACHED */
		}
\*[ \t]*{identifier}/[ \t]*[^a-zA-Z0-9_\$(+-][^+-]	{ /* indirect assignment or dcl */
			while (!isalnum(yytext[jfirst]) && 
			       yytext[jfirst] != '_' &&
			       yytext[jfirst] != '$') {
				++jfirst;
			}
			goto ident;
			/* NOTREACHED */
		}
{identifier}/[ \t\n\r]*(=[^=]|[-+*/%&^|]=|<<=|>>=)	{ /* assignment */
			if ((fcndef == YES || ppdefine == YES || rules == YES) &&
			    localdef == NO) {
				token = ASSIGNMENT;
				goto iflongline;
			}
			goto ident;
			/* NOTREACHED */
		}
{identifier}	{
			struct	keystruct *p;
			char	*s;

		ident:	token = IDENT;
			if(arraydimension == NO
			    && initializer == NO) {
				
				/* if a class definition */
				if (classdef == YES && braces == 0) {
					token = CLASSDEF;
				}
				/* if a global definition */
				else if (globalscope == YES) {
					token = GLOBALDEF;
				}
				/* if a function parameter definition */
				else if (fcndef == YES && braces == classbraces && parens > 0) {
					token = PARAMETER;
				}
				/* if a local definition */
				else if (localdef == YES) {
					token = LOCALDEF;
				}
			}
		iflongline:
			/* if a long line */
			if (yyleng > STMTMAX) {
				int	c;
				
				/* skip to the end of the line */
				warning("line too long");
				while ((c = input()) != EOF) {
					if (c == '\n') {
						unput(c);
						break;
					}
				}
			}
			/* truncate a long symbol */
			if (yyleng - jfirst > PATLEN) {
				warning("symbol too long");
				yyleng = jfirst + PATLEN;
				yytext[yyleng] = '\0';
			}
			/* if a keyword */
			yymore();
			if ((p = lookup(yytext + jfirst)) != NULL) {
				jfirst = yyleng;
				s = p->text;
				
				/* recognise "public" class definitions 
				if (s != classtext && classdef == YES) {
					jfirst = 0;
					jlast = yyleng;
					return(IDENT);
				}*/
				/* if a class definition */
				if (s == classtext || s == interfacetext) {
					classdef = YES;
					classtoken = 'c';
				}
				/* if a local definition */
				else if (p->type == DECL && fcndef == YES &&
				    parens == 0) {
					localdef = YES;
				}
			}
			else {	/* identifier */
				jlast = yyleng;

				if (classtoken && classdef == YES) {
					token = classtoken;
					classtoken = '\0';
				}
				return(token);
			}
		}
\[		{	/* array dimension (don't worry about subscripts) */
			arraydimension = YES;
			goto more;
			/* NOTREACHED */
		}
\]		{
			arraydimension = NO;
			goto more;
			/* NOTREACHED */
		}
\\\n		{	/* preprocessor statement is continued on next line */
			goto eol;
			/* NOTREACHED */
		}
\n		{	/* end of the line */
			if (ppdefine == YES) {	/* end of a #define */
				ppdefine = NO;
				yyless(yyleng - 1);	/* rescan \n */
				jlast = jfirst;
				yymore();
				return(DEFINEEND);
			}
		eol:
			++jmyylineno;
			jfirst = 0;
			jlast = 0;
			if (symbols > 0) {
				return(NEWLINE);
			}
			jlineno = jmyylineno;
		}
\'		{	/* character constant */
			multicharconstant('\'');
			goto more;
			/* NOTREACHED */
		}
\"		{	/* string constant */
			multicharconstant('"');
			goto more;
			/* NOTREACHED */
		}
^[ \t\f\b]+	{	/* don't save leading white space */
		}
(import|package)[ \t]+[^;\n\r]+	{ /* imported package */
			char	*s;
			
			s = strpbrk(yytext, " \t");
			while (*s == '\t' || *s == ' ') {
				++s;
			}
			--s;
			jfirst = s - yytext;
			incfile(s + 1, *s);
			jlast = yyleng;
			yymore();
			return(INCLUDE);
			/* NOTREACHED */
		}
{number}	|	/* number */
.		{	/* punctuation and operators */
		more:	jfirst = yyleng;
			yymore();
		}
%%

void
jinitscanner(srcfile)
char	*srcfile;
{
	char	*s;
	
	jfirst = 0;		/* buffer index for first char of symbol */
	jlast = 0;		/* buffer index for last char of symbol */
	jlineno = 1;		/* symbol line number */
	jmyylineno = 1;		/* input line number */
	arraydimension = NO;	/* inside array dimension declaration */
	braces = 0;		/* unmatched left brace count */
	classbraces = 0;	/* class brace count */
	classdef = NO;		/* class definition */
	classtoken = '\0';	/* class token */
	fcndef = NO;		/* function definition */
	globalscope = YES;	/* file global scope (outside functions) */
	initializer = NO;	/* data initializer */
	initializerbraces = -1;	/* data initializer outer brace count */
	localdef = NO;		/* function/block local definition */
	parens = 0;		/* unmatched left parenthesis count */
	ppdefine = NO;		/* preprocessor define statement */
	rules = NO;		/* lex/yacc rules */
	BEGIN 0;
}

/* getc that ignores comments and RETURN characters */

static int
sourceinput()
{
	register int c;

	if ((c = getc(yyin)) == '/') {
		c = comment();
	}
	if (c == EOF) {
		c = 0;
	}
/* #ifdef __BORLANDC__*/
	if (c == '\r') {
		c = msdosgetc(yyin);
	}
/* #endif*/
	return(c);
}

/* getc that ignores RETURN characters */

static int
noncommentinput()
{
	register int c;

	c = getc(yyin);
	if (c == EOF) {
		c = 0;
	}
/* #ifdef __BORLANDC__*/
	if (c == '\r') {
		c = msdosgetc(yyin);
	}
/* #endif*/
	return(c);
}

static int
comment()
{
	register int	c, lastc;

	do {
		if ((c = getc(yyin)) == '*') {	/* C comment */
			lastc = '\0';
			while ((c = getc(yyin)) != EOF &&
			    (c != '/' || lastc != '*')) { /* fewer '/'s */
				if (c == '\n') {
					++jmyylineno;
				}
				lastc = c;
			}

			if(feof(yyin)) {	/* unterminated comment at end of file */
				c = '\n';
				(void) ungetc(c,yyin);
				break;
			}

			/* return a blank for Reiser cpp token concatenation */
			if ((c = getc(yyin)) == '_' || isalnum(c)) {
				(void) ungetc(c, yyin);
				c = ' ';
				break;
			}
		}
		else if (c == '/') {		/* C++ comment */
			while ((c = getc(yyin)) != EOF && c != '\n') {
				;
			}
			break;
		}
		else {	/* not a comment */
			(void) ungetc(c, yyin);
			c = '/';
			break;
		}
		
	/* there may be an immediately following comment */
	} while (c == '/');
/* #ifdef __BORLANDC__*/
	if (c == '\r') {
		c = msdosgetc(yyin);
		if (c == '/') {
			c = comment();	/* recurse */
		}
	}
/* #endif*/
	return(c);
}

static void
multicharconstant(terminator)
register char	terminator;
{
	register char	c;

	/* scan until the terminator is found */
	while ((c = yytext[yyleng++] = noncommentinput()) != terminator) {
		switch (c) {
		case '\\':	/* escape character */
			if ((yytext[yyleng++] = noncommentinput()) == '\n') {
				++jmyylineno;
			}
			break;
			
		case '\n':	/* illegal character */
			
			/* assume the terminator is missing, so put
			   this character back */
			unput(c);
			yytext[--yyleng] = '\0';
			/* fall through */
			
		case EOF:	/* end of file */
			return;
			
		default:
			/* change a control character to a blank */
			if (!isprint(c)) {
				yytext[yyleng - 1] = ' ';
			}
		}
		/* if this token will overflow the line buffer */
		/* note: '\\' may cause yyleng to be > STMTMAX */
		if (yyleng >= STMTMAX) {
			
			/* truncate the token */
			while ((c = noncommentinput()) != EOF) {
				if (c == terminator) {
					unput(c);
					break;
				}
				else if (c == '\n') {
					++jmyylineno;
				}
			}
		}
	}
	yytext[yyleng] = '\0';
}
#ifdef __BORLANDC__

/* getc for MS-DOS that ignores RETURN characters */

static int
msdosgetc(FILE *inputfile)
#else

/* getc for MS-DOS that ignores RETURN characters */

static int
msdosgetc(inputfile)
FILE *inputfile;
#endif
{
	int	c;

	while ((c = getc(inputfile)) == '\r') {
		;
	}
	if (c == EOF) {
		c = 0;
	}
	return(c);
}
/* #endif*/

jyywrap()
{
	return(1);
}
