/*
    module: cvrin.c
    purpose: cube and cover input routines
*/

#include "espresso.h"

static bool3 line_length_error;
static int lineno;

/** MM: osetrene pre NULL vystup */
void skip_line(register FILE *fpin, register FILE *fpout, register int echo)
{
    register int ch;
    while ((ch=getc(fpin)) != EOF && ch != '\n')
    	if (echo && (fpout!=NULL) )
    	    putc(ch, fpout);
    if (echo && (fpout!=NULL))
    	putc('\n', fpout);
    lineno++;
}

char *get_word(register FILE *fp, register char *word)
{
    register int ch, i = 0;
    while ((ch = getc(fp)) != EOF && isspace(ch))
	;
    word[i++] = ch;
    while ((ch = getc(fp)) != EOF && ! isspace(ch))
	word[i++] = ch;
    word[i++] = '\0';
    return word;
}

/*
 *  Yes, I know this routine is a mess
 */
/** MM: Nacita 1 riadok zo vstupu */
/** MM: upravuje PLA->label,... */
/** MM: sama o sebe nic nealokuje, ale fukcie, ktore vola ano */
/** MM: vracia -1 len v pripadoch, ked povodne volala fatal alebo exit */
int read_cube(register FILE *fp, pPLA PLA)
{
    register int var, i;
    pcube cf = cube->temp[0], cr = cube->temp[1], cd = cube->temp[2];
    bool3 savef = FALSE3, saved = FALSE3, saver = FALSE3;
    char token[256]; 			/* for kiss read hack */
    int varx, first, last, offset;	/* for kiss read hack */
    char tmp;

    set_clear(cf, cube->size);

    /* Loop and read binary variables */
    for(var = 0; var < cube->num_binary_vars; var++){
        tmp = getc(fp);
    	switch(tmp) {
    	    case EOF:
                goto bad_char;
    	    case '\n':
        		if (! line_length_error)
        		    if (erroroutput) fprintf(erroroutput, "product term(s) %s\n", "span more than one line (warning only)\n");
        		line_length_error = TRUE3;
        		lineno++;
        		var--;
        		break;
    	    case ' ': case '|': case '\t':
                var--;
                break;
    	    case '2': case '-':
        		set_insert(cf, var*2+1);
    	    case '0':
        		set_insert(cf, var*2);
        		break;
    	    case '1':
        		set_insert(cf, var*2+1);
        		break;
    	    case '?':
        		break;
    	    default:
                if (!isspace(tmp)) goto bad_char;
                var--;
                break;
    	}
    }


    /* Loop for the all but one of the multiple-valued variables */	
    for(var = cube->num_binary_vars; var < cube->num_vars-1; var++)

    	/* Read a symbolic multiple-valued variable */
    	if (cube->part_size[var] < 0) {
    	    (void) fscanf(fp, "%s", token);
    	    if (str_equal(token, "-") || str_equal(token, "ANY")) {
        		if (kiss && var == cube->num_vars - 2) {
        		    /* leave it empty */
        		} else {
        		    /* make it full */
        		    set_or(cf, cf, cube->var_mask[var]);
        		}
    	    } else if (str_equal(token, "~")) {
        		;
        		/* leave it empty ... (?) */
    	    } else {
        		if (kiss && var == cube->num_vars - 2)
        		    varx = var - 1, offset = ABS(cube->part_size[var-1]);
        		else
        		    varx = var, offset = 0;
        		/* Find the symbolic label in the label table */
        		first = cube->first_part[varx];
        		last = cube->last_part[varx];
        		/** MM: prechadzanie pola labelov a hladanie volneho miesta na vlozenie aktualneho, ak sa v poli este nenachadza */
        		for(i = first; i <= last; i++)
        		    if (PLA->label[i] == (char *) NULL) {
            			PLA->label[i] = util_strsav(token);	/* add new label */
            			set_insert(cf, i+offset);
            			break;
        		    } else if (str_equal(PLA->label[i], token)) {
            			set_insert(cf, i+offset);	/* use column i */
            			break;
        		    }
        		if (i > last) { /** MM: namiesto volania fatal-u */
            		snprintf(errorbuffer, sizeof(errorbuffer), "declared size of variable %d (counting from variable 0) is too small", var); /** MM: pridane kvoli hlaske pre vynimku */
        		    if (erroroutput) { 
                        fprintf(erroroutput, "espresso: declared size of variable %d (counting from variable 0) is too small\n", var);
             		    return -1; /** MM: toto je zavazna chyba a musi byt ukoncene nacitavanie */
                    }
        		}
    	    }
    	
    	} else for(i = cube->first_part[var]; i <= cube->last_part[var]; i++){
            tmp = getc(fp);
    	    switch (tmp) {
        		case EOF:
        		    goto bad_char;
        		case '\n':
        		    if (! line_length_error)
            			if (erroroutput) fprintf(erroroutput, "espresso: product term(s) span more than one line (warning only)\n");
        		    line_length_error = TRUE3;
        		    lineno++;
        		    i--;
        		    break;
        		case ' ': case '|': case '\t':
        		    i--;
        		    break;
        		case '1':
        		    set_insert(cf, i);
        		case '0':
        		    break;
        		default:
                    if (!isspace(tmp)) goto bad_char;
                    else i--; 
                    break;
    	    }
        }

    /* Loop for last multiple-valued variable */
    if (kiss) {
    	saver = savef = TRUE3;
    	(void) set_xor(cr, cf, cube->var_mask[cube->num_vars - 2]);
    } else
	set_copy(cr, cf);
    set_copy(cd, cf);
    for(i = cube->first_part[var]; i <= cube->last_part[var]; i++){
        tmp = getc(fp);
    	switch (tmp) {
    	    case EOF:
        		goto bad_char;
    	    case '\n':
        		if (! line_length_error)
        		    if (erroroutput) fprintf(erroroutput, "product term(s) %s\n",	"span more than one line (warning only)\n");
        		line_length_error = TRUE3;
        		lineno++;
        		i--;
        		break;
    	    case ' ': case '|': case '\t':
        		i--;
        		break;
    	    case '4': case '1':
        		if (PLA->pla_type & F_type)
        		    set_insert(cf, i), savef = TRUE3;
        		break;
    	    case '3': case '0':
        		if (PLA->pla_type & R_type)
        		    set_insert(cr, i), saver = TRUE3;
        		break;
    	    case '2': case '-':
        		if (PLA->pla_type & D_type)
        		    set_insert(cd, i), saved = TRUE3;
    	    case '~':
        		break;
    	    default:
        		if (!isspace(tmp)) goto bad_char;
        		i--;
        		break;
    	}
    }
    if (savef) { PLA->F = sf_addset(PLA->F, cf); if (PLA->F == NULL) return -1; /** MM: ak chyba alokacie */}
    if (saved) { PLA->D = sf_addset(PLA->D, cd); if (PLA->D == NULL) return -1; /** MM: ak chyba alokacie */}
    if (saver) { PLA->R = sf_addset(PLA->R, cr); if (PLA->R == NULL) return -1; /** MM: ak chyba alokacie */}
    return 0;

bad_char:
    if (erroroutput) fprintf(erroroutput, "(warning): input line #%d ignored\n", lineno);
    skip_line(fp, standardoutput, TRUE3);
    return 0; /** MM: 0, lebo chybny riadok neznamena zavaznu chybu nacitania */
}

/** MM: Hlavna nacitacia funkcia - parsuje vstupny "subor", ziska inicializacne data a opakovane vola read_cube() */
/** MM: upravuje fp, PLA->F, PLA->D, PLA->R, PLA->label, PLA->symbolic, PLA->phase, PLA->symbolic_output, PLA->pla_type... */
/** MM: dokym sa neprejde k read_cube, upravuju sa len primitivne premenne struktury cube */
/** MM: pri chybe vrati -1, cube, cdata a  PLA budu v stave, ze setdown_cube a free_PLA nesposobia pad */
/** MM: chyba nacitania je aj ked nedojde k nacitaniu ziadneho riadku => PLA->F == NULL, ale to zisti az volajuci */
int parse_pla(FILE *fp, pPLA PLA)
{
    int i, var, ch, np, last;
    int tmp; /** MM: kvoli navratovej hodnote */
    char word[256];

    lineno = 1;
    line_length_error = FALSE3;
    /** MM: nastavenie hodnot kocky tak, aby sa nahodne spusteny cube_setup predcasne ukoncil */
    cube->num_binary_vars = -1;
    cube->num_vars = -2;

loop:
    switch(ch = getc(fp)) {
    	case EOF:
    	    return 0; /** MM: doslo sa na koniec bez .end */
    
    	case '\n':
    	    lineno++;
    
    	case ' ': case '\t': case '\f': case '\r':
    	    break;
    
    	case '#':
    	    (void) ungetc(ch, fp);
    	    skip_line(fp, eatoutput, echo_comments);
    	    break;
    
    	case '.':
    	    /* .i gives the cube input size (binary-functions only) */
    	    if (str_equal(get_word(fp, word), "i")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .i ignored\n");
        		    skip_line(fp, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (fscanf(fp, "%d", &cube->num_binary_vars) != 1){
                        fatal2("error reading .i");
                        return -1;
                    }
        		    cube->num_vars = cube->num_binary_vars + 1; /** MM: nastavenie num_vars, aby boli hodnoty oboch premennych spravne */
        		    cube->part_size = ALLOC(int, cube->num_vars);
        		    if (cube->part_size == NULL) return -1; /** MM: ak chyba alokacie */
        		}
    
    	    /* .o gives the cube output size (binary-functions only) */
    	    } else if (str_equal(word, "o")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .o ignored\n");
        		    skip_line(fp, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (cube->part_size == NULL){
                        fatal2(".o cannot appear before .i");
                        return -1; /** MM: ak chyba */
                        
                    }
        		    if (fscanf(fp, "%d", &(cube->part_size[cube->num_vars-1]))!=1){
                    	fatal2("error reading .o");
                    	return -1; /** MM: ak chyba */
                    }
        		    tmp = cube_setup(); 
        		    if (tmp == -1){ /** MM: ak chyba alokacie */
                        return -1;
                    }
        		    tmp = PLA_labels(PLA); 
        		    if (tmp == -1){ /** MM: ak chyba alokacie */
                        return -1;
                    }
        		}
    
    	    /* .mv gives the cube size for a multiple-valued function */
    	    } else if (str_equal(word, "mv")) {
        		if (cube->fullset != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .mv ignored\n");
        		    skip_line(fp, standardoutput, /* echo */ FALSE3);
        		} else {
        		    if (cube->part_size != NULL){
            			fatal2("cannot mix .i and .mv"); /** MM: ak chyba citania*/
            			return -1;
                    }
        		    if (fscanf(fp,"%d %d", &cube->num_vars,&cube->num_binary_vars) != 2){
                        fatal2("error reading .mv"); /** MM: ak chyba citania*/
                        return -1;
                    }
        		    if (cube->num_binary_vars < 0){
                        fatal2("num_binary_vars (second field of .mv) cannot be negative"); /** MM: ak chyba */
                        return -1;
                    }
        		    if (cube->num_vars < cube->num_binary_vars){
                    	fatal2("num_vars (1st field of .mv) must exceed num_binary_vars (2nd field of .mv)"); /** MM: ak chyba */
                    	return -1;
                    }
        		    cube->part_size = ALLOC(int, cube->num_vars);
        		    if (cube->part_size == NULL) return -1; /** MM: ak chyba alokacie*/
        		    for(var=cube->num_binary_vars; var < cube->num_vars; var++)
            			if (fscanf(fp, "%d", &(cube->part_size[var])) != 1){
            			    fatal2("error reading .mv"); /** MM: ak chyba citania*/
            			    return -1; /** MM: okrem setdown_cube zavolat aj FREE(cube->part_size)!!! */
                        }
        		    tmp = cube_setup();
        		    if (tmp == -1) return -1; /** MM: ak chyba alokacie / premennych */
        		    tmp = PLA_labels(PLA);
        		    if (tmp == -1) return -1; /** MM: ak chyba alokacie */
        		}
    
    	    /* .p gives the number of product terms -- we ignore it */
    	    } else if (str_equal(word, "p"))
        		(void) fscanf(fp, "%d", &np); /** MM: tato hodnota sa ignoruje, preto nas nezaujima, ako skonci jej citanie */
    	    /* .e and .end specify the end of the file */
    	    else if (str_equal(word, "e") || str_equal(word,"end"))
        		return 0; /** MM: doslo sa na korektny koniec */
    	    /* .kiss turns on the kiss-hack option */
    	    else if (str_equal(word, "kiss"))
        		kiss = TRUE3;
    
    	    /* .type specifies a logical type for the PLA */
    	    else if (str_equal(word, "type")) {
        		(void) get_word(fp, word);
        		for(i = 0; pla_types[i].key != 0; i++)
        		    if (str_equal(pla_types[i].key + 1, word)) {
            			PLA->pla_type = pla_types[i].value;
            			break;
        		    }
        		if (pla_types[i].key == 0){
        		    fatal2("unknown type in .type command"); /** MM: ak chyba zadaneho typu PLA */
        		    return -1;
                }
    
    	    /* parse the labels */
    	    } else if (str_equal(word, "ilb")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .ilb or .ob"); /** MM: ak chyba */
        		    return -1; 
                }
        		if (PLA->label == NULL)
        		    PLA_labels(PLA);
        		for(var = 0; var < cube->num_binary_vars; var++) {
        		    (void) get_word(fp, word);
        		    i = cube->first_part[var];
        		    PLA->label[i+1] = util_strsav(word);
        		    PLA->label[i] = ALLOC(char, strlen(word) + 6);
        		    if ( (PLA->label[i+1] == NULL) || (PLA->label[i] == NULL) ) return -1; /** MM: ak chyba alokacie */
        		    (void) snprintf(PLA->label[i], strlen(word) + 6, "%s.bar", word); /** MM: zmenene na secure version */
        		}
    	    } else if (str_equal(word, "ob")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .ilb or .ob"); /** MM: ak chyba */
        		    return -1;
                }
        		if (PLA->label == NULL)
        		    tmp = PLA_labels(PLA); 
                    if (tmp == -1) return -1; /** MM: ak chyba alokacie */
        		var = cube->num_vars - 1;
        		for(i = cube->first_part[var]; i <= cube->last_part[var]; i++) {
        		    (void) get_word(fp, word);
        		    PLA->label[i] = util_strsav(word);
        		    if (PLA->label[i] == NULL) return -1; /** MM: ak chyba alokacie */
        		}
    	    /* .label assigns labels to multiple-valued variables */
    	    } else if (str_equal(word, "label")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .label"); /** MM: ak chyba */
        		    return -1;
                }
        		if (PLA->label == NULL)
        		    tmp = PLA_labels(PLA);
        		    if (tmp == -1) return -1; /** MM: ak chyba alokacie */
        		if (fscanf(fp, "var=%d", &var) != 1){
        		    fatal2("Error reading labels"); /** MM: ak chyba citania */
        		    return -1;
                }
        		for(i = cube->first_part[var]; i <= cube->last_part[var]; i++) {
        		    (void) get_word(fp, word);
        		    PLA->label[i] = util_strsav(word);
        		    if (PLA->label[i] == NULL ) return -1; /** MM: ak chyba alokacie */
        		}
    
    	    } else if (str_equal(word, "symbolic")) {
        		symbolic_t *newlist, *p1;
        		if (read_symbolic(fp, PLA, word, &newlist)) {
        		    if (PLA->symbolic == NIL(symbolic_t)) {
            			PLA->symbolic = newlist;
        		    } else {
                        /** MM: prechadzanie spojovym zoznamom do konca a pridanie noveho listu */
            			for(p1=PLA->symbolic;p1->next!=NIL(symbolic_t); p1=p1->next){
            			}
            			p1->next = newlist;
        		    }
        		} else {
        		    fatal2("error reading .symbolic"); /** MM: ak chyba */
        		    return -1;
        		}
    
    	    } else if (str_equal(word, "symbolic-output")) {
        		symbolic_t *newlist, *p1;
        		if (read_symbolic(fp, PLA, word, &newlist)) {
        		    if (PLA->symbolic_output == NIL(symbolic_t)) {
            			PLA->symbolic_output = newlist;
        		    } else {
            			for(p1=PLA->symbolic_output;p1->next!=NIL(symbolic_t); p1=p1->next){
            			}
                        p1->next = newlist;
        		    }
        		} else {
        		    fatal2("error reading .symbolic-output"); /** MM: ak chyba */
        		    return -1;
        		}
        		
    	    /* .phase allows a choice of output phases */
    	    } else if (str_equal(word, "phase")) {
        		if (cube->fullset == NULL){
        		    fatal2("PLA size must be declared before .phase"); /** MM: ak chyba */
        		    return -1;
                }
        		if (PLA->phase != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .phase ignored\n");
        		    skip_line(fp, standardoutput, /* echo */ FALSE3);
        		} else {
        		    do ch = getc(fp); while (ch == ' ' || ch == '\t');
        		    (void) ungetc(ch, fp);
        		    PLA->phase = set_save(cube->fullset);
        		    if (PLA->phase==NULL) return -1; /** MM: ak chyba alokacie */
        		    last = cube->last_part[cube->num_vars - 1];
        		    for(i=cube->first_part[cube->num_vars - 1]; i <= last; i++)
            			if ((ch = getc(fp)) == '0')
            			    set_remove(PLA->phase, i);
            			else if (ch != '1'){
            			    fatal2("only 0 or 1 allowed in phase description"); /** MM: ak chyba parametra */
            			    return -1;
                        }
        		}
    
    	    /* .pair allows for bit-pairing input variables */
    	    } else if (str_equal(word, "pair")) {
        		int j;
        		if (PLA->pair != NULL) {
        		    if (erroroutput) fprintf(erroroutput, "extra .pair ignored\n");
        		} else {
        		    ppair pair;
        		    PLA->pair = pair = ALLOC(pair_t, 1);
        		    if (PLA->pair == NULL) return -1; /** MM: ak chyba alokacie */
        		    if (fscanf(fp, "%d", &(pair->cnt)) != 1){
                    	fatal2("syntax error in .pair"); /** MM: ak chyba vstupu */
                    	return -1;
                    }
        		    pair->var1 = ALLOC(int, pair->cnt);
        		    pair->var2 = ALLOC(int, pair->cnt);
        		    if ( (pair->var1 == NULL) || (pair->var2 == NULL) ) return -1; /** MM: ak chyba alokacie */
        		    for(i = 0; i < pair->cnt; i++) {
            			(void) get_word(fp, word);
            			if (word[0] == '(') (void) strcpy(word, word+1);
            			if (label_index(PLA, word, &var, &j)) {
            			    pair->var1[i] = var+1;
            			} else {
            			    fatal2("syntax error in .pair"); /** MM: ak chyba */
            			    return -1;
            			}
            
            			(void) get_word(fp, word);
            			if (word[strlen(word)-1] == ')') {
            			    word[strlen(word)-1]='\0';
            			}
            			if (label_index(PLA, word, &var, &j)) {
            			    pair->var2[i] = var+1;
            			} else {
            			    fatal2("syntax error in .pair"); /** MM: ak chyba */
            			    return -1;
            			}
        		    }
        		}
        		
    	    } else {
        		if (echo_unknown_commands)
        		    fprintf(eatdotsoutput, "%c%s ", ch, word);
        		skip_line(fp, eatdotsoutput, echo_unknown_commands);
    	    }
    	    break;
    	/** MM: spusti sa, ak nie su ziadne ".nieco" prikazy */
    	default:
    	    (void) ungetc(ch, fp);
    	    if (cube->fullset == NULL) { /** MM: fullset sa inicializuje prostrednictvom cube_setup */
        		if (echo_comments && (eatoutput!=NULL) )
        		    fputc('#', eatoutput);
        		skip_line(fp, eatoutput, echo_comments);
        		break;
    	    }
    	    /** MM: ak prebieha prve citanie, inicializuju sa struktury */
    	    if (PLA->F == NULL) {
        		PLA->F = new_cover(10);
        		PLA->D = new_cover(10);
        		PLA->R = new_cover(10);
        		if ( (PLA->F == NULL) || (PLA->D == NULL) || (PLA->R == NULL) ){ /** MM: ak chyba alokacie */
                    return -1; /** MM: o korektnu dealokaciu sa postara free_PLA */
                }
    	    }
    	    /** MM: nacita sa jedna kocka */
    	    if (read_cube(fp, PLA) == -1){ /** MM: neskoncilo citanie zavaznou chybou? ["az" v jednom pripade; ostatne su warningy]*/
                /** MM: netreba nic dealokovat */
                return -1;
            }
    }
    goto loop;
}


/** MM: uz kontroluje parametre */
/** MM: navratova hodnota -1 pre chybu */
int PLA_summary(pPLA PLA, FILE* fp)
{
    int var, i;
    symbolic_list_t *p2;
    symbolic_t *p1;

    if ( (fp == NULL) || (PLA == NULL) ) return -1; /** MM: ak chyba parametrov */

    if (PLA->filename)
        fprintf(fp, "# PLA is %s", PLA->filename);
    if (cube->num_binary_vars == cube->num_vars - 1)
	   fprintf(fp, " with %d inputs and %d outputs\n",
	    cube->num_binary_vars, cube->part_size[cube->num_vars - 1]);
    else {
    	fprintf(fp, " with %d variables (%d binary, mv sizes",
    	    cube->num_vars, cube->num_binary_vars);
    	for(var = cube->num_binary_vars; var < cube->num_vars; var++)
    	    fprintf(fp, " %d", cube->part_size[var]);
    	fprintf(fp, ")\n");
    }
    fprintf(fp, "# ON-set cost is  %s\n", print_cost(PLA->F));
    fprintf(fp, "# OFF-set cost is %s\n", print_cost(PLA->R));
    fprintf(fp, "# DC-set cost is  %s\n", print_cost(PLA->D));
    if (PLA->phase != NULL)
	   fprintf(fp, "# phase is %s\n", pc1(PLA->phase));
    if (PLA->pair != NULL) {
    	fprintf(fp, "# two-bit decoders:");
    	for(i = 0; i < PLA->pair->cnt; i++)
    	    fprintf(fp, " (%d %d)", PLA->pair->var1[i], PLA->pair->var2[i]);
    	fprintf(fp, "\n");
    }
    if (PLA->symbolic != NIL(symbolic_t)) {
    	for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1->next) {
    	    fprintf(fp, "# symbolic: ");
    	    for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) {
        		fprintf(fp, " %d", p2->variable);
    	    }
    	    fprintf(fp, "\n");
    	}
    }
    if (PLA->symbolic_output != NIL(symbolic_t)) {
    	for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1->next) {
    	    fprintf(fp, "# output symbolic: ");
    	    for(p2=p1->symbolic_list; p2!=NIL(symbolic_list_t); p2=p2->next) {
        		fprintf(fp, " %d", p2->pos);
    	    }
    	    fprintf(fp, "\n");
    	}
    }
    (void) fflush(fp);
    return 0;
}

/** MM: vytvori nove PLA */
/** MM: Kontroluje uspesne alokovanie; vrati pPLA alebo NULL */
pPLA new_PLA(void)
{
    pPLA PLA;

    PLA = ALLOC(PLA_t, 1); /** MM: malloc */
    /** MM: malloc pri neuspechu vrati NULL */
    if (PLA){
        PLA->F = PLA->D = PLA->R = (pcover) NULL;
        PLA->phase = (pcube) NULL;
        PLA->pair = (ppair) NULL;
        PLA->label = (char **) NULL;
        PLA->filename = (char *) NULL;
        PLA->pla_type = 0;
        PLA->symbolic = NIL(symbolic_t);
        PLA->symbolic_output = NIL(symbolic_t);
    }
    return PLA;
}


int PLA_labels(pPLA PLA)
{
    int i;

    PLA->label = ALLOC(char *, cube->size);
    if (PLA->label == NULL) return -1; /** MM: ak chyba alokacie */
    for(i = 0; i < cube->size; i++)
    	PLA->label[i] = (char *) NULL;
	return 0;
}

/** MM: uvolni aj samotnu strukturu PLA_t */
void free_PLA(pPLA PLA)
{
    symbolic_list_t *p2, *p2next;
    symbolic_label_t *p3, *p3next; /** MM: kvoli memory leaku na symbolic_label_t */
    symbolic_t *p1, *p1next;
    int i;
    
    if (PLA==NULL) return; /** MM: ak chyba dealokacie neplatneho PLA */

    if (PLA->F != (pcover) NULL)
	   free_cover(PLA->F);
    if (PLA->R != (pcover) NULL)
	   free_cover(PLA->R);
    if (PLA->D != (pcover) NULL)
	   free_cover(PLA->D);
    if (PLA->phase != (pcube) NULL)
	   free_cube(PLA->phase);
    if (PLA->pair != (ppair) NULL) {
	   FREE(PLA->pair->var1);
	   FREE(PLA->pair->var2);
	   FREE(PLA->pair);
    }
    if (PLA->label != NULL) {
        for(i = 0; i < cube->size; i++)
            if (PLA->label[i] != NULL)
                FREE(PLA->label[i]);
        FREE(PLA->label);
    }
    if (PLA->filename != NULL) {
        FREE(PLA->filename);
    }
    /** MM: najvonkajsi cyklus prechadza zoznamom symbolic_t struktur */
    for(p1 = PLA->symbolic; p1 != NIL(symbolic_t); p1 = p1next) {
        for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) {
            p2next = p2->next;
            FREE(p2);
        }
		/** MM: cyklus pridany kvoli memory leakom */
        for(p3 = p1->symbolic_label; p3 != NIL(symbolic_label_t); p3 = p3next) {
            p3next = p3->next;
			//FREE(p3->label);
            FREE(p3);
        }
        p1next = p1->next;
        FREE(p1);
    }
    PLA->symbolic = NIL(symbolic_t);
    for(p1 = PLA->symbolic_output; p1 != NIL(symbolic_t); p1 = p1next) {
        for(p2 = p1->symbolic_list; p2 != NIL(symbolic_list_t); p2 = p2next) {
            p2next = p2->next;
            FREE(p2);
        }
		/** MM: cyklus pridany kvoli memory leakom */
        for(p3 = p1->symbolic_label; p3 != NIL(symbolic_label_t); p3 = p3next) {
            p3next = p3->next;
			//FREE(p3->label);
            FREE(p3);
        }
        p1next = p1->next;
        FREE(p1);
    }
    PLA->symbolic_output = NIL(symbolic_t);
    FREE(PLA);
}


int read_symbolic(FILE *fp, pPLA PLA, char *word, symbolic_t **retval)  
           		                      /* word scratch string for words */
                    
{
    symbolic_list_t *listp, *prev_listp;
    symbolic_label_t *labelp, *prev_labelp;
    symbolic_t *newlist;
    int i, var;

    newlist = ALLOC(symbolic_t, 1);
    newlist->next = NIL(symbolic_t);
    newlist->symbolic_list = NIL(symbolic_list_t);
    newlist->symbolic_list_length = 0;
    newlist->symbolic_label = NIL(symbolic_label_t);
    newlist->symbolic_label_length = 0;
    prev_listp = NIL(symbolic_list_t);
    prev_labelp = NIL(symbolic_label_t);

    for(;;) {
    	(void) get_word(fp, word);
    	if (str_equal(word, ";"))
    	    break;
    	if (label_index(PLA, word, &var, &i)) {
    	    listp = ALLOC(symbolic_list_t, 1);
    	    listp->variable = var;
    	    listp->pos = i;
    	    listp->next = NIL(symbolic_list_t);
    	    if (prev_listp == NIL(symbolic_list_t)) {
                newlist->symbolic_list = listp;
    	    } else {
        		prev_listp->next = listp;
    	    }
    	    prev_listp = listp;
    	    newlist->symbolic_list_length++;
    	} else {
    	    return FALSE3;
    	}
    }

    for(;;) {
    	(void) get_word(fp, word);
    	if (str_equal(word, ";"))
    	    break;
    	labelp = ALLOC(symbolic_label_t, 1);
    	labelp->label = util_strsav(word);
    	labelp->next = NIL(symbolic_label_t);
    	if (prev_labelp == NIL(symbolic_label_t)) {
    	    newlist->symbolic_label = labelp;
    	} else {
    	    prev_labelp->next = labelp;
    	}
    	prev_labelp = labelp;
    	newlist->symbolic_label_length++;
    }

    *retval = newlist;
    return TRUE3;
}


int label_index(pPLA PLA, char *word, int *varp, int *ip)
{
    int var, i;

    if (PLA->label == NIL(char *) || PLA->label[0] == NIL(char)) {
    	if (sscanf(word, "%d", varp) == 1) {
    	    *ip = *varp;
    	    return TRUE3;
    	}
    } else {
    	for(var = 0; var < cube->num_vars; var++) {
    	    for(i = 0; i < cube->part_size[var]; i++) {
        		if (str_equal(PLA->label[cube->first_part[var]+i], word)) {
        		    *varp = var;
        		    *ip = i;
        		    return TRUE3;
        		}
    	    }
    	}
    }
    return FALSE3;
}
