/*
 *	binkleyforce -- unix FTN mailer project
 *	
 *	Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11
 *	
 *	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 2 of the License, or
 *	(at your option) any later version.
 *	
 *	$Id: expression_lex.c,v 1.1.1.1 2001/08/30 13:33:48 kst Exp $
 */

typedef struct lextable {
const	char *str;
	int value;
	int retc;
	int len;
} s_lextable;

static bool initialised = FALSE;
static s_lextable *next = NULL;

static s_lextable operators[] =
{
	{ "==",          EQ,          AROP,        0 },
	{ "!=",          NE,          AROP,        0 },
	{ ">",           GT,          AROP,        0 },
	{ ">=",          GE,          AROP,        0 },
	{ "<",           LT,          AROP,        0 },
	{ "<=",          LE,          AROP,        0 },
	{ "(",           OPENB,       OPENB,       0 },
	{ ")",           CLOSEB,      CLOSEB,      0 },
	{ "&&",          AND,         LOGOP,       0 },
	{ "&",           AND,         LOGOP,       0 },
	{ "||",          OR,          LOGOP,       0 },
	{ "|",           OR,          LOGOP,       0 },
	{ "Xor",         XOR,         LOGOP,       0 },
	{ "!",           NOT,         NOT,         0 },
	{ ",",           COMMA,       COMMA,       0 },
	{ NULL,          0,           0,           0 }
};

s_lextable elements[] =
{
	{ "TZ",          TZ,          TZ,          0 },
	{ "Address",     ADDRESS,     ADDRESS,     0 },
	{ "Time",        TIME,        TIME,        0 },
	{ "Phone",       PHONE,       PHONE,       0 },
	{ "Flag",        FLAG,        FLAG,        0 },
	{ "Incoming",    INCOMING,    INCOMING,    0 },
	{ "Outgoing",    OUTGOING,    OUTGOING,    0 },
	{ "Listed",      LISTED,      LISTED,      0 },
	{ "Protected",   PROTECTED,   PROTECTED,   0 },
	{ "Connspeed",   CONNSPEED,   CONNSPEED,   0 },
	{ "Exec",        EXEC,        EXEC,        0 },
	{ "Exist",       EXIST,       EXIST,       0 },
	{ "Port",        PORT,        PORT,        0 },
	{ "Mailer",      MAILER,      MAILER,      0 },
	{ NULL,          0,           0,           0 }
};

static void expr_inittables(void)
{
	int i;
	
	for( i = 0; operators[i].str; i++ )
		operators[i].len = strlen(operators[i].str);

	for( i = 0; elements[i].str; i++ )
		elements[i].len = strlen(elements[i].str);
}

static int yylex(void)
{
	int i, retc = 0;
	s_lextable *entry = NULL;

	ASSERT(expr_p_pos != NULL);
	
	if( !initialised )
		{ expr_inittables(); initialised = TRUE; }

	if( next )
	{
		/*
		 *  Found operator left from previous call to yylex()
		 */
		yylval = next->value;
		DEB((D_EVENT, "yylex: got next \"%s\", yylval = %d, ret = %d",
			next->str, next->value, next->retc));
		retc = next->retc;
		next = NULL;
		return retc;
	}
			
	while( isspace(*expr_p_pos) ) expr_p_pos++;

	if( *expr_p_pos == '\0' ) return 0;
		
	for( i = 0; operators[i].str; i++ )
	{
		if( strncasecmp(expr_p_pos, operators[i].str, operators[i].len) == 0 )
			{ entry = &operators[i]; break; }
	}
	
	if( entry == NULL )
	{
		for( i = 0; elements[i].str; i++ )
		{
			if( strncasecmp(expr_p_pos, elements[i].str, elements[i].len) == 0 )
				{ entry = &elements[i]; break; }
		}
	}

	if( entry )
	{
		expr_p_pos += entry->len;
		yylval = entry->value;
		DEB((D_EVENT, "yylex: got token \"%s\", yylval = %d, ret = %d",
			entry->str, entry->value, entry->retc));
		return entry->retc;
	}
	else
	{

		if( *expr_p_pos == '"' )
		{
			expr_p_text = ++expr_p_pos;
			
			while( *expr_p_pos != '"' && *expr_p_pos )
				++expr_p_pos;
		}
		else
		{
			expr_p_text = expr_p_pos++;
			
			while( !isspace(*expr_p_pos) && *expr_p_pos )
			{
				for( i = 0; operators[i].str; i++ )
					if( strncasecmp(expr_p_pos, operators[i].str, operators[i].len) == 0 )
					{
						next = &operators[i];
						goto enough;
					}
				expr_p_pos++;
			}
		}

enough:	
		if( *expr_p_pos )
		{
			*expr_p_pos = '\0';			
			if( next && next->len > 1 )
				expr_p_pos += next->len;
			else
				expr_p_pos += 1;
		}
		
		if( ISDEC(expr_p_text) )
		{
			/* It is decimal number */
			yylval = atol(expr_p_text);
			DEB((D_EVENT, "yylex: got NUMBER %d", yylval));
			return NUMBER;
		}
		else
		{
			/* It is text */
			DEB((D_EVENT, "yylex: got TEXT \"%s\"", expr_p_text));
			return(yylval = TEXT);
		}
	}
}
