Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken

  • 1,513 views
Uploaded on

 

More in: Education
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,513
On Slideshare
1,513
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
9
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Von Automaten zu Programmen Manuelle und automatische Entwicklung von Parsern Tim Furche Compilerbau, Wintersemester 2008/09, Prof. F. Bry 1
  • 2. Formale Sprachen: Beispiele aus der Praxis 2
  • 3. Formale Sprachen: Nicht nur in Compilern! 3
  • 4. Browser 4
  • 5. 5
  • 6. URIs Google Anfrage HTML JavaScript CSS Browser: Formale Sprachen 6
  • 7. Spreadsheets: Excel/ Numbers/OpenCalc 7
  • 8. 8
  • 9. Formeln Format Felder Macros 9
  • 10. A Endliche Automaten Parser für Reguläre Sprachen z.B.: URIs, Datumsangaben, Gleitpunktzahlen 10
  • 11. Beispiel: Gleitpunktzahlen 11
  • 12. -666.797E-14 parsen, normalisieren 12
  • 13. $

java
‐jar
FPParser.jar
‐666.797E‐14
‐‐step (Initial,
‐666.797E‐14)
 |‐
(WholeNrDigit,
666.797E‐14)
 |‐
(WholeNrDigit_or_Fraction_or_Exponent,
66.797E‐14)
 |‐
(WholeNrDigit_or_Fraction_or_Exponent,
6.797E‐14)
 |‐
(WholeNrDigit_or_Fraction_or_Exponent,
.797E‐14)
 |‐
(FractionDigit,
797E‐14)
 |‐
(FractionDigit_or_Exponent,
97E‐14)
 |‐
(FractionDigit_or_Exponent,
7E‐14)
 |‐
(FractionDigit_or_Exponent,
E‐14)
 |‐
(Exponent,
‐14)
 |‐
(ExponentDigit,
14)
 |‐
(ExponentDigit_or_End,
4)
 |‐
(ExponentDigit_or_End,
)
 Success:
‐6.66797E‐12
 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
 Gleitpunktzahlen Parsen und Normalisieren mit Endlichem Automaten 13
  • 14. 14
  • 15. Wie? z.B. in Java 15
  • 16. 16
  • 17. Bibliothek: Double.parseDouble() 17
  • 18. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher 17
  • 19. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton 17
  • 20. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton Manuelle Implementierung 17
  • 21. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton Manuelle Implementierung 17
  • 22. 41 } ‘0’–‘9’ ‘ -’ start I F ‘0’–‘9’ R ‘0’–‘9’ Ganzzahlen in Java Endlicher Automat für den Ganzzahlparser in Long.parseLong 18
  • 23. 1 public static long parseLong(String s, int radix) throws NumberFormatException { 3 if (s == null) throw new NumberFormatException(quot;nullquot;); [...] 5 int max = s.length(); [...] 7 // State 1: Treat the sign if (s.charAt(0) == ’-’) { 9 negative = true; limit = Long.MIN_VALUE; 11 i++; } else 13 limit = -Long.MAX_VALUE; 15 // State 2: Treat first digit if (i < max) { 17 digit = Character.digit(s.charAt(i++),radix); if (digit < 0) // Not a digit 19 throw NumberFormatException.forInputString(s); else 21 result = -digit; } 23 // State 3: Treat all other digits 19 25 while (i < max) { digit = Character.digit(s.charAt(i++),radix);
  • 24. 21 result = -digit; } 23 // State 3: Treat all other digits 25 while (i < max) { digit = Character.digit(s.charAt(i++),radix); 27 if (digit < 0) // Not a digit throw NumberFormatException.forInputString(s); 29 result *= radix; // Check if out-of-bounds [...] 31 result -= digit; } 33 if (negative) { if (i > 1) 35 return result; else /* Only got quot;-quot; */ 37 throw NumberFormatException.forInputString(s); } else 39 return -result; 41 } ‘0’–‘9’ ‘ -’ start I F ‘0’–‘9’ R 20 ‘0’–‘9’
  • 25. 21
  • 26. en, die unser Parser erkennen soll: 2.1 Regulärer Ausdruck für Gleitpunktzahlen (‘Für -’)? digit+ (‘.’ digit+)? ((‘e’|‘E’) digit+)? Aus +’|‘ unser Beispiel beginnen wir mit einem regulären Gleitpunktzahlen, die unser Parser erkennen soll: 0’ | ‘1’ | ‘2’ | ‘3’ | ‘4’ | ‘5(‘+’|‘-’ | ‘7’ | ‘8’.|’ ‘9’ ’ | ‘6 ’)? digit+ (‘ digit+)? ((‘e’|‘E’) digit digit digit* digit := ‘0’ | ‘1’ | ‘2’ | ‘3’ | ‘4’ | ‘5’ | ‘6’ | ‘7’ | ‘8’ | ‘9’ digit+ := digit digit* tion ist fast wie in den Übungen behandelt, allerdin omma-Anteil wegfallenfast wie in den der Exponent). a Die Spezifikation ist kann (wie Übungen behandelt, dass der Nachkomma-Anteil wegfallen kann (wie der Expon Gleitpunktzahlen in Java utomat für Gleitpunktzahlen 2.2 Endlicher Automat für Gleitpunktzahlen Spezifikation: Regulärer Ausdruck 22 ache können wir durch folgenden Automaten besch Die gleiche Sprache können wir durch folgenden Automate
  • 27. ‘+’, ‘-’ start S s,d Sd ‘0’–‘9’ ‘.’ ‘0’–‘9’ ‘0’–‘9’ S d ,p,e ‘0’–‘9’ Fd ‘0’–‘9’ F d ,e ‘e’, ‘E’ ‘e’, ‘E’ E s,d ‘0’–‘9’ ‘+’, ‘-’ Ed ‘0’–‘9’ E d ,# ‘0’–‘9’ 23 Der Automat verwendet die folgenden Zustände, benannt nach d
  • 28. gibt. Dabei nennen wir für eine Gleitpunktzahl s. f · 10 : s den significand (oder Vorkomma-Anteil der Mantisse), f die fraction (oder Nachkomma-Anteil der Man- tisse), und e den exponent. Zustand Teil der Zahl Nachfolgerzeichen Beschreibung S s,d significand Ziffer (d ) oder Vorzeichen (s ) Anfangszustand, erkennt optionales Vor- zeichen Sd –”– Ziffer stellt sicher, dass zumindest eine Ziffer im significand vorkommt S d , f ,e –”– Ziffer, Punkt (p ) oder e erkennt beliebige Folgen von Ziffern, fährt mit Erkennung von fraction oder expo- nent fort, Endzustand Fd fraction Ziffer stellt sicher, dass zumindest eine Ziffer in fraction vorkommt F d ,e –”– Ziffer or e erkennt beliebige Folgen von Ziffern, fährt mit Erkennung von exponent fort, Endzu- stand E s,d exponent Ziffer oder Vorzeichen Ziffer oder Vorzeichen als Beginn des ex- ponent Ed –”– digit stellt sicher, dass zumindest eine Ziffer in exponent vorkommt Ed –”– digit erkennt beliebige Folgen von Ziffern, End- zustand 24
  • 29. Implementierung Endlicher Automaten Ansätze … Implicit state: wie Long.parseLong(); Zustand implizit Bereich im Programm identifiziert den aktuellen Zustand (PC) für einfach, im wesentlichen sequentielle Automaten geeignet Loop-and-switch: Schleife über Eingabe + goto/switch je nach akt. Zustand und Symbol effizient nur wenn Sprünge berechnet werden können typisch für komplexere Automaten mit oft wiederkehrenden Zuständen Loop-and-lookup: Schleife + Nachschlagen in Tabellenrepr. von δ Zeilen: Zustände, Spalten: Eingabesymbole, Zelleninhalt: Folgezustand Zeit-effizient auf Kosten von Speicher, nur bei kleinem Eingabealphabet z.B. reguläre Ausdrücke über Basispaarsequenzen (nur A, T, G, C). 25
  • 30. Implementierung Endlicher Automaten Umgebung für FP-Parser … FPParser: abstrakte Oberklasse für alle Floating-Point-Parser Attribute & Methoden zur Verwaltung & Berechnung der FP-Zahl FPPaser.FPNumberPart: hält ganzzahligen Anteil einer FP-Zahl significand (Vorkomma-Anteil), fraction (Nachkomma-Antail), exponent #parse(char): Transition & Berechnung des Automaten bei Eingabe eines einzelnen Zeichens #parse(String): Schleife über die Eingabe für jedes Zeichen wird #parse(char) aufgerufen 26
  • 31. Implementierung Endlicher Automaten Umgebung für FP-Parser … FPParser: abstrakte Oberklasse für alle Floating-Point-Parser Attribute & Methoden zur Verwaltung & Berechnung der FP-Zahl FPPaser.FPNumberPart: hält ganzzahligen Anteil einer FP-Zahl significand (Vorkomma-Anteil), fraction (Nachkomma-Antail), exponent #parse(char): Transition & Berechnung des Automaten bei Eingabe eines einzelnen Zeichens #parse(String): Schleife über die Eingabe für jedes Zeichen wird #parse(char) aufgerufen FPParser 26
  • 32. einer Ziffer bleiben wir im gleichen Zustand und fügen die Ziffer zur aktu- ellen Repräsentation des significand hinzu. Bei einem Punkt gehen wir in den Zustand F d , also erwarten die erste Ziffer der fraction (würden wir hier Implementierung Endlicher Automaten in F d ,e übergehen, wären auch Zahlen der Form 12.E10 erlaubt). Bei einem e oder E gehen wir in Zustand E s,d (STATE_Exponent). In den beiden letzten Loop-and-Switch … Fällen dienen die Zeichen nur als Trennzeichen und werden nicht zur aktu- ellen Repräsentation hinzugefügt. 1 case STATE_SignifDigit_Fraction_Exponent: if(Character.isDigit(c)) { 3 state = STATE_SignifDigit_Fraction_Exponent; significand.addDigit(c); 5 } else if(c == ’.’) { 7 state = STATE_FractionDigit; } 9 else if(c == ’e’ || c == ’E’) { state = STATE_Exponent; 11 } else state = STATE_Failure; 13 break; Loop-and-Lookup: realisiert in MatrixFPParser. Die Idee von loop-and-lookup Im- plementierungen ist, in der Schleife über die Eingabezeichen mit Hilfe ei- 27 ner (konstanten) Lookup-Tabelle den Folgezustand (und eventuelle Berech-
  • 33. einer Ziffer bleiben wir im gleichen Zustand und fügen die Ziffer zur aktu- ellen Repräsentation des significand hinzu. Bei einem Punkt gehen wir in den Zustand F d , also erwarten die erste Ziffer der fraction (würden wir hier Implementierung Endlicher Automaten in F d ,e übergehen, wären auch Zahlen der Form 12.E10 erlaubt). Bei einem e oder E gehen wir in Zustand E s,d (STATE_Exponent). In den beiden letzten Loop-and-Switch … Fällen dienen die Zeichen nur als Trennzeichen und werden nicht zur aktu- ellen Repräsentation hinzugefügt. 1 case STATE_SignifDigit_Fraction_Exponent: if(Character.isDigit(c)) { 3 state = STATE_SignifDigit_Fraction_Exponent; significand.addDigit(c); 5 } else if(c == ’.’) { 7 state = STATE_FractionDigit; } 9 else if(c == ’e’ || c == ’E’) { state = STATE_Exponent; 11 } else state = STATE_Failure; 13 break; PlainFPParser Loop-and-Lookup: realisiert in MatrixFPParser. Die Idee von loop-and-lookup Im- plementierungen ist, in der Schleife über die Eingabezeichen mit Hilfe ei- 27 ner (konstanten) Lookup-Tabelle den Folgezustand (und eventuelle Berech-
  • 34. 0 Implementierung Endlicher Automaten SIGNIF_DIGIT_FRACTION_EXPONENT { 2 Loop-and-Switch … State transition(char c, FPNumberPart nr){ if(Character.isDigit(c)) { 4 nr.addDigit(c); return SIGNIF_DIGIT_FRACTION_EXPONENT; 6 } else if(c == ’.’) { 8 return FRACTION_DIGIT; } 10 else if(c == ’e’ || c == ’E’) { return EXPONENT; 12 } else return FAILURE; 14 } FPNumberPart select(FPNumberPart s, FPNumberPart f, FPNumberPart← e){ return s; } 16 boolean isFinal(){ return true; } boolean isFailure(){ return false; } 18 }, 28 3.1 Tests
  • 35. 0 Implementierung Endlicher Automaten SIGNIF_DIGIT_FRACTION_EXPONENT { 2 Loop-and-Switch … State transition(char c, FPNumberPart nr){ if(Character.isDigit(c)) { 4 nr.addDigit(c); return SIGNIF_DIGIT_FRACTION_EXPONENT; 6 } else if(c == ’.’) { 8 return FRACTION_DIGIT; } 10 else if(c == ’e’ || c == ’E’) { return EXPONENT; 12 } else return FAILURE; 14 } FPNumberPart select(FPNumberPart s, FPNumberPart f, FPNumberPart← e){ return s; } 16 boolean isFinal(){ return true; } boolean isFailure(){ return false; } 18 }, EnumFPParser 28 3.1 Tests
  • 36. nungsschritte) zu spezifizieren. In der Lookup-Tabelle sind den Zuständen Zeilen, den Eingabezeichen Spalten zugeordnet. Implementierung Endlicher Automaten Die Lookup-Tabelle findet sich in MatrixFPParser#stateMatrix und ist eine ziemlich direkte Umsetzung der δ Übergangsfunktion des Automaten. Für Loop-and-Lookup … den gleichen Zustand wie oben ergibt sich z.B. folgender Eintrag in der Ma- trix: 1 // STATE_SignifDigit_Fraction_Exponent { // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Digit) 3 new DigitEffect(STATE_SignifDigit_Fraction_Exponent,← significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Sign) 5 new Effect(STATE_Failure, significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Expn) 7 new Effect(STATE_Exponent, significand), // (STATE_Initial, SCLASS_Period) 9 new Effect(STATE_FractionDigit, significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Rest) 11 new Effect(STATE_Failure, significand) }, In jeder Zelle der Lookup-Tabelle findet sich ein Effect Objekt, dass den nächsten Zustand und die auszuführenden Berechnungsschritte enthält. Um die Berechnungsschritte zu paramerterisieren verwendet 29 MatrixFPParser Funktionsobjekte (wo Sprachen wie C++ Funktionspointer
  • 37. nungsschritte) zu spezifizieren. In der Lookup-Tabelle sind den Zuständen Zeilen, den Eingabezeichen Spalten zugeordnet. Implementierung Endlicher Automaten Die Lookup-Tabelle findet sich in MatrixFPParser#stateMatrix und ist eine ziemlich direkte Umsetzung der δ Übergangsfunktion des Automaten. Für Loop-and-Lookup … den gleichen Zustand wie oben ergibt sich z.B. folgender Eintrag in der Ma- trix: 1 // STATE_SignifDigit_Fraction_Exponent { // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Digit) 3 new DigitEffect(STATE_SignifDigit_Fraction_Exponent,← significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Sign) 5 new Effect(STATE_Failure, significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Expn) 7 new Effect(STATE_Exponent, significand), // (STATE_Initial, SCLASS_Period) 9 new Effect(STATE_FractionDigit, significand), // (STATE_SignifDigit_Fraction_Exponent, SCLASS_Rest) 11 new Effect(STATE_Failure, significand) }, In jeder Zelle der Lookup-Tabelle findet sich MatrixFPParser ein Effect Objekt, dass den nächsten Zustand und die auszuführenden Berechnungsschritte enthält. Um die Berechnungsschritte zu paramerterisieren verwendet 29 MatrixFPParser Funktionsobjekte (wo Sprachen wie C++ Funktionspointer
  • 38. Implementierung Endlicher Automaten Loop-and-Lookup … Ziffer Vorzeichen ‘e’, ‘E’ Punkt Initial SignifD_F_E SignifD Failure Failure SignifD SignifD Failure Failure Failure SignifD_F_E SignifD_F_E Failure Exponent FractionD FractionD FractionD_E Failure Failure Failure FractionD_E FractionD_E Failure Exponent Failure Exponent ExponentD_End ExponentD Failure Failure ExponentD ExponentD_End Failure Failure Failure ExponentD_End ExponentD_End Failure Failure Failure Failure Failure Failure Failure Failure 30
  • 39. $

java
‐jar
FPParser.jar
33E0
‐‐step
‐‐pEnum (INITIAL,
33E0)
 


|‐
(SIGNIF_DIGIT_FRACTION_EXPONENT,
3E0)
 


|‐
(SIGNIF_DIGIT_FRACTION_EXPONENT,
E0)
 


|‐
(EXPONENT,
0)
 


|‐
(EXPONENT_DIGIT_END,
<epsilon>)
 Success:



33.0
 ‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
 Gleitpunktzahlen Parsen und Normalisieren mit Endlichem Automaten 31
  • 40. 32
  • 41. B Keller- Automaten Parser für kontextfreie Sprachen++ z.B. für arithmetische Ausdrücke und Erweiterungen 33
  • 42. Beispiel: Arithmetischer Ausdruck 34
  • 43. 2 + 4 * 11 - 2 * 3 + 2 parsen, ausrechnen 35
  • 44. 2
+
4
*
11
‐
2
*
3
+
2 $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr
‐‐file
plain‐intexpr <no
output>
(=
no
error) $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr_Eval
‐‐file
plain‐intexpr Expression
in
line
1:
42
 $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr_AST
‐‐file
plain‐intexpr (+
(‐
(+
2
(*
4
11))
(*
2
3))
2) Arithmetische Ausdrücke Parsen und Ausrechnen mit Kellerautomaten 36
  • 45. 37
  • 46. x
=
78 y
=
2 112
+
4
*
x
‐
2
*
y
+
z
*
2 5
+
3
‐
2 $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr
‐‐file
var‐intexpr <no
output>
(=
no
error) $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr_Var
‐‐file
var‐intexpr line
3:24
rule
atom
failed
predicate:
{
declaredVariables.contains($ID.text)
}? $

java
‐jar
ParserGenerators.jar
‐‐pIntExpr_Eval
‐‐file
var‐intexpr line
3:24
rule
atom
failed
predicate:
{undeclared
variable
z}? Expression
in
line
3:
420 Expression
in
line
4:
6 + Variablen Parsen und Ausrechnen mit Kellerautomaten 38
  • 47. 39
  • 48. 1 /*------------------------------------------------------------------ Arithmetik & Parsergeneratoren 3 * PARSER RULES *------------------------------------------------------------------*/ Grammatik prog: stat+ ; 5 stat: expr NEWLINE 7 |ID ’=’ expr NEWLINE |NEWLINE 9 ; 11 expr : multExpr ( (’+’ |’-’) multExpr )* 13 ; 15 multExpr : atom (’*’ atom )* 17 ; 19 atom : INT 21 |ID |’(’ expr ’)’ 23 ; 40 25 /*------------------------------------------------------------------
  • 49. 17 ; 19 atom Arithmetik & Parsergeneratoren : INT |ID Lexer-Regeln der Grammatik 21 |’(’ expr ’)’ 23 ; 25 /*------------------------------------------------------------------ * LEXER RULES 27 *------------------------------------------------------------------*/ 29 ID : (’a’..’z’|’A’..’Z’)+ ; INT : ’0’..’9’+ ; 31 NEWLINE:’r’? ’n’ ; WS : (’ ’|’t’)+ {skip();} ; Was ist die Aufgabe eines Lexers? Beispiel: -666.797E-14 Zum Ausprobieren der Parser einfach folgendem Rezept folgen: 41 • FPParser.jar herunterladen und mit
  • 50. direkte Ausgaben, Fehler Lexer Parser Character Token Abstract Strom Strom Syntax Tree (auch Scanner, Tokenizer) Struktur eines ANTLR-Parser Lexer, Parser, AST, Token vs. Character-Strom 42
  • 51. w i d t h = 2 0 0 ; n Characters ID = INT ; Tokens WS WS WS Von Characters zu Tokens Aufgabe des Lexers 43
  • 52. void multExpr() { try { atom(); while( <<next input symbol is '*' >> ) { match('*'); atom(); } } [... error handling] } void atom() { try { int alt=3; switch (<< next input symbol >>) { case INT: alt = 1; break; case ID: alt = 2; break; case '(': alt = 3; break; default: [error] } switch(alt){ case 1: match(INT); break; case 2: match(ID); break; case 3: match('('); expr(); match(')'); break; } Parser.java Was hinten herauskommt … } [... error handling] } 44
  • 53. 1 /*------------------------------------------------------------------ Arithmetik & Parsergeneratoren 3 * PARSER RULES *------------------------------------------------------------------*/ Grammatik prog: stat+ ; 5 { declaredVariables.add($ID.text); } stat: expr NEWLINE 7 |ID ’=’ expr NEWLINE |NEWLINE 9 ; 11 expr : multExpr ( (’+’ |’-’) multExpr )* 13 ; 15 multExpr : atom (’*’ atom )* 17 ; 19 atom : INT 21 |ID { declaredVariables.contains($ID.text) }? |’(’ expr ’)’ 23 ; 45 25 /*------------------------------------------------------------------
  • 54. 1 /*------------------------------------------------------------------ Arithmetik & Parsergeneratoren 3 * PARSER RULES *------------------------------------------------------------------*/ Grammatik prog: stat+ ; 5 { declaredVariables.add($ID.text); } stat: expr NEWLINE 7 |ID ’=’ expr NEWLINE |NEWLINE 9 ; 11 expr : multExpr ( (’+’ |’-’) multExpr )* 13 ; 15 multExpr : atom (’*’ atom )* 17 ; 19 atom : INT Test! 21 |ID { declaredVariables.contains($ID.text) }? |’(’ expr ’)’ 23 ; 45 25 /*------------------------------------------------------------------
  • 55. grammar IntExpr_Var; options { language = Java; superClass = RunnableParser; } @lexer::header{ package de.lmu.ifi.pms.parsergenerators; } @header{ package de.lmu.ifi.pms.parsergenerators; import java.util.Set; import java.util.HashSet; } @members { /** Set for maintaining already declared variables. */ Set declaredVariables = new HashSet(); public static RunnableParser getParserInstance(ANTLRStringStream stream){ [...] } public void run(ASTProcessor... processors){ try { Prolog prog(); } catch (Exception e) [...] } } 46
  • 56. prog: stat+ ; stat: // Semantic action for printing out the value returned by the evaluation of each expression expr NEWLINE { System.out.println(quot;Expression in line quot; + input.get(input.index()-1).getLine() + quot;: quot; + $expr.value);} // Semantic action for constructing the set of declared variables. | ID '=' expr NEWLINE { varValues.put($ID.text, new Integer($expr.value)); } | NEWLINE ; // All rules of the grammar get a return value, the computed value of their matching expression expr returns [int value] : e=multExpr {$value = $e.value;} // We need to distinguish addition and subtraction ( '+' e=multExpr {$value += $e.value;} | '-' e=multExpr {$value -= $e.value;} )* ; multExpr returns [int value] : e=atom {$value = $e.value;} ('*' e=atom {$value *= $e.value;})* ; atom returns [int value] : INT {$value = Integer.parseInt($INT.text);} | ID { Integer v = varValues.get($ID.text); if ( v!=null ) $value = v.intValue(); else throw new FailedPredicateException(input, quot;atomquot;, quot;undeclared variable quot;+$ID.text); } | '(' expr ')' {$value = $expr.value;} 47 ;
  • 57. prog: stat+ ; stat: // Semantic action for printing out the value returned by the evaluation of each expression expr NEWLINE { System.out.println(quot;Expression in line quot; + input.get(input.index()-1).getLine() + quot;: quot; + $expr.value);} // Semantic action for constructing the set of declared variables. | ID '=' expr NEWLINE { varValues.put($ID.text, new Integer($expr.value)); } | NEWLINE ; // All rules of the grammar get a return value, the computed value of their matching expression expr returns [int value] : e=multExpr {$value = $e.value;} // We need to distinguish addition and subtraction ( '+' e=multExpr {$value += $e.value;} | '-' e=multExpr {$value -= $e.value;} )* ; multExpr returns [int value] : e=atom {$value = $e.value;} ('*' e=atom {$value *= $e.value;})* ; atom returns [int value] : INT {$value = Integer.parseInt($INT.text);} | ID { Integer v = varValues.get($ID.text); if ( v!=null ) $value = v.intValue(); else throw new FailedPredicateException(input, quot;atomquot;, quot;undeclared variable quot;+$ID.text); } | '(' expr ')' {$value = $expr.value;} 47 ;
  • 58. public int expr() { int value = 0; // return value int e = 0; try { e = multExpr(); value = e; loop3: while(true) { int alt = 3; if (<<next input symbol is '+'>>) alt = 1; else if (<<next input symbol is '-'>>) alt = 2; switch(alt) { case 1: match('+'); e = multExpr(); value += e; break; case 2: [...] } } } } [...] Parser + Aktionen Was hinten herauskommt … 48
  • 59. 49
  • 60. Jenseits von Syntax Semantische Analyse Trennung syntaktische / semantische Analyse effiziente, kontext-freie Parser für syntaktische Analyse Semantische Analyse volle Programmiersprache mittels Traversierung/Transformation des AST aber: schwer, oft weitgehend unabhängig von Sprache, ineffizient Attribute Grammars (Attributgrammatiken), SDDs Formalismus zur Einbettung der semantischen in die syntaktische Analyse Anreicherung des ASTs durch “semantische” Attribute in der Praxis: oft auch Seiteneffekte 50
  • 61. Attribute Grammars Produktion Semantische Aktion 〈E〉 ::= 〈int〉 E.val = int.val | 〈E1 〉 ‘+’ 〈E2 〉 E.val = E1 .val + E2 .val | ‘(’ 〈E1 〉 ‘)’ E.val = E1 .val Beispiele 51
  • 62. Attribute Grammars Produktion Semantische Aktion 〈E〉 ::= 〈int〉 E.val = int.val | 〈E1 〉 ‘+’ 〈E2 〉 E.val = E1 .val + E2 .val | ‘(’ 〈E1 〉 ‘)’ E.val = E1 .val ).5&+$:'(!'$:2+#;(!+(4,&567.(012+$/3 Beispiele # M-+(&/U,,,,8,6,49,6,quot;5 # I%?*&'U,,,(&-8 @6A @4@ (&-9 @6A (&-quot; @5A *,V[R0; * L+%)C=-(%&',,,,,,,,,,,,,,,,,2^C0-(%&' R0;C*,40&),(', 2,,! 2! 6,29,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2[R0; O,2![R0;,6,29[R0 2! ! (&-8 2![R0;,O,(&-8[R0;,,O,8 'U 29 ! 4,2quot;5,,,,,,,,,,,,,,,,,,,,,,,,29[R0;,O,2quot;[R0; 2quot; ! 2H 6,28 2quot;[R0;,O,2H[R0;,6,28[R 2H ! (&-9 2H[R0;,O,(&-9[R0;,O,9 28 ! (&-quot; 28[R0;,O,(&-quot;[R0;,,O,quot; !Z Prof. Aiken CS 143 Lecture 6 51
  • 63. Attribute Grammars Produktion Semantische Aktion 〈E〉 ::= 〈int〉 E.val = int.val | 〈E1 〉 ‘+’ 〈E2 〉 E.val = E1 .val + E2 .val ).5&+$:'(!'$:2+#;(!+(4,&567.(012+$/3 | ‘(’ 〈E1 〉 ‘)’ E.val = E1 .val ).5&+$:'(!'$:2+#;(!+(4,&567.(012+$/3 Beispiele # M-+(&/U,,,,8,6,49,6,quot;5 # M-+(&/U,,,,8,6,49,6,quot;5 # I%?*&'U,,,(&-8 @6A @4@ (&-9 @6A (&-quot; @5A # I%?*&'U,,,(&-8 @6A @4@ (&-9 @6A (&-quot; @5A *,V[R0; * L+%)C=-(%&',,,,,,,,,,,,,,,,,2^C0-(%&' L+%)C=-(%&',,,,,,,,,,,,,,,,,2^C0-(%&' R0;C*,40&),(', 2,,! 2! 6,29,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2[R0; O,2![R0;,6,29[R0 2,,! 2! 6,29,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,2[R0; O,2![R0;,6,29[R0; 2! ! (&-8 2!2! ! (&-88[R0;,,O,8 [R0;,O,(&- 2![R0;,O,(&-8[R0;,,O,8 'U 29 ! 4,2quot;5,,,,,,,,,,,,,,,,,,,,,,,,2929 ! 4,2[R0; [R0;,O,2quot; quot;5,,,,,,,,,,,,,,,,,,,,,,,,29[R0;,O,2quot;[R0; 2quot; ! 2H 6,28 2quot; ! 2 6,28 2quot;[R0;,O,2H [R0;,6,28[R0; 2quot;[R0;,O,2H[R0;,6,28[R H 2H ! (&-9 2H ! (&-9 2H[R0;,O,(&-9[R0;,O,9 2H[R0;,O,(&-9[R0;,O,9 28 ! (&-quot; 28 ! (&-quot; 28[R0;,O,(&-quot;[R0;,,O,quot; 28[R0;,O,(&-quot;[R0;,,O,quot; !Z Prof. Aiken CS 143 Lecture 6 Prof. Aiken CS 143 Lecture 6 !] 51
  • 64. /quot;0quot;%1quot;%(2)34$05 9 + # 9'+F,(-7%,8'D%8%7,9 F'.,-(%,.8-),0-6,)F%,>'8 9! A 9H '))6*D3)% # L-)%,)F%,7%/%(7%(+*%. *()B 5 J 9< + K 9@ A 9B *()H 2 *()< 3 Prof. Aiken CS 143 Lecture 6 HI 52
  • 65. /quot;0quot;%1quot;%(2)34$05 9 + # 9'+F,(-7%,8'D%8%7,9 F'.,-(%,.8-),0-6,)F%,>'8 9! A 9H '))6*D3)% # L-)%,)F%,7%/%(7%(+*%. *()B 5 J 9< + K /quot;0quot;%1quot;%(2)34$05 9@ A 9B 9 +-&/3)%7,'0)%6,'88,*)., 10 %(7%(+1,N6'/F,F'>%,D%%(, *() 2 H *()< 3 9! 5 A 9H 5 )6*D3)%.,+'(,D%,+-&/3)%7, Prof. Aiken CS 143 Lecture 6 HI *()B 5 J 9< 5 K QF%(,)F%6%,'6%,(-,+1+8%. 9@ 2 A 9B 3 D3)%.,'6%,(-),8%N'8 *()H 2 *()< 3 52 143 Lecture 6 H! Prof. Aiken CS 143 Lecture 6
  • 66. Jenseits von Syntax Attribute Grammars Attribute grammar := kontextfreie Grammatik mit Attributen und Regeln Attribute zu Symbolen, Regeln zu Produktionen S.a bezeichnet das Attribut ‘a’ des Symbols ‘S’ Synthetisiertes Attribut (“Rückgabewerte) a von S definiert nur unter Verwendung von Attributen von S und Kinder von S Vererbtes Attribut (“Parameter”) b von S definiert nur unter Verwendung von Attributen von S, des Vaters von S und der Geschwister von S 53
  • 67. Jenseits von Syntax Attribute Grammars Ergebnis: Gleichungssystem Auswertungsordnung ist nicht fixiert e.g., E3.val = E4.val + E5.val E4.val und E5.val nötig um E3.val zu berechnen (dependency) aber: ob erst E4.val oder E5.val berechnet wird ist offen Parser muß Auswertungsordnung festlegen Problem: zyklische Abhängigkeiten EXPTIME: für eine gegebene Grammatik feststellen, ob Abhängigkeiten für alle Parsebäume zyklenfrei sind. daher: Einschränkung von Attribute Grammars 54
  • 68. Jenseits von Syntax Attribute Grammars S-attributed attribute grammar entählt ausschließlich synthetisierte Attribute L-attributed attribute grammar: alle Attribute entweder synthetisiert oder vererbt, aber dann, für Regel A ::= X1 X2 … Xn Berechnung von Xi.a nur durch vererbte Attribute von A oder (synthetisierte oder vererbte) Attribute von Xj fuer j < i oder (synthetisierte oder vererbte) Attribute von Xi selbst falls nicht abhängig von a verwendet vor allem in Recursive Descent Parsern wie ANTLR 55
  • 69. | ‘(’ 〈E〉1 ‘)’ E.val = E1 .val bdigits2 .val 〈bnumeral〉 ::= 〈bdigits〉1 ‘.’ 〈bdigits〉2 bnumeral.val = bdigits1 .val + 2bdigits2 .len 〈bdigits〉 ::= 〈bdigits〉1 〈bit〉 bdigits.val = 2 · bdigits2 .val + bit.val bdigits.len = bdigits2 .len + 1 | 〈bit〉 bdigits.val = bit.val; bdigits.len = 1 〈bit〉 ::= ‘0’ bit.val = 0 | ‘1’ bit.val = 1 Beispiele 56
  • 70. | ‘(’ 〈E〉1 ‘)’ E.val = E1 .val Val (<bit>) ! 0 | 1 bdigits2 .val 〈bnumeral〉 ::= 〈bdigits〉1 ‘.’ 〈bdigits〉2 bnumeral.Val= bdigits1 .val + 2bdigits2 .len val (<bit>) ! 1 〈bdigits〉 ::= 〈bdigits〉1 〈bit〉 The derivation bdigits2 .val + bit.val illustrates the use of attributes that give the bdigits.val = 2 · tree in Figure 3.7 semantics for the binary numeral 1101.01 to be the real number 13.25. bdigits.len = bdigits .len + 1 2 | 〈bit〉 bdigits.val = bit.val; bdigits.len = 1 〈bit〉 ::= ‘0’ bit.val = 0 <binary numeral> | ‘1’ bit.val = 1 Val: 13 + 1/22 = 13.25 Beispiele <binary digits> <binary digits> Val : 13 Val : 1 Len : 4 Len : 2 <binary digits> <bit> <binary digits> <bit> Val : 6 Val : 1 Val : 0 Val : 1 Len : 3 Len : 1 1 1 <binary digits> <bit> <bit> Val : 3 Val : 0 Val : 0 Len : 2 0 0 <binary digits> <bit> Val : 1 Val : 1 Len : 1 1 <bit> Val : 1 1 56 Figure 3.7: Binary Numeral Semantics Using Synthesized Attributes
  • 71. D Fazit 57
  • 72. Zusammenfassung Parsergeneratoren 1. Implementierung von Endlichen Automaten loop-and-switch, loop-and-lookup, Lexer, Automatenbibliotheken manuelle Implementierung oft in Bibliotheken und bei zeitkritischem Parsing (Basispaarsequenzen) verwendet Lexer erlauben auch komplexe endliche Automaten ohne signifikanten Effizienzverlust Automatenbibliotheken ineffizienter als Lexer oder manuelle Implementierung aber: Konstruktion und Manipulation der Automaten zur Laufzeit möglich 58
  • 73. Zusammenfassung Parsergeneratoren 2. Implementierung von Kellerautomaten Parsergeneratoren manuelle Implementierung meist zu aufwendig Parsergeneratoren erzeugen Lexer und Parser Mehr als kontextfreie Sprachen dank semantischer Aktionen kontext-sensitive Eigenschaften “von Hand” programmieren Recursive-descent oder LL(k)/LL(*) Parser wie ANTLR einfach zu lesender Code, leichte manuelle Anpassung Andere verbreitete Ansätze: LR, LALR, Left-Corner, Earley 59
  • 74. Zusammenfassung Parsergeneratoren Beispielprogramme + Dokumentation im Laufe der Woche auf der Webseite Mehr Details zu Attributgrammatiken in den Übungen Kapitel 5, Drachenbuch (“Compilers …”, Aho et al., 2007) Selber ausprobieren! 60
  • 75. E Fragen 61