ΘΠ06 - Μεταγλωττιστές Συντακτική Ανάλυση, Bison 1
Ένα απλό παράδειγμα Απλή γλώσσα αριθμητικών εκφράσεων Γραμματική E -> T | E + T T -> F | T * F F -> (E) | num Υλοποίηση σε bison %token TK_NUM %left '+' %left '*' %% program :expression ; expression : term | expression ‘+’ term term : factor | term ‘*’ factor factor : ‘(‘ expression ‘)’ | TΚ_num 2
Διφορούμενη Ανάλυση Οι προτεραιότητες τελεστών επιτυγχάνουν την αποφυγή της παραγωγής μιας έκφρασης με περισσότερους του ενός τρόπους arithmetic_expr: TK_NUM | arithmetic_expr ‘+’arithmetic_expr | arithmetic_expr ‘-’ arithmetic_expr | arithmetic_expr ‘*’ arithmetic_expr | arithmetic_expr ‘/’ arithmetic_expr | ‘-’ arithmetic_expr %prec UMINUS | ‘(‘arithmetic_expr ‘)’ ;
Διφορούμενη Ανάλυση Ανάλυση της έκφρασης 1*2+5 (1*2)+5 1*(2+5) a_e Ανάλυση της έκφρασης 1*2+5 (1*2)+5 1*(2+5) a_e a_e NUM
Συντακτική Ανάλυση Bottom-Up Ο συντακτικός αναλυτής που παράγεται απο τον bison είναι αναλυτής “από κάτω προς τα επάνω” (bottom-up) Για την υλοποίηση μιας “από κάτω προς τα επάνω” ανάλυσης, χρησιμοποιούνται τα εξής: μια στοίβα αποθήκευσης των στοιχείων της γλώσσας η ενέργεια “μετάθεση/ολίσθηση” (shift) που τοποθετεί το επόμενο στοιχείο εισόδου στην στοίβα η ενέργεια “αναγωγή/ελάττωση“ (reduce) που εφαρμόζεται στην κορυφή της στοίβας όταν έχει εμφανιστεί το δεξί μέλος ενός κανόνα και το αντικαθιστά με το αριστερό μέλος του οι ενέργειες accept και abort που δηλώνουν την επιτυχημένη ή όχι ανάλυση της εισόδου
Επίλυση Συγκρούσεων (I) Στη διάρκεια της ανάλυσης μιας ακολουθίας εισόδου μπορεί να εμφανιστούν καταστάσεις όπου ο συντακτικός αναλυτής έχει δύο επιλογές (διφορούμενη γραμματική): είτε να συνεχίσει με ολίσθηση είτε να κάνει ελλάτωση σε κάποιο κανόνα (shift – reduce conflict) Ο bison δημιουργεί συντακτικό αναλυτή παρά τα conflicts. Σε αυτή την περίπτωση κάνει shift stmt -> IF expr THEN stmt |IF expr THEN stmt ELSE stmt |other
Επίλυση Συγκρούσεων (II) να κάνει ελλάτωση σε περισσότερους απο έναν κανόνες (reduce – reduce conflict) Ο bison κάνει reduce στον κανόνα που έχει περιγραφεί πρώτος στο αρχείο γραμματικής Αν χρησιμοποιήσουμε την επιλογή bison –v παράγεται ένα αρχείο (.output) με περιγραφές των συγκρούσεων
Σημασιολογία (I) Σε κάθε σύμβολο της γραμματικής μπορεί να αποδοθεί μια σημασιολογική τιμή. Ο τύπος των σημασιολογικών τιμών καθορίζεται από το macro YYSTYPE, #define YYSTYPE double Οι σημασιολογικές τιμές μπορούν να είναι διαφορετικού τύπου για διαφορετικά σύμβολα. Οι τύποι αυτοί δεν δηλώνονται με ορισμό του YYSTYPE, αλλά στο πρώτο μέρος ως εξής: %union{ double number; char* string; } Ο τύπος των συμβόλων καθορίζεται επίσης στο πρώτο μέρος της περιγραφής με δηλώσεις όπως: %token<number> TK_NUMCONST %token<string> TK_STRCONST %type<number> expression 8
Σημασιολογία (II) Με $$ συμβολίζεται η σημασιολογική τιμή του αριστερού μέλους ενός κανόνα. Τα σύμβολα $n, όπου n>0, παριστάνουν τη σημασιολογική τιμή του n-οστού συμβόλου του δεξιού μέλους του κανόνα. Το πρώτο σύμβολο αντιστοιχεί στο $1, κ.ο.κ. Οι σημασιολογικές τιμές των τερματικών συμβόλων συνήθως καθορίζονται από το λεκτικό αναλυτή και τοποθετούνται στη μεταβλητή yylval. Στην περιγραφή του λεκτικού αναλυτή πρέπει σε κάθε αναγνωρίσιμο στοιχείο να αποθηκεύσουμε την τιμή του {id} {yylval.string=strdup(yytext); return(TK_ID);} 9
Προσθήκη Σημασιολογικών Κανόνων %{ typedef int YYSTYPE; %} program: expression { printf(“Value: %d\n”, $1};) ; expression : term { $$ = $1; } | expression ‘+’ term { $$ = $1 + $3; } term : factor { $$ = $1; } | term ‘*’ factor { $$ = $1 * $3; } factor: ‘(‘ expression ‘)’ { $$ = $2; } | TK_NUM { $$ = $1; } 10