%{
static char *scan_l =
	"$Header: /private/postgres/src/parser/RCS/scan.lex,v 1.24 1992/07/28 19:11:28 mao Exp $";
/**********************************************************************
  scan.l
  lexical scanner for POSTGRES 
 **********************************************************************/

#include <ctype.h>
#include <stdlib.h>

#include "parser/parse.h"
#include "nodes/pg_lisp.h"
#include "parser/atoms.h"


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; \
		bcopy(InputFrag, (char *) buf, len); \
		InputFrag += len; \
		FragLen -= len; \
	    } else { \
		if(Ch == NULL) \
		    Ch = TheString; \
		if((len = strlen(Ch)) > max_len) \
		    len = max_len; \
		result = len; \
		bcopy(Ch, (char *) buf, 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 */)

extern LispValue 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	\`
character	"'"

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

param		\${integer}

comment		"/*"

space		[ \t\n\f]
other		.

%%
{comment}	{ scancmnt();		}
"::"		{ return TYPECAST;	}
{specialstr}	{
			char buf[8192];
			scanspecial(buf,sizeof(buf));
			yylval = lispString(buf);
			return (SCONST);
		}
{self}		{ return (yytext[0]);	}
{operator}	{
			yylval = lispString(yytext);
			return (Op);
		}
{param}	        {       yylval = lispInteger(atoi(&yytext[1]));		
	                return (PARAM);
                }
{integer}	{
			yylval = lispInteger(atoi(yytext));		
			return (ICONST);
		}
{real}		{
			yylval = lispFloat(atof(yytext));
			return (FCONST);
		}
{string}	{
			char buf[8192];
			scanstr(buf,sizeof(buf));
			yylval = lispString(buf);
			return (SCONST);
		}

{character}	{
			char buf[2];
			scanchar(buf);
			yylval = lispString(buf);
			return (CCONST);
		}
{identifier}	{
			ScanKeyword	*keyword;

			keyword = ScanKeywordLookup(yytext);
			if (keyword != NULL) {
				yylval = lispAtom(keyword->name);
				return (keyword->value);
			} else {
				yylval = (LispValue) lispName(yytext);
				return (IDENT);
			}
		}
{space}		{ /* void */		}
{other}		{ return (yytext[0]);	}

%%


/*
 * 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;
}
