// lexical_analyzer.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <ctype.h>
//#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <iostream>
using namespace std;

// типы лексем....
enum Type_lexem { spacer,	// разделитель
				intconst,	//	целочисленная константа
				strconst,	//	строковая константа
				variable,	//	имя переменной
				label,		//	метка
				function,	//  имя функции
				keyword };	//	ключевое слово

// состояния автомата...
enum status {	H,		// начальное состояние автомата
				N,		// состояние анализа целого числа
				I,		// анализ индентификатора (имени переменной, функции или метки)	
				K,		// анализ ключевого слова
			//	A,		// ввод знака присваивания :=
				S,		// обработка текстовых констант	
				X	};	// пустышка	

enum propriety { rightl,
				 rightend,
				 wrongend };

struct Lexeme {
	Type_lexem ind;					// индентификатор типа лексемы
	char *s;						// указатель на строку, хранящую саму лексему	
	short int numstr;				// номер строки лексемы
	propriety sign;					// знак конца списка
	Lexeme() {   };					// конструктор
	Lexeme *next;					// указатель на следующую лексему
	Lexeme (const Lexeme& x) {  };	// конструктор копирования
	~Lexeme () {  };				// деструктор
};


class Lexic_analyzer {
	Lexeme *list;
	FILE *fp;
	short int nums;
	Lexeme* GetNextLexem();
	status analis(int c);
	void processing(status t, Lexeme *a, int c);
	int f(status t, int c);
	int spacerr(status t, int c);
public:
	Lexic_analyzer (FILE *fp_ext) { fp = fp_ext; list = NULL; nums = 1; }
	bool list_Lexem ();
	void printlist();
	Lexeme* getlist();
};

Lexeme* Lexic_analyzer :: getlist()
{
	return list;
}

int Lexic_analyzer :: spacerr(status t, int c)
{
	if (t == N || t == I || t == K || t == H)
		if (c == '+' || c== '-' || c == '*' || c == '/' || c == '%' || c == ':' || c == '(' || c == ',' 
			|| c == ')' || c == '|' || c == '[' || c == ']' || c == '<' || c == '>' || c == '=' 
			|| c == ';' || c != ' '  ||  c != '\t' || c != 13 || c != '\n' )
				return 1;
	if (t == S)
		if (c == '"') return 1;
	return 0;
}

int Lexic_analyzer :: f( status t, int c)
{
	switch (t) {
		case N: if (isdigit(c)) return 1; break;
		case I: if (isdigit(c) || c >= 'A' && c <= 'Z' || c>= 'a' && c <= 'z' || c == '_')
					return 1;
				break;
		case K: if ( c >= 'A' && c <= 'Z' || c>= 'a' && c <= 'z' || c == '_') return 1; break;
		case S: if ( c != '"') return 1; break;
	}
	return 0;
}

status Lexic_analyzer ::analis (int c)
{
	if (isdigit(c)) return N;
	if (c == '?' || c == '@' || c == '$') return I;
	if ( c >= 'A' && c <= 'Z' || c>= 'a' && c <= 'z' || c == '_' )
		return K;
	//if (c == ':') return A;
	if (c == '"') return S;
	if (c == '+' || c == '-' || c == '*' || c == '/' || c == '(' || c == ')' || c == '|' || c == ',' 
		|| c == '[' || c == ']' || c == '%' || c == '<' || c == '>' || c == '=' || c == ';' || c == ':') return H;
	return H;
}



Lexeme* Lexic_analyzer :: GetNextLexem ()
{
	Lexeme *a;
	int c, i = 0;
	bool sign = false;
	status state = H;
	status curstate = H;
	a = new Lexeme;
	a->sign = wrongend;
	a->s = NULL;
	char s[100];


	while ( (c = getc(fp)) != EOF ) {
		if (c == ' '  ||  c == '\t' || c == '\n' || c == 13) 
		{  
			if (c == '\n') 
				++nums;
			if (sign && !f(state, c)) break;
			else if (sign && f(state,c)) s[i++] = c;
			continue; 
		}	
		
		if (!sign) { 
			state  =  analis(c);
			if ( state != S )
				s[i++] = c;
			sign = true;
			continue;
		}	
		if (f(state, c)) { s[i++] = c; continue; }
		else break;
	}
	
	if (spacerr(state, c) || c == EOF) { 
		//if (state != S && state != H || (state == H && c != 13 && c != '\n')) ungetc(c, fp);
		if (state != S) ungetc(c, fp);
		s[i]='\0';
		
		if ( c != EOF ) a->sign = rightl;
		else a->sign = rightend;
		
		if (c == '\n')
			a->numstr = --nums;
		else  a->numstr = nums;
		a->s = new char [strlen(s)+1];
		strcpy(a->s, s);
		
		if (state == H) a->ind = spacer; 
		if (state == N) a->ind = intconst;
		if (state == K) a->ind = keyword;
		if (state == I)
			switch (s[0]) {
			case '?': a->ind = function; break;
			case '@': a->ind = label; break;
			case '$': a->ind = variable; break; 
		}
		if (state == S) a->ind = strconst;
	}
	else cout << "Error in text!\n";
	a->next=NULL;
	return a;
}	
	
bool Lexic_analyzer ::list_Lexem() 
{
	Lexeme *l;
	l = GetNextLexem ();
	list = l;
	while ( l->sign == rightl )
	{
		l->next = GetNextLexem ();
		if (l->next->sign == rightend && l->next->s == NULL) 
		{
			l->sign = rightend;
			l->next = NULL;
			break;
		}
		l = l->next;
	}
	if ( l->sign == rightend )
		return true;
	else 
		return false;
}

void Lexic_analyzer :: printlist()
{	
	Lexeme *l;
	l = list;
	int i = 1;
	while (l != NULL) {
		cout << "LexemeNum  " << i <<": ";
		cout << "identifier: ";
		switch (l->ind) {
			case spacer:	cout << "spacer"; break;
			case intconst:	cout << "intconst"; break;
			case strconst:	cout << "strconst"; break;
			case variable:	cout << "variable"; break;
			case label:		cout << "label"; break;
			case function:	cout << "function"; break;
			case keyword:	cout << "keyword"; break;
		}
		cout << "\n num string: " << l->numstr << "  ";
		cout << " Lexeme: " << l->s << "\n\n";
		l = l->next;
		++i;
	}
}

char *keywords[] = {	"program", 
						"end",
						"goto",
						"if",
						"then",
						"else",
						"endturn",
						"prod",
						"build",
						"buy",
						"sell",
						"print" };


char *funcs_without_param[] = {  // функции без параметров
	"?my_id",
	"?turn",
	"?players",
	"?active_players",
	"?supply",
	"?raw_price",
	"?demand",
	"?production_price"
};

char *funcs_with_oneparam[] = { 
	"?money",
	"?raw",
	"?production",
	"?factories",
	"?auto_factories",
	"?manufactured",
	"?result_raw_sold",
	"?result_raw_price",
	"?result_prod_bought",
	"?result_prod_price"
};
struct variables {
	char *name;
	int *value;
	
};

variables var[100];

struct labels {
	char *name;
	Lexeme *jump; 
	bool b1 ;
	bool b2 ;
	labels() { b1 = false; b2 = false; };
};

labels mark[10];

class Syntax_analyzer {
	Lexeme *l;
	Lexeme* next();
	void B();
	void S();
	int E();
	int E1();
	int T();
	int F();
	int K();
	void O();
	void O1();
	int W();
public:
	Syntax_analyzer(Lexic_analyzer& L) { l = L.getlist(); } 
	void handler();
};

Lexeme* Syntax_analyzer :: next()
{
	l = l->next;
	return l;
}


int Syntax_analyzer :: K()
{
	bool sign = false;
	int temp;
	int i = 0;
	try {
		while (i<8){
			if (!strcmp(funcs_without_param[i],l->s)){
				temp = 1; // пока не определены функции
				sign = true;
				next();
				break;
			}
			++i;
		}
		
		if (!sign) {
			i = 0;
			while (i<10){
				if (!strcmp(funcs_with_oneparam[i],l->s)){
					// пока не определены функции
					sign = true;
					next();
					if (strcmp(l->s,"("))
						throw "expecting '(' \n";
					next();
					if (l->ind != intconst) 
						temp = K(); 
					else {
						temp = 1;	
						next();
					}
					if (strcmp(l->s,")"))
						throw "expecting ')' \n";
					next();
					break;
				}
				++i;
			}
			if (!sign)
				throw " There is no such function! :  " ;	
		}
	}
	
	catch (const char *str) {
		cout << "error in string " << l->numstr << ": " << str << l->s << "\n";
		exit(1);
	}
	
	return temp;
}

int Syntax_analyzer :: F()
{	
	int temp; 
	bool sign = false;
	try {
	if (l->ind == variable) {
		int i = 0;
		while (var[i].name != NULL){
			if (!strcmp(var[i].name, l->s)) {
				temp = var[i].value[0];
				sign = true;
				next();
				break;
			}
			++i;
		}
		if (!sign)
			throw " undefined variable! :  " ;
	} else
	if (l->ind == intconst){
		temp = atoi(l->s);
		next();
	} else if (l->ind == function) 
		temp = K();
	else if (!strcmp(l->s,"(")) {
		next();
		temp = E();
		if (strcmp(l->s,")"))
			throw 1 ;
		next();
	}
	else throw "Expecting of int expression not : '";
	}
	
	catch (const char *str) {
		cout << "error in string " << l->numstr << ": " << str << l->s << "'\n";
		exit(1);
	}
	catch (int n) {
		cout << "error in string " << l->numstr << ": " << "Expecting of ')'\n";
		exit(1);
	}
	return temp;
}

int Syntax_analyzer :: T()
{
	int temp;
	temp = F();
	while (l->s[0] == '*' || l->s[0] == '/') {
		if (l->s[0] == '*') { 
			next();
			temp = temp * F();
		}
		if (l->s[0] == '/') { 
			next();
			temp = temp / F();
		}
	}
	return temp;
}

int Syntax_analyzer :: E1()
{	
	int temp;
	temp = T();
	while (l->s[0] == '+' || l->s[0] == '-') {
		if (l->s[0] == '+') { 
			next();
			temp = temp + T();
		}
		if (l->s[0] == '-') { 
			next();
			temp = temp - T();
		}
	}
	return temp;
}

int Syntax_analyzer :: E()
{
	int temporary;
	temporary  = E1();
	if (l->s[0] ==  '<'  ||  l->s[0] == '>') {
		if (l->s[0] ==  '<'){
			next();
			temporary = temporary < E1();
		}
		if (l->s[0] ==  '>') {
			next();
			temporary = temporary > E1();
		}
	}
	return temporary;
}

void Syntax_analyzer:: O1()
{
	if (l->ind == strconst) {
		next();
	} else E();
}


void Syntax_analyzer:: O()
{
	O1();
	while (!strcmp(l->s, ",")) {
		next();
		O1();
	}
}

int Syntax_analyzer:: W()
{
	int t = 0;
	try {
		if (!strcmp(l->s,"=")) {
			next();
		}
		else if (!strcmp(l->s,"[")){
			next();
			t = E();
			if (strcmp(l->s,"]"))
				throw "Expecting of ']'\n";
			next();
			if (strcmp(l->s,"=")) 
				throw "Expecting of '='\n";
			next(); 
		} else throw "Expecting of '=' or '['\n";
	} 
	catch (const char *str) {
		cout << "error in string " << l->numstr << ": " << str;
		exit(1);
	}
	return t;
}

void Syntax_analyzer:: S()
{
	try {
		if (l->ind == variable) {
			int i = 0;
			bool sign = false;
			while (var[i].name != NULL) {
				if (!strcmp(var[i].name, l->s)){
					sign = true;
					break;
				}
			++i;
			}
			if (!sign){
				var[i].name = new char [strlen(l->s) + 1];
				strcpy(var[i].name, l->s);
			}
			next();
			int t = 0;
			t = W();
			if (t < 20 && t > 0)
				var[i].value = new int [20];
			else  var[i].value = new int;
			var[i].value[t] = E();
		} else if (l->ind == keyword) {
			
			if (!strcmp(l->s,"endturn"))  
				next();
			else if (!strcmp(l->s,"prod") || !strcmp(l->s,"build")){  
				next();
				E();
			}
			else if (!strcmp(l->s,"buy") || !strcmp(l->s,"sell")){ 
				next();  
				E();
				if (strcmp(l->s,","))
					throw "expecting ',' \n";
				next();  
				E();				
			}
			else if (!strcmp(l->s,"print")) {			
				next();
				O();
			}
			else if (!strcmp(l->s,"if")) {				 
				next();
				E();
				if (strcmp(l->s, "then"))
					throw "Mistake in 'if' expression!\n";
				next();
				S();
			} // пока без else
			else if (!strcmp(l->s,"goto")) {				
				next();
				if (l->ind != label)
					throw "expecting label\n";
				
				int i = 0;
				bool sign = false;
				while (mark[i].name != NULL)
				{
				if (!strcmp(mark[i].name, l->s)){
					if (mark[i].b1 == true)
						throw 2;
					else {
						sign = true;
						break;
					}
				}
				++i;
				}
				if (!sign) {
					mark[i].name = new char [strlen(l->s) + 1];
					strcpy(mark[i].name, l->s);
				}
				mark[i].b1 = true;
				next();	
			} else if (!strcmp(l->s, "end")) ;
			else
				throw 1;
		
		}  else if (l->ind == label) {
			int i = 0;
			bool sign = false;
			while (mark[i].name != NULL)
			{
				if (!strcmp(mark[i].name, l->s)){
					if (mark[i].b2 == true)
						throw 2;
					else {
						sign = true;
						break;
					}
				}
				++i;
			}
			if (!sign) {
				mark[i].name = new char [strlen(l->s) + 1];
				strcpy(mark[i].name, l->s);
			}
			mark[i].b2 = true;
			
			next();
			if (strcmp(l->s,":"))
				throw "expecting ':' \n";
			
			next();
			S();
		} else throw 3;

	} 
	
	catch (const char *str) {
		cout << "error in string " << l->numstr << ": " << str;
		exit(1);
	}
	catch (int n) {
		switch (n) {
			case 1: cout <<"error in string " << l->numstr << ": " << "There is no such keyword: '"<< l->s << "'\n"; break;
			case 2: cout <<"error in string " << l->numstr << ": " << "too much declarations of label: " << l->s << "\n";	break;	
			case 3: cout <<"error in string " << l->numstr << ": " << "syntax error: unexpected '" << l->s << "'\n"; break; 
		}
		exit(1);
	}
}


void Syntax_analyzer:: B()
{
	try {
		S();
		while (!strcmp(l->s,";")) {
			next();
			S();
			if (strcmp(l->s, ";") && strcmp(l->s, "end"))
				throw "Expecting of ';'\n";
		}
	}
	catch (const char *str) {
		cout <<"error in string " << l->numstr - 1 << ": " << str;
		exit(1);
	}
}

void Syntax_analyzer:: handler()
{	
	int i = 0;
	try {
		if (strcmp(l->s, "program"))
			throw "There is no keyword program!\n";

		next();
		B();
		if (strcmp(l->s, "end"))
			throw "Expecting 'end'!\n";
	
		while (mark[i].name != NULL) {
			if (!mark[i].b1) 
				throw 1;
			if (!mark[i].b2)
				throw 2;
			++i;
		}
	}
	catch (const char *str) {
		cout <<"error " <<l->numstr << ": " << str << "\n";
		exit(1);
	}
	catch (int n) {
		switch (n) {
		case 1: cout << "error: label " << mark[i].name << " defined without 'goto'\n"; break;
		case 2: cout << "error: label " << mark[i].name << " defined without distination!\n"; break;
		}
	exit(1);
	}
}


int main(int argc, char** argv[])
{
	FILE *fp;
	fp = fopen("c:\\robo.txt", "r");
	Lexic_analyzer L(fp);
	if (L.list_Lexem())
		L.printlist();
	else cout << " Error: cannot to create list!\n";
	
	Syntax_analyzer S(L);
	S.handler();
	cout << "Syntax analis has been successful!\n";
	return 0;
}

