%{
/* lexical scanner for VRML97 */
#define _VRML2_UTF8_SCANNER_SOURCE_

#include <stdio.h>
#include <assert.h>
#include <string.h>

#include "pools.h"
#include "fieldValue.H"
#include "scanner.H"

namespace vrml2_utf8 {

#define YY_DECL int vrml2_utf8::scanner::yylex(YYSTYPE *lvalp)
#define YY_USER_ACTION lastvalp = lvalp;

#ifdef DEBUG
#define PR(tok) fprintf(stderr, "%d: %s '%s'\n", yylinenr, tok, yytext)
#else
#define PR(tok)
#endif

int scanner::LexerInput(char *buf, int max_size)
{
  return fread(buf, 1, max_size, scanfp);
}

}  // namespace vrml2_utf8

%}
%option c++
%option noyywrap
%option prefix="vrml"
%option never-interactive

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

namespace vrml2_utf8 {

void scanner::new_string(void)
{
  if (!*sbuf) {
    *sbuf = new char[1000];
    sbufsize = 1000;
  }
  sbufptr = *sbuf;
}

void scanner::add_char(char c)
{
  if (sbufptr-(*sbuf) >= sbufsize) {
    int i = sbufptr-(*sbuf);
    char *newsbuf = new char[sbufsize+1000];
    memcpy(newsbuf, *sbuf, sbufsize);
    delete *sbuf;
    *sbuf = newsbuf;
    sbufsize += 1000;
    sbufptr = (*sbuf)+i;
  }
  *sbufptr++ = c;
}

char *scanner::strsave(char *text)
{
  return strdup(text);
}

char *scanner::read_string(void)
{
  int c, c2, sline;

  if (unputstr) {        /* previously unput string */
    char *s = unputstr; unputstr = 0;
    return s;
  }

  new_string();
  sline = yylineno;
  do {
    switch (c=yyinput()) {
    case '\\':
      switch (c2=yyinput()) {
      case '\\': 
      case '\"':  add_char(c2); break;
      default:	 add_char(c); add_char(c2); 
      }
      break;
    case '\n': 	add_char(c); yylineno++; break;
    case '\"': 	break;
    default:	add_char(c);
    }
  } while (c!=EOF && c!='\"');
  add_char('\0');
  if (c==EOF) {
    char buf[100];
    sprintf(buf, "End-Of-File encountered while reading string starting at line %d", sline);
    yyerror(buf);
  }

  return strsave(*sbuf);
}

/* puts back a string. 
 * Warning: this routine may trash yytext. */
void scanner::UnputString(char *s)
{
  char *p;
  for (p=s+strlen(s)-1; p>=s; p--)
    unput(*p);
}

/* puts back the current token */
void scanner::UnputToken(void)
{
  if (yytext[0] == '\"') {      /* token is a (previously saved) string */
    assert(!unputstr);
    unputstr = lastvalp->s;
  }

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

void scanner::yyerror(char *s)
{
   Error(NULL, "%s", s);
}

}  // namespace vrml2_utf8

int vrmlFlexLexer::yylex(void)
{
   xrml::Error(NULL, "vrmlFlexLexer::yylex() called instead of vrml_parser::yylex()\n");
   return 0;
}
