%option noyywrap
%{
#include <string.h>
#include <stdlib.h>

enum tokeni {ETIKETA=1,ZATVORENA_ETIKETA,CIFRA,REC,OSTALO};
enum slozenost {SLOZENA,PROSTA};

#define MAX_IME_ETIKETE 20
#define MAX_NIVOA_NAZUBLJENOSTI 16


typedef struct EC
{	char *etiketa;
	int  slozena;
        int  kod;
	struct EC  *leva,*desna;
} CVOR_ETIKETE;

CVOR_ETIKETE* drvo_etiketa=NULL;

int tekuci_kod=0;
int broj_linije;
%}

 
%%
"<"[a-zA-Z_]+">"		{return ETIKETA;}
"</"[a-zA-Z_]+">"		{return ZATVORENA_ETIKETA;}
[0-9]			{return CIFRA;}
([a-zA-Z_]|[0-9])+	{return REC;}
[ \t]+
"\n"			{broj_linije++;}		
.			{return OSTALO;}
%%

CVOR_ETIKETE* nova_etiketa(char* e, int sl)
{	CVOR_ETIKETE* ce;
	ce=(CVOR_ETIKETE*)malloc(sizeof(CVOR_ETIKETE));
	ce->etiketa=strdup(e);
	ce->slozena=(sl!=0)?SLOZENA:PROSTA;
	ce->kod=tekuci_kod++;
	ce->leva=ce->desna=NULL;
	return ce;
}

void obrisi_etiketu(CVOR_ETIKETE* c)
{	if (c!=NULL)
	{	free(c->etiketa);
		obrisi_etiketu(c->leva);
		obrisi_etiketu(c->desna);
		free(c);
	}
}

int ubaci_etiketu(CVOR_ETIKETE* c, char* e, int sl)
{	int cmp=strcmp(e,c->etiketa);
	if (cmp==0)
	{	printf("UPOZORENJE : Etiketa %s vec postoji!\n",e);
		return -1;
	}
	else 
		if (cmp<0)
		{	if (c->leva!=NULL)
				return ubaci_etiketu(c->leva,e,sl);
			else
			{	c->leva=nova_etiketa(e,sl);
				return 0;
			}
		} else
			if (c->desna!=NULL)
				return ubaci_etiketu(c->desna,e,sl);
			else
			{	c->desna=nova_etiketa(e,sl);
				return 0;
			
			}
}


CVOR_ETIKETE* pronadji_etiketu(CVOR_ETIKETE* c, char* e)
{	int cmp=strcmp(e,c->etiketa);
	if (cmp==0)
	{	return c;
	}
	else 
		if (cmp<0)
		{	if (c->leva!=NULL)
				return pronadji_etiketu(c->leva,e);
			else
				return NULL;
		} else
			if (c->desna!=NULL)
				return pronadji_etiketu(c->desna,e);
			else
				return NULL;
}


main(int argc, char* args[])
{	int token;
	int broj_otvorenih_etiketa;
	char etiketa[MAX_IME_ETIKETE];

        int stek_etiketa[MAX_NIVOA_NAZUBLJENOSTI];

	FILE* out;
	int i;

	if (argc<3)
	{	printf("Ocekivano ime ulazne i izlazne datoteke\n");
		return EXIT_FAILURE;
	}

	if ((yyin=fopen("tags.def","r"))==NULL)
	{	printf("Nisam uspeo da otvorim tags.def");
		return EXIT_FAILURE;
	}

	while ((token=yylex())!=0)
	  {	if (token!=ETIKETA)
		{	printf("Greska u datoteci tags.def\n");
			printf("Neocekivan simbol : %s",yytext);
			fclose(yyin);
			return EXIT_FAILURE;
		}

		strcpy(etiketa,yytext+1);
		etiketa[strlen(etiketa)-1]='\0';
			
		if (yylex()!=CIFRA)
		{	printf("Greska u datoteci tags.def\n");
			printf("Ocekivana oznaka slozenosti etikete %s\n",etiketa);
		}

		printf("Pronadjena %s etiketa : %s\n",((yytext[0]-'0')==SLOZENA?"slozena":"prosta"),etiketa);
		if (drvo_etiketa==NULL)
			drvo_etiketa=nova_etiketa(etiketa,yytext[0]-'0');
		else 
			if (ubaci_etiketu(drvo_etiketa,etiketa,yytext[0]-'0')!=0)
			{	printf("Nisam uspeo da obradim etiketu %s\n",etiketa);
			}

	}
	fclose(yyin);

	printf("Otvaram %s...\n",args[1]);
	broj_linije=0;

	if ((yyin=fopen(args[1],"r"))==NULL)
	{	printf("Nisam uspeo da otvorim %s",args[1]);
		return EXIT_FAILURE;
	}

	if ((out=fopen(args[2],"w"))==NULL)
	{	printf("Nisam uspeo da otvorim %s",args[2]);
		return EXIT_FAILURE;
	}

	
	broj_otvorenih_etiketa=0;
	while ((token=yylex())!=0)
	{	switch(token)
		{	case ETIKETA:
			{	CVOR_ETIKETE* et;
				strcpy(etiketa,yytext+1);
				etiketa[strlen(etiketa)-1]='\0';
				et=pronadji_etiketu(drvo_etiketa,etiketa);
				if (et==NULL)
				{	printf("GRESKA u liniji %d: Nedozvoljena etiketa : %s\n",broj_linije,etiketa);
					return EXIT_FAILURE;
				} else
				  {	if (et->slozena==SLOZENA)
					     stek_etiketa[broj_otvorenih_etiketa++]=et->kod;
					     for (i=1; i<((et->slozena==SLOZENA)?broj_otvorenih_etiketa:broj_otvorenih_etiketa+1); i++)
						fprintf(out,"  ");
					fprintf(out,"<%s>\n",etiketa);

				}
				break;
			}
			case ZATVORENA_ETIKETA:
			{	CVOR_ETIKETE* et;
				strcpy(etiketa,yytext+2);
				etiketa[strlen(etiketa)-1]='\0';
				et=pronadji_etiketu(drvo_etiketa,etiketa);
				if (et==NULL)
				{	printf("GRESKA u liniji %d: Nedozvoljena etiketa : %s\n",broj_linije,etiketa);
					return EXIT_FAILURE;
				} else
				{	if (et->slozena!=SLOZENA)
				        {	printf("GRESKA u liniji %d : Etiketa %s nije slozena\n",broj_linije,etiketa);
						return EXIT_FAILURE;
					}
				        if (et->kod!=stek_etiketa[broj_otvorenih_etiketa-1])
					{	printf("GRESKA u liniji %d: Etiketa %s nije poslednja otvorena\n",broj_linije,etiketa);
						return EXIT_FAILURE;
					}
					for (i=1; i<broj_otvorenih_etiketa; i++)
						fprintf(out,"  ");
					fprintf(out,"</%s>\n",etiketa);
                                        broj_otvorenih_etiketa--;
				}
				break;
			}

		}

	}
		
	fclose(out);
	fclose(yyin);
	obrisi_etiketu(drvo_etiketa);
	return EXIT_SUCCESS;
}
