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

%skeleton "lalr1.cc"						/* For C++ */
%define "parser_class_name" "SceneParser"
%defines
%{
#include <string>
#include "SceneDriver.h"
#include "SceneFile.h"
using namespace teg;
%}

// The parsing context.
%parse-param { SceneDriver& driver }
%lex-param   { SceneDriver& driver }

%locations
%initial-action {
	// Initialize the initial location.
	@$.begin.filename = @$.end.filename = &driver.file;
};

%debug
%error-verbose

%expect 1		// To avoid the warning for the if statement

// Symbols.
%union {
  int          ival;
  bool         bval;
  float        fval;
  std::string *sval;
  IData* dval;
};

%token        TOKEN_EOF      0 "end of file"
%token <sval> TOKEN_ID "identifier"
%type <dval> exp              "expression"

%type <dval> bool_exp
%type <dval> arithmetic_exp
%type <dval> left_exp

%type <dval> lines
%type <dval> line
%type <dval> instructions
%type <dval> def_function
%type <dval> def_params
%type <dval> def_param
%type <dval> call_function
%type <dval> call_params
%type <dval> call_param

%type <dval> global_def

%type <dval> list list_item list_items

%type <dval> if
%type <dval> action
%type <dval> for_statement
%type <dval> while_statement

%token <ival> TOKEN_INT "int"
%token <bval> TOKEN_BOOL "bool"
%token <fval> TOKEN_FLOAT "float"
%token <sval> TOKEN_STRING "string"
%type <dval> value

%token TOKEN_DOT "." TOKEN_COMMA "," TOKEN_SEMICOLON ";"
%token TOKEN_LSQUAREBRACKET "[" TOKEN_RSQUAREBRACKET "]"
%token TOKEN_LPAREN "(" TOKEN_RPAREN ")"
%token TOKEN_LBRACKET "{" TOKEN_RBRACKET "}"

%token TOKEN_NEG "!" TOKEN_ASSIGN "="
%token TOKEN_AND "&&" TOKEN_OR "||"
%token TOKEN_EQUAL "==" TOKEN_NOT_EQUAL "!="
%token TOKEN_LESS "<" TOKEN_GREATER ">"
%token TOKEN_LESS_EQUAL "<=" TOKEN_GREATER_EQUAL ">="

%token TOKEN_PLUS "+" TOKEN_PLUS_PLUS "++" TOKEN_PLUS_EQUAL "+="
%token TOKEN_MINUS "-" TOKEN_MINUS_MINUS "--" TOKEN_MINUS_EQUAL "-="
%token TOKEN_MULT "*" TOKEN_MULT_EQUAL "*="
%token TOKEN_DIV "/" TOKEN_DIV_EQUAL "/="
%token TOKEN_MOD "%" TOKEN_MOD_EQUAL "%="

%token TOKEN_RETURN "return"

/* Palabra reservada para futuro ... */
%token TOKEN_NULL "null"

%token TOKEN_IF "if" TOKEN_ELSE "else"
%token TOKEN_FOR "for" TOKEN_WHILE "while"

%token TOKEN_DEF "def"

%destructor { delete $$; } "identifier" "string"
%printer    { debug_stream () << *$$; } "identifier" "string"
%printer    { debug_stream () << $$; } "int" "float" "expression"

%%

%start main;

main: /**/ { }
	| global_defs { };

// Sintatic rules for 
global_defs: global_def { }
	| global_defs global_def { };

global_def: line { addGlobalInst($1); }
	| def_function { };

// Sintatic rules for a function definition.
def_function: "def" TOKEN_ID "(" def_params ")" "{" instructions "}" { $$ = addFunction(*$2, $4, $7); };

def_params: /*nothing*/ { $$ = NULL; }
	| def_param { };
def_param: TOKEN_ID { $$ = addVector(addDataId(*$1)); }
	| def_param "," TOKEN_ID { $$ = addVector($1, addDataId(*$3)); };

// Sintatic rules for a 
instructions: /**/ { $$ = NULL; }
	| lines { };
//	| "return" exp ";" { $$ = addReturn($2); };

// Sintatic rules for 
lines: line { $$ = addVector($1); }
	| lines line { $$ = addVector($1, $2); }
	| "return" exp ";" { $$ = addVector(addReturn($2)); }
	| lines "return" exp ";" { $$ = addVector($1, addReturn($3)); };

// Sintatic rules for 
line: exp ";" { }
	| if { }
	| while_statement { }
	| for_statement { };

%left "=" "+=" "-=" "*=" "/=" "%=";
%left "!" "&&" "||" "==" "!=" "<=" ">=" "<" ">";
%left "+" "-";
%left "*" "/" "%";
%left "++" "--";
%left ".";

// TODO: ...
exp : value { }
	| list { }
	| bool_exp { }
	| arithmetic_exp { }
	| left_exp { };

// Sintatic rules for 
list: "(" list_items ")" { $$ = $2; };
list_items: /*nothing*/ { $$ = addVector(NULL); }
	| list_item { };
list_item: exp { $$ = addVector($1); }
	| list_item "," exp { $$ = addVector($1, $3); };

// Sintatic rules for arithmetic expressions.
arithmetic_exp: "-" exp { $$ = addOperation($2, "-"); }
	| exp "+" exp { $$ = addOperation($1, $3, "+"); }
	| exp "-" exp { $$ = addOperation($1, $3, "-"); }
	| exp "*" exp { $$ = addOperation($1, $3, "*"); }
	| exp "/" exp { $$ = addOperation($1, $3, "/"); }
	| exp "%" exp { $$ = addOperation($1, $3, "%"); }
	| left_exp "=" exp { $$ = addOperation($1, $3, "="); }
	| "++" left_exp { $$ = addOperation($2, "++"); }
	| left_exp "++" { $$ = addOperation($1, "++"); }
	| "--" left_exp { $$ = addOperation($2, "--"); }
	| left_exp "--" { $$ = addOperation($1, "--"); }
	| left_exp "+=" exp { $$ = addOperation($1, $3, "+="); }
	| left_exp "-=" exp { $$ = addOperation($1, $3, "-="); }
	| left_exp "*=" exp { $$ = addOperation($1, $3, "*="); }
	| left_exp "/=" exp { $$ = addOperation($1, $3, "/="); }
	| left_exp "%=" exp { $$ = addOperation($1, $3, "%="); };

left_exp: TOKEN_ID { $$ = addDataId(*$1); }
	| call_function { }
	| left_exp "." TOKEN_ID { $$ = addOperation($1, addDataId(*$3), "."); }
	| left_exp "." call_function { $$ = addOperation($1, $3, "."); }
	| left_exp "[" exp "]" { $$ = addOperation($1, $3, "[]"); };

// Sintatic rules for boolean expressions.
bool_exp: "!" exp { $$ = addOperation($2, "!"); }
	| exp "<" exp { $$ = addOperation($1, $3, "<"); }
	| exp ">" exp { $$ = addOperation($1, $3, ">"); }
	| exp "<=" exp { $$ = addOperation($1, $3, "<="); }
	| exp ">=" exp { $$ = addOperation($1, $3, ">="); }
	| exp "==" exp { $$ = addOperation($1, $3, "=="); }
	| exp "!=" exp { $$ = addOperation($1, $3, "!="); }
	| exp "&&" exp { $$ = addOperation($1, $3, "&&"); }
	| exp "||" exp { $$ = addOperation($1, $3, "||"); };
	
// Sintatic rules for basic data types.
value: TOKEN_INT { $$ = addData($1); } 
	| TOKEN_BOOL { $$ = addData($1); }
	| TOKEN_FLOAT { $$ = addData($1); }
	| TOKEN_STRING { $$ = addData(*$1); };

// 
if: "if" "(" exp ")" action { $$ = addIf($3, $5, NULL); };
	| "if" "(" exp ")" action "else" action { $$ = addIf($3, $5, $7); };

// Sintatic rules for loop iterators.
while_statement: "while" "(" exp ")" action { $$ = addWhile($3, $5); }
for_statement: "for" "(" exp ";" exp ";" exp ")" action { $$ = addFor($3, $5, $7, $9); };

// Define an action, that can be one or more with and without brackets.
action: line { $$ = addVector($1); }
	| "return" exp ";" { $$ = addVector(addReturn($2)); }
	| "{" instructions "}" { $$ = $2; };

// Sintatic rules for call a function or a method.
call_function: TOKEN_ID "(" call_params ")" { $$ = addCallFunction(*$1, $3); };
call_params: /*nothing*/ { $$ = NULL; }
	| call_param { };
call_param: exp { $$ = addVector($1); }
	| call_param "," exp { $$ = addVector($1, $3); };

%%

// Method to report erorrs in the parsing.
void yy::SceneParser::error(const yy::SceneParser::location_type& l, const std::string& m) {
	driver.error (l, m);
}
