#include "bench_parser.h"
#include "config.h"
#include "err.h"
#include <stdexcept>
#include <string>
#include <sstream>
//---------------------------------------------------------------------------
void BenchParser::run (const std::string& fn) {
    l.init (fn.c_str());
    token=l.NextToken();
    inputs();
    outputs();
    assigns();
    l.CheckToken (token,LEX_B_NULL);
}
//---------------------------------------------------------------------------
void BenchParser::inputs() {
    while (token == LEX_B_INPUT) { 			// Outputs -> OUTPUT ( IDENT ) Outputs
	token=l.CheckNextToken(LEX_B_LPA);
	token=l.CheckNextToken(LEX_B_IDENT);		// input name
	//client_->haveInPort (l.Lex_AStr);
	client_->input->Vloz(l.Lex_AStr);
	token=l.CheckNextToken(LEX_B_RPA);
	token=l.NextToken();
    }
}
//---------------------------------------------------------------------------
void BenchParser::outputs() {
    while (token == LEX_B_OUTPUT) {			// Outputs -> OUTPUT ( IDENT ) Outputs
	token=l.CheckNextToken(LEX_B_LPA);
	token=l.CheckNextToken(LEX_B_IDENT);		// output name
	client_->output.push_back(l.Lex_AStr);
	token=l.CheckNextToken(LEX_B_RPA);
	token=l.NextToken();
    }
}
//---------------------------------------------------------------------------
void BenchParser::assigns()
{
	int f_token;								// function lex symbol
	std::string typ;
	typedef pair<std::string,Hradlo> Dvojce;
    while (token==LEX_B_IDENT) {				// Assigns -> IDENT ASSIGN Hradlo Assigns
		Hradlo hradl;
		std::string OutputName = l.Lex_AStr;
		token = l.CheckNextToken(LEX_B_ASSIGN);
		token = f_token = l.CheckNextToken(LexanBench :: isFunc, LEX_B_ANY_FUNC);
		switch (token) {
			case 5: typ = "and"; break;
			case 6: typ = "or"; break;
			case 7: typ = "nand"; break;
			case 8: typ = "nor"; break;
			case 9: typ = "xor"; break;
			case 10: typ = "xnor"; break;
			case 11: typ = "not"; break;
			case 12: typ = "buf"; break;
		}
	
		if (token != 9 && token != 10) {  // neni to ani xor ani xnor
			list<std::string> listInputNames;       // object #5
			hradlo (&listInputNames);				// set list of inputs
			hradl.typ = typ;
			hradl.inputs = listInputNames;
			hradl.hotove_hradlo[0] = NULL;
			hradl.hotove_hradlo[1] = NULL;

			client_->hradla.insert(Dvojce(OutputName,hradl));

			for (list<std::string>::iterator i=listInputNames.begin(); i!=listInputNames.end(); i++)
				client_->vystup_hradla.insert(*i);
		}
		else if (token == 9) {  // XOR(x,y) = x.!y + !x.y   OR(AND(x,NOT(y)),AND(NOT(x),y))
			list<std::string> listInputNames;       // object #5
			hradlo(&listInputNames);				// set list of inputs
			list<std::string>::iterator i = listInputNames.begin();
			std::string x = *i;
			std::string y = *(++i);
			hradl.typ = "or";
			hradl.inputs.push_back("muj"+x+"ANDNOT"+y);
			hradl.inputs.push_back("mujNOT"+x+"AND"+y);
			hradl.hotove_hradlo[0] = NULL;
			hradl.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce(OutputName,hradl));
			client_->vystup_hradla.insert("muj"+x+"ANDNOT"+y);
			client_->vystup_hradla.insert("mujNOT"+x+"AND"+y);

			Hradlo hradl2;
			hradl2.typ = "and";  // AND(x,NOT(y))
			hradl2.inputs.push_back(x);
			hradl2.inputs.push_back("mujNOT"+y);
			hradl2.hotove_hradlo[0] = NULL;
			hradl2.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("muj"+x+"ANDNOT"+y,hradl2));
			client_->vystup_hradla.insert(x);
			client_->vystup_hradla.insert("mujNOT"+y);

			Hradlo hradl3;
			hradl3.typ = "not";  // NOT(y)
			hradl3.inputs.push_back(y);
			hradl3.hotove_hradlo[0] = NULL;
			hradl3.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+y,hradl3));
			client_->vystup_hradla.insert(y);

			Hradlo hradl4;
			hradl4.typ = "and";  // AND(NOT(x),y)
			hradl4.inputs.push_back("mujNOT"+x);
			hradl4.inputs.push_back(y);
			hradl4.hotove_hradlo[0] = NULL;
			hradl4.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+x+"AND"+y,hradl4));
			client_->vystup_hradla.insert("mujNOT"+x);
			client_->vystup_hradla.insert(y);

			Hradlo hradl5;
			hradl5.typ = "not";  // NOT(x)
			hradl5.inputs.push_back(x);
			hradl5.hotove_hradlo[0] = NULL;
			hradl5.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+x,hradl5));
			client_->vystup_hradla.insert(x);
		}
		else if (token == 10) {  // XNOR(x,y) = x.y + !x.!y   OR(AND(x,y),AND(NOT(x),NOT(y)))
			list<std::string> listInputNames;       // object #5
			hradlo(&listInputNames);				// set list of inputs
			list<std::string>::iterator i = listInputNames.begin();
			std::string x = *i;
			std::string y = *(++i);
			hradl.typ = "or";
			hradl.inputs.push_back("muj"+x+"AND"+y);
			hradl.inputs.push_back("mujNOT"+x+"ANDNOT"+y);
			hradl.hotove_hradlo[0] = NULL;
			hradl.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce(OutputName,hradl));
			client_->vystup_hradla.insert("muj"+x+"AND"+y);
			client_->vystup_hradla.insert("mujNOT"+x+"ANDNOT"+y);

			Hradlo hradl2;
			hradl2.typ = "and";  // AND(x,y)
			hradl2.inputs.push_back(x);
			hradl2.inputs.push_back(y);
			hradl2.hotove_hradlo[0] = NULL;
			hradl2.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("muj"+x+"AND"+y,hradl2));
			client_->vystup_hradla.insert(x);
			client_->vystup_hradla.insert(y);

			Hradlo hradl4;
			hradl4.typ = "and";  // AND(NOT(x),NOT(y))
			hradl4.inputs.push_back("mujNOT"+x);
			hradl4.inputs.push_back("mujNOT"+y);
			hradl4.hotove_hradlo[0] = NULL;
			hradl4.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+x+"ANDNOT"+y,hradl4));
			client_->vystup_hradla.insert("mujNOT"+x);
			client_->vystup_hradla.insert("mujNOT"+y);

			Hradlo hradl5;
			hradl5.typ = "not";  // NOT(x)
			hradl5.inputs.push_back(x);
			hradl5.hotove_hradlo[0] = NULL;
			hradl5.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+x,hradl5));
			client_->vystup_hradla.insert(x);

			Hradlo hradl3;
			hradl3.typ = "not";  // NOT(y)
			hradl3.inputs.push_back(y);
			hradl3.hotove_hradlo[0] = NULL;
			hradl3.hotove_hradlo[1] = NULL;
			client_->hradla.insert(Dvojce("mujNOT"+y,hradl3));
			client_->vystup_hradla.insert(y);
		}


    }
}
//---------------------------------------------------------------------------
void BenchParser::hradlo (list<std::string> *listInputNames) {
//    int id=0;
    token=l.CheckNextToken(LEX_B_LPA);
    token=l.NextToken();
    idents(listInputNames);
    if(token==LEX_B_RPA) {
	token=l.NextToken();
    } else {
	throw SyntaxException (TokenReason (l, token, LEX_B_RPA), LexPosition(l));
    }
}
//---------------------------------------------------------------------------
void BenchParser::idents(list<std::string> *listInputNames)
{
   if(token==LEX_B_IDENT) // Idents -> IDENT R_O_Idents
   {
      listInputNames->push_back(l.Lex_AStr);
      token=l.NextToken();
      r_o_idents(listInputNames);
   }
   else
   {
      throw SyntaxException (TokenReason (l, token, LEX_B_IDENT), LexPosition(l));
   }
}
//---------------------------------------------------------------------------
void BenchParser::r_o_idents(list<std::string> *listInputNames)
{
   if(token!=LEX_B_COMMA) return; 	// R_O_Idents -> , IDENT R_O_Idents
   token=l.CheckNextToken(LEX_B_IDENT);
   listInputNames->push_back(l.Lex_AStr);
   token=l.NextToken();
   r_o_idents(listInputNames);
}
//---------------------------------------------------------------------------
void BenchParserClient :: haveDesign (void) {}
void BenchParserClient :: endDesign (void) {}
void BenchParserClient :: haveInPort  (const std::string& portName) {}
void BenchParserClient :: haveOutPort (const std::string& portName) {}
void BenchParserClient :: haveAssign (const std::string& OutputName, 
			     int function, 
			     const list<std::string> listInputNames) {}
BenchParserClient :: ~BenchParserClient () { }
