Creazione Grafo effettuando il parsing di un file txt

di il
7 risposte

Creazione Grafo effettuando il parsing di un file txt

Sia data una certa grammatica in formato EBNF, il file grafo1.txt contiene i simboli corrispondenti al grafo stesso :
(3) 1->(1.0) 1|2; 2->(1.0) 2|3; 3->(0.0).
Cerco di spiegare in due parole la grammatica... Il primo numero intero tra parentesi rappresenta il numero dei nodi; '->' indica che il nodo che lo precede raggiunge i nodi che seguono la barra verticale, fino al punto e virgola che indica la fine della lista di adiacenza; il numero reale tra parentesi subito dopo -> è il peso del vertice in questione.
Quindi il grafo di esempio è : 1->2->3
Fatta questa premessa, devo creare delle librerie per la traduzione del file grafo1.txt..
Premetto che è la prima volta che ho a che fare con funzioni di parsing quindi sicuramente le mie funzioni presenteranno diversi errori. Ma il mio problema è più che altro, il fatto che le mie librerie compilano singolarmente, quando invece scrivo un main di prova e provo a compilarlo.. a seconda di come posiziono gli #include "libreria1" e #include"libreria2" non trova qualche funzione, piuttosto che altre. Ho provato tutte le combinazioni per l'ordine delle librerie, non so proprio cosa sbaglio... Magari mi sfugge qualche piccolo particolare che ad altri occhi risulta lampante. Uso codeBlock.
Ecco il mio codice:
parsemain.c
#include <stdio.h>
#include "grafo.h"
#include "grafoparser.h"

int main()
{
    FILE *file;
    char *nome = "grafo1.txt";
    GrafoAdj G=NULL;

    file = fopen(nome,"r");
    G=parsegrafo(file);        // Parse grafo
    fclose(file);

   /* if (g)
        stampa grafo
    else
        printf("Grafo vuoto\n"); */
    return 0;
}
grafo.h
#ifndef GRAFO_H_INCLUDED
#define GRAFO_H_INCLUDED

typedef struct grafo * GrafoAdj;
typedef struct lista * ListaAdj;

GrafoAdj creaNodo(GrafoAdj g, int val);
ListaAdj lista_insert(ListaAdj adj , int elem);
GrafoAdj creaNodoAdj (GrafoAdj g, int nodo, int val);

#endif // GRAFO_H_INCLUDED
grafo.c
#include <stdio.h>
#include <stdlib.h>
#include "grafo.h"
#include "grafoparser.h"

typedef struct grafo {
int vertice;
ListaAdj adiacenze;
struct grafo * next;
}grafo;

typedef struct lista{
int vertice;
struct lista *next;
}lista;


GrafoAdj creaNodo(GrafoAdj g, int val)
{
    if(g!=NULL)
        g->next=creaNodo(g->next,val);
    else
    {
        g=(grafo *)malloc(sizeof(grafo));
        if(g==NULL) printf("Errore allocazione nodo grafo!\n");
        g->vertice=val;
        g->adiacenze=NULL;
        g->next=NULL;
    }
return g;
}

ListaAdj lista_insert(ListaAdj adj , int elem)
{
    if(adj==NULL)
    {
        ListaAdj tmp=(lista*)malloc(sizeof(lista));
        tmp->vertice=elem;
        tmp->next=NULL;
        return tmp;
    }
    else
    {
        adj->next=lista_insert(adj->next,elem);
        return adj;
    }
}

GrafoAdj creaNodoAdj (GrafoAdj g, int nodo, int val)
{
    if (g->vertice==nodo) g->adiacenze=lista_insert(g->adiacenze,val);
    else g=creaNodoAdj(g->next,nodo,val);

    return g;
}
grafoparser.h
#ifndef GRAFOPARSER_H_INCLUDED
#define GRAFOPARSER_H_INCLUDED

typedef enum {PARSX, PARDX, PUNT, PUNTOV, BARRA, PUNTO, NUM, PESO, NODO} type; // Tipo dei simboli terminali

GrafoAdj parsegrafo (FILE *file);
int confronto(FILE *file, type x);
void sposta (FILE *file, type x);
void verticiAdj (GrafoAdj G, int nodo, FILE *file);
int traduciNumeroNodi(FILE *file);
int traduciIntero(FILE *file);
float traduciPeso (FILE *file);

#endif // GRAFOPARSER_H_INCLUDED
grafoparser.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include "grafo.h"
#include "grafoparser.h"

// Elaborazione simboli NON TERMINALI

GrafoAdj parsegrafo (FILE *file)
{ //Traduce il grafo [ritorna il puntatore alla radice]
    int x,n=0,val;
    GrafoAdj G=NULL;

    n=traduciNumeroNodi(file); //leggi il numero di nodi che dovrà contenere il grafo
    if(n)
    {
        x=confronto(file,NODO); //verifica che dopo il numero di nodi ci sia un nodo stesso
        if(x)
        {
            val=traduciIntero(file); //estrai il primo nodo
            G=creaNodo(G,val); //crea il nodo con il simbolo estratto
            verticiAdj(G,val,file); //traduce i vertici adiacenti al nodo
        }
    }
    // else ERRORE NESSUN NODO PRESENTE!!!
    return G;
}

int numeroNodi(FILE *file)
{//Esamina i simboli che rappresentano il numero di nodi [se ' (numeroIntero) ' ritorna il numero, altrimenti errore]
    int n;
    if(confronto(file,PARSX)) //se il simbolo corrente è una parentesi aperta è verificato il primo simbolo
    {
        sposta(file,PARSX); //ci si sposta al simbolo successivo la parentesi
        if (confronto(file,NODO)) // se il simbolo corrente è del tipo nodo è verificato il secondo simbolo
            {
                n=traduciIntero(file);
                sposta(file,NODO); //ci si sposta al simbolo successivo al nodo
                if(confronto(file,PARDX)) //se il simbolo corrente è una parentesi chiusa è verificato anche il terzo simbolo
                    {sposta(file,PARDX); //si sposta al simbolo successivo all'interno del file
                    return n;}
                }
    }

    return 0;
    // ritorna ERRORE!!!
}

int traduciIntero (FILE *file)
{//Traduci il simbolo non terminale che rappresenta un intero [ritorna il vertice intero del nodo]
	int c=0,num=0,l=0;

	while ((c=fgetc(file)) != EOF && isdigit(c)) {
		  if (num <= ((INT_MAX - (c-'0'))/10)){
		      num = num*10 + (c-'0');
		      l++;
   		  }
	     // else syntax_error("Integer ID <= 2147483647",file); // Number too big: ERROR
	}
	//if (l==0) syntax_error("Integer ID",file); // The ID is not a number
	if(c != EOF)       // If EndOfFile not yet reached
		ungetc(c,file);      // push the last character back to the file
	return num;
}

float traduciPeso (FILE *file)
{
    float peso;
    int res, x;
    res=confronto(file,PARDX); //Verifica che il primo simbolo del peso sia una parentesi aperta
    if(res)
    {
        sposta(file,PARDX);
        x=traduciIntero(file);
        if (confronto(file,PUNTO)) //se dopo l'intero c'è un un punto allora è un float
        sposta(file,PARDX); //sposta alla parentesi chiusa perchè la parte decimale del float è indifferente nel nostro caso
        // else ERRORE FLOAT
        peso=(float)x;
        return peso;
    }
    // else ERRORE FLOAT
    return 0;
}

void verticiAdj (GrafoAdj G, int nodo, FILE *file)
{//Traduci vertici adiacenti
    int res,val;
    float peso;
    res = confronto(file,PARSX);  // Cerca una partesi aperta
    if (res)
    {// Se la parentesi è stata trovata verificare che il simbolo successivo sia il peso
        sposta(file,PARSX);
        if(confronto(file,PESO))
        {
            peso=traduciPeso(file);
            while (peso>0)
            {
                sposta(file,BARRA); //dopo la barra si trovano i vertici adiacenti
                val=traduciIntero(file);
                G=creaNodoAdj(G,val,nodo);
            }
            sposta(file,PUNTOV);
        }
        else printf("ERRORE SINTASSI PESO!");
	}
	 else printf("ERRORE SINTASSI PESO!");
}

// Elaborazione simboli TERMINALI

int confronto(FILE *file, type x)
{ //Verifica se il tipo x corrisponde al simbolo nel file [ritorna 1  se vero, 0 altrimenti]

	char c,y;
	type rp;                       // Read symbol type
	int res=0;

	while(((c = fgetc(file)) == '\t') || (c== '\n') || (c== ' '))
			;
    switch(c) {               // Determine the read symbol type
       case '(': rp = PARSX; break;
       case ')': rp = PARDX; break;
       case '-': y=fgetc(file); if(y=='>')rp=PUNT; ungetc(y,file); break;
       case ';': rp = PUNTOV; break;
       case '|': rp = BARRA; break;
       case '.': rp= PUNTO; break;
       default : rp = NUM; break;
    }

    ungetc(c,file); // Push the read character back to the file
    if (rp==NUM)
    {
        c=fgetc(file);
        if( (c!=EOF) && (c=='.'))
            rp=PESO;
        else
            rp=NODO;
        ungetc(c,file); // Push the read character back to the file
    }

    if (rp==x)        // The expexted type et and the read symbol type rp match
			res = 1;

  return res;
}

void sposta (FILE *file, type x)
{//si sposta nel file al simbolo successivo a quello del tipo x
	int dim = 0;
	switch(x) {               // Assign the read symbol type
   	   case PARSX:; case PARDX:; case PUNT:; case PUNTOV:; case BARRA:; case PUNTO:; case NUM:; case NODO:; case PESO:dim = 1; break;
    } //qualunque sia il simbolo ricevuto dim=1, ci si sposta di un passo

	fseek(file,dim,SEEK_CUR);   // Si muove di dim passi a partire da quello corrente all'interno del file
}
Errore:
undefined reference to 'traduciNumeroNodi'
undefined reference to 'creaNodo'
undefined reference to 'creaNodoAdj'

Spero qualcuno possa essermi d'aiuto.

P.S : Nelle impostazioni del linker, ho caricato prima la libreria grafo, e poi grafoparser. Se li inverto, mi viene restituito lo stesso errore solo per traduciNumeroNodi.

7 Risposte

  • Re: Creazione Grafo effettuando il parsing di un file txt

    In grafoparser.h dovresti includere
    stdio.h per FILE*
    graph.h per GrafoAdj e ListAdj
    altrimenti il compilatore non ha idea di cosa siano.
  • Re: Creazione Grafo effettuando il parsing di un file txt

    Mmm ma li includo nei rispettivi file .c ..
  • Re: Creazione Grafo effettuando il parsing di un file txt

    Ok, ma quando il compilatore analizza grafoparser.h si chiede: "che diamine è FILE? E che diamine sono GrafoAdj e ListAdj"?
    In linea teorica potresti ripetere i typedef per gli ultimi due, ma FILE è un oggetto di libreria per cui almeno stdio.h devi includerlo.
  • Re: Creazione Grafo effettuando il parsing di un file txt

    Bhè devo dire che non capisco tanto bene quello che mi dici, in quanto i file .h vengono inclusi in quelli .c dove ho tutte le definizioni e gli include, tanto è vero che in tutte le librerie che fin ora ho creato per diverse strutture dati, non ho mai mai incluso qualcosa nei file .h, in quanto contengono solo i prototipi delle funzioni, e non ho mai avuto questo tipo di problemi. In ogni caso, ho fatto come mi dici, ma il problema rimane il medesimo, quindi non credo c'entri questo con la mancata compilazione del main..
  • Re: Creazione Grafo effettuando il parsing di un file txt

    shine_ms ha scritto:


    quindi non credo c'entri questo con la mancata compilazione del main..
    No, non centra in quanto dovresti avere un errore del compilatore mentre tu hai un errore di linking. E questo perché il linker non trova l'implementazione di traduciNumeroNodi dato che l'hai chiamata numeroNodi.
    A ogni modo il discorso sugli header resta corretto.
  • Re: Creazione Grafo effettuando il parsing di un file txt

    shodan ha scritto:


    No, non centra in quanto dovresti avere un errore del compilatore mentre tu hai un errore di linking. E questo perché il linker non trova l'implementazione di traduciNumeroNodi dato che l'hai chiamata numeroNodi.
    A ogni modo il discorso sugli header resta corretto.
    giusto avevo modificato il nome della funzione dimenticando di cambiarlo lì, ma ora ho un warning nella compilazione del main..
    warning: variable 'G' set but not used [-Wunused-but-set-variable]|
  • Re: Creazione Grafo effettuando il parsing di un file txt

    Dovrebbe sparire appena la G del main la usi nuovamente.
Devi accedere o registrarti per scrivere nel forum
7 risposte