#include "StdAfx.h"
#include "Lexeme.h"
#include "LexAnalyser.h"
#include <string.h>
//#include "SyntaxRichTextBox.h"
namespace Lex
{
	//int ind=0;
	int end=0;
	LexAnalyser::LexAnalyser(void)
	{
		nBufPos=0;
		c = '\0';
		//fp = NULL;
		//nCN = 0;
		//nID = 0;
	}

	LexAnalyser::~LexAnalyser(void)
	{
	}

	void LexAnalyser::clear()
	{
		memset(buf,0,sizeof(buf));
		nBufPos = 0;
	}
	void LexAnalyser::clear2()
	{
		for(int ind10=0;ind10<80;ind10++)buff[ind10]='\0';
		nBufPos = 0;
	}

	// Дописывание символа c в конец буфера buf
	void LexAnalyser::add(void)
	{
		if(nBufPos!=BUFSIZE)buf[nBufPos++] = c;
		else throw 10;
	}
		void LexAnalyser::add2(void)
	{
		if(nBufPos!=BUFSIZE)buff[nBufPos++] = c2;
		else throw 10;
	}
	// Проверяет, является ли строка в buf служебным словом. Если "да" - возврашает номер в таблице CC
	// Если нет - возврашает -1
	int LexAnalyser::isCC(void)
	{
		for(int i=0; i < sizeof(CC)/sizeof(char*); i++)
		{
			if(strcmp(CC[i],buf) == 0) return i;
		}
		return -1;
	}

		int LexAnalyser::isCC2(void)
	{
		for(int i=0; i < sizeof(CC2)/sizeof(wchar_t*); i++)
		{
			if(wcscmp(CC2[i],buff) == 0) return i;
		}
		return -1;
	}
	// Проверяет, является ли строка в buf разделителем. Если "да" - возврашает номер в таблице CC
	// Если нет - возврашает -1
	int LexAnalyser::isDC(void)
	{
		for(int i=0; i < sizeof(DC)/sizeof(char*); i++)
		{
			if(strcmp(DC[i],buf) == 0) return i;
		}
		return -1;
	}

		int LexAnalyser::isDC2(void)
	{
		for(int i=0; i < sizeof(DC)/sizeof(char*); i++)
		{
			if(wcscmp(DC2[i],buff) == 0) return i;
		}
		return -1;
	}


	//int LexAnalyser::AddConstant(void)
	//{
	//	for(int i=0; i < nCN; i++)
	//	{
	//		if(strcmp(CN[i],buf) == 0) return i;
	//	}

	//	//Проверка переполнения
	//	if(nCN == sizeof(CN)/sizeof(char*))
	//	{
	//		cout << "Переполнен массив констант" << endl;
	//	}
	//	
	//	// Добавляем новый элемент в таблицу констант
	//	CN[nCN] = _strdup(buf);
	//	return nCN++;
	//}
	int LexAnalyser::AddConstant(void){
		CN.push_back(buf);
		return(CN.size());
	}
	//int LexAnalyser::AddIdent(void)
	//{
	//	for(int i=0; i < nID; i++)
	//	{
	//		if(strcmp(ID[i],buf) == 0) return i;
	//	}
	//
	//	//Проверка переполнения
	//	if(nID == sizeof(ID)/sizeof(char*))
	//	{
	//		cout << "Perepolnen massiv identeficatorov" << endl;
	//	}
	//	
	//	// Добавляем новый элемент в таблицу идентификаторов
	//	ID[nID] = _strdup(buf);
	//	return nID++;
	//
	//}
	int LexAnalyser::AddIdent(void){
		int ind2=0;
		//cout<<ID.size();
		vector<char*>::iterator p;
		p=ID.begin();
		while(p!=ID.end()){
		if(strcmp(*p,buf) == 0) return ind2;
		p++;
		ind2++;
		}
		ID.push_back(buf);
		return(ID.size());
	}

	int LexAnalyser::Analyze(const wchar_t*inFileName, const wchar_t*outFileName)
	{
		//int a;

		ifstream f(inFileName);
		ofstream fout(outFileName);

		if(!f){cerr<<"err";return(1);}
		gc(f);
		TC=H;
		try{
		do
		{
			switch(TC)
			{
			case H:
				if(c == ' ')gc(f);
				else if(c=='\n'){
				clear();TC=H;gc(f);}
				else if(isalpha(c))
				{ 
					clear();
					add();
					gc(f);
					TC = ID1;
				}
				else if (isdigit(c))
				{
					//d = c-'0'; 
					// десятичное значение
					this->add();
					gc(f);
					TC = NUM; 
				}
				else if(c=='{'||c=='}'||c=='*'||c=='('||c==')'||c==';'||c=='+'||c=='-'||c==',')//и так далее дописать подумать как сделать
					//операцию сравнения == и другие такое а также комментарии //
				{
					add();
					TC = DLM;
					gc(f);
				}
				else if(c=='/'){//{выполняем данные махинации для проверки является это комментарием или просто делением
				char d=c;
				gc(f);
				if(c=='*'){gc(f);TC=COM;}
				else{
				char e=c;
				c=d;
				d=e;
				add();
				c=d;
				TC=DLM;/////////////////////////}
				}}
				//else if(c=='+'){//{выполняем данные махинации для проверки является это ++ или просто +
				//char d=c;
				//gc(f);
				//if(c=='+'){//{
				//char h=c;
				//c=d;
				//add();//////////////все-таки ++
				//c=h;
				//add();
				//gc(f);
				//TC=DLM;}//}
				//else{/////
				//char e=c;
				//c=d;
				//d=e;////// обычный + увы :(
				//add();
				//c=d;
				//TC=DLM;/////////////////////////}
				//}}
				//else if(c=='-'){//{выполняем данные махинации для проверки является это -- или просто -
				//char d=c;
				//gc(f);
				//if(c=='-'){//{
				//char h=c;
				//c=d;
				//add();//////////////все-таки --
				//c=h;
				//add();
				//gc(f);
				//TC=DLM;}//}
				//else{/////
				//char e=c;
				//c=d;
				//d=c;////// обычный - увы :(
				//add();
				//c=d;
				//TC=DLM;/////////////////////////}
				//}}
				else if(c=='='){//{выполняем данные махинации для проверки является это == или просто =
				char d=c;
				gc(f);
				if(c=='='){//{
				char h=c;
				c=d;
				add();//////////////все-таки ==
				c=h;
				add();
				gc(f);
				TC=DLM;}//}
				else{/////
				char e=c;
				c=d;
				d=e;////// обычный = увы :(
				add();
				c=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c=='>'){//{выполняем данные махинации для проверки является это >= или просто >
				char d=c;
				gc(f);
				if(c=='='){//{
				char h=c;
				c=d;
				add();//////////////все-таки >=
				c=h;
				add();
				gc(f);
				TC=DLM;}//}
				else{/////
				char e=c;
				c=d;
				d=e;////// обычный > увы :(
				add();
				c=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c=='<'){//{выполняем данные махинации для проверки является это <= или просто <
				char d=c;
				gc(f);
				if(c=='='){//{
				char h=c;
				c=d;
				add();//////////////все-таки <=
				c=h;
				add();
				gc(f);
				TC=DLM;}//}
				else{/////
				char e=c;
				c=d;
				d=e;////// обычный < увы :(
				add();
				c=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c=='!'){//{выполняем данные махинации для проверки является это != или просто !
				char d=c;
				gc(f);
				if(c=='='){//{
				char h=c;
				c=d;
				add();//////////////все-таки !=
				c=h;
				add();
				gc(f);
				TC=DLM;}//}
				else{/////
				char e=c;
				c=d;
				TC=ER;/////////////////////////}
				}}
				else if(c=='"'){
				gc(f);
				TC=CHCONST;
				}
				else if(c=='\0') // EOF ???
				{
					// Создаём новую лексему
					/////    Lexeme l(...); // 
					// Добавляем лексему в таблице лексем
					// 
					TC=FIN;
				}
				else 
				{
					fout<<"Oshibka"<<endl;
					TC = ER;
				}
				break;
			case CHCONST:
					{
				while((c!='"')&&(c!='\0')){
				add();
				gc(f);
				if(c=='\0')throw "Кавычки";
				}
					int k = this->AddConstant();
					int ind3=CN.size()-1;
					Lexeme LL=Lexeme(Type_CN,CN[ind3]); // Записать в таблицу лекксем
					//LexArray[ind]=LL;
					LexArray.push_back(LL);
					
					fout<< "Constanta"<<LL<<endl;
					clear();
					gc(f);
					TC = H;
					break;
					}
			case ID1:
				if((isalpha(c) || isdigit(c))&&(c!='\n'))
				{
					add();
					gc(f);
				}
				else
				{
					int i = -1;

					i = this->isCC();
					if(i >=0) 
					{
						// Служебное слово
						Lexeme Lex1(Type_CC, CC[i]); //-->> 
						//LexArray[ind]=Lex1;
						LexArray.push_back(Lex1);
						//ind++;
						fout<<"Slugebnoye slovo"<<Lex1<<endl;
						clear();
						TC = H;
					}
					else
					{
						// Не служебное слово - иднтификатор, добавляем в таблицу
						i = this->AddIdent();
						int ind3=ID.size()-1;
						Lexeme Lex1(Type_ID, ID[ind3]); //-->>
						LexArray.push_back(Lex1);
						//LexArray[ind]=Lex1;
						//ind++;
						fout<<"Identeficator"<<Lex1<<endl;
						clear();
						TC = H;
					}

				}
				break; //case ID
			case NUM:
				if(isdigit(c) || c == '.')
				{
					this->add();
					gc(f);
				}
				else
				{
					int k = this->AddConstant();
					int ind3=CN.size()-1;
					Lexeme LL=Lexeme(Type_CN,CN[ind3]); // Записать в таблицу лекксем
					//LexArray[ind]=LL;
					LexArray.push_back(LL);
					fout<< "Constanta"<<LL<<endl;
					clear();
					TC = H;
				}
				break; // case NUM
			case COM:{
				char k=c;
					while(!((k=='*')&&(c=='/'))&&(k!='\0')&&(c!='\0')){
				k=c;
				gc(f);
				if((k=='\0')||(c=='\0'))throw "Kommentariy";
				}TC=H;
				fout<<"Kommentariy"<<endl;
				gc(f);}
				break; // case COM
			case DLM:
				{int k = this->isDC();
				Lexeme LL=Lexeme(Type_DC,DC[k]);
				//LexArray[ind]=LL;
				LexArray.push_back(LL);
				fout<<"Razdelitel";
				fout<<LL<<endl;
				clear();
				TC = H;}
				//
				break; //case DLM
			case ER:
				{
				}
				break;
			case FIN:
				break;
			} // end of switch(TC)
		} while (TC!= FIN && TC != ER);
		}
		catch(int k){cerr<<"Too long Identificator or Constant"<<endl;}
		catch(char*k){if(strcmp(k,"Kavichki")==0)cerr<<"Ne zakritiye kavichki"<<endl;
		else if(strcmp(k,"Kommentariy")==0)cerr<<"Ne zakritiy kommentariy"<<endl;}
		return 0;
	}

	char LexAnalyser::gc(ifstream& f)
	{f.get(c);
	if(f.eof()){
	end=1;
	c='\0';
	return '\0';}
	else return c;
	}


////
////
int LexAnalyser::Syntax(const wchar_t * stroka,vector<ints> &lexemmes)
	{	ints intss;
		int position=0;
		int length=0;
		int lextype=0;
		int ind=0;
		int ind2=0;
		int i1=0;
		cur=0;
		clear2();
		gc2(stroka);
		ind++;
		TC=H;
		try{
		do
		{
			switch(TC)
			{
			case H:
				if(c2 == L' '){gc2(stroka);ind++;}
				else if(c2==L'\n'){
				clear2();TC=H;gc2(stroka);
				ind++;}
				else if(isalpha(c2))
				{ 
					clear2();
					add2();
					gc2(stroka);
					position=ind;
					ind++;
					TC = ID1;
				}
				else if (isdigit(c2))
				{
					//d = c-'0'; 
					// десятичное значение
					this->add2();
					position=ind;
					gc2(stroka);
					ind++;
					TC = NUM; 
				}
				else if(c2==L'{'||c2==L'}'||c2==L'*'||c2==L'('||c2==L')'||c2==L';'||c2==L'+'||c2==L'-'||c2==L',')//и так далее дописать подумать как сделать
					//операцию сравнения == и другие такое а также комментарии //
				{
					position=ind;
					add2();
					TC = DLM;
					gc2(stroka);
					ind++;
				}
				else if(c2==L'/'){//{выполняем данные махинации для проверки является это комментарием или просто делением
				position=ind;
				wchar_t d=c2;
				gc2(stroka);
				ind++;
				if(c=='*'){gc2(stroka);ind++;TC=COM;}
				else{
				wchar_t e=c2;
				c2=d;
				d=e;
				add2();
				c2=d;
				TC=DLM;/////////////////////////}
				}}
				//else if(c2==L'+'){//{выполняем данные махинации для проверки является это ++ или просто +
				//position=ind;
				//wchar_t d=c2;
				//gc2(stroka);
				//ind++;
				//if(c2==L'+'){//{
				//wchar_t h=c2;
				//c2=d;
				//add2();//////////////все-таки ++
				//c2=h;
				//add2();
				//gc2(stroka);
				//ind++;
				//TC=DLM;}//}
				//else{/////
				//wchar_t e=c2;
				//c2=d;
				//d=e;////// обычный + увы :(
				//add2();
				//c2=d;
				//TC=DLM;/////////////////////////}
				//}}
				//else if(c2==L'-'){//{выполняем данные махинации для проверки является это -- или просто -
				//position=ind;
				//wchar_t d=c2;
				//gc2(stroka);
				//ind++;
				//if(c2==L'-'){//{
				//wchar_t h=c2;
				//c2=d;
				//add2();//////////////все-таки --
				//c2=h;
				//add2();
				//gc2(stroka);
				//ind++;
				//TC=DLM;}//}
				//else{/////
				//wchar_t e=c2;
				//c2=d;
				//d=c2;////// обычный - увы :(
				//add2();
				//c2=d;
				//TC=DLM;/////////////////////////}
				//}}
				else if(c2==L'='){//{выполняем данные махинации для проверки является это == или просто =
				position=ind;
				wchar_t d=c2;
				gc2(stroka);
				ind++;
				if(c2==L'='){//{
				wchar_t h=c2;
				c2=d;
				add2();//////////////все-таки ==
				c2=h;
				add2();
				gc2(stroka);
				ind++;
				TC=DLM;}//}
				else{/////
				wchar_t e=c2;
				c2=d;
				d=e;////// обычный = увы :(
				add2();
				c2=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c2==L'>'){//{выполняем данные махинации для проверки является это >= или просто >
				position=ind;
				wchar_t d=c2;
				gc2(stroka);
				ind++;
				if(c2==L'='){//{
				wchar_t h=c2;
				c2=d;
				add2();//////////////все-таки >=
				c2=h;
				add2();
				gc2(stroka);
				ind++;
				TC=DLM;}//}
				else{/////
				wchar_t e=c2;
				c2=d;
				d=e;////// обычный > увы :(
				add2();
				c2=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c2==L'<'){//{выполняем данные махинации для проверки является это <= или просто <
				position=ind;
				wchar_t d=c2;
				gc2(stroka);
				ind++;
				if(c2==L'='){//{
				wchar_t h=c2;
				c2=d;
				add2();//////////////все-таки <=
				c2=h;
				add2();
				gc2(stroka);
				ind++;
				TC=DLM;}//}
				else{/////
				wchar_t e=c2;
				c2=d;
				d=e;////// обычный < увы :(
				add2();
				c2=d;
				TC=DLM;/////////////////////////}
				}}
				else if(c2==L'!'){//{выполняем данные махинации для проверки является это != или просто !
				position=ind;
				wchar_t d=c2;
				gc2(stroka);
				ind++;
				if(c2==L'='){//{
				wchar_t h=c2;
				c2=d;
				add2();//////////////все-таки !=
				c2=h;
				add2();
				gc2(stroka);
				ind++;
				TC=DLM;}//}
				else{/////
				wchar_t e=c2;
				c2=d;
				TC=ER;/////////////////////////}
				}}
				else if(c2==L'"'){
				position=ind;
				gc2(stroka);
				ind++;
				TC=CHCONST;
				}
				else if(c2==L'\0') // EOF ???
				{
					// Создаём новую лексему
					/////    Lexeme l(...); // 
					// Добавляем лексему в таблице лексем
					// 
					TC=FIN;
				}
				else 
				{
					//fout<<"Oshibka"<<endl;
					TC = ER;
				}
				break;
			case CHCONST:
					{
				clear2();
				bool b=false;
				if(c2==L'\0')b=true;
				while((c2!=L'"')&&(c2!=L'\0')&&(c2!=L'\n')){
				add2();
				gc2(stroka);
				ind++;
				if(c2==L'\0'||c2==L'\n')b=true;
				}
					intss.len=wcslen(buff)+2;
					if(b)
					{
						int sum=0;
						for(int ind2=0;ind2<lexemmes.size();ind2++)sum=sum+lexemmes[ind2].len;
						intss.len=wcslen(stroka)-sum;
					}
					intss.pos=position;
					intss.type=Type_CN;
					lexemmes.push_back(intss);
					ind2++;
					//fout<< "Constanta"<<LL<<endl;
					clear2();
					if(b)throw"err";
					gc2(stroka);
					ind++;
					TC = H;
					break;
					}
			case ID1:
				if((isalpha(c2) || isdigit(c2))&&(c2!=L'\n'))
				{
					add2();
					gc2(stroka);
					ind++;
				}
				else
				{
					int i = -1;

					i = this->isCC2();
					if(i >=0) 
					{
						// Служебное слово
						intss.len=wcslen(buff);
						intss.pos=position;
						intss.type=Type_CC;
						lexemmes.push_back(intss);
						ind2++;
						clear2();
						TC = H;
					}
					else
					{
						// Не служебное слово - иднтификатор, добавляем в таблицу
						intss.len=wcslen(buff);
						intss.pos=position;
						intss.type=Type_ID;
						lexemmes.push_back(intss);
						ind2++;
						//fout<<"Identeficator"<<Lex1<<endl;
						clear2();
						TC = H;
					}

				}
				break; //case ID
			case NUM:
				if(isdigit(c) || c2 == L'.' ||c2 == L'e')
				{
					if(c2==L'e')
					{
						this->add2();
						gc2(stroka);
						ind++;
						if((c2==L'+')||(c2==L'-'))
						{
							this->add2();
							gc2(stroka);
							ind++;
						}
					}
					else
					{
						this->add2();
						gc2(stroka);
						ind++;
					}
				}
				else
				{

					intss.len=wcslen(buff);
					intss.pos=position;
					intss.type=Type_CN;
					lexemmes.push_back(intss);
					ind2++; // Записать в таблицу лекксем
					//fout<< "Constanta"<<LL<<endl;
					clear2();
					TC = H;
				}
				break; // case NUM
			case COM:{
				wchar_t k=c;
					while(!((k==L'*')&&(c==L'/'))&&(k!=L'\0')&&(c!=L'\0')){
				k=c;
				gc2(stroka);
				ind++;
				if((k==L'\0')||(c==L'\0'))throw "Kommentariy";
				}TC=H;
				//fout<<"Kommentariy"<<endl;
				gc2(stroka);
				ind++;}
				break; // case COM
			case DLM:
				{int k = this->isDC2();
				intss.len=wcslen(buff);
				intss.pos=position;
				intss.type = Type_DC; //////////////
				lexemmes.push_back(intss);
				ind2++;
				clear2();
				TC = H;}
				//
				break; //case DLM
			case ER:
				{
				}
				break;
			case FIN:
				break;
			} // end of switch(TC)
		} while (TC!= FIN && TC != ER);
		}
		catch(int k){}
		catch(char*k){}
		return 0;
	}


	wchar_t LexAnalyser::gc2(const wchar_t* stroka)
	{if(cur < (int) wcslen(stroka)){c2=stroka[cur];cur++;return stroka[cur];}
	else {c2='\0';return '\0';}
	}


	Lexeme LexAnalyser::get(int num)
	{if(num<=(int) LexArray.size())return(LexArray[num]);
	else throw "error";
	}


	}

