%option noyy_scan_string
%option 8bit

%{

/*
Copyright (C) 2001-2002 Charles Hollemeersch

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

PENTA: the whole file is freakin penta...

This file defines the lexical analzer for the tenebrae shader/particle/decail scripts...
Basic lexing stuff returning tokens for keywords and storing semantics in global vars...


*/

#include <stdio.h>
#include "te_scripts.h"

#define MAX_STR_CONST 512

/* Semantics are stored in here */

static char string_buf[MAX_STR_CONST];
static char *string_buf_ptr, *string_end_buf;
static float float_value;

int line_num; /* current line number */

float Q_atof (char *str);

%}

%x str comment comment2 foo

DIGIT    [0-9]
ID       [a-z][a-z0-9_]*

%%

        
  /***************************************************************************
  Parse C-like strings, this means including stuff like escape sequences....
  ****************************************************************************/

\"      { BEGIN(str); string_buf_ptr = string_buf; string_end_buf = string_buf_ptr+MAX_STR_CONST; }

<str>\"        { /* saw closing quote - all done */
        BEGIN(INITIAL);
        *string_buf_ptr = '\0';
        /* return string constant token type and
         * value to parser
         */
         return TOK_STR_CONST;
        }

<str>\n        {
        /* error - unterminated string constant */
        /* generate error message */
		Con_Printf("\002Parse error at line %i: Newline in constant string", line_num);
        line_num++; /*for error messages*/
		return TOK_STR_CONST; //more of a mock up this will generate lots of errors probably
        }

<str>\\[0-7]{1,3} {
        /* octal escape sequence */
        int result;

        (void) sscanf( yytext + 1, "%o", &result );

        if ( result > 0xff )
                /* error, constant is out-of-bounds */

	if (string_buf_ptr < string_end_buf)
        	*string_buf_ptr++ = result;
        }

<str>\\[0-9]+ {
        /* generate error - bad escape sequence; something
         * like '\48' or '\0777777'
         */
        }

<str>\\n  *string_buf_ptr++ = '\n';
<str>\\t  *string_buf_ptr++ = '\t';
<str>\\r  *string_buf_ptr++ = '\r';
<str>\\b  *string_buf_ptr++ = '\b';
<str>\\f  *string_buf_ptr++ = '\f';

<str>\\(.|\n)  {
		if (string_buf_ptr < string_end_buf)
			*string_buf_ptr++ = yytext[1];
		}
		

<str>[^\\\n\"]+        {
        char *yptr = yytext;

        while ( (*yptr) && (string_buf_ptr < string_end_buf) )
                *string_buf_ptr++ = *yptr++;
        }
        
  /****************************************************************************
  Skip the / *  * / comments
  *****************************************************************************/
        
"/*"         BEGIN(comment);

<comment>[^*\n]*        /* eat anything that's not a '*' */
<comment>"*"+[^*/\n]*   /* eat up '*'s not followed by '/'s */
<comment>\n		{ line_num++; /*for error messages*/ }
<comment>"*"+"/"        BEGIN(INITIAL);

  /****************************************************************************
   Skip the //
  *****************************************************************************/

"//"         BEGIN(comment2);
<comment2>\n        { BEGIN(INITIAL); line_num++; } /* end of comment */
<comment2>.	/*eat up the rest */

  /****************************************************************************
  Parse the numeric constants
  *****************************************************************************/

-?{DIGIT}+       {
		float_value = Q_atof(yytext);
		//Con_Printf("tok: =%s=%f=\n",yytext,float_value);
		return TOK_FLOAT_CONST;
            }

-?{DIGIT}+"."{DIGIT}*        {
		float_value = Q_atof(yytext);
		//Con_Printf("tok: =%s=%f=\n",yytext,float_value);
		return TOK_FLOAT_CONST;
            }
            
emitter	{ return TOK_EMITTER; }
velocity	{  return TOK_VELOCITY; }
lifetime	{  return TOK_LIFETIME; }
flags		{  return TOK_FLAGS; }
gravity	{  return TOK_GRAVITY; }
drag	{  return TOK_DRAG; }
blendfunc	{  return TOK_BLENDFUNC; }
bounces	{  return TOK_BOUNCES; }
map	{  return TOK_MAP; }
particle	{  return TOK_PARTICLE; }
decal	{  return TOK_DECAL; }
startcolor		{  return TOK_STARTCOLOR; }
endcolor		{  return TOK_ENDCOLOR; }
grow			{  return TOK_GROW; }
size			{  return TOK_SIZE; }
rotation		{  return TOK_ROTATION; }
orientation		{  return TOK_ORIENTATION; }
onhit			{  return TOK_ONHIT; }

{ID}        {
		strcpy(string_buf,yytext);
		return TOK_ID;
	    }
	    
<<EOF>>  {  BEGIN(INITIAL); return TOK_FILE_END; }
\000     {  BEGIN(INITIAL); return TOK_FILE_END; }

[ \t\x0D] 	 { /* eat whitespace */ }

[\n]	 { line_num++; /*for error messages*/ }
	    
.	    {
		strcpy(string_buf,yytext);
		//return a 1 karakter token... (e.g. },{,],...)
		return yytext[0];
	    }
	    	  	    
%%

int yywrap(void) {
  return 1;
}

/*

	Engine communication with parser

*/

char *SC_ParseString() {
	int token = yylex();
	if (token == TOK_STR_CONST) {
		return string_buf;
	} else {
		Con_Printf("\002Parse error at line %i: Expected string constant (found id%i)\n", line_num, token);
		return string_buf;
	}
}

char *SC_ParseIdent() {
	int token = yylex();
	if (token == TOK_ID) {
		return string_buf;
	} else {
		Con_Printf("\002Parse error at line %i: Expected identifier (found id%i)\n", line_num, token);
		return string_buf;
	}
}

float SC_ParseFloat() {
	int token = yylex();
	if (token == TOK_FLOAT_CONST) {
		return float_value;
	} else {
		Con_Printf("\002Parse error at line %i: Expected float constant (found id%i)\n", line_num, token);
		return float_value;
	}
}

int SC_ParseToken() {
	return yylex();
}

static void *buffHandle = NULL;

/*
Parse from the given block of bytes
*/
void SC_Start(const char *bytes,int len) {
	line_num = 1;
	strcpy(string_buf,"newfile");
	
	buffHandle = yy_scan_bytes(bytes,len);
	
	//Con_Printf("new file\n");
	/*
	if (YY_CURRENT_BUFFER)
		yy_delete_buffer( YY_CURRENT_BUFFER );
    yy_switch_to_buffer(yy_create_buffer( yyin, YY_BUF_SIZE));

	yyrestart(fin);
	*/
}

void SC_End() {
	yy_delete_buffer( buffHandle );	
	buffHandle = NULL;
}