PDA

Visualizza la versione completa : [C] E' possibile parserizzare due volte uno stesso file in Yacc/Bison?


MarikaRod
23-03-2009, 11:13
Ciao,
mi chiedevo se e' possibile parserizzare due volte uno stesso file d'input in Yacc/Bison.
In questo modo potrei, nella prima lettura del file, crearmi una struttura dati che mi contenga tutte le informazioni che mi serviranno in un secondo momento e poi, nella seconda lettura, usare tale struttura dati per ricavarmi tutte le informazioni che mi servono.

Nel main ho queste istruzioni:

ofstream * designs_defines;
bool second_time = false;

main( int argc, char *argv[] )
{ extern FILE *yyin;
++argv; --argc;
string fname = argv[0];

designs_defines = new ofstream();
string base_file_name = fname.substr(0, fname.length() - 4);
designs_defines->open( (base_file_name + "_defines.h").c_str(), ios::trunc );
yyin = fopen( argv[0], "r" );
/*yydebug = 1;*/
errors = 0;
SystemObject * st = new SystemObject();
yyparse (st);
printf ( "Parse Completed\n" );

....

}

quindi ho provato a modificare tale codice in questo modo:

ofstream * designs_defines;
bool second_time = false;

main( int argc, char *argv[] )
{ extern FILE *yyin;
++argv; --argc;
string fname = argv[0];

designs_defines = new ofstream();
string base_file_name = fname.substr(0, fname.length() - 4);
designs_defines->open( (base_file_name + "_defines.h").c_str(), ios::trunc );
yyin = fopen( argv[0], "r" );
/*yydebug = 1;*/
errors = 0;
SystemObject * st = new SystemObject();
yyparse (st);


second_time = true;
SystemObject * st2 = new SystemObject();
yyparse(st2);


printf ( "Parse Completed\n" );

....

}

dove il valore booleano "second_time" verra' utilizzato all'interno di una grammatica del parser per poter ricavare delle informazioni che potranno essere disponibili solo se viene effettuata la seconda lettura del file di input.
In questo modo non viene effettuata alcuna altra lettura del file, inoltre dopo aver passato il file di input al parser, questo termina con "syntax error 1".

Grazie in anticipo a chiunque mi aiuti e se questo messaggio non e' molto chiaro o se avete bisogno di altre informazioni, chiedetemi pure!!

Vincenzo1968
23-03-2009, 21:21
Ciao,

Compilatori, interpreti e tecniche di parsing: argomento(per quel che mi riguarda) affascinante.

Invece di parsare due volte lo stesso file, io ti consiglio di costruire, in una sola passata, l'AST (http://en.wikipedia.org/wiki/Abstract_syntax_tree) e la tabella dei simboli.
Una volta costruito l'AST, puoi attraversarlo per ulteriori elaborazioni(type checking, analisi semantica, etc).

Un esempio di costruzione dell'AST, in Yacc/Bison, lo trovi qui(vedi pag. 20, Calculator):

http://epaperpress.com/lexandyacc/index.html

:)

MarikaRod
24-03-2009, 16:16
Ciao!
Grazie per avermi risposto, ma ho una domanda da porti:
il mio file di input contiene una serie di definizioni di macchine a stati a partire dagli automi "foglia" fino via via ad arrivare a descrivere le macchine piu' complesse che contengono tali automi.
Quando trovo la descrizione di una macchina a stati, non conosco il nome vero e proprio della macchina, bensi una sua etichetta ed io ho bisogno di mantenere il riferimento di tutte le macchine che comprendono altre macchine.
Inserisco di seguito un pezzo di codice relativo al file di input:

@StateMachine StateMachineSpec_179 =

@State
Incremento1 = StateMachineSpec_180
[[ Pos440 = "451 440 669 512 60 1 114689" ]],
Incremento2 = StateMachineSpec_181
[[ Pos440 = "804 437 1019 521 71 1 114689" ]],
IncrementoVeloce = StateMachineSpec_182
[[ Pos440 = "1132 434 1335 522 76 1 114689" ]],
Decremento1 = StateMachineSpec_183
[[ Pos440 = "446 685 656 766 69 1 114689" ]],
Decremento2 = StateMachineSpec_184
[[ Pos440 = "807 679 1017 762 71 1 114689" ]],
DecrementoVeloce = StateMachineSpec_185
[[ Pos440 = "1142 676 1344 759 70 1 114689" ]];

@StateRegion
Region1 (Incremento1, Incremento2, IncrementoVeloce, Decremento1,
Decremento2, DecrementoVeloce)
[[ Pos440 = "0 0 1072 392" ]];

@Entry
#a_flag_MovEnc1();

@Exit;

@Do;

@InternalRule;

@TransitionRule;

@TerminationRule;

@End;

@StateMachine StateMachineSpec_178 =

@State;

@StateRegion
Region1
[[ Pos440 = "0 0 182 30" ]];

@Entry
#a_flag_MovEnc0();

@Exit;

@Do;

@InternalRule;

@TransitionRule;

@TerminationRule;

@End;

@StateMachine StateMachineSpec_177 =

@State
FERMO = StateMachineSpec_178
[[ Pos440 = "92 561 275 641 50 1 114689" ]],
@Initial _InitialState73
[[ Pos440 = "106 502 126 522 114689" ]],
MOSSO = StateMachineSpec_179
[[ Pos440 = "377 361 1450 791 37 1 114689" ]];

@StateRegion
Region1 (FERMO, _InitialState73, MOSSO)
[[ Pos440 = "0 0 1434 500" ]];

@Entry;

@Exit;

@Do;

@InternalRule;

@TransitionRule;

@TerminationRule;

@End;

Supponendo che la macchina StateMachineSpec_177 sia quella piu' esterna, gia' quando analizzo la macchina StateMachineSpec_179 devo essere a conoscenza che il suo vero nome e' MOSSO.
Quindi, quando analizzo nel parser la macchina 179, per ogni stato devo associare il seguente identificativo:

StateMachineSpec177_MOSSO_Incremento1
StateMachineSpec177_MOSSO_Incremento2
e cosi via...

Quindi e' possibile, tramite AST recuperare le informazioni che necessito in ogni StateMachineSpec_# sebbene potro' conoscere il nome vero e proprio delle macchine maggiori solo successivamente?

Grazie in anticipo!
Marika

Vincenzo1968
24-03-2009, 17:38
Il tuo problema simile a quello che deve affrontare un assembler con le istruzioni di salto.
Quando un programma in assembly contiene un'istruzione di salto con un'etichetta che definita pi avanti nel file, l'assembler non conosce l'indirizzo dell'etichetta in questione(forward references).

In questo caso l'assembler effettua due passate nel file di input(buona, dunque, la tua idea iniziale. L'AST non va bene, ma credevo che tu dovessi risolvere un problema simile a quello dell'esempio che ti ho linkato).
Nella prima passata costruisci una tabella dei simboli(ti consiglio di utilizzare una hash-table).
Nella seconda passata, ogni volta che incontri un identificatore, lo cerchi nella tabella dei simboli e ne ricavi le informazioni che ti necessitano.

Ricordati di riportare il puntatore all'inizio del file prima della seconda chiamata alla funzione yyparse:



fseek(yyin, 0, SEEK_SET);




...
...
yyparse (st);

fseek(yyin, 0, SEEK_SET);

second_time = true;
SystemObject * st2 = new SystemObject();
yyparse(st2);
...
...

MarikaRod
25-03-2009, 09:56
Fantastico!! Ora funziona! Non mi da piu' errori di sintassi, mi mancava il puntatore all'inizio del file allora!

Grazie mille per l'aiuto!

Buona giornata,
Marika

Loading