%{
/*-------------------------------------------------------------------------
 *
 * scan.l--
 *    lexical scanner for POSTGRES 
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
 *    $Header: /usr/local/devel/pglite/cvs/src/backend/parser/scan.l,v 1.3 1995/04/28 23:17:10 andrew Exp $
 *
 *-------------------------------------------------------------------------
 */
#include <ctype.h>
#ifndef __linux__
#include <math.h>
#else
#include <stdlib.h>
#endif /* __linux__ */
#include <string.h>

#include "postgres.h"
#include "nodes/pg_list.h"
#include "nodes/parsenodes.h"
#include "parser/keywords.h"
#include "parse.h"

#ifndef __linux__
#undef input
#undef unput
#include "parser/io.h"
#else
extern int StringInput;
extern char *TheString;
extern char *Ch;
char *InputFrag;
int FragLen;

/*
 * kai:
 * Porting this from Unix standard lex to Linux' flex wasn't fun. First of all,
 * they use very different input styles (lex does it character by character,
 * while flex uses a big buffer). And then there are functions in parse_query.c
 * which reverse the order of scanning. Nevertheless I hope everything is
 * working now.
 *
 * It seems that StringInput == 0 does not happen (the old code in
 * parse_query.c would break badly for queries with or without a from-clause),
 * but I am not sure, whether other statements are passed directly or not.
 */

#undef YY_INPUT
#define YY_INPUT(buf,result,max_len) \
	if (StringInput) { \
	    int len; \
	    if (InputFrag && FragLen <= 0) \
		InputFrag = 0; \
	    if (InputFrag) { \
		if((len = FragLen) > max_len) \
		    len = max_len; \
		result = len; \
		memmove((char *) buf, InputFrag, len); \
		InputFrag += len; \
		FragLen -= len; \
	    } else { \
		if(Ch == NULL) \
		    Ch = TheString; \
		if((len = strlen(Ch)) > max_len) \
		    len = max_len; \
		result = len; \
		memmove((char *) buf, Ch, len); \
		Ch += len; \
	    } \
	} else { \
	    if ( (result = read( stdin, (char *) buf, max_len )) < 0 ) \
		YY_FATAL_ERROR( "read() in flex scanner failed" ); \
	}

#undef YY_BUF_SIZE
#define YY_BUF_SIZE \
	(StringInput ? \
	    strlen(TheString) + 4 : \
	    (YY_READ_BUF_SIZE * 2) /* size of default input buffer */)
#endif /* __linux__ */


extern YYSTYPE yylval;
%}

digit		[0-9]
letter		[_A-Za-z]
letter_or_digit	[_A-Za-z0-9]

identifier	{letter}{letter_or_digit}*

self		[,()\[\].;$\:\+\-\*\/\<\>\=\|]
op_and_self	[\~\!\@\#\%\^\&\|\`\?\$\:\+\-\*\/\<\>\=]
op_only		[\~\!\@\#\%\^\&\`\?]

operator	({op_and_self}{op_and_self}+)|{op_only}+
string		["']
specialstr	\`

integer		-?{digit}+
real		-?{digit}+\.{digit}+([Ee][-+]?{digit}+)?

param		\${integer}

comment		"--".*\n

space		[ \t\n\f]
other		.

%%
{comment}	{ /* ignore */	}

"::"		{ return TYPECAST;	}

{specialstr}	{
			char buf[8192];
			scanspecial(buf,sizeof(buf));
			yylval.str = strdup(buf);
			return (SCONST);
		}

{self}		{ return (yytext[0]);	}

{operator}	{
			yylval.str = strdup((char*)yytext);
			return (Op);
		}
{param}	        {       yylval.ival = atoi((char*)&yytext[1]);		
	                return (PARAM);
                }
{integer}	{
			yylval.ival = atoi((char*)yytext);		
			return (ICONST);
		}
{real}		{
			yylval.dval = atof((char*)yytext);
			return (FCONST);
		}
{string}	{
			char buf[8192];
			scanstr(buf,sizeof(buf),yytext);
			yylval.str = strdup(buf);
			return (SCONST);
		}

{identifier}	{
			ScanKeyword	*keyword;

			keyword = ScanKeywordLookup((char*)yytext);
			if (keyword != NULL) {
				return (keyword->value);
			} else {
				yylval.str = strdup((char*)yytext);
				return (IDENT);
			}
		}
{space}		{ /* ignore */		}

{other}		{ return (yytext[0]);	}

%%

#ifdef __linux__
/*
 * Switch to new input (discard the read buffer)
 */
void NewInput(void)
{
    if(yy_current_buffer)
	YY_NEW_FILE;
}


/*
 * Get a character out of flex's buffer
 */
int DoInput(void)
{
    char *yy_cp = yy_c_buf_p;
    char *yy_bp = yytext;

    /* undo effects of setting up yytext */
    *yy_cp = yy_hold_char;
    if ( yy_c_buf_p >= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
	switch ( yy_get_next_buffer() ) {
	    case EOB_ACT_CONTINUE_SCAN:
		break;

	    case EOB_ACT_LAST_MATCH:
	    case EOB_ACT_END_OF_FILE:
		return -1;
	}

    yy_cp++;
    yy_c_buf_p = yy_cp;
    YY_DO_BEFORE_ACTION; /* set up yytext again */ \

    return yy_cp[-1];
}


/*
 * This function determines the current position of the lexical scanning
 * relative to TheString.
 */
char *CurScan(void)
{
    return (InputFrag ? InputFrag : Ch) +
	   (yy_c_buf_p - &yy_current_buffer->yy_ch_buf[yy_n_chars]);
}


/*
 * Put a character back into flex's buffer
 */
void DoUnput(char c)
{
    yyunput(c, yytext);
}


/*
 * Delete the input buffer.
 */
void DeleteBuffer(void)
{
    if(yy_current_buffer)
	yy_delete_buffer(yy_current_buffer);
    yy_init = 1;
}
#endif /* __linux__ */

