%{
/* lex.l for VRML97 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "vrml.H"
#include "yacc.h"
extern int lineno;

static char *strsave(char *text), *read_string(void);
%}
IdFirstChar	[\!\$\%\&\(\)\*\/\:\;\<\=\>\?\@A-Z\^\_\`a-z\|\~]
IdRestChar	{IdFirstChar}|[\+\-0-9]
%%
[\ \t\,\r]+	{;							}
\n              {lineno++;						}
^\#VRML2NodeCatalog.*\n {lineno++; if (lineno == 2) {			\
			     yylval.s = yytext; return tNODECATALOG;}	}
^\#VRML.*\n     {lineno++; if (lineno == 2) {				\
			     yylval.s = yytext; return tVRML;}		}
\#.*\n          {lineno++;						}
\"		{yylval.s = strsave(read_string());			\
						return tSTRING;		}
0x[0-9a-fA-F]+	{sscanf(yytext, "%lx", &yylval.i);			\
						return tHEX;		}
[+-]?[0-9]+	{sscanf(yytext, "%ld", &yylval.i);			\
						return tINT;		}
[+-]?([0-9]+\.?|[0-9]*\.[0-9]+)([eE][+-]?[0-9]+)? {sscanf(yytext, "%lf", &yylval.f);\
						return tFLOAT;		}
DEF		{				return tDEF;		}
USE		{				return tUSE;		}
PROTO		{				return tPROTO;		}
EXTERNPROTO	{				return tEXTERNPROTO;	}
ROUTE		{				return tROUTE;		}
TO		{				return tTO;		}
IS		{				return tIS;		}
TRUE		{				return tTRUE;		}
FALSE		{				return tFALSE;		}
NULL		{				return tNULL;		}
Script		{				return tScript;		}
eventIn		{				return teventIn;	}
eventOut	{				return teventOut;	}
field		{				return tfield;		}
exposedField	{				return texposedField;	}
MFNode		{yylval.t = tMFNode; 		return tMFNODE;		}
SFNode		{yylval.t = tSFNode; 		return tSFNODE;		}
MFColor		{yylval.t = tMFColor; 		return tSIMPLEFIELD;	}
MFFloat		{yylval.t = tMFFloat; 		return tSIMPLEFIELD;	}
MFInt32		{yylval.t = tMFInt32; 		return tSIMPLEFIELD;	}
MFRotation	{yylval.t = tMFRotation; 	return tSIMPLEFIELD;	}
MFString	{yylval.t = tMFString; 		return tSIMPLEFIELD;	}
MFTime		{yylval.t = tMFTime;    	return tSIMPLEFIELD;	}
MFVec2f		{yylval.t = tMFVec2f; 		return tSIMPLEFIELD;	}
MFVec3f		{yylval.t = tMFVec3f; 		return tSIMPLEFIELD;	}
SFBool		{yylval.t = tSFBool; 		return tSIMPLEFIELD;	}
SFColor		{yylval.t = tSFColor; 		return tSIMPLEFIELD;	}
SFFloat		{yylval.t = tSFFloat; 		return tSIMPLEFIELD;	}
SFImage		{yylval.t = tSFImage; 		return tSIMPLEFIELD;	}
SFInt32		{yylval.t = tSFInt32; 		return tSIMPLEFIELD;	}
SFRotation	{yylval.t = tSFRotation; 	return tSIMPLEFIELD;	}
SFString	{yylval.t = tSFString; 		return tSIMPLEFIELD;	}
SFTime		{yylval.t = tSFTime; 		return tSIMPLEFIELD;	}
SFVec2f		{yylval.t = tSFVec2f; 		return tSIMPLEFIELD;	}
SFVec3f		{yylval.t = tSFVec3f; 		return tSIMPLEFIELD;	}
{IdFirstChar}({IdRestChar})* {yylval.s = strsave(yytext); return tID;	}
.               {				return yytext[0];	}
%%
int yywrap(void) {return 1;}

static char *strsave(char *text)
{
  return strdup(text);
}

static char *sbuf, *sbufptr;
static int sbufsize = 0;

static void new_string(void)
{
  if (!sbuf)
    sbuf = malloc(1000);
  sbufptr = sbuf;
}

static void add_char(char c)
{
  if (sbufptr-sbuf >= sbufsize)
    sbuf = realloc(sbuf, sbufsize+1000);
  *sbufptr++ = c;
}

static char *read_string(void)
{
  int c, c2;

  new_string();
  do {
    switch (c=input()) {
    case '\\':
      switch (c2=input()) {
      case '\\': 
      case '"':  add_char(c2); break;
      default:	 add_char(c); add_char(c2); 
      }
      break;
    case '\n': 	add_char(c); lineno++; break;
    case '"': 	break;
    default:	add_char(c);
    }
  } while (c!=EOF && c!='"');
  add_char('\0');

  return strsave(sbuf);
}

/* puts back a string */
void UnputString(char *s)
{
  char *p;
  for (p=s+strlen(s)-1; p>=s; p--)
    unput(*p);
}

/* puts back the current token */
void UnputToken(void)
{
  if (yytext[0] == '"') {  /* token is a string */
    unput('"');			/* unput the closing '"' */
    UnputString(yylval.s);	/* unput the string itself */
    free(yylval.s);	/* dispose of its memory */
  }

  while (yyleng > 0) {
    unput(yytext[yyleng-1]);
    yyleng--;
  }
  yytext[0] = '\0';
}

