%{
/*-
 * Lexical analyzer for yacc date parser and calculator
 *
 * caller must define and point at a buffer loaded with string to be analyzed:
 *	char *sp;
 *
 * J. A. Rupley, Tucson, Arizona 
 */

#include <ctype.h>
#include <string.h>
#include <c.h>

#include "jul_greg.h"

#include "y.tab.h"	/* yacc defines */

/*
 * OLD = ATT LEX REDEFINITION OF INPUT() FOR READ OF SP=STRING INPUT VARIABLE
 *	for gnu bison/yacc replace with definiton of YY_INPUT
 *
 * #undef input() 
 * #undef unput(c)
 * #define input()	(isupper(yytchar=(*sp++))?tolower(yytchar):yytchar)
 * #define unput(c)	sp-- 
 */

/*
 * redefine YY_INPUT
 * from oreilly book by levine et al - lex/yacc...
 * from comp.lang.c post
 *	From: Garrett Wollman (wollman@emily.uvm.edu)
 *	Subject: Re: using lex with strings, not files 
 *	Date: 1991-05-13 02:05:37 PST 
 *
 *  the inline code reading sp by character works
 *  block read inline code works also..... used it
 */

#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
	{ \
	int c = '*', n; \
	for ( n = 0; n < max_size && \
		     (c = *sp) != '\0' && c != '\n'; ++n, ++sp) \
	{ \
		buf[n] = (char) tolower(c); \
	} \
/*  	if ( c == '\n' || c == '\0' ) \ */ \
	if ( c == '\n' ) \
 		buf[++n] = '\n'; \
	result = n; \
	}

#if 0
#undef YY_INPUT
#define YY_INPUT(buf,result,max_size) \
	{ \
	int c = '*', n; \
printf("YY_INPUT enter: c=%c, n=%d, *sp=\"%d\", sp=%d, sp=\"%s\", buf=\"%s\"\n", c, n, *sp, sp, sp, buf); \
	for ( n = 0; n < max_size && \
		     (c = *sp) != '\0' && c != '\n'; ++n, ++sp) \
	{ \
		buf[n] = (char) tolower(c); \
printf("YY_INPUT loop: c=%c, n=%d, *sp=\"%d\", sp=%d, sp=\"%s\", buf=\"%s\"\n", c, n, *sp, sp, sp, buf); \
	} \
	result = n; \
printf("YY_INPUT exit: c=%c, n=%d, *sp=\"%d\", sp=%d, sp=\"%s\", buf=\"%s\"\n", c, n, *sp, sp, sp, buf); \
	}
*/
/* 	if ( c == '\n' || c == '\0' ) \ */ \
/* 	if ( c == '\n' ) \ */ \
/* 		buf[n++] = (char) '\n'; \ */ \
#endif

#if 0
#undef YY_INPUT
/* #define YY_INPUT(buf, result, max)	input_from_sp(buf, result, max)	\ */
#define YY_INPUT(buf, result, max)	\
{ \
	int len = strlen(sp); \
	result = 0; \
	if (len) strncpy(buf, sp, result=MIN(len, max - 1));  \
	buf[result] = '\0'; \
	sp += result; \
/* printf("buf on input=\"%s\"\nwith # char read=%d and length=%d\n", buf, * strlen(buf), result);  \ */ \
/* printf("contents of sp=\"%c\",%d\n", *sp, *sp);  \ */ \
}
#endif


void input_from_sp ( );


extern char *sp;
extern int day_map[], month_map[];
%}

W	[ \t\n"()]
NW	[^ \t\n"()]
NWP	[^ \t\n"(),/.]
P	[,/.]
M	(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)[a-z]*
WD	(mon?|tue?|wed?|thu?|fri?|sat?|sun?)
WDD	{WD}|{WD}[a-z]*day
U	d|w|m|y|day|week|month|year
D	[+-]?[0-9]+
%%
{M}/{W}		{
	yylval.val = month_map[(yytext[1] + yytext[2]) & 0x1f]; 
	return MONTH;
}
{WDD}/{W}	{
	yylval.val = day_map[(yytext[0] & 7) + (yytext[1] & 4)]; 
	return DAY;
}
{D}/({W}|{P})	{
#define GREGORIAN	2299161		/* julian date for gregorian epoch */
	long	atol();
	if ((yylval.julian = atol(yytext)) >= GREGORIAN)
		return JULIAN;		/* assume large numbers are julian */
	else {
		yylval.val = yylval.julian; return NUMBER;
	}
}
{U}/{W}		{yylval.val = yytext[0]; return UNIT;}
(today|now)/{W}	{yylval.val = yytext[0]; return TODAY;}
{P}		{yylval.val = yytext[0]; return PUNC;}
-/{W}		{yylval.val = yytext[0]; return MINUS;}
{W}+		;
{NWP}+		{fprintf(stderr, "\nlexical error: %s\n", yytext); return ERROR;}
%%


/*
void
input_from_sp(buf, result, max)
char *buf;
int result, max_size;
{
	int len = strlen(sp);
	if (len) strncpy(buf, sp, result=MIN(len, max - 1));
	buf[result] = '\0';
	sp += result;
	printf("buf on input=\"%s\"\nwith # char read=%d and length=%d\n", 
		buf, strlen(buf), result);
	printf("contents of sp=\"%c\",%d\n", *sp, *sp);
}
*/


int
yywrap()
{
	return 1;
}

/*-
 * Month and weekday hashing is from the tws library, 
 * found in the ``phoon'' distribution, 
 * from comp.sources.unix, volume 8, 1987:
 * 
 * 01B 15nov86 JP  Thouroughly hacked by Jef Poskanzer.
 * 01A ??????? MTR Original version from the MH 6.5 distribution, courtesy
 * 	          of Marshall Rose.
 */
/*-
 * Table to convert month names to numeric month.  We use the
 * fact that the low order 5 bits of the sum of the 2nd & 3rd
 * characters of the name is a hash with no collisions for the 12
 * valid month names.  (The mask to 5 bits maps any combination of
 * upper and lower case into the same hash value).
 * Jan = 1;
 *
 * hash function:
 *  (c2 + c3) & 0x1f
 */
static int month_map[] = {
	0,
	7,	/* 1 - Jul */
	4,	/* 2 - Apr */
	6,	/* 3 - Jun */
	0,
	11,	/* 5 - Nov */
	0,
	2,	/* 7 - Feb */
	12,	/* 8 - Dec */
	0,
	0,
	0,
	0,
	0,
	0,
	1,	/*15 - Jan */
	0,
	0,
	0,
	3,	/*19 - Mar */
	0,
	9,	/*21 - Sep */
	0,
	10,	/*23 - Oct */
	0,
	0,
	5,	/*26 - May */
	0,
	8,	/*28 - Aug */
};
/*-
 * Same trick for day-of-week; Sun = 0;
 *
 * hash function:
 *  (c1 & 7) + (c2 & 4)
 */
static int day_map[] = {
	0,
	0,
	0,
	6,	/* 3 - Sat */
	4,	/* 4 - Thu */
	0,
	5,	/* 6 - Fri */
	0,	/* 7 - Sun */
	2,	/* 8 - Tue */
	1	/* 9 - Mon */,
	0,
	3,	/*11 - Wed */
};
