Παρουσίαση του εργαλείου BISON Γεννήτρια Συντακτικών Αναλυτών Β Φάση Συντακτική Ανάλυση
Χαρακτηριστικά του bison Γεννήτρια συντακτικών αναλυτών σε C/C++. Συµβατό µε το εργαλείο του Unixyacc. Σχετικά εύκολο στη χρήση. Υψηλές επιδόσεις. υνατότητα δηµιουργίας συντακτικών αναλυτών από γραµµατικές χωρίς συµφραζόµενα (context free) τύπου LALR(1). υνατότητα περιγραφής σηµασιολογίας.
Συνήθης λειτουργία του bison Περιγραφή λεκτικού αναλυτή flex Λεκτικός αναλυτής σε C/C++ Περιγραφή συντακτικού αναλυτή bison Συντακτικός αναλυτής σε C/C++ Βοηθητικά µέρη Μεταγλωττιστής C/C++ Κατασκευή µεταγλωττιστή Χρήση µεταγλωττιστή Αρχικό πρόγραµµα Λεκτικός αναλυτής Συντακτικός αναλυτής Αποτελέσµατα συντακτικής ανάλυσης
Μορφή αρχείου περιγραφής %{ ηλώσεις C/C++ %} ηλώσεις bison %% Κανόνες γραµµατικής %% Επιπρόσθετος κώδικας C/C++
ηλώσεις bison ηλώσεις τερµατικών συµβόλων, π.χ. %token TK_void %token TK_PLUS 43 ήλωση αρχικού συµβόλου %start program ηλώσεις προτεραιότητας και προσεταιριστικότητα τελεστών, π.χ. %left TK_PLUS TK_MINUS %left TK_TIMES TK_DIV TK_MOD %right TK_EXPON %nonassoc TK_EQ
Κανόνες γραµµατικής Γενική µορφή: αριστερό_µέλος: δεξιό_µέλος ; Το αριστερό µέλος είναι ένα µη τερµατικό σύµβολο. Το δεξιό µέλος µπορεί να περιέχει µηδέν ή περισσότερα τερµατικά και µη τερµατικά σύµβολα, π.χ. expression: term TK_PLUS expression ;
Κανόνες γραµµατικής Επίσης µπορούν να δίνονται σηµασιολογικές ρουτίνες. Ιδιαίτερα χρήσιµες είναι αυτές στο τέλος ενός δεξιού µέλους, π.χ. statement: TK_STOP { } printf("stop requested.\n"); exit(0);
Επιπρόσθετος κώδικας C/C++ Το τρίτο µέρος της περιγραφής είναι προαιρετικό (όπως και ο διαχωριστής %%). Περιέχει κώδικα C/C++ που ενσωµατώνεται όπως είναι. Χρησιµεύει συνήθως για τον ορισµό βοηθητικών συναρτήσεων που καλούνται από τις διάφορες σηµασιολογικές ρουτίνες.
Ένα απλό παράδειγµα %token TK_NUM %left '+' %left '*' %right '^' %% input: /* empty */ '\n' input expression '\n' input ; expression: TK_NUM '(' expression ')' expression '+' expression expression '*' expression expression '^' expression ; %%
int main () { if (yyparse() == 0) printf("accepted\n"); else printf("rejected\n"); return 0; } int yylex () {... if (isdigit(ch)) {... return TK_NUM; } else if (strchr("\n+*^()", ch)!= NULL) return ch; else... }
Επίδειξη του παραδείγµατος > bison -o example1.c example1.y > gcc -o example1 example1.c > example1 < example1.tst example1.tst 5+3*2 2^ 7^ 3+5*( 3+2) ^ 2 example1 Ac c e pt e d
Σηµασιολογία Σε κάθε σύµβολο της γραµµατικής µπορεί να αποδοθεί µια σηµασιολογική τιµή. Ο τύπος των σηµασιολογικών τιµών καθορίζεται από το macro YYSTYPE, π.χ. #define YYSTYPE double Οι σηµασιολογικές τιµές µπορούν να είναι διαφορετικού τύπου για διαφορετικά σύµβολα. Οι τύποι αυτοί δε δηλώνονται µε ορισµό του YYSTYPE, αλλά στο πρώτο µέρος ως εξής: %union{ double number; char * string; }
Σηµασιολογία Ο τύπος των συµβόλων καθορίζεται επίσης στο πρώτο µέρος της περιγραφής µε δηλώσεις όπως: %token<number> TK_NUMCONST %token<string> TK_STRCONST %type<number> expression Το σύµβολο $$ στη σηµασιολογική ρουτίνα ενός κανόνα παριστάνει την σηµασιολογική τιµή του αριστερού µέλους του κανόνα. Το σύµβολα $n, όπου n θετικός ακέραιος αριθµός, παριστάνει τη σηµασιολογική τιµή του n-οστού συµβόλου του δεξιού µέλους του κανόνα. Το πρώτο σύµβολο αντιστοιχεί στο $1, κ.ο.κ. Οι σηµασιολογικές τιµές των τερµατικών συµβόλων συνήθως καθορίζονται από το λεκτικό αναλυτή και τοποθετούνται στη µεταβλητή yylval.
Ένα πιο σύνθετο παράδειγµα (αρχείο flex) %{ #include <math.h> #include "example2.tab.h" %} digit [0-9] %% [ \t]+ { /* nothing */} \n{ return '\n'; } \+{ return '+'; } \*{ return '*'; } \^{ return '^'; } \({ return '('; } \){ return ')'; } {digit}+(\.{digit}+)?([ee](\+ \-)?{digit}+)? { yylval = atof(yytext); return TK_NUM; }
Ένα πιο σύνθετο παράδειγµα (αρχείο bison - 1) %{ %} #include <math.h> #define YYSTYPE double int count = 0; %token TK_NUM %left '+' %left '*' %right '^ %%
Ένα πιο σύνθετο παράδειγµα (αρχείο bison - 1) input: /*empty*/ input '\n' input expression '\n' { printf("expression(%d) = %lg\n", ++count, $2); } ; expression: TK_NUM {$$ = $1;} '(' expression ') {$$ = $2;} expression '+' expression {$$ = $1 + $3;} expression '*' expression {$$ = $1 * $3;} expression '^' expression {$$ = pow($1, $3);} ;
Ένα πιο σύνθετο παράδειγµα (αρχείο bison - 1) %% int main () { yyparse(); return 0; } yyerror (s) char *s; { printf("line %d: %s\n", count, s); }
Επίδειξη του παραδείγµατος > bison -o example2.c -d example2.y > flex example2.l > gcc -o example2 example2.c lex.yy.c -lfl > example2 < example1.tst example1.tst 5+3*2 2^ 7^ 3+5*( 3+2) ^ 2 example2 Expr e s s i on( 1) = 11 Expr e s s i on( 2) = 1. 7918e +103
Κυριότερες συναρτήσεις του παραγόµενου συντακτικού Σύµβολο int yyparse() int yylex() void yyerror(s) const char *s αναλυτή Περιγραφή Η κύρια συνάρτηση του συντακτικού αναλυτή, που παράγεται βάσει της περιγραφής. Επιστρέφει 0 αν η συντακτική ανάλυση τελειώσει χωρίς σφάλµατα, 1 αν βρέθηκαν συντακτικά σφάλµατα. Η κύρια συνάρτηση του λεκτικού αναλυτή που πρέπει να δίνεται από το χρήστη. Επιστρέφει έναν ακέραιο αριθµό, που αντιστοιχεί σε ένα τερµατικό σύµβολο. Η συνάρτηση χειρισµού σφαλµάτων που πρέπει να δίνεται από το χρήστη. Η συµβολοσειρά s περιέχει το µήνυµα σφάλµατος που παρουσιάστηκε.
Σύµβολο Τύπος ΥΥSTYPE YYSTYPE yylval Περιγραφή Ο τύπος της σηµασιολογικής τιµής των συµβόλων. Η µεταβλητή όπου η συνάρτηση yylex() πρέπει να τοποθετεί τις σηµασιολογικές τιµές των τερµατικών συµβόλων.