#include "LexAnalyzer.h"

LexAnalyzer::LexAnalyzer(FILE* source)
{
	this->line = 1;
	this->pos = 0;
	this->source = source;
	this->state = s_init;
}

LexAnalyzer::~LexAnalyzer()
{
}

LexAnalyzer::Lexem LexAnalyzer::GetNext()
{
	Lexem lexem;
	lexem.line = line;
	
	while(true)
	{
		char c = getc(source);
		
		switch (state)
		{
		//-------------------------------------------------------------	
		case s_init:
			{
				if (c == EOF)
				{
					lexem.type = l_end;
					return lexem;
				}
				
				if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
				{
					state = s_identifier;
					buffer = c;
				} else
					if (c >= '0' && c <= '9')
					{
						state = s_number;
						buffer = c;
					} else
					{										
						switch (c)
						{
							case '+': lexem.type = l_plus; return lexem;
							case '-': lexem.type = l_minus; return lexem;
							case '*': lexem.type = l_mul; return lexem;
							case '/': lexem.type = l_div; return lexem;
							case '%': lexem.type = l_mod; return lexem;
							
							case '>': lexem.type = l_more; return lexem;
							case '<': lexem.type = l_less; return lexem;
							
							case '&': lexem.type = l_and; return lexem;
							case '|': lexem.type = l_or; return lexem;
							
							case '(': lexem.type = l_eopen; return lexem;
							case ')': lexem.type = l_eclose; return lexem;
							case '{': lexem.type = l_bopen; return lexem;
							case '}': lexem.type = l_bclose; return lexem;
							case '[': lexem.type = l_iopen; return lexem;
							case ']': lexem.type = l_iclose; return lexem;
							
							case ';': lexem.type = l_semi; return lexem;							
							case '$': lexem.type = l_var; return lexem;
							
							case '=':
							{
								state = s_eq;
								break;
							}
							
							case '\n': line++; pos = 0; lexem.line++;
							case '\t': case ' ': break;
							
							default: throw ParserError(line, pos, c);
						}
					}
					
				break;
			}
			
			case s_identifier:
			{
				if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
					buffer += c;
				else
				{
					state = s_init;
					ungetc(c, source);
									
					lexem.type = l_identifier;
					
					if (buffer == "if") lexem.type = l_if; else
					if (buffer == "else") lexem.type = l_else; else
					if (buffer == "while") lexem.type = l_while;
					if (lexem.type != l_identifier) return lexem;
					
					lexem.info = buffer;
					return lexem;
				}
				
				break;
			}
			
			case s_number:
			{
				if (c >= '0' && c <= '9')
					buffer += c;
				else
				{
					state = s_init;
					ungetc(c, source);
									
					lexem.type = l_number;								
					lexem.info = buffer;
					
					return lexem;
				}
				
				break;
			}
			
			case s_eq:
			{
				if (c == '=')
				{
					lexem.type = l_eq;				
				}
				else
				{
					lexem.type = l_assign;
					ungetc(c, source);
				}
				state = s_init;
				
				return lexem;
			}
		}
	}
}