%{
#include "syntree.hpp"
#include "function.hpp"
#include <string>
#include <vector>
#include <iostream>
#include <map>
using namespace std;

extern int yylex();

#define YYDEBUG 1
void yyerror(char* s)
{
	cerr<<s<<endl;
}

%}

%union
{
	SynTreeNode* syntree_a;
	string* string_a;
	int	int_a;
	vector<string>* stringvec_a;
	vector<SynTreeNode*>* syntreevec_a;
	
};


%token PRINT FUNCTION
%nonassoc '?' ':'
%left EQ
%left '+' '-'
%left '*' '/'

%type <syntree_a> code expr statement
%token <string_a> ID 
%token <int_a> NUM
%type <stringvec_a> fun_args id_list
%type <syntreevec_a> call_args expr_list

%%

program : program function
	| 
	;
	
function : 
// Funkcija sa povratnom vrednoscu
FUNCTION ID '=' ID fun_args '{' code '}'	
	{	// Kreiramo novu funkciju sa datim imenom, argumentima, rezultatom i telom
		Function *f = new Function(*$4, *$5, *$2, $7);
		delete $2;
		delete $4;
		delete $5;
	}
|
// Funkcija bez povratne vrednosti
FUNCTION ID fun_args '{' code '}'	
	{
		// Kreiramo novu funkciju sa datim imenom, argumentima i telom
		Function* f =  new Function(*$2, *$3, "", $5);
		delete $2;
		delete $3; 
	}
;

	
fun_args : '(' id_list ')'
	{	$$ = $2;	}
	| '(' ')'
	{	$$ = new vector<string>();	}
	;
	
id_list : id_list ',' ID
	{
		$$ = $1;
		$$->push_back(*$3);
		delete $3;
	}
	| ID
	{
		$$ = new vector<string> ();
		$$->push_back(*$1);
		delete $1;
	}
	;
	
code : code statement
	{	$$ = new SequenceNode($1, $2);		}
	| statement 
	{	$$ = $1;	}
	;
	
statement : ID '=' expr ';'
	{
		$$ = new AssignmentNode(*$1, $3);
		delete $1;
	}
	| PRINT '(' expr ')' ';'
	{	$$ = new PrintNode($3);		}
	| expr ';'
	{	$$ = $1;	}
	;
	
expr : expr '+' expr 
	{ $$ = new PlusNode($1, $3); 	}
	| expr '-' expr
	{ $$ = new MinusNode($1, $3); 	}
	| expr '*' expr
	{ $$ = new TimesNode($1, $3); 	}
	| expr '/' expr
	{ $$ = new DivideNode($1, $3); 	}
	| '(' expr ')'
	{ $$ = $2; 	}
	| expr '?' expr ':' expr
	{ $$ = new QuestionNode($1, $3, $5); 	}
	| expr EQ expr
	{ $$ = new EqNode($1, $3); 	}
	// Poziv funkcije
	| ID call_args
	{ $$ = new FunctionCallNode(*$1, *$2); 	
	  delete $1;
	  delete $2;
	}
	| ID
	{ $$ = new VariableNode(*$1); 	
	  delete $1;
	}
	| NUM
	{ $$ = new ConstantNode($1); 	}
	;
	
call_args : '(' ')'
	{	$$ = new vector<SynTreeNode*>();	}
	| '(' expr_list ')'
	{ $$ = $2; }
	;
	
expr_list : expr_list ',' expr
	{
		$$ = $1;
		$$->push_back($3);
	}
	| expr
	{
		$$ = new vector<SynTreeNode*>();
		$$->push_back($1);
	}
	;
	

%%
int main()
{
	yydebug = 0;
	try
	{
		// Parsiramo ulaznu datoteku
		yyparse();
		
		// Pozivamo funkciju main bez argumenata
		vector<int> empty;
		Function::Call("main", empty);
		
		// Uklanjamo sve definisane funkcije
		Function::DeleteFunctions();
	}
	catch(char* s)
	{	cerr<<s<<endl;	}
	
	return 0;
}
