%{
#define YYDEBUG 1

#include <cstdlib>
#include <iostream>
#include <string>
#include <map>
using namespace std;

void yyerror(char* s)
{
	cerr<<s<<endl;
	exit(EXIT_FAILURE);
}

extern int yylex();

int DaLiJeKonstanta(const string& str)
{
	return str.size() == 1 && (str[0] == 'T' || str[0] == 'F');
}

int DaLiJeSlovo(const string& str)
{
	return str.size() == 1 && (str[0] >= 'a' && str[0] <= 'z');
}



#include "formule.hpp"
#include "promenljive.hpp"
map<string, Formula*> formule;


%}

%left IMPL
%left DISJ
%left KONJ
%nonassoc NEG

%union
{
	string* string_a;
	Formula* formula_a;
};

%token VAR FORMULA VAL ASSIGN KONJ DISJ IMPL NEG
%token <string_a> ID
%type <formula_a> izraz
%%

program : program linija '\n' prompt
	| prompt
	;

linija : 
		VAR niz_varijabli 
	|	FORMULA niz_formula
	|	VAL ID
	{
		map<string, Formula*>::iterator i = formule.find(*$2);
		if (i != formule.end())
			cout <<"value of "<<*$2<<" is "<<(i->second->vrednost()?'T':'F')<<endl;
		else
			cout <<*$2<< " is undefined"<<endl;
		delete $2;
	}
	;

prompt : /* eps */	{cout<<">> ";}	
	;

niz_varijabli : niz_varijabli ',' varijabla
	| varijabla
	;
	
varijabla :
	ID ASSIGN ID		
	{
		if (!DaLiJeSlovo(*$1))
			yyerror("Var name should be [a-z]");
		if (!DaLiJeKonstanta(*$3))
			yyerror("Var value should be T or F");
		postavi_promenljivu((*$1)[0], (*$3)[0]);
		cout<<"Variable "<<(*$1)[0]<<" is set to "<<(*$3)[0]<<endl;
		delete $1;
		delete $3;
	}
	;

niz_formula : niz_formula ',' formula
	| formula
	;

formula : ID ASSIGN izraz
	{
		map<string, Formula*>::iterator i = formule.find(*$1);
		if (i != formule.end())
			delete i->second;
		formule[*$1] = $3;

		cout<<"Formula "<<*$1<<" is set to ";
		$3->ispisi(cout);
		cout<<endl;
		delete $1;
	}
	;

izraz : 
		ID
	{
		if (DaLiJeSlovo(*$1))
			$$ = new Slovo((*$1)[0]);
		else if (DaLiJeKonstanta(*$1))
			$$ = new Konstanta((*$1)[0]=='T');
		delete $1;
	}
	|	'(' izraz ')'
	{	$$ = $2;	}
	|	izraz KONJ izraz
	{
		$$ = new Konjunkcija($1, $3);
	}
	|	izraz DISJ izraz
	{
		$$ = new Disjunkcija($1, $3);
	}
	|	izraz IMPL izraz
	{
		$$ = new Implikacija($1, $3);
	}
	|	NEG izraz
	{
		$$ = new Negacija($2);
	}
	|	'[' ID ']'
	{
		map<string, Formula*>::iterator i = formule.find(*$2);
		if (i != formule.end())
			$$ = i->second->Klon();
		else
			cout <<*$2<< " is undefined"<<endl;
		delete $2;
	}
	;
		

%% 

void obrisi_formule()
{
	map<string, Formula*>:: iterator i;
	for (i = formule.begin(); i!=formule.end(); i++)
		delete i->second;
}

main()  
{
	yydebug = 0;
	yyparse();
	obrisi_formule();
}
