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.