%{
/*
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 1, or (at your option)
** any later version.

** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.

** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include <string.h>
#include "common.h"
#include "parser.h"

// Current line number
int currentLineNumber = 1;

// token expected by the parser
kTokens expectToken = kNone;

CRevNumber revnumber;

extern "C" int yywrap() { BEGIN INITIAL; return 1; }
%}

	/* Normal state:  parsing nodes.  The initial start state is used */
	/* only to recognize the VRML header. */
%x NODE

	/* Start tokens for all of the field types, */
	/* except for MFNode and SFNode, which are almost completely handled */
	/* by the parser: */
%x ST_STRING ST_TAG ST_REV ST_REVORNIL ST_INREV ST_INT
%x ST_ANYBUTSEP ST_DATE

	/* positive integer */
int ([\+-]?[0-9]+)

	/* Whitespace. */
ws ([ \t\r\n]+)
	/* And the same pattern without the newline */
wsnnl ([ \t\r])
	/* a string */
str ([^ \t\r\n][^\t\r\n]*)
	/* a tag/author/state string */
tag ([^ \t\r\n:;])+
	/*revfollow (----------------------------)*/
revfollow (\-{28})
	/*endfollow (=============================================================================)*/
endfollow (\={50,})
%%

%{
	/* Switch into a new start state if the parser */
	/* just told us that we've read a field name */
	/* and should expect a field value (or IS) */
#if qCvsDebug
	if (yy_flex_debug)
		fprintf(stderr,"LEX--> Start State %d\n", expectToken);
#endif
	
	switch(expectToken)
	{
	case kNone: BEGIN NODE; break;
	case kString: BEGIN ST_STRING; break;
	case kRevnum: BEGIN ST_REV; break;
	case kRevnumOrNil: BEGIN ST_REVORNIL; break;
	case kInt: BEGIN ST_INT; break;
	case kDate: BEGIN ST_DATE; break;
	case kAnyButSep: BEGIN ST_ANYBUTSEP; break;
	default: yyerror("ACK: Bad expectToken"); break;
	}
%}

<INITIAL>{ws}*	{ BEGIN NODE; }

<NODE>RCS\ file				{ return ID_RCS; }
<NODE>Working\ file			{ return ID_WORKING; }
<NODE>head					{ return ID_HEAD; }
<NODE>branch				{ return ID_BRANCH; }
<NODE>locks					{ return ID_LOCKS; }
<NODE>access\ list			{ return ID_ACCESS; }
<NODE>symbolic\ names		{ return ID_SYMBOLIC; }
<NODE>keyword\ substitution	{ return ID_KEYWORD; }
<NODE>total\ revisions		{ return ID_TOTREVISIONS; }
<NODE>selected\ revisions	{ return ID_SELREVISIONS; }
<NODE>description			{ return ID_DESCRIPTION; }
<NODE>revision				{ return ID_REVISION; }
<NODE>date					{ return ID_DATE; }
<NODE>author				{ return ID_AUTHOR; }
<NODE>state					{ return ID_STATE; }
<NODE>branches				{ return ID_BRANCHES; }
<NODE>strict				{ return ID_STRICT; }
<NODE>lines					{ return ID_LINES; }
<NODE>locked\ by			{ return ID_LOCKEDBY; }

<NODE>{revfollow}			{ return ID_REVFOLLOW; }
<NODE>{endfollow}			{ return ID_ENDFOLLOW; }
<NODE>{tag}					{
	yylval_set(yytext);
	return TAG;
}

<ST_ANYBUTSEP>{revfollow}		{
	BEGIN NODE;
	expectToken = kNone;

	return ID_REVFOLLOW;
}

<ST_ANYBUTSEP>{endfollow}		{
	BEGIN NODE;
	expectToken = kNone;
	return ID_ENDFOLLOW;
}

<ST_ANYBUTSEP>\n		{
	++currentLineNumber;
#if qCvsDebug
	if (yy_flex_debug)
		fprintf(stderr,"LINESEP--> %d\n", currentLineNumber);
#endif

	yylval_set((int)(unsigned char)yytext[0]);
	return ID_CHAR;
}

<ST_ANYBUTSEP>.		{
	yylval_set((int)(unsigned char)yytext[0]);
	return ID_CHAR;
}

<ST_STRING>{str}		{
	yylval_set(yytext);
	BEGIN NODE;
	expectToken = kNone;

	return STRING;
}

<ST_REV>{int}		{
	int v;
	revnumber.reset();
	if(sscanf(yytext, "%d", &v) == 1)
		revnumber += v;
	else
		yyerror("%s not an integer value", yytext);
	BEGIN ST_INREV;
	expectToken = kNone;
}

<ST_REVORNIL>{int}		{
	int v;
	revnumber.reset();
	if(sscanf(yytext, "%d", &v) == 1)
		revnumber += v;
	else
		yyerror("%s not an integer value", yytext);
	BEGIN ST_INREV;
	expectToken = kNone;
}

<ST_REVORNIL>[^ \t\r\n]		{
	yyless(0); /* put back the spaces */
	BEGIN NODE;
	expectToken = kNone;

	return REVNUM;
}

<ST_INREV>\.{int}		{
	int v;
	if(sscanf(yytext + 1, "%d", &v) == 1)
		revnumber += v;
	else
		yyerror("%s not an integer value", yytext);
	BEGIN ST_INREV;
	expectToken = kNone;
}

<ST_INREV>.		{
	yyless(0); /* put back the spaces */
	BEGIN NODE;
	expectToken = kNone;
	yylval_set(revnumber);

	return REVNUM;
}

<ST_INT>{int}		{
	int v;
	if(sscanf(yytext, "%d", &v) == 1)
		revnumber += v;
	else
		yyerror("%s not an integer value", yytext);
	BEGIN NODE;
	expectToken = kNone;
	yylval_set(v);

	return INTEGER;
}

<ST_DATE>{int}		{
	int v;
	if(sscanf(yytext, "%d", &v) == 1)
		revnumber += v;
	else
		yyerror("%s not an integer value", yytext);
	yylval_set(v);

	return INTEGER;
}

<ST_DATE>[:/]		{
	return yytext[0];
}

	/* Whitespace and catch-all rules apply to all start states: */
<*>{wsnnl}+		;

	/* This is also whitespace, but we'll keep track of line number */
	/* to report in errors: */
<*>{wsnnl}*\n{wsnnl}*		{
								++currentLineNumber;
#if qCvsDebug
								if (yy_flex_debug)
									fprintf(stderr,"LINE--> %d\n", currentLineNumber);
#endif
								if(expectToken == kAnyButSep)
								{
									// strange bug, flex is sometimes getting here in
									// a kAnyButSep mode, while it should not
									yylval_set(yytext);
									  return STRING;
								}
							}

	/* This catch-all rule catches anything not covered by any of */
	/* the above: */
<*>. 			{
	yylval_set((int)(unsigned char)yytext[0]);
	return (int)(unsigned char)yytext[0];
}
