/**
 * __author__ = Juan Carlos De Abreu (jcabreur@gmail.com)
 *
 * Description:
 *   Define a lexical analizer for a 3d scene descriptor file.
 */

%{
#pragma warning (disable:4996)

#include <cstdlib>
#include <errno.h>
#include <limits.h>
#include <string>
#include "SceneDriver.h"
#include "scene.parser.hh"
%}

%option noyywrap nounput batch debug

%{
# define YY_USER_ACTION  yylloc->columns (yyleng);
%}

/* Data Types definition */
DIGIT		[0-9]
INT			{DIGIT}+

EXPONENT	[eE][+-]?{DIGIT}+
FLOAT		({DIGIT}+\.{DIGIT}*)|(\.{DIGIT}+){EXPONENT}?

STRING		(\"([^"]|"\\\"")*\"|\'([^']|"\\\'")*\')

CHAR		[a-zA-Z_]
ID			{CHAR}({CHAR}|{DIGIT})*

WHITE_SPACE	[ \t]+
NEW_LINE	(\n|\n\r)

SINGLE_LINE_COMMENT		"//".*
MULTI_LINE_COMMNET		"/*"([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+\/

TRUE	"true"|"TRUE"
FALSE	"false"|"FALSE"

NULL	"null"|"NULL"

RETURN	"return"

%%

%{
  yylloc->step ();
%}

{NEW_LINE} { /* Ignore */ yylloc->lines(yyleng); yylloc->step(); }
{WHITE_SPACE} { /* Ignore */ yylloc->step(); }
{SINGLE_LINE_COMMENT} { /* Ignore */ yylloc->lines(yyleng); yylloc->step(); }
{MULTI_LINE_COMMNET} { /* Ignore */ yylloc->lines(yyleng); yylloc->step(); }

"." { return TOKEN_DOT; }
"," { return TOKEN_COMMA; }
";" { return TOKEN_SEMICOLON; }
"=" { return TOKEN_ASSIGN; }
"(" { return TOKEN_LPAREN; }
")" { return TOKEN_RPAREN; }
"{" { return TOKEN_LBRACKET; }
"}" { return TOKEN_RBRACKET; }
"[" { return TOKEN_LSQUAREBRACKET; }
"]" { return TOKEN_RSQUAREBRACKET; }

"+" { return TOKEN_PLUS; }
"-" { return TOKEN_MINUS; }
"*" { return TOKEN_MULT; }
"/" { return TOKEN_DIV; }
"%" { return TOKEN_MOD; }
"++" { return TOKEN_PLUS_PLUS; }
"--" { return TOKEN_MINUS_MINUS; }

"+=" { return TOKEN_PLUS_EQUAL; }
"-=" { return TOKEN_MINUS_EQUAL; }
"*=" { return TOKEN_MULT_EQUAL; }
"/=" { return TOKEN_DIV_EQUAL; }
"%=" { return TOKEN_MOD_EQUAL; }

"!" { return TOKEN_NEG; }
"&&" { return TOKEN_AND; }
"||" { return TOKEN_OR; }
"<" { return TOKEN_LESS; }
">" { return TOKEN_GREATER; }
"<=" { return TOKEN_LESS_EQUAL; }
">=" { return TOKEN_GREATER_EQUAL; }
"==" { return TOKEN_EQUAL; }
"!=" { return TOKEN_NOT_EQUAL; }

"def" { return TOKEN_DEF; }

"if" { return TOKEN_IF; }
"else" { return TOKEN_ELSE; }
"for" { return TOKEN_FOR; }
"while" { return TOKEN_WHILE; }

{INT} {
	// TODO: Check if the number is out of range
	yylval->ival = atoi(yytext);
	return TOKEN_INT;
}

{FLOAT} { 
	yylval->fval = (float)atof(yytext);
	return TOKEN_FLOAT;
}

{STRING} { 
	std::string s(yytext); s = s.substr(1, s.size() - 2);
	yylval->sval = new std::string(s);
	return TOKEN_STRING;	
}

{TRUE} { yylval->bval = true; return TOKEN_BOOL; }
{FALSE} { yylval->bval = false;	return TOKEN_BOOL; }

{NULL} { /*reserverd for the future*/ }

{RETURN} { return TOKEN_RETURN; }

{ID} {
	yylval->sval = new std::string(yytext);
	return TOKEN_ID;
}

. { driver.error(*yylloc, "invalid character"); }

%%

// Method to start the parser.
void SceneDriver::scan_begin() {
	yy_flex_debug = trace_scanning;
	if (!(yyin = fopen(file.c_str(), "r")))
		error(std::string("cannot open ") + file);
}

// Method to finish the parser.
void SceneDriver::scan_end() {
	fclose(yyin);
}
