/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
** Copyright 1989 Massachusetts Institute of Technology
**/
/****************************\
* 			     *
*  Lex generator for Wool   *
* 			     *
\****************************/

%{

/* to have always at least MAX_TOKEN_LENGTH chars in all lexes */
#undef YYLMAX
#define YYLMAX MAX_TOKEN_LENGTH

/* here goes the definition of lex I/O, as macros for efficiency */

/* first, we forget the previous definitions, */
#undef output
#undef input
#undef unput
/* which were :
#define output(c) putc(c,yyout)
#define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):\
getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;\
*yysptr++=yytchar;}
*/

/* So here are OUR macros */

static int yyin_is_string;	/* 0 ==> reading from STREAM yyin */
				/* 1 ==> reading from STRING yystrin */
static int yyout_is_string;	/* 0 ==> printing on STREAM yyout */
		/* 1 ==> printing on WOOL_STRING_STREAM yystrout */
static char *yystrin;		/* current pointer on input string */
static WOOL_STRING_STREAM yystrout; /* current wool output stream */

#define output(c) {\
    if(yyout_is_string){\
        *(yystrout->ptr)++ = c;\
        *(yystrout->ptr) = '\0';\
        if((yystrout->ptr) >= (yystrout->last)){\
	    yyoutflush();\
	}\
    }else{\
	putc(c,yyout);\
    }\
}

#define input() (((\
    	yytchar =\
        (yysptr>yysbuf ?\
	    U(*--yysptr)\
	:   (yyin_is_string ?\
	        ( *yystrin ? *yystrin++ : 0)\
	    :   getc(yyin))))\
	==10 ?\
	    (yylineno++,yytchar)\
	:   yytchar)\
    ==EOF ?\
        0\
    :   yytchar)

#define unput(c) {\
    yytchar= (c);\
    if(yytchar=='\n')\
        yylineno--;\
    *yysptr++=yytchar;\
}

/* externally callable function for unput:
 */

wool_unput(buffer)
char *buffer;
{
    while (*buffer) {
	unput(*buffer);
	buffer++;
    }
}

/* counting the parentheses -- hack for wool_pool */

#define INC_PAR wool_pool_parentheses_level++
#define DEC_PAR if(wool_pool_parentheses_level)wool_pool_parentheses_level--
%}

FNCP	[^-+\004 \t\n"'()0-9]
FNC	[^\004 \t\n"'()0-9]
NC	[^\004 \t\n"'()]
SIGN	[-+]

%%
.[\010]		;				/* handles backspacing */
.[\177]		;				/* handles deleting */
\"([^\\\"\n]|\\(.|\n)|\"\")*\"  return(STRING); /* strings */
\"([^\\\"\n]|\\(.|\n)|\"\")*\n  return(NON_CLOSED_STRING); /* error */
\;.*\n		;				/* comments */
[-+]?[0-9]+	return(NUMBER);			/* integers */
0[xX][0-9a-fA-F]+	return(HEX_NUMBER);	/* hex integers */
"("		{INC_PAR; return(LEFTPAR);}	/* start of list */
")"		{DEC_PAR; return(RIGHTPAR);}    /* end of list */
"'"		return(QUOTECHAR);		/* quoting */
"{"		{INC_PAR; return(LEFTBRA);}	/* (progn */
"}"		{DEC_PAR; return(RIGHTBRA);}	/* ) */
{FNCP}{NC}*	return (NAME);			/* identifier */
{SIGN}{FNC}{NC}*	return (NAME);		/* +foo */
{SIGN}		return (NAME);			/* + */
[ \t\n]		;				/* blanks */
[\004]		return(END_OF_FILE);		/* pseudo-EOF handling */
.		;				/* skip over control codes */
%%

/**********************\
* 		       *
*  WOOL's I/O package  *
* 		       *
\**********************/

/* 
 * yywrap
 * we treat EOF (or EOString) as a TOKEN, for yacc.
 */

yywrap(){		/* to make EOF a "normal" character */
    unput('\004');	/* EOF is pushed back on the input as ^D */
    return 0;		/* tell Lex there is more to read */
}

/*
 * yyinflush
 * to flush wool input buffers (i.e. the unput buffer)
 * stores old input buffer in arg (should be ~ 16) if not NULL
 */

void
yyinflush(wool_old_unput_buffer)
char *wool_old_unput_buffer;
{
    if (wool_old_unput_buffer) {
	if (yysptr != yysbuf)
	    strncpy(wool_old_unput_buffer, yysbuf, yysptr - yysbuf);
	wool_old_unput_buffer[yysptr - yysbuf] = '\0';
    }
    yysptr = yysbuf;
}

/*
 * yyoutflush
 * to flush wool output buffer.
 */

void
yyoutflush(){
    if(yyout_is_string){
	ASSERT(yystrout->overflow_handler);
/*XXX-UWE-XXX*/
	(*(yystrout->overflow_handler))(yystrout);
	/* yystrout->ptr = yystrout-> buffer; */
/*XXX-UWE-XXX*/
    }else{
	fflush(yyout);
    }
}

/*
 * wool_input_redirect
 * to set wool's parsing to the stream or string argument.
 * arg1 = type (0 = string, 1 = stream);
 * arg2 = stream or string
 * arg3 = POINTER to (FILE *) or (char *) where will go the old stream
 *        (if NULL not set)(returns the old type)
 * arg4 = where to save contents of unput buffer (if not NULL)
 */

int wool_input_redirect(type, stream, oldstream_p, old_buffer_contents)
int type;
char *stream;
char **oldstream_p;
char *old_buffer_contents;
{
    int oldtype = yyin_is_string;
    if(oldstream_p) *oldstream_p =
    	(oldtype ? (char *) yystrin : (char *) yyin);
    yyinflush(old_buffer_contents);
    if(yyin_is_string = type){
	yystrin = stream;
    }else{
	yyin = (FILE *) stream;
    }
    return oldtype;
}

/*
 * wool_output_redirect
 * to set wool's outputs to the stream or string argument.
 * arg1 = type (0 = string, 1 = stream);
 * arg2 = stream or string
 * arg4 = POINTER to (FILE *) or WOOL_STRING_STREAM tu put the old stream
 *        (if NULL not set)(returns the old type)
 */

wool_output_redirect(type, stream, oldstream_p)
int type;
char *stream;
char **oldstream_p;
{
    int oldtype = yyout_is_string;
    if(oldstream_p) *oldstream_p =
    	(oldtype ? (char *) yystrout : (char *) yyout);
    yyoutflush();
    if(yyout_is_string = type){
	yystrout = (WOOL_STRING_STREAM) stream;
    }else{
	yyout = (FILE *) stream;
    }
    return oldtype;
}

/*
 * now, some functions to provide a printf - like service on wool's output.
 */

/* prints a string */

void
wool_puts(string)
register char *string;
{
    while(*string) output(*string++);
}

/* put a newline */

wool_newline()
{
    output('\n');
}

/* does a format with ONE arg. */

wool_printf(string, arg)
register char *string;
char *arg;
{
    static char wool_temp_string[MAX_TEMP_STRING_SIZE];
    sprintf(wool_temp_string, string, arg);
    wool_puts(wool_temp_string);
}

/* prints a char */

void
wool_putchar(c)
char c;
{
    output(c);
}

/*
 * function to make a WOOL_STRING_STREAM of a given capacity
 * arg1 = capactity in bytes
 * arg2 = user function to be called on buffer when overflow occurs
 */

WOOL_STRING_STREAM WOOL_STRING_STREAM_make(nbytes, handler)
int nbytes;
int (* handler)();
{
    WOOL_STRING_STREAM str = (WOOL_STRING_STREAM)
    	Malloc(sizeof(struct _WOOL_STRING_STREAM));
    str->buffer = (char *) Malloc(nbytes);
    *str->buffer = '\0';        /*XXX-UWE-XXX*/
    str->ptr = str->buffer;
    str->last = str->buffer + nbytes -1;
    str->overflow_handler = handler;
    return str;
}

/* 
 * and the function to free a stream
 */

WOOL_STRING_STREAM_free (str)
WOOL_STRING_STREAM str;
{
    Free(str->buffer);
    Free(str);
}
