#include <windows.h>
#include "coutputwnd.h"
#include "clexical.h"
#include "cstringtable.h"

#ifndef __SYNTACTICCLASS
#define __SYNTACTICCLASS

#define	PTR(x,y)						((x)y->GetPointer())
/*#define	SYNTACTICATOMFULLNAME(x)		((SYNTACTIC_ATOM_FULLNAME*)x->GetPointer())
#define SYNTACTICTABLERULES(x)			((SYNTACTIC_TABLE_RULES*)x->GetPointer())
#define SYNTACTICRULE(x)				((SYNTACTIC_RULE*)x->GetPointer())
#define SYNTACTICATOMRULE(x)			((SYNTACTIC_ATOM_RULE*)x->GetPointer())
#define SYNTACTICATOMARIT(x)			((SYNTACTIC_ATOM_ARIT*)x->GetPointer())
#define	SYNTACTICATOMEDB(x)				((SYNTACTIC_ATOM_EDB*)x->GetPointer())
*/
//pre ReadExpression
#define SYNTACTIC_LEFTPARENTHESIS			0x00000001
#define SYNTACTIC_RIGHTPARENTHESIS			0x00000002
#define SYNTACTIC_OPERATOR_MULDIV			0x00000004
#define SYNTACTIC_OPERATOR_PLSMIN			0x00000008
#define SYNTACTIC_OPERATOR_VARNUM			0x00000010
#define SYNTACTIC_STRING					0x00000020
#define SYNTACTIC_EOL						0x10000000

//#define SYNTACTIC_ATOM_NULLATOM			0
#define SYNTACTIC_ATOM_IDBATOM				1
#define SYNTACTIC_ATOM_EDBATOM				2
#define SYNTACTIC_ATOM_RELATOM				3
#define SYNTACTIC_ATOM_ARITATOM				4
#define SYNTACTIC_ATOM_ANSWER				7		//vysledok dotazu
#define SYNTACTIC_ATOM_GROUPBYATOM			8
#define SYNTACTIC_ATOM_ARITATOM_BINDED		9
#define	SYNTACTIC_ATOM_DROPPEDIDBATOM		10		//IDB pred., ktore sa nepotrebuju pri vysledku, sa oznacia ako vymazane
													//(potrebujeme vsak o nich vediet pri uvolnovani pamate)

//vyraz
#define SYNTACTIC_ARG_STRING				1		//vyrazom je	len string
#define SYNTACTIC_ARG_VARIABLE				2		//		--		len premenna
#define SYNTACTIC_ARG_NUMERIC				3		//		--		vyraz zlozeny len z cisel (5+5-2)*10 (bez premenych)
#define SYNTACTIC_ARG_COMPOSE				4		//		--		vyraz zlozeny z cisel a premennych (bezny vyraz)
#define	SYNTACTIC_ARG_ANONYMOUS				5

#define SYNTACTIC_OPERAND_STRING			1
#define SYNTACTIC_OPERAND_NUMBER			2
#define SYNTACTIC_OPERAND_VARIABLE			3

#define SYNTACTIC_AGREG_COUNT				1
#define SYNTACTIC_AGREG_MIN					2
#define SYNTACTIC_AGREG_MAX					3
#define SYNTACTIC_AGREG_AVG					4
#define SYNTACTIC_AGREG_SUM					5

//typ operacie v SYNTACTIC_ATOM_ARIT

//mozu byt kombinacie EQUAL|SUB alebo ASSIGN|SUB
#define SYNTACTIC_ARIT_OPERAND_EQUAL		1		//= vo funkcii podmienky
#define SYNTACTIC_ARIT_OPERAND_LESS			2
#define SYNTACTIC_ARIT_OPERAND_GREATER		3
#define SYNTACTIC_ARIT_OPERAND_LEEQ			4		//<=
#define SYNTACTIC_ARIT_OPERAND_GREQ			5		//>=
#define SYNTACTIC_ARIT_OPERAND_NOTEQ		6		//!=
#define SYNTACTIC_ARIT_OPERAND_ASSIGN		7		//= vo funkcii priradenia

#pragma warning(push)
#pragma warning( disable : 4200 ) //kvoli poliam nulovej velkosti, tj. []

//relacny atom so svojim nazvom a nazvami argumentov
struct SYNTACTIC_ATOM_FULLNAME_REL
{
	BYTE type;
	bool not;//negovany atom

	char *name;//meno atomu
	DWORD nArgs;//pocet argumentov
	BYTE *argTypes;//typ argumentov
	char *argValues[];//hodnoty argumentov
	//..NULL, ak ide o nepodstatny argument (tj. _)
	//..ak ide o COMPOSE typ, tak je to pointer na SYNTACTIC_ATOM_FULLNAME_ARIT, kde su data o jednotlivych premennych
	//....pamat treba uvolnit pomocou freex(*)
	//..inak char* (NUMERIC, STRING)
};

//aritmeticky atom s nazvom premennej
struct SYNTACTIC_ATOM_FULLNAME_ARIT
{
	BYTE type;
	bool not;//negovany atom

	BYTE typeOp;//typ operacie
	DWORD nVar;//pocet premennych + agregacnych funkcii -> pocet poloziek vo var[]
	char *expression;//artimeticky vyraz
	struct varArray//pole lokalnych pointrov na premenne/agr. funkcie v expression a ich dlzka
	{
		DWORD start, len;
	} var[];
};

struct SYNTACTIC_ATOM_FULLNAME_GROUPBY
{
	BYTE type;
	bool not;//negovany - nemoze byt!

	DWORD nVar;//pocet premennych
	char *varsName[];//mena premennych
};

struct SYNTACTIC_ATOM_FULLNAME
{
	union
	{
		SYNTACTIC_ATOM_FULLNAME_REL rel;
		SYNTACTIC_ATOM_FULLNAME_ARIT arit;
		SYNTACTIC_ATOM_FULLNAME_GROUPBY groupby;
	};
};

struct SYNTACTIC_VAR_TYPE
{
	BYTE error;//semanticka typa, ktora vznikla pri tejto premennej; aby sa znovu nevypisala, treba si to pamatat
	BYTE type;//typ premennej
	BYTE mark;//typ pouzitia premennej (viazana v relacii/priradeni)
};

//aritmeticky atom
struct SYNTACTIC_ATOM_ARIT
{
	BYTE type;//..!musi byt prva polozka!
	BYTE typeOp;//typ operacie
	bool substitution;//je vyraz substituciou?
	char expression[];//aritmeticky vyraz, v ktorom su premenne nahradene DWORD konstantou (zacina 01h, teda 01 id id id), ktora urcuje poradie premennej)
};

//(kazdy) substituovany atom v pravidle (na pravej strane)
struct SYNTACTIC_ATOM_RULE
{
	DWORD id;//poradove cislo atomu v SYNTACTIC_TABLE_RULES.atoms
	bool not;//negovany atom?


	DWORD nArgs;//pocet argumentov (aritm. atom nema)
	DWORD argsId[];//pole id premennych; -1 pre anonymny argument (len pre IDB/EDB atomy)
};

//prava strana jedneho pravidla in-atomu
struct SYNTACTIC_RULE
{
	bool skip;//pravidlo je chybne, preskoc ho
	DWORD nAtoms;//pocet atomov v pravidle (oddelenych spojkami AND)
	DWORD inputLine;//cislo riadku na vstupe, kde bol definovane toto pravidlo (kvoli neskorsie kontrole a vypise chyby)
	CStringTable *varNames;//mena premennych
	SYNTACTIC_VAR_TYPE *varTypes;//pointer na pole typov premennych
	SYNTACTIC_ATOM_RULE *atom[];//atomy v pravidle (uz so substituovanymi premennymi)
};

//relacny intencionalny atom, tj. definovany v datalogu
//je to mnozina pravidiel
struct SYNTACTIC_ATOM_IDB
{
	BYTE type;//..!musi byt prva polozka!
	DWORD nArgs;//pocet argumentov
	DWORD nRules;//pocet pravidiel
	BYTE *argTypes;//pointer na pole typov argumentov (je to index do CStringTable)
	char *name;//meno atomu (potrebne neskor pre semanticku analyzu)
	SYNTACTIC_RULE *rules[];//pravidla
};

//relacny extencionalny atom, tj. tabulka
struct SYNTACTIC_ATOM_EDB
{
	//len typ, ostatne data v strukture databazy
	BYTE type;//..!musi byt prva polozka!
};

struct SYNTACTIC_ATOM_GROUPBY
{
	BYTE type;//..!musi byt prva polozka!
/*
	DWORD nVar;//pocet premennych v predikate
	DWORD groupbyVarId[];//id premennych, podla ktorych sa robi groupby
*/
};

//zakladna struktura kazdeho atomu
struct SYNTACTIC_ATOM
{
	union
	{
		//zakladne atomy
		SYNTACTIC_ATOM_EDB edb;//extencionalny atom
		SYNTACTIC_ATOM_IDB idb;//definicia intencionalneho atomu (tj. hlavicka (lava strana) )
		SYNTACTIC_ATOM_ARIT arit;//aritmeticky atom
		SYNTACTIC_ATOM_GROUPBY groupby;//groupby atom
	};
};

//tabulka obsahujuca vsetky informacie o atomoch a pravidlach
struct SYNTACTIC_TABLE_RULES
{
	DWORD nAtoms;//pocet atomov
	DWORD nEdb;//pocet EDB atomov
	DWORD nIdb;//pocet IDB atomov
	DWORD answerID;//atom, ktory vracia vysledok dotazu
	SYNTACTIC_ATOM *atoms[];//vsetky atomy; poradie v poli urcuje identifikator
};

#pragma warning(pop)

class CSyntacticAnalyzer
{
	private:
		CLexicalAnalyzer *lexicalAnalyzer;
		CMemory *table;

		//ReadExpression overi, ci je na vstup syntakticky spravny vyraz
		//asArgument ak je true, tak sa pokusa nacitat vyraz, ktory je argumentom relacneho atomu
		//tj. pri nadbytku zatvorky ')' nevyhodi chybu ale skonci (zatvorka znamena koniec parametrov atomu)

		SYNTACTIC_ATOM_FULLNAME_ARIT *ReadExpression(bool asArgument);
		SYNTACTIC_ATOM_FULLNAME *ReadAtom();

		void DestroyTable();//zrusi tabulku nacitanu pomocou ReadRules()

	public:
		bool output;
		CSyntacticAnalyzer(void *input);
		~CSyntacticAnalyzer();

		void ReadRules();//syntakticky spracuje vstup a vytvori vystupnu strukturu do *table
			//chyby pise pri output = true, inak nepise (pouziva sa takto v hilightingu slov - v urceni IDB atmov)
		const SYNTACTIC_TABLE_RULES *GetTable();//vrati pointer na data z *table
		void AddEqAritAtom(DWORD newVarId, CMemory *_tableRules, CMemory *_rule, char *value);
};

#endif __SYNTACTICCLASS