%{
#include "ideal.h"
#include "y.tab.h"
extern int lineno, yylval;
extern boolean flyback;

#define	BUFLEN	100

struct filenode {
	struct filenode *next;
	FILE *file;
	int lineno;
	char *name;
	char buf[BUFLEN];
	int head;
};

struct filenode *filestack = NULL;

FILE *curfile;
#undef	input
#undef	unput

boolean file_start = TRUE;
boolean just_popped = FALSE;

void filepush ();
void filepop ();
char input ();
void unput ();
%}
%Start	PROGRAM COMMENT OUTSIDE LIBRARY INCLUDE
%%
%{
	int numitems, i;
	char item[5][20];
	char cmd[20];
	static int ISnest, bracenest, commnest, omode;
	if (file_start) {
		BEGIN OUTSIDE;
		ISnest = 0;
	};
	file_start = FALSE;
%}
<OUTSIDE>^\.IS.*\n	{
			BEGIN PROGRAM;
			if (!ISnest)
				printf ("%s", yytext);
			ISnest ++;
			bracenest = commnest = 0;
			}
<OUTSIDE>[ \t]		{
			if (just_popped) {
				if (omode == LIBFIL)
					BEGIN LIBRARY;
				else if (omode == CHATTY)
					BEGIN INCLUDE;
				else impossible ("idlex");
				just_popped = FALSE;
			} else
				printf ("%s", yytext);
			}
<OUTSIDE>.		{
			printf ("%s", yytext);
			}
<OUTSIDE>\n		{
			if (just_popped) {
				BEGIN PROGRAM;
				just_popped = FALSE;
			} else {
				printf ("\n");
			}
			}
<PROGRAM>box		return(yylval = BOX);
<PROGRAM>var		return(yylval = VAR);
<PROGRAM>bdlist		return(yylval = BDLIST);
<PROGRAM>boundary	return(yylval = BDLIST);
<PROGRAM>put		return(yylval = PUT);
<PROGRAM>conn		return(yylval = CONN);
<PROGRAM>to		return(yylval = TO);
<PROGRAM>using		return(yylval = USING);
<PROGRAM>construct	return(yylval = CONSTRUCT);
<PROGRAM>draw		return(yylval = DRAW);
<PROGRAM>opaque		return(yylval = OPAQUE);
<PROGRAM>left		return(yylval = LEFT);
<PROGRAM>text		return(yylval = CENTER);
<PROGRAM>right		return(yylval = RIGHT);
<PROGRAM>spline		return(yylval = SPLINE);
<PROGRAM>at		return(yylval = AT);
<PROGRAM>interior	return(yylval = INTERIOR);
<PROGRAM>exterior	return(yylval = EXTERIOR);
<PROGRAM>[a-zA-Z][a-zA-Z0-9]*	{
			yylval = lookup(&yytext[0]);
			return(NAME);
			}
<PROGRAM>[0-9]+|[0-9]*\.[0-9]+|[0-9]+\.[0-9]*|[0-9]+\.?[0-9]*[eE]\ *[+\-]?[0-9]+|[0-9]*\.[0-9]+[eE]\ *[+\-]?[0-9]+ {
			float temp;
			sscanf(yytext, "%f", &temp);
			yylval = (int) fextlgen(temp);
			return(CONST);
			}
<PROGRAM>^\.\.\.forget.*	{
			numitems = sscanf (yytext, "%s %s %s %s %s %s",
				cmd,
				&item[0][0],
				&item[1][0],
				&item[2][0],
				&item[3][0],
				&item[4][0]
			);
			numitems --;
			for (i = 0; i < numitems; i ++)
				forget (lookup (&item[i][0]));
			}
<PROGRAM>^\.\.\.radians.*	radflag = TRUE;
<PROGRAM>^\.\.\.degrees.*	radflag = FALSE;
<PROGRAM>^\.\.\.libfile	{
			omode = LIBFIL;
			BEGIN LIBRARY;
			}
<LIBRARY>[ \t]+		;
<LIBRARY>[^ \t\n]+	{
			idinclude (yytext, LIBFIL);
			BEGIN OUTSIDE + 1;
			}
<LIBRARY>\n		{
			BEGIN PROGRAM + 1;
			}
<PROGRAM>^\.\.\.include	{
			omode = CHATTY;
			BEGIN INCLUDE;
			}
<INCLUDE>[ \t]+		;
<INCLUDE>[^ \t\n]+	{
			idinclude (yytext, CHATTY);
			BEGIN OUTSIDE + 1;
			}
<INCLUDE>\n		{
			BEGIN PROGRAM + 1;
			}
<PROGRAM>^\.I[EF].*\n	{
			interpret ();
			ISnest --;
			if (!ISnest)
				printf ("%s", yytext);
			if (bracenest > 0)
				fprintf (stderr, "ideal: excess {\n");
			BEGIN OUTSIDE;
			}
<PROGRAM>^\..*		{
			sscanf (yytext, "%s", cmd);
			if (strcmp (cmd, "...libfile") && strcmp (cmd, "...include"))
				printf ("%s\n", yytext);
			else
				REJECT;
			}
<PROGRAM>#.*		;
<PROGRAM>"/*"		{
			commnest = 1;
			BEGIN COMMENT;
			}
<COMMENT>"/*"		{
			commnest ++;
			}
<COMMENT>"*/"		{
			commnest --;
			if (!commnest)
				BEGIN PROGRAM;
			}
<COMMENT>.		;
<COMMENT>\n		{
			}
<PROGRAM>"'"[^']*	{
			if (yytext[yyleng-1] == '\\') {
				yytext[yyleng-1] = yytext[yyleng];
				yyleng --;
				yymore();
			} else {
				char *temp;
				temp = malloc((unsigned) yyleng+1);
				yytext[yyleng] = '\0';
				strcpy(temp, &yytext[1]);
				yylval = (int) temp;
				input();
				return(STRING);
			}
			}
<PROGRAM>\"[^\"]*	{
			if (yytext[yyleng-1] == '\\') {
				yytext[yyleng-1] = yytext[yyleng];
				yyleng --;
				yymore();
			} else {
				char *temp;
				temp = malloc((unsigned) yyleng+1);
				yytext[yyleng] = '\0';
				strcpy(temp, &yytext[1]);
				yylval = (int) temp;
				input();
				return(STRING);
			}
			}
<PROGRAM>[ \t]+		{
			if (just_popped) {
				if (omode == LIBFIL)
					BEGIN LIBRARY;
				else if (omode == CHATTY)
					BEGIN INCLUDE;
				else impossible ("idlex");
				just_popped = FALSE;
			}
			}
<PROGRAM>\n		{
			}
<PROGRAM>"{"		{
			bracenest ++;
			return (yylval = LBRACE);
			}				
<PROGRAM>"}"		{
			bracenest --;
			if (bracenest < 0)
				fprintf (stderr, "ideal: excess }\n");
			return (yylval = RBRACE);
			}
<PROGRAM>[\<\>\(\)\[\]\+\-\*\/\=\,\;\:\.\^\~]	return(yytext[0]);
<PROGRAM>.		fprintf(stderr, "ideal: unknown input token %s flushed\n", &yytext[0]);
%%
void filepush (f)
FILE *f;
{
	struct filenode *newfile;
	newfile = (struct filenode *) calloc (1, sizeof (struct filenode));
	if (newfile) {
		newfile->next = filestack;
		newfile->file = curfile = f;
		newfile->head = -1;
		if (filestack)
			filestack->lineno = lineno;
		newfile->name = malloc ((unsigned)strlen(filename)+1);
		strcpy (newfile->name, filename);
		filestack = newfile;
		lineno = 1;
	} else {
		fprintf (stderr, "ideal: no room for file descriptor\n");
		exit (1);
	}
}

void filepop ()
{
	struct filenode *oldfile;
	if (filestack) {
		if (filestack->head > -1)
			fprintf (stderr, "ideal: characters ignored in file %s\n", filename);
		oldfile = filestack;
		filestack = filestack->next;
		fclose (oldfile->file);
		if (filestack) {
			curfile = filestack->file;
			lineno = filestack->lineno;
			filename = filestack->name;
		} else
			curfile = NULL;
		free ((char *)oldfile);
	} else {
		fprintf (stderr, "ideal: file stack botch\n");
		exit (1);
	}
}

int idgetc (f)
struct filenode *f;
{
	int c;
	if (!f)
		return (EOF);
	if (f->head > -1) {
		c = f->buf[f->head--];
	} else
		c = getc(f->file);
	return (c);
}

char input ()
{
	int c;
	c = 0;
	if (filestack)
		c = idgetc(filestack);
	while (c == EOF && filestack) {
		filepop();
		if (filestack) {
			c = idgetc(filestack);
			just_popped = TRUE;
		}
		else
			c = EOF;
	}
	if (c == '\n')
		lineno++;
	return ((c == EOF)?0:c);
}

void unput (c)
char c;
{
	struct filenode *f;
	if (f = filestack) {
		if (f->head < BUFLEN) {
			f->buf[++f->head] = c;
			if (c == '\n')
				-- lineno;
		} else {
			fprintf (stderr, "ideal: out of pushback space\n");
			exit (1);
		}
	}
}
