#ifndef LEX_DEF
 #define LEX_DEF


//------------------- LEXICAL ANALYZER Module -------------------//
//						  v 25 . 04 .  2007						 //
//																 //
//								MT								 //
//---------------------------------------------------------------//



//---------------------- Incudes 
#include "stdio.h"
#include "ctype.h"
#include "strings.h"
#include "../../ui/onerror.hpp"
//====================== Includes


//---------------------- Defines
#define PL_ERROR "___error"
//====================== Defines

//--- Functions ---
bool IsStr(char c, char *str);

//--- State enum
enum EState  {
	S_INIT,
	S_NTHNG,
	S_ERR,

	S_ROBOT, 
	S_VARBL,
	S_ASSGN,
	S_SPACE,
	S_NUMBR,
	S_STRNG,
	S_LABEL,
	S_FUNCT,
	S_KEYWD
};


//--- Type enum
enum lxType {	
	lx_err,
	lx_begin,

	lx_robotdata,
	lx_assign,
	lx_spacer,			
	lx_int_const,		
	lx_str_const,		
	lx_var,		
	lx_label,			
	lx_func,		
	lx_keyword 
};


//--- Correct enum
enum lxCorrect { 
	ok,
	not_ok 
};


//--- Lexeme class
class Lexeme 
{
public:
	Lexeme *next;
	
	char *s;
	int line;
	lxType id;	
	lxCorrect sign;	

public:

	void MakeOk(char *s, int current_line);

	//--- Constructor 
	Lexeme () 
	{ sign = not_ok; s=strdup(PL_ERROR); next = NULL; id = lx_err; };
	//--- Destructor
	~Lexeme() 
	{ if (s != NULL) delete[] s;	if (next != NULL) delete next; };
};



//--- Lexic class ---
class CLexic 
{
public : 
//--- CBuffer ---
	class CBuffer 
	{
	private : 
		char *s;
		int count;
		
	public :
		CBuffer() { s = NULL; Clear(); };
		~CBuffer() { delete [] s; };

		//--- Clear buffer
		void Clear() 
		{ delete[] s; count = 1; s=new char[1];	s[0]='\0'; };

		//--- Add char to buffer
		void Add(char c)
		{
			count += 1;
			char *tmp = new char [count];
			for (int i=0; i<count-2; i++)	
				tmp[i] = s[i];
			tmp[count-2] = c;
			tmp[count-1] = '\0';
			delete [] s;
			s = tmp;
		};

		//--- Add char to buffer
		void Unadd()
		{ 
			if (count>1) {
			count = count-1;
			s[count-1] = '\0';
			}
		};

		//--- Get Buffer String 
		char* GetStr() { return strdup(s); };

		//--- Print Buffer
		void Print() { printf("%s\n", s); };
	};


//--- CFile ---
	class CFile  
	{
	private :
		CError error;
		FILE *fp;
		int ch;

	public : 
		CBuffer buf;
		
	public :
		int GetNextChar(bool back = false)
		{ 
			if (back) {
				ch=ungetc(ch,fp);	
				buf.Unadd();
			}
			else { 
				ch=getc(fp); 
				buf.Add(ch);
			}
		  return ch; 
		};
		
		int GetChar() { return ch; };
		int c() { return ch; };

		//--- Constructor 
		void Open(char *s) 
		{ 
			fp = fopen(s, "r"); 
			if (fp==NULL) 
				error.OnError("Robot command file not open.",-511);
			ch = 0;
		};
	};


//--- --- ---

private : 
	CError  error;
	CFile  file;
	EState  state;
	Lexeme  *begin;
	Lexeme  *lex;
	int  line;

private :
	EState  GetState();
	bool  IsStatusChanged();
	bool  IsRight(); 

	void  Parse();
	void  Parse_Init();
	void  Parse_Back();

	void  SubPrint(Lexeme *l);
	
public : 
	void  Print() { SubPrint(begin); };
	bool  MakeAnalysis();
	Lexeme*  GetBegin () const { return begin; };

	//--- Constructor 
	CLexic(char *s);
	//--- Destructor
	~CLexic() { if (begin != NULL) delete begin; };
};


#endif

