ΘΠ06 - Μεταγλωττιστές Ανάνηψη από σφάλματα κατά τη συντακτική ανάλυση 1
Ανάνηψη από σφάλματα Διαδικασία κατά την οποία ανιχνεύεται ένα συντακτικό σφάλμα και συνεχίζεται η ανάλυση για την ανίχνευση περισσότερων λαθών. Τεχνικές ανάνηψης: Error Recovery Error Repair Error Correction
Error Recovery Ανίχνευση συντακτικού λάθους. Αγνόηση μέρους της εισόδου. Aρχικοποίηση περιβάλλοντος αναλυτή (στοίβα, μεταβλητές) για την ανάλυση της υπόλοιπης συμβολοσειράς εισόδου. Μπορεί να οδηγήσει σε ανίχνευση επόμενων λαθών που δεν είναι στην πραγματικότητα λάθη (cascaded errors) => ποιότητα ανάνηψης από σφάλματα. Οι φάσεις της σημασιολογικής ανάλυσης και της παραγωγής ενδιάμεσου κώδικα απενεργοποιούνται. Panic Mode: αναζήτηση για ένα ασφαλές σύμβολο (π.χ. ‘;’) από το οποίο επανεκκινείται η συντακτική ανάλυση.
Error Repair Διαδικασία κατά την οποία ανιχνεύεται ένα σφάλμα και τροποποιείται το κομμάτι της συμβολοσειράς που έχει ήδη αναλυθεί ή το επόμενο του με σκοπό την παραγωγή μίας έγκυρης εισόδου. Εισαγωγή/διαγραφή τερματικών συμβόλων. x=a b+c; //εισαγωγή του συμβόλου ‘=‘ ή ’+’ κτλ. μετά το a Οι επόμενες φάσεις συνεχίζονται κανονικά. Διορθωμένα συντακτικά σφάλματα μπορεί να δημιουργήσουν σφάλματα για τις επόμενες φάσεις.
Error Correction Ό,τι και στην τεχνική του Error Repair με τη διαφορά ότι οι τροποποιήσεις της εισόδου αντικατοπτρίζουν το τί ήθελε ο χρήστης να γράψει.
Error Recovery στον Bison (1/3) Προκαθορισμένη συμπεριφορά κατά την ανίχνευση σφάλματος: κλήση yyerror() για την εκτύπωση διαγνωστικού μηνύματος τερματισμός %error-verbose: οδηγία για πιο κατατοπιστικά μηνύματα Η προκαθορισμένη συμπεριφορά δεν υλοποιεί Error Recovery.
Error Recovery στον Bison (2/3) Παράγεται όταν ανιχνευθεί ένα συντακτικό σφάλμα. error: Όταν ανιχνευθεί σφάλμα, σηματοδοτεί μέχρι που θα πρέπει να αγνοηθεί η είσοδος, ώστε να συνεχίσει η συντακτική ανάλυση. stmt: error ‘;’ ; // είσοδος y = d; x = a b; Στοίβα: stmt ‘x’ ‘=‘ ‘a’, lookahead: ‘b’ Ανιχνεύεται σφάλμα=> εξάγονται τα ‘x’, ‘=‘, ‘a (Στοίβα: stmt) shift του error (Στοίβα: stmt error) διαγραφή ‘b’, lookahead: ‘;’ Στοίβα: stmt error ‘;’ => Στοίβα: stmt stmt
Error Recovery στον Bison (3/3) error: Μόλις ενεργοποιηθεί το σύμβολο καλείται η yyerror() yyerrok: μακροεντολή για την ένδειξη τέλους φάσης Error Recovery Φειδώ στη χρήση του error: δημιουργία συγκρούσεων αναφορά λαθών που δεν υπάρχουν “Error recovery strategies are necessarily guesses. When they guess wrong, one syntax error often leads to another.”
Παράδειγμα v1.0 (1/3) %{ #include <stdio.h> void yyerror (char const *s); extern int num_lines; %} %token TK_NUM TK_ID TK_BADID %left '-' '+' %left '*' '/' %left TK_NEG /* negation--unary minus */ %right '^' /* exponentiation */ %% /* The grammar follows. */ input: /* empty */ | input line ; line: ';' | exp ';'
Παράδειγμα v1.0 (2/3) exp: TK_NUM | TK_ID | exp '+' exp {printf("exp + exp\n");} | exp '-' exp {printf("exp - exp\n");} | exp '*' exp {printf("exp * exp\n");} | exp '/' exp {printf("exp / exp\n");} | '-' exp %prec TK_NEG {printf("-exp\n");} | exp '^' exp {printf("exp ^ exp\n");} | '(' exp ')' {printf("( exp )\n");} ; %% int main(void) { return yyparse(); } void yyerror (char const *s) { printf("%d: %s\n", num_lines, s);
Παράδειγμα v1.0 (3/3) Είσοδος: Έξοδος: 1. sdf 1234; 1: syntax error 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error
Παράδειγμα v1.1 Είσοδος: Έξοδος: 1. sdf 1234; Προσθήκη: %error-verbose Είσοδος: 1. sdf 1234; 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error, unexpected TK_NUM
Παράδειγμα v1.2 (1/2) %{ #include <stdio.h> void yyerror (char const *s); extern int num_lines; %} %error-verbose %token TK_NUM TK_ID TK_BADID %left '-' '+' %left '*' '/' %left TK_NEG /* negation--unary minus */ %right '^' /* exponentiation */ %% /* The grammar follows. */ input: /* empty */ | input line ; line: ';' | exp ';‘ | error ';‘ {yyerrok;} ;
Παράδειγμα v1.2 (2/2) Είσοδος: Έξοδος: 1. sdf 1234; 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error, unexpected TK_NUM 2: syntax error, unexpected TK_BADID exp + exp ( exp ) 5: syntax error, unexpected ';' 7: syntax error, unexpected ')' exp * exp
Παράδειγμα v1.3 (1/2) exp: TK_NUM | TK_ID | TK_BADID {yyerror("invalid ID"); YYERROR; yyerrok;} | exp '+' exp {printf("exp + exp\n");} | exp '-' exp {printf("exp - exp\n");} | exp '*' exp {printf("exp * exp\n");} | exp '/' exp {printf("exp / exp\n");} | '-' exp %prec TK_NEG {printf("-exp\n");} | exp '^' exp {printf("exp ^ exp\n");} | '(' exp ')' {printf("( exp )\n");} ; %% int main(void) { return yyparse(); } void yyerror (char const *s) { printf("%d: %s\n", num_lines, s);
Παράδειγμα v1.3 (2/2) Είσοδος: Έξοδος: 1. sdf 1234; 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error, unexpected TK_NUM 2: invalid ID exp + exp ( exp ) 5: syntax error, unexpected ';' 7: syntax error, unexpected ')' exp * exp
Παράδειγμα v1.4 (1/2) %{ #include <stdio.h> void yyerror (char const *s); extern int num_lines; %} %error-verbose %token TK_NUM TK_ID TK_BADID %left '-' '+' %left '*' '/' %left TK_NEG /* negation--unary minus */ %right '^' /* exponentiation */ %% /* The grammar follows. */ input: /* empty */ | input line ; line: ';' | exp ';‘ | exp error exp ';' {yyerror("missing arithmetic operator or ';'"); yyerrok;} | error ';‘ {yyerrok;} ;
Παράδειγμα v1.4 (2/2) Είσοδος: Έξοδος: 1. sdf 1234; 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error, unexpected TK_NUM 1: missing arithmetic operator or ';' 2: invalid ID exp + exp ( exp ) 5: syntax error, unexpected ';‘ 7: syntax error, unexpected ')' exp * exp 8: missing arithmetic operator or ';'
Παράδειγμα v1.5 (1/2) exp: TK_NUM | TK_ID | TK_BADID {yyerror("invalid ID"); YYERROR; yyerrok;} | exp '+' exp {printf("exp + exp\n");} | exp '-' exp {printf("exp - exp\n");} | exp '*' exp {printf("exp * exp\n");} | exp '/' exp {printf("exp / exp\n");} | '-' exp %prec TK_NEG {printf("-exp\n");} | exp '^' exp {printf("exp ^ exp\n");} | '(' exp ')' {printf("( exp )\n");} | '(' exp error {yyerror("Missing operator ')'"); yyerrok;} ; %% int main(void) { return yyparse(); } void yyerror (char const *s) { printf("%d: %s\n", num_lines, s);
Παράδειγμα v1.5 (2/2) Είσοδος: Έξοδος: 1. sdf 1234; 2. 234fsdf + 234; 3. 1234 + asf; 4. (2345); 5. (asdf; 6. 1243 + 234; 7. 234); 8. 234 * 234; Έξοδος: 1: syntax error, unexpected TK_NUM 1: missing arithmetic operator or ';' 2: invalid ID exp + exp ( exp ) 5: syntax error, unexpected ';‘ 5: Missing operator ')' 7: syntax error, unexpected ')' exp * exp 8: missing arithmetic operator or ';'
Αναφορές Εγχειρίδιο χρήσης Bison. http://www.gnu.org/software/bison/manual/html_mono/bi son.html.gz . Charles Fischer, University of Wisconsin, Richard LeBlanc. Crafting a Compiler with C. Addison-Wesley, 1991.