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

/*	cscope - interactive C symbol cross-reference
 *
 *	SDL 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); \
	}

/* not a preprocessor line (allow Ingres(TM) "## char var;" lines) */
#define	notpp()	(ppdefine == NO && (*yytext != '#' || yytext[1] == '#'))

/* not an m4 macro */
#define	notm4()	(m4macro == NO && (yytext[6] != '(' || yytext[7] != '('))

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

int	sfirst;	/* buffer index for first char of symbol */
int	slast;	/* buffer index for last char of symbol */
int	slineno;/* symbol line number */
int	smyylineno = 1;

static	BOOL	arraydimension;		/* inside array dimension declaration */
static	int	braces;			/* unmatched left brace count */
static	int	cesudeftoken;		/* class/enum/struct/union definition */
static	BOOL	elseelif;		/* #else or #elif found */
static	BOOL	esudef;			/* enum/struct/union definition */
static	int	esubraces;		/* outermost enum/struct/union 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	localdef;		/* function/block local definition */
static	BOOL	m4macro;		/* M4 macro */
static	int	parens;			/* unmatched left parenthesis count */
static	BOOL	ppdefine;		/* preprocessor define statement */
static	BOOL	psuedoelif;		/* psuedo-#elif */
static	BOOL	oldtype;		/* next identifier is an old type */
static	BOOL	sdl;			/* SDL file */
static	BOOL	structfield;		/* structure field declaration */
static	BOOL	template;		/* function template */
static	int	templateparens;		/* function template outer parentheses count */
static	BOOL	typedefdef;		/* typedef name definition */
static	BOOL	typedefname;		/* typedef name use */
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 SDL
%a 12000
%o 18000
%p 5000
%%
PROCEDURE[ \t]+{identifier}	{ /* SDL procedure */
			braces = 1;
			fcndef = YES;	/* treat as function definition */
			token = FCNDEF;
			globalscope = NO;
			goto findident;
			/* NOTREACHED */
		}
STATE[ \t]+({identifier}|\*)	{ /* SDL state */
			braces = 1;
			fcndef = YES;	/* treat as function definition */
			token = FCNDEF;
			globalscope = NO;

		sdlfindident:
			sfirst = yyleng - 1;
			while (isalnum(yytext[sfirst]) || yytext[sfirst] == '_' ||
				yytext[sfirst] == '*') {
				--sfirst;
			}
			++sfirst;
			goto iflongline;
			/* NOTREACHED */
		}
CALL[ \t]+{identifier}	{ /* SDL call */
			token = FCNCALL;
			goto findident;	/* treat as function call */
			/* NOTREACHED */
		}
NEXTSTATE[ \t]+({identifier}|\*)	{ /* SDL nextstate */
			token = FCNCALL;
			goto sdlfindident;	/* treat as function call */
			/* NOTREACHED */
		}
END(PROCEDURE|STATE)[ \t]+({identifier}|\*)	{ /* end of an SDL procedure or state */
			goto endstate;	/* treat as the end of a function */
			/* NOTREACHED */
		}
COMMENT[ \t]+\'	{ /* SDL comment */
			multicharconstant('\'');
			goto more;
		}
changecom\(	{ /* M4 preprocessor change comments, thrown away */
			multicharconstant(')');
                        goto more;
		}
define\({identifier}	{ /* M4 preprocessor macro definition */
			m4macro = YES;
			token = DEFINE;
			++parens;
			goto findident;
			/* NOTREACHED */
		}			
dnl\(	{ /* M4 preprocessor comments, thrown away */
			multicharconstant(')');
                        goto more;
		}
include\([^) \t\n\r]+	{ /* M4 preprocessor include */
			char	*s;
			int 	c;
			
			s = strpbrk(yytext, "(");
			incfile(s + 1, *s);
			sfirst = s - yytext;
			slast = yyleng;
			multicharconstant(')');
			yymore();
			return(INCLUDE);
			/* NOTREACHED */
		}
\{		{	/* count unmatched left braces for fcn def detection */
			++braces;
			
			/* mark an untagged enum/struct/union so its beginning
			   can be found */
			if (cesudeftoken) {
				slast = sfirst;
				ssavesymbol(cesudeftoken);
				cesudeftoken = '\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 an outermost enum/struct/union definition */
			if (esudef == YES && braces == esubraces) {
				esudef = NO;
				esubraces = -1;
				slast = sfirst;
				yymore();
				return(ESUEND);
			}
			/* if the end of a function */
			if ((braces == 0) &&
			    fcndef == YES) {
				fcndef = NO;
				globalscope = YES;
				slast = sfirst;
				yymore();
				return(FCNEND);
			}
			goto more;
			/* NOTREACHED */
		}
\(		{	/* count unmatched left parentheses for function templates */
			++parens;
			goto more;
			/* NOTREACHED */
		}
\)		{
			if (--parens <= 0) {
				parens = 0;
			}
			/* if the end of a function template */
			if (parens == templateparens) {
				templateparens = -1;
				template = NO;
			}
			if (parens == 0 && m4macro == YES) {
				m4macro = NO;
				yymore();
				return(DEFINEEND);
			}
			goto more;
			/* NOTREACHED */
		}
=		{	/* if a global definition initializer */
			if ((globalscope == YES || localdef == YES) && notpp() && notm4()) {
				initializerbraces = braces;
				initializer = YES;
			}
			goto more;
			/* NOTREACHED */
		}
:		{	/* if a structure field */
			/* note: a pr header has a colon in the date */
			if (esudef == YES && notpp() && notm4()) {
				structfield = YES;
			}
			goto more;
			/* NOTREACHED */
		}
\,		{
			if (braces == initializerbraces) {
				initializerbraces = -1;
				initializer = NO;
			}
			structfield = NO;
			goto more;
			/* NOTREACHED */
		}
;		{
			/* if not in an enum/struct/union declaration */
			if (esudef == NO) {
				typedefdef = NO;
				localdef = NO;
			}
			structfield = NO;
			initializer = NO;
			oldtype = NO;
			goto more;
			/* NOTREACHED */
		}
\#[ \t]*define[ \t]+{identifier}	{
				
			/* preprocessor macro or constant definition */
			ppdefine = YES;
			token = DEFINE;
			if (compress == YES) {
				yytext[0] = '\7';	/* compress the keyword */
			}
		findident:
			sfirst = yyleng - 1;
			while (isalnum(yytext[sfirst]) || yytext[sfirst] == '_') {
				--sfirst;
			}
			++sfirst;
			goto iflongline;
			/* NOTREACHED */
		}
<SDL>{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 */
			/* note: "#define a (b) {" and "#if defined(a)\n#" are not */
			if (braces == 0 && notpp() && notm4()) {
				fcndef = YES;
				token = FCNDEF;
				globalscope = NO;
				goto iflongline;
			}
			goto iffcncall;
			/* NOTREACHED */
		}
{identifier}/[ \t]*\(	{
			/* if a function call */
		iffcncall:
			if ((fcndef == YES || ppdefine == YES || m4macro == YES) &&
			    (localdef == NO || initializer == YES)) {
				token = FCNCALL;
				goto iflongline;
			}
			if (template == NO && typedefdef == NO) {
				templateparens = parens;
				template = YES;
			}
		}
(\+\+|--)[ \t]*{identifier}	{	/* prefix increment or decrement */
			token = ASSIGNMENT;
			goto findident;
			/* 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[sfirst]) && yytext[sfirst] != '_') {
				++sfirst;
			}
			goto ident;
			/* NOTREACHED */
		}
{identifier}/[ \t\n\r]*(=[^=]|[-+*/%&^|]=|<<=|>>=)	{ /* assignment */
			if ((fcndef == YES || ppdefine == YES || m4macro == YES) &&
			    localdef == NO) {
				token = ASSIGNMENT;
				goto iflongline;
			}
			goto ident;
			/* NOTREACHED */
		}
{identifier}/[* \t\n\r]+[a-zA-Z0-9_\$]	{	/* possible typedef name use */
			if (notpp() && notm4() && esudef == NO && fcndef == YES && 
			   typedefdef == NO && parens == 0) {
				char	c, *s = yytext + sfirst - 1;
				
				while (--s >= yytext && (c = *s) != ';' && c != '{') {
					if (!isspace(c) && !isalpha(c)) {
						goto nottypedefname;
					}
				}
				typedefname = YES;
			}
		nottypedefname:
			token = IDENT;	/* skip the global/parameter/local tests */
			goto iflongline;
			/* NOTREACHED */
		}
{identifier}	{
			struct	keystruct *p;
			char	*s;

		ident:	token = IDENT;
			if (notpp() && notm4() && arraydimension == NO
			    && initializer == NO) {
				
				/* if an enum/struct/union member definition */
				if (esudef == YES) {
					if (structfield == NO) {
						token = MEMBERDEF;
					}
				}
				/* if a typedef name */
				else if (typedefdef == YES && oldtype == NO) {
					token = TYPEDEF;
				}
				/* if a global definition */
				else if (globalscope == YES && template == NO
				    && oldtype == NO) {
					token = GLOBALDEF;
				}
				/* if a function parameter definition */
				else if (fcndef == YES && braces == 0 && 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 - sfirst > PATLEN) {
				warning("symbol too long");
				yyleng = sfirst + PATLEN;
				yytext[yyleng] = '\0';
			}
			/* if a keyword */
			yymore();
			if ((p = lookup(yytext + sfirst)) != NULL) {
				sfirst = yyleng;
				s = p->text;
				
				/* if a typedef name definition */
				if (s == typedeftext) {
					typedefdef = YES;
					oldtype = YES;
				}
				/* if a local definition */
				else if (p->type == DECL && fcndef == YES &&
				    typedefdef == NO && parens == 0) {
					localdef = YES;
				}
				/* keyword doesn't start a function template */
				else if (templateparens == parens && template == YES) {
					templateparens = -1;
					template = NO;
				}
				else {	/* next identifier after typedef was a keyword */
					oldtype = NO;
				}
				/* keyword can't be in a local definition */
				localdef = NO;
				typedefname = NO;
			}
			else {	/* identifier */
				slast = yyleng;
				
				/* if an enum/struct/union keyword preceded this ident. */
				if (esudef == YES && cesudeftoken) {
					token = cesudeftoken;
					cesudeftoken = '\0';
				}
				else {
					oldtype = NO;
				}
				/* if a local definition using a typedef name */
				if (typedefname == YES) {
					localdef = YES;
				}
				typedefname = NO;
				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 */
				slast = sfirst;
				yymore();
				return(DEFINEEND);
			}
		eol:
			++smyylineno;
			sfirst = 0;
			slast = 0;
			if (symbols > 0) {
				return(NEWLINE);
			}
			slineno = smyylineno;
		}
\'		{	/* character constant */
			goto more;
			/* NOTREACHED */
		}
\"		{	/* string constant */
			multicharconstant('"');
			goto more;
			/* NOTREACHED */
		}
^[ \t\f\b]+	{	/* don't save leading white space */
		}
\#[# \t]*include[ \t]*["<][^"> \t\n\r]+	{ /* #include or Ingres ##include */
			char	*s;
			
			s = strpbrk(yytext, "\"<");
			incfile(s + 1, *s);
			sfirst = s - yytext;
			slast = yyleng;
			if (compress == YES) {
				yytext[0] = '\1';	/* compress the keyword */
			}
			/* avoid multicharconstant call triggered by trailing
			   ", which puts a trailing comment in the database */
			if (*s == '"') {
				int	c;

				while ((c = input()) != EOF) {
					if (c == '"') {
						yytext[yyleng] = '"';
						yytext[++yyleng] = '\0';
						break;
					}
					/* the trailing '"' may be missing */
					if (c == '\n') {
						unput('\n');
						break;
					}
				}
			}
			yymore();
			return(INCLUDE);
			/* NOTREACHED */
		}
\#[ \t]*{identifier}	|	/* preprocessor keyword */
{number}	|	/* number */
.		{	/* punctuation and operators */
		more:	sfirst = yyleng;
			yymore();
		}
%%

void
sinitscanner(srcfile)
char	*srcfile;
{
	char	*s;

	sfirst = 0;		/* buffer index for first char of symbol */
	slast = 0;		/* buffer index for last char of symbol */
	slineno = 1;		/* symbol line number */
	smyylineno = 1;		/* input line number */
	arraydimension = NO;	/* inside array dimension declaration */
	braces = 0;		/* unmatched left brace count */
	cesudeftoken = '\0';	/* class/enum/struct/union definition */
	elseelif = NO;		/* #else or #elif found */
	esudef = NO;		/* enum/struct/union definition */
	esubraces = -1;		/* outermost enum/struct/union brace count */
	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 */
	m4macro = NO;		/* M4 macro */
	parens = 0;		/* unmatched left parenthesis count */
	ppdefine = NO;		/* preprocessor define statement */
	psuedoelif = NO;	/* psuedo-#elif */
	oldtype = NO;		/* next identifier is an old type */
	sdl = NO;		/* SDL file */
	structfield = NO;	/* structure field declaration */
	template = NO;		/* function template */
	templateparens = -1;	/* function template outer parentheses count */
	typedefdef = NO;	/* typedef name definition */
	typedefname = NO;	/* typedef name use */
	BEGIN 0;

	/* if this is not a C file */
	if ((s = strrchr(srcfile, '.')) != NULL) {
		switch (*++s) {	/* this switch saves time on C files */
		case 'l':
			if (strcmp(s, "lh") == 0) { /* SDL */
				sdl = YES;
			}

			break;
		case 'p':
		case 's':
		case 'm':
			if (strcmp(s, "pr") == 0 || 
			    strcmp(s, "sd") == 0 ||
			    strcmp(s, "m") == 0  ) {	/* SDL */
				sdl = YES;
			}
			break;
		}
	}
}

/* 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') {
					++smyylineno;
				}
				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') {
				++smyylineno;
			}
			break;
		case '\t':	/* tab character */
		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') {
					++smyylineno;
				}
			}
		}
	}
	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*/

syywrap()
{
	return(1);
}
