%{
#include <iostream>
#include <string>
using namespace std;
#include "izrazi.h"
#include "funkcija.h"

#define YYDEBUG 1

int yylex();
void yyerror(char* str) {
	cerr << str << endl;	
}

%}

%token NUM ID
%token IF DEFUN

%union {
	string* str_atr;
	int num_atr;
	Izraz* izraz_atr;
	vector<string>* vec_str_atr;
	vector<Izraz*>* vec_izraz_atr;
}

%type <str_atr> ID
%type <num_atr> NUM
%type <izraz_atr> izraz
%type <vec_str_atr> promenljive
%type <vec_izraz_atr> nizizraza

%%
program : program naredba
	|
	;

naredba : izraz {
		map<string, int> promenljive;
		cout << $1->Vrednost(promenljive) << endl;
		delete $1;
	}
	| defun
	;

izraz : 
	  '(' '+' izraz izraz ')' {
		$$ = new Plus($3, $4);
	}
	| '(' '*' izraz izraz ')' {
		$$ = new Puta($3, $4);
	}
	| '(' '-' izraz izraz ')' {
		$$ = new Minus($3, $4);
	}
	| '(' '=' izraz izraz ')' {
		$$ = new Jednako($3, $4);
	}
	| '(' '<' izraz izraz ')' {
		$$ = new Manje($3, $4);
	}
	| '(' IF izraz izraz izraz ')' {
		$$ = new IfThenElse($3, $4, $5);
	}
	| '(' ID nizizraza ')' {
		$$ = new PozivFunkcije(*$2, $3);
		delete $2;
	}
	| NUM {
		$$ = new Konstanta($1);
	}
	| ID {
		$$ = new Promenljiva(*$1);
		delete $1;
	}
	;

defun : '(' DEFUN ID '(' promenljive ')' izraz ')' {
		Funkcija::DefinisiFunkciju(*$3, $5, $7);
		cout << *$3 << " successfully defined" << endl;
		delete $3;
	}
	;

nizizraza : nizizraza izraz {
	   $$ = $1;
	   $$->push_back($2);
	}
	| { $$ = new vector<Izraz*>; }
	;

promenljive : promenljive ID {
		$$ = $1;
		$$->push_back(*$2);
		delete $2;
	}
	| { $$ = new vector<string>; }
	;
%%
 
int main() {
	yydebug = 0;
	yyparse();
	Funkcija::ObrisiFunkcije();
	return 0;
}
