#include "lex_old.hpp"


//------------------------- LEXIC Module ------------------------//
//						  v 08 . 04 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//


//============================ HELPER ===================================

//--- Is <str> ---'
bool IsStr(char c, char *str)
{
	for (char* tmp = str; (*tmp) != '\0'; tmp++)
		if ( (*tmp) == c )	return true;

	return false;
};


//--- Is Digit ---
bool IsDigit(int c) { return isdigit(c); };


//--- Is Symbol ---
bool IsSymbol(int c) 
{
	if (c >= 'A' && c <= 'Z' ||
		c >= 'a' && c <= 'z' ||
		c == '_') 
		return true;

	return false;
};


//--- Is Operation ---
bool IsSpacer(int c) 
{
	return IsStr(c, "+-*/%()|[]<>={},&|;!");
};


//--- Is Special ---
int IsSpecial(int c) 
{ 
	char str[5];
	str[0] = ' ';	str[1] = '\t';	str[2] = 13;	str[3] = '\n';
	str[4] = '\0';
	
	return IsStr(c, str);
};

//-----------------------------------------------------------------------


char CLexic :: GetChar(bool back)
{
	if (back) 
		c = ungetc(fp);
	else
		c = getc(fp);

	return c;
};


void CLexic :: Make_Ok(Lexeme *lx, char *s, int is_only_char)
{
	lx->line = current_line;
	lx->sign = ok;
	delete [] lx->s;

	if  (is_only_char) {
		lx->s = new char[2];
		lx->s[0] = s[0];
		lx->s[1] = '\0';
	} else
		lx->s = strdup(s);	
}


bool CLexic :: IsStatusTrue(lxStatus t, char c)
{
	switch (t) {
		case N: if ( IsDigit(c) ) return true; 
		break;	
		
		case I: if ( IsDigit(c) || IsSymbol(c) ) return true; 
		break;	

		case K: if ( IsSymbol(c) ) return true;
		break;		

		case S: if ( c != '"') return true;
		
		default : break;
	}

	return false;
}


lxStatus CLexic :: GetStatus (char c)
{
	if ( IsDigit(c) )	return N;

	if ( IsStr(c, "?@$.") )	return I;

	if ( IsSymbol(c) )	return K;

	if ( c == ':' )		return A;

	if ( c == '"' )		return S;

	if ( IsSpacer(c) )	return H;

	return X;
}


void  CLexic :: NIKS (lxStatus t, Lexeme *a)
{
	if ( t == S ) 
		GetChar();

	char s[256];
	int i = 0;
		
		
	do {
		if (c == EOF)  { a->sign = not_ok_all; return; }
		s[i] = c;
		i++;
		GetChar();
	} while (IsStatusTrue(t, c));
		
	s[i] = '\0';
	Make_Ok(a, s);

	if (t == N)
		{ a -> id = lx_int_const;
		
		/*if (!IsSpacer(GetChar())) a->sign=not_ok_all;  
		else  {
			a->next = new Lexeme;
			a = a->next;
			Spacer (a);
		}*/

		a->next = GetNextLexem();
		a = a->next;
		if (a->id != lx_spacer) a->sign = not_ok_all;
	}

	if (t == S) a -> id = lx_str_const;
	if (t == K) a -> id = lx_keyword; 

	if (t == I) {
		switch (s[0]) {
			case '?' : a->id = lx_func;			break;
			case '@' : a->id = lx_label;		break;
			case '$' : a->id = lx_var;			break; 
			case '.' : a->id = lx_robotdata;	break; 
		}
		if (strlen(s)<2) a->sign = not_ok_all;
	}

}


Lexeme* CLexic :: GetNextLexem ()
{
	Lexeme *a = new Lexeme;
	
	a->next = NULL;

	if (stat == N || stat == I || stat == K) ; else GetChar();
	
	while (c != EOF) {
		if (c == 13) current_line++; 
		else if (!IsStr(c, " \n\t")) break;
		GetChar();
	}
	if (c == EOF) { a->sign = ok_all; return a; }

	switch (stat = GetStatus(c)) {
		case N: case I : case K : case S : NIKS(stat, a); break; 
		case A : 
			Assignment(a); 
			break;
		case H : 
			Spacer(a);
			break;	
		
		default : break;
	}
	return a;
};

void CLexic :: Spacer(Lexeme *a)
{
	Make_Ok(a, &c, 1);
	a->id = lx_spacer;
}			

void CLexic :: Assignment(Lexeme *a) 
{
	char s[3]; s[0] = c; s[2]='\0';

	if ( (s[1] = GetChar()) == EOF ) 
		return;

	if (s[1] == '=') {						
		Make_Ok(a, s);
		a->id = lx_assign;
	};
};


bool CLexic :: MakeAnalysis() 
{
	Lexeme *l = GetNextLexem ();
	begin = l;

	while ( l -> sign == ok ) {
		l -> next = GetNextLexem ();
		if ( l->next->sign == ok_all && l->next->s == NULL) {
			l->sign = ok_all;
			l->next = NULL;
			return true;
		}

		if (l->next->next == NULL)
			l = l -> next;
		else l = l -> next->next;
	}

	return false;
};


Lexeme* CLexic :: GetBeginLexeme()
{
	return begin;
}


void CLexic :: Print(Lexeme *l)
{	
	printf("-------------------------------------------------\n");
	printf(" Line    ::  %d		Type    ::  _",  l->line) ;
	switch (l->id) {
		case lx_err:		printf( "error" ); break;
		case lx_assign:		printf( "assign" ); break;
		case lx_spacer:		printf( "spacer" ); break;
		case lx_int_const:	printf( "int_const" ); break;
		case lx_str_const:	printf( "str_const" ); break;
		case lx_var:		printf( "var" ); break;
		case lx_label:		printf( "label" ); break;
		case lx_func:		printf( "func" ); break;
		case lx_keyword:	printf( "keyword" ); break;
		case lx_robotdata:	printf( "robotdata" ); break;
	}
	printf("\n Lexeme:  '%s'\n", l->s);
	if (l->sign == not_ok_all) printf("		:: [error]"); 
	
	l = l -> next;
	if (l->next != NULL) Print(l);
};


CLexic :: CLexic (char *s) 
{ 
	fp = fopen(s, "r"); 
	if (fp==NULL) Error.OnError("Robot command file not open.",-511); 
	
	begin = NULL; 
	current_line = 1;   
	c=0;  
	stat = H;
};

