#include <stdio.h>
#include "cQueue.cpp"
#include "cLexer.h"

int SkipSpace(char *p){
	char *pOld = p;
	while(*p != '\0' && *p == 32) p ++;
	if(*p == '\0') return -1;
	return p - pOld;
}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
cRGToBG::cRGToBG(){
	ParseIdx = NULL;

}

cRGToBG::~cRGToBG(){
	if(ParseIdx) delete [] ParseIdx;
}

int cRGToBG::SetGrammar(sRegularGrammar *_prg, int _RGCount){
	int idx, i;

	prg = _prg;
	RGCount = _RGCount;

	BGCount = 0;
	if(ParseIdx) delete [] ParseIdx;
	ParseIdx = new int[RGCount];
	for(i = 0; i < RGCount; i ++){
		ParseIdx[i] = -1;
	}

	for(i = 0; i < RGCount; i ++){
		if(ParseIdx[i] < 0){
			if(ExtractGrammar(prg[i].Grammar, &idx) < 0) return -1;
			ParseIdx[i] =  idx;
		}
	}

	return BGCount;
}

void cRGToBG::GetBinaryGrammar(sBRG *pbrg){
	int i;
	int Count = 0;

//	printf("\n Parsing Result.\n");
	while(brgq.Get(pbrg)){
		for(i = 0; i < RGCount; i ++){
			if(pbrg->RealIdx == ParseIdx[i]) break;
		}
		if(i == RGCount)
			pbrg->RealIdx = -1;
		else 
			pbrg->RealIdx = i;


/*		printf("%d : \t", Count);
		Count ++;
		switch(pbrg->Relation){
		case GR_ASCII: printf("ASCII\t"); break;
		case GR_AND: printf("AND\t"); break;
		case GR_OR: printf("OR\t"); break;
		case GR_REPEAT: printf("REPEAT\t"); break;
		}
		if(pbrg->Relation == GR_ASCII){
			printf("%c-%c, ", pbrg->First, pbrg->Second);
		}else{
			printf("F:%d, S:%d, ", 
				pbrg->First, pbrg->Second);
		}
		printf("%d\n", pbrg->RealIdx);
*/
		pbrg ++;
	}
}

int cRGToBG::ExtractGrammar(char *pg, int *idx){
	sBRG brg;
	char *pgOld;
	int Count;

	pgOld = pg;

	// 공백을 무시한다.
	Count = SkipSpace(pg);
	if(Count < 0) return -1;
	pg += Count;

	Count = ExtractOr(pg, idx);
	brg.First = *idx;
	if(Count < 0) return -1;
	pg += Count;

	while(true){
		Count = SkipSpace(pg);
		if(Count < 0) break;
		pg += Count;
		if(*pg != '|') break;
		pg ++;
		Count = ExtractOr(pg, idx);
		brg.Second = *idx;
		if(Count < 0) return -1;
		pg += Count;
		// Or 문법이 완성됨
		brg.Relation = GR_OR;
		brg.RealIdx = BGCount;
		brgq.Add(brg);
		brg.First = BGCount;
		*idx = BGCount;
		BGCount ++;
	}
	return pg - pgOld;
}

int cRGToBG::ExtractOr(char *pg, int *idx){
	sBRG brg;
	char *pgOld;
	int Count;

	pgOld = pg;

	// 공백을 무시한다.
	Count = SkipSpace(pg);
	if(Count < 0) return 0;
	pg += Count;

	Count = ExtractAnd(pg, idx);
	brg.First = *idx;
	if(Count < 0) return -1;
	pg += Count;

	while(true){
		Count = SkipSpace(pg);
		if(Count < 0) break;
		pg += Count;
		if(*pg != '&') break;
		pg ++;
		Count = ExtractAnd(pg, idx);
		brg.Second = *idx;
		if(Count < 0) return -1;
		pg += Count;
		// & 문법이 완성됨
		brg.Relation = GR_AND;
		brg.RealIdx = BGCount;
		brgq.Add(brg);
		brg.First = BGCount;
		*idx = BGCount;
		BGCount ++;
	}
	return pg - pgOld;
}


int cRGToBG::ExtractAnd(char *pg, int *idx){
	sBRG brg;
	char *pgOld;
	int Count;

	pgOld = pg;

	Count = SkipSpace(pg);
	if(Count < 0) return -1;
	pg += Count;

	Count = ExtractStar(pg, idx);
	brg.First = *idx;
	if(Count < 0) return -1;
	pg += Count;

	Count = SkipSpace(pg);
	if(Count < 0) return pg - pgOld;
	pg += Count;

	if(*pg == '*'){
		pg ++;
		// * 문법이 완성됨
		brg.Relation = GR_REPEAT;
		brg.Second = 0;
		brg.RealIdx = BGCount;
		brgq.Add(brg);
		*idx = BGCount;
		BGCount ++;

	}
	return pg - pgOld;
}

int cRGToBG::ExtractStar(char *pg, int *idx){
	char *pgOld;
	int Count;

	pgOld = pg;

	Count = SkipSpace(pg);
	if(Count < 0) return -1;
	pg += Count;

	if(*pg == '('){
		pg ++;
		Count = ExtractGrammar(pg, idx);
		pg += Count;

		Count = SkipSpace(pg);
		if(Count < 0) return -1;
		pg += Count;

		if(*pg != ')') return -1;
		pg ++;
		return pg - pgOld;
	}else if(isalpha(*pg)){
		return Count + ExtractSymbol(pg, idx);
	}else if(isdigit(*pg)){
		return Count + ExtractRange(pg, idx);
	}
	return -1;

}
// Lexical 분석기
int cRGToBG::ExtractSymbol(char *pg, int *idx){
	int i;
	char buff[256];
	char *pgOld;
	
	pgOld = pg;

	if(!isalpha(*pg)) return -1;
	pg ++;
	if(*pg == '\0') return 1;

	while(isalnum(*pg)){
		pg ++;
		if(*pg == '\0') break;
	}
	strncpy(buff, pgOld, pg - pgOld);
	buff[pg - pgOld] = '\0';
	for(i = 0; i < RGCount; i ++){
		if(stricmp(prg[i].Symbol, buff) == 0)
			break;
	}
	if(i == RGCount) return -1;
	if(ParseIdx[i] < 0){
		if(ExtractGrammar(prg[i].Grammar, idx) < 0) return -1;
		ParseIdx[i] = *idx;
	}else{
		*idx = ParseIdx[i];		
	}
	return pg - pgOld;
}
/*
int cLexer::ExtractRange(char *pInput, sBRG *pBRG, int Limit){
	char *p;
	int Count;

	p = pInput;

	Low = GetNumber(p);
	if(Low < 0) return -1;
	if(*p != '-') return -1; 
	pInput ++;
	High = GetNumber(pInput);
	if(High < 0) return -1;
	pBRG->Relation = GR_ASCII;
}
*/
/*
int GetNumber(char *&pInput){
	int n = 0;

	while(*pInput != '\0' && isdigit(*pInput)){
		n *= 10;
		n += *pInput - '0';
		*pInput ++;
	}
	return n;
}
*/
int cRGToBG::ExtractRange(char *pg, int *idx){
	sBRG brg;
	char *pgOld;
	int Count;

	pgOld = pg;

	Count = ExtractNumber(pg, &brg.First);
	if(Count < 0) return -1;
	pg += Count;

	if(*pg != '-') return -1;
	pg ++;

	Count = ExtractNumber(pg, &brg.Second);
	if(Count < 0) return -1;
	pg += Count;

	brg.Relation = GR_ASCII;
	brg.RealIdx = BGCount;
	brgq.Add(brg);
	*idx = BGCount;
	BGCount ++;
	
	return pg - pgOld;
}

int cRGToBG::ExtractNumber(char *pg, int *Value){
	char *pgOld;
	int n = 0;

	pgOld = pg;

	while(*pg != '\0' && isdigit(*pg)){
		n *= 10;
		n += *pg - '0';
		pg ++;
	}
	if(pg == pgOld) return -1;
	*Value = n;
	return pg - pgOld;
}




//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
cLexer::cLexer(){
	Grammars = NULL;
}

cLexer::~cLexer(){
	if(Grammars) delete [] Grammars;

}

BOOL cLexer::SetGrammar(sRegularGrammar *_RG, int _RGCount){
	cRGToBG Converter;

	GrammarCount = Converter.SetGrammar(_RG, _RGCount);
	if(GrammarCount < 0) return FALSE;

	if(Grammars) delete [] Grammars;
	Grammars = new sBRG[GrammarCount];
	if(!Grammars) return FALSE;

	Converter.GetBinaryGrammar(Grammars);
	return TRUE;
}



int cLexer::GetLexeme(char *&pInput, char *pLexeme, int MaxLen){
// 임력 문자열로부터 하나의 렉심을 얻어낸다.
	int Count;
	int i;
	
	for(i = GrammarCount - 1; i >= 0; i --){
		if(Grammars[i].RealIdx < 0) continue;
		Count = IsMatch(i, pInput, pLexeme);
		if(Count > 0){
			pInput += Count;
			pLexeme[Count] = '\0';
			return Grammars[i].RealIdx;
		}
	}
	return -1;
}

int cLexer::IsMatch(int idx, char *pInput, char *pLexeme){
// 하나의 문법에 대해 맞는지 틀린지를 검사한다.
	sBRG *p;
	int Count, Count2;

	p = &Grammars[idx];
	switch(p->Relation){
	case GR_ASCII: // 문법이 문자영역일 경우
		if(*pInput == '\0') return -1;
		if(p->First <= *pInput && *pInput <= p->Second){
			*pLexeme = *pInput;
			pInput ++;
			pLexeme ++;
//			*pLexeme = '\0';
			return 1;
		}
		break;
	case GR_AND:
		Count = IsMatch(p->First, pInput, pLexeme);
		if(Count >= 0){
			Count2 = IsMatch(p->Second, pInput + Count, pLexeme + Count);
			if(Count2 >= 0) return Count + Count2;
		}			
		break;
	case GR_OR:
		Count = IsMatch(p->First, pInput, pLexeme);
		if(Count >= 0) return Count;
		Count = IsMatch(p->Second, pInput, pLexeme);
		if(Count >= 0) return Count;
		break;
	case GR_REPEAT:
		Count2 = 0; 
		while(true){
			Count = IsMatch(p->First, pInput, pLexeme);
			if(Count <= 0) break;
			pInput += Count;
			pLexeme += Count;
			Count2 += Count;
		}
//		if(Count2 == 0) break;
		return Count2;
	}
	return -1;
}

