%{
/*  File: aqlparse.l
 *  Author: Stefan Wiesmann and Richard Durbin (wiesmann,rd@sanger.ac.uk)
 *  Copyright (C) J Thierry-Mieg and R Durbin, 1996
 * -------------------------------------------------------------------
 * Acedb 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 2
 * of the License, 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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * or see the on-line version at http://www.gnu.org/copyleft/gpl.txt
 * -------------------------------------------------------------------
 * This file is part of the ACEDB genome database package, written by
 * 	Richard Durbin (MRC LMB, UK) rd@sanger.ac.uk, and
 *	Jean Thierry-Mieg (CRBM du CNRS, France) mieg@kaa.cnrs-mop.fr
 *
 * Description: lex for AQL
 * Exported functions:
 * HISTORY:
 * Last edited: Sep 13 15:57 1999 (fw)
 * * Mar  1 13:19 1999 (fw): fixed lex/flex incompatability for Linux
 * * Feb 24 10:26 1999 (fw): reintroduced exist_tag (interpreted as tag[0])
 * * Jan 11 11:26 1999 (fw): replaced order_by with order and by
 *                           removed keyword 'exists_tag' (now done with tag[0])
 * * Aug 17 16:13 1998 (fw): ~ changed to 'like'
 * * Aug 14 18:11 1998 (fw): added ~ comparator for string wildcard matching
 * * Aug 10 11:55 1998 (fw): removed keyword ACTIVE (now replaced by context vars in tace)
 * * Jul 27 15:33 1998 (fw): changed error code for invalid character from 700 to 701
 * Created: Tue Oct 29 00:01:02 1996 (rd)
 *-------------------------------------------------------------------
 */

/* $Id: aqlparse.l,v 1.29 2002/05/10 16:39:53 srk Exp $ */

#if !defined(LINUX) && !FreeBSD && !defined(__CYGWIN__) && !defined(DARWIN)

  /* for system that use the AT&T lex and its derivatives
   * we can redefine the input method for the lexer quite
   * easily - by replacing the macros input/unput
   */

#undef input
#undef unput
  /* redefine them using a function that accesses the global string */
  static char input (void) { ++lexPos ; return *lexString++ ; }
  static void unput (char c) { --lexPos ; *--lexString = c ; }
  
#else  /* LINUX || FreeBSD  or CYGWIN */
  
  /* LINUX uses flex, which doesn't provide the above functionality
   * the fact that input/unput are macros was never defined in the
   * POSIX standard. The standard define setting the global 'yyin' to
   * a user supplied FILE* stream as the only way to change the input
   * from stdin to another stream. So flex rigerously implements the standard.
   * We have to do a lot of trickery to convince flex not to work on a FILE* stream.
   */

#define YY_SKIP_YYWRAP		/* yywrap() is used to switch to the next input file 
				 *  if it's finished with one. We're not dealing with
				 *  multiple inputs and ignore this feature.
				 * We need to link with -lfl (flex library) to provide
				 *  the yywrap stub.
				 */
  

#define YY_NEVER_INTERACTIVE 1	/* flex has a notion of interactive buffers
				 *  (streams from tty devices such as stdin) and
				 *  non-interactive buffers (streams from fopen on a file)
				 * To find out which it is, the function 'isatty' is
				 *  is called. When this compiler flag is set, we
				 *  make sure it doesn't need to call this function
				 *  at all. We need to prevent it from calling file-ops
				 *  on yyin, because we set it to (FILE*)1 in aqlParse()
				 *  to fool flex into thinking we have a stream (which prevents
				 *  it from defaulting to stdin)
				 */

  /* redefine the macro which is used by flex to get at another character
   * from the ficticous input stream. We have set yyin to (FILE*)1 and
   * now we let flex get the input from out global input string instead.
   * the redefinition is based on an example given on the Linux flex man-page.
   */
#define YY_INPUT(buf,result,max_size) \
               { \
               int c = *lexString++; ++lexPos ; \
               result = (c == '\0') ? YY_NULL : (buf[0] = c, 1); \
               }

#endif /* LINUX */

  /****************************************************/

#define token(x)	tokPos[x] = lexPos - yyleng ; return x

%}

letter			[A-Za-z]
digit			[0-9]
id			{letter}({letter}|{digit}|"_")*
number			{digit}+

%%

\"([^"]|\\["\n])*\"     { yytext[strlen((const char*)&yytext[0])-1] = 0 ;
                          yylval.String = strnew ((char*)&yytext[1], aql_L->query->handle) ;
                          token(StringLiteral) ;
			  /* match string literals before all keyword, 
			   * so we can quote keywords and match them as tagnames etc. */
                        }

select 			{ token(SELECT) ; }
from  			{ token(FROM) ; }
where   		{ token(WHERE) ; }
all                     { token(ALL); }
as   			{ token(AS) ; }
in   			{ token(IN) ; }
class                   { yylval.String = strnew ("class", aql_L->query->handle); /* for EXPR_LOC_FUNC */
                          token(CLASS) ; }
object  		{ token(OBJECT) ; }
exists   		{ token(EXISTS) ; }
exists_tag   		{ token(EXISTS_TAG) ; }
now			{ token(NOW) ; }
today			{ token(TODAY) ; }
not  			{ token(NOT) ; }
and  			{ token(AND) ; }
or   			{ token(OR) ; }
xor   			{ token(XOR) ; }
union  			{ token(UNION) ; }
intersect		{ token(INTERSECT) ; }
except 			{ token(DIFF) ; }
diff 			{ token(DIFF) ; }
order   		{ token(ORDER) ; }
sort	   		{ token(ORDER) ; }
by                      { token(BY) ; }
true   			{ token(TRUEtok) ; }
false  			{ token(FALSEtok) ; }

yeardiff		{ yylval.Int = oYEARDIFF ; token(ExprExprFunc) ; }
monthdiff		{ yylval.Int = oMONTHDIFF ; token(ExprExprFunc) ; }
weekdiff		{ yylval.Int = oWEEKDIFF ; token(ExprExprFunc) ; }
daydiff			{ yylval.Int = oDAYDIFF ; token(ExprExprFunc) ; }
hourdiff		{ yylval.Int = oHOURDIFF ; token(ExprExprFunc) ; }
mindiff			{ yylval.Int = oMINDIFF ; token(ExprExprFunc) ; }
secdiff			{ yylval.Int = oSECDIFF ; token(ExprExprFunc) ; }

count			{ yylval.Int = oCOUNT ; token(TableFunc) ; }
first			{ yylval.Int = oFIRST ; token(TableFunc) ; }
last			{ yylval.Int = oLAST ; token(TableFunc) ; }
min			{ yylval.Int = oMIN ; token(TableFunc) ; }
max			{ yylval.Int = oMAX ; token(TableFunc) ; }
sum			{ yylval.Int = oSUM ; token(TableFunc) ; }
avg			{ yylval.Int = oAVG ; token(TableFunc) ; }

abs			{ yylval.Int = oABS ; token(ExprFunc) ; }
modulo			{ yylval.Int = oMOD ; token(ExprExprFunc) ; }
mod			{ yylval.Int = oMOD ; token(ExprExprFunc) ; }

asc   			{ yylval.Int = oASC ; token(Ordering) ; }
desc   	 		{ yylval.Int = oDESC ; token(Ordering) ; }

like                    { yylval.Int = oLIKE ; token(Comparator) ; }

{id}			{ yylval.String = strnew ((char*)&yytext[0], aql_L->query->handle) ;
			  token(Identifier) ;
			}

[\@\$\;\:\.\(\)\[\]\+\-\*\/\%\,\_\|]	token(yytext[0]) ;

":="			{ token(ASSIGN) ; }
"->"			{ token(ARROW) ; }
"::"			{ token(DOUBLE_COLON) ; }

"="                     { yylval.Int = oEQ ; token(Comparator) ; }
"<"                     { yylval.Int = oLT ; token(Comparator) ; }
">"                     { yylval.Int = oGT ; token(Comparator) ; }
"!="                    { yylval.Int = oNE ; token(Comparator) ; }
"<="                    { yylval.Int = oLE ; token(Comparator) ; }
">="                    { yylval.Int = oGE ; token(Comparator) ; }

{number}                { sscanf ((const char*)&yytext[0], "%d", &yylval.Int) ;
                          token(Number) ;
                        }

[0-9]+[eE][+-]?[0-9]+		|
[0-9]+"."[0-9]*[eE][+-]?[0-9]+	|
"."[0-9]*[eE][+-]?[0-9]+	|
[0-9]+"."[0-9]*			|
"."[0-9]+		{ sscanf ((const char*)&yytext[0], "%f", &yylval.Float) ;
			  token(FloatLiteral) ;
                        }


"`"[12][90][0-9][0-9]"-"[01][0-9]"-"[0-3][0-9]"_"[0-2][0-9]":"[0-5][0-9]":"[0-5][0-9]	|	/* YYYY-MM-DD_HH:MM:SS */	
"`"[12][90][0-9][0-9]"-"[01][0-9]"-"[0-3][0-9]"_"[0-2][0-9]":"[0-5][0-9]		|	/* YYYY-MM-DD_HH:MM */	
"`"[12][90][0-9][0-9]"-"[01][0-9]"-"[0-3][0-9]"_"[0-2][0-9]				|	/* YYYY-MM-DD_HH */	
"`"[12][90][0-9][0-9]"-"[01][0-9]"-"[0-3][0-9]						|	/* YYYY-MM-DD */	
"`"[12][90][0-9][0-9]"-"[01][0-9]							|	/* YYYY-MM */	
"`"[12][90][0-9][0-9]	{ yylval.String = strnew ((char*)&yytext[1], aql_L->query->handle) ;    /* YYYY */	
			  token(DateLiteral) ;
			}



[ \t\r\f\n]+              ;  /* whitespace */

.                       aqlError (aql_L, 701, lexPos == 0 ? 1 : lexPos-1, "syntax error: invalid character") ;

%%

void yyerror (char *s)
{
  /* Syntax error */
  aqlError (aql_L, 700, lexPos ? lexPos-1 : 1, s);  /* aql is a static in aqlparse.y - the current AQL object */
}


/********************** end of file *******************/
