%{
#define YYDEBUG 1
#include <iostream>
#include <set>
#include <string>
#include <map>
#include <iterator>

#include "relacija.h"
#include "formula.h"
using namespace std;

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

extern int yylex();

map<string, set<int>*> tipovi;
map<string, Relacija*> relacije;
map<string, Formula*> formule;

%}
%union {
       string*   str_attr;
       int       int_attr;
       set<int>* set_attr;
       vector<int>* vector_attr;
       vector< set<int> >* vector_set_attr;
       Relacija* relacija_attr;
       Formula*  formula_attr;
}

%token TYPE RELATION QUESTION ANSWER PP IMP
%token <str_attr> ID
%token <int_attr> NUM
%type  <set_attr> type_def num_list
%type <relacija_attr> niz_ntorki rel_def
%type <vector_attr> ntorka
%type <vector_set_attr> niz_domena
%type <formula_attr> formula

%left IMP
%left '|'
%left '&'
%right '~'

%%

file : file line
     | 
     ;

line : TYPE ID '=' type_def ';' {
       tipovi[*$2] = $4;
       cout << "Type " << (*$2) << " defined as {";

       set<int>::const_iterator it;
       for (it = $4->begin();  it != $4->end(); ) {
	   cout << *it;
	   if (++it != $4->end())
	      cout << ", ";
       }
       cout << "}" << endl;
       delete $2;
     }
     | RELATION ID '(' niz_domena ')' '=' rel_def ';' {
       if ($7->korektna(*$4)) {
              cout << "Relation " << (*$2) << " defined" << endl;
              relacije[*$2] = $7;
       }
       else
	      cerr << "Error: " << *$2 << " incorrect. Skipping" << endl;
       delete $2;
     }
     | QUESTION ID '=' formula ';' {
	formule[*$2] = $4;
	cout << "Question " << *$2 << " defined" << endl;
	delete $2;
     }
     | ANSWER ID ';' {
       cout << "Answering : " << *$2 << endl;
       cout << "Answer: " << (formule[*$2]->vrednost() ? "TRUE" : "FALSE") << endl;
       delete $2;
     }
     ;

type_def : NUM PP NUM {
	$$ = new set<int>();
	for (int i = $1; i <= $3; i++)
	    $$->insert(i);
     }
     | '{' num_list '}' {
       $$ = $2;
     }
     ;

num_list : num_list ',' NUM {
       $$ = $1;
       $$->insert($3);
     }
     | NUM {
       $$ = new set<int>();
       $$->insert($1);
     }
     ;

rel_def : '{' niz_ntorki '}' {
	  $$ = $2;
     }
     ;

niz_ntorki : niz_ntorki ',' '(' ntorka ')'{
	     $$ = $1;
	     $$->dodaj(*$4);
	   }    
     | '(' ntorka ')' {
         $$ = new Relacija();
	 $$->dodaj(*$2);
     }
     ;

ntorka : ntorka ',' NUM {
	 $$ = $1;
	 $1->push_back($3);
       }
       | NUM {	
	 $$ = new vector<int>();
	 $$->push_back($1);
       }
       ;

niz_domena : niz_domena ',' ID {
	   $$ = $1;
	   $1->push_back(*tipovi[*$3]);
	   delete $3;
	   }
       | ID {
	   $$ = new vector< set <int> >();
	   $$ -> push_back(*tipovi[*$1]);
	   delete $1;
       }
       ;

formula : ID '(' ntorka ')' {
	  $$ = new Atom(*$1, *$3);
	  delete $1;
	}
	| formula '|' formula {
          $$ = new Disjunkcija($1, $3);
	}
	| formula '&' formula {
	  $$ = new Konjunkcija($1, $3);
	}
	| formula IMP formula {
	  $$ = new Implikacija($1, $3);
	}
	| '~' formula {
	  $$ = new Negacija($2);
	} 
	| '(' formula ')' {
	  $$ = $2;
	}
	;

%%

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