Von Automaten zu Programmen
Manuelle und automatische Entwicklung von Parsern




                           Tim Furche
  ...
Formale Sprachen:



   Beispiele aus der Praxis




                              2
Formale Sprachen:



   Nicht nur in Compilern!




                             3
Browser




          4
5
URIs
                     Google
                     Anfrage

                      HTML


                  JavaScript

...
Spreadsheets: Excel/
 Numbers/OpenCalc




                       7
8
Formeln


Format
Felder



Macros




     9
A
 Endliche
Automaten
Parser für Reguläre Sprachen
              z.B.: URIs, Datumsangaben, Gleitpunktzahlen



          ...
Beispiel:
Gleitpunktzahlen




                   11
-666.797E-14


  parsen, normalisieren



                          12
$

java
‐jar
FPParser.jar
‐666.797E‐14
‐‐step
(Initial,
‐666.797E‐14)

        |‐
(WholeNrDigit,
666.797E‐14)

        |‐
...
14
Wie?


z.B. in Java



               15
16
Bibliothek:
Double.parseDouble()




                       17
Bibliothek:
Double.parseDouble()


   Regulärer Ausdruck über Bibliothek:
   java.util.regex.Pattern&Matcher




         ...
Bibliothek:
Double.parseDouble()


   Regulärer Ausdruck über Bibliothek:
   java.util.regex.Pattern&Matcher


           ...
Bibliothek:
Double.parseDouble()


   Regulärer Ausdruck über Bibliothek:
   java.util.regex.Pattern&Matcher


           ...
Bibliothek:
Double.parseDouble()


   Regulärer Ausdruck über Bibliothek:
   java.util.regex.Pattern&Matcher


           ...
41    }

                                                              ‘0’–‘9’
                 ‘ -’

     start   I      ...
1   public static long parseLong(String s, int radix) throws NumberFormatException
     {
 3       if (s == null) throw ne...
21             result = -digit;
          }
23
          // State 3: Treat all other digits
25        while (i < max) {
  ...
21
en, die unser Parser erkennen soll:
        2.1 Regulärer Ausdruck für Gleitpunktzahlen

      (‘Für -’)? digit+ (‘.’ digi...
‘+’, ‘-’

start   S s,d                 Sd


                                ‘0’–‘9’      ‘.’                       ‘0’–‘9...
gibt. Dabei nennen wir für eine Gleitpunktzahl s. f · 10 : s den significand (oder
Vorkomma-Anteil der Mantisse), f die fra...
Implementierung Endlicher Automaten
                                                   Ansätze …
  Implicit state: wie Lon...
Implementierung Endlicher Automaten
           Umgebung für FP-Parser …
  FPParser: abstrakte Oberklasse für alle Floating...
Implementierung Endlicher Automaten
           Umgebung für FP-Parser …
  FPParser: abstrakte Oberklasse für alle Floating...
einer Ziffer bleiben wir im gleichen Zustand und fügen die Ziffer zur aktu-
         ellen Repräsentation des significand h...
einer Ziffer bleiben wir im gleichen Zustand und fügen die Ziffer zur aktu-
         ellen Repräsentation des significand h...
0

             Implementierung Endlicher Automaten
                 SIGNIF_DIGIT_FRACTION_EXPONENT {
         2
         ...
0

             Implementierung Endlicher Automaten
                 SIGNIF_DIGIT_FRACTION_EXPONENT {
         2
         ...
nungsschritte) zu spezifizieren. In der Lookup-Tabelle sind den Zuständen
     Zeilen, den Eingabezeichen Spalten zugeordne...
nungsschritte) zu spezifizieren. In der Lookup-Tabelle sind den Zuständen
     Zeilen, den Eingabezeichen Spalten zugeordne...
Implementierung Endlicher Automaten
                                Loop-and-Lookup …
                   Ziffer        Vor...
$

java
‐jar
FPParser.jar
33E0
‐‐step
‐‐pEnum

           (INITIAL,
33E0)

           


|‐
(SIGNIF_DIGIT_FRACTION_EXPONEN...
32
B
    Keller-
  Automaten
Parser für kontextfreie Sprachen++
                 z.B. für arithmetische Ausdrücke und Erweite...
Beispiel:
Arithmetischer Ausdruck




                          34
2 + 4 * 11 - 2 * 3 + 2


      parsen, ausrechnen



                           35
2
+
4
*
11
‐
2
*
3
+
2
$

java
‐jar
ParserGenerators.jar
‐‐pIntExpr
‐‐file
plain‐intexpr

  <no
output>
(=
no
error)

$

j...
37
x
=
78
                             y
=
2
                             112
+
4
*
x
‐
2
*
y
+
z
*
2
                       ...
39
1   /*------------------------------------------------------------------

Arithmetik & Parsergeneratoren
 3
     * PARSER ...
17      ;


19   atom
      Arithmetik & Parsergeneratoren
       : INT
        |ID
                Lexer-Regeln der Gramm...
direkte Ausgaben,
                                                  Fehler




            Lexer                          ...
w i d t h        =        2 0 0 ;     n     Characters

   ID            =         INT   ;              Tokens
           ...
void multExpr() {
  	try {
  		    atom();
  		    while( <<next input symbol is '*' >> ) {
  		    	    match('*');
  		 ...
1   /*------------------------------------------------------------------

Arithmetik & Parsergeneratoren
 3
     * PARSER ...
1   /*------------------------------------------------------------------

Arithmetik & Parsergeneratoren
 3
     * PARSER ...
grammar IntExpr_Var;

options {
	    language = Java;
	    superClass = RunnableParser; }

@lexer::header{
	    package de...
prog:   stat+ ;

stat:   // Semantic action for printing out the value returned by the evaluation of each expression
     ...
prog:   stat+ ;

stat:   // Semantic action for printing out the value returned by the evaluation of each expression
     ...
public int expr() {
  	   int value = 0; // return value
  	   int e = 0;
  	   try {
  	   	   e = multExpr();
  	   	   ...
49
Jenseits von Syntax
                            Semantische Analyse
  Trennung syntaktische / semantische Analyse
   effizi...
Attribute Grammars

      Produktion               Semantische Aktion
 〈E〉 ::=   〈int〉               E.val = int.val
     ...
Attribute Grammars

                 Produktion               Semantische Aktion
          〈E〉 ::=     〈int〉              ...
Attribute Grammars

                Produktion                Semantische Aktion
          〈E〉 ::=
            〈int〉      ...
/quot;0quot;%1quot;%(2)34$05

            9         +                            # 9'+F,(-7%,8'D%8%7,9
                   ...
/quot;0quot;%1quot;%(2)34$05

                      9           +                             # 9'+F,(-7%,8'D%8%7,9
      ...
Jenseits von Syntax
                               Attribute Grammars
  Attribute grammar :=
   kontextfreie Grammatik mit...
Jenseits von Syntax
                                    Attribute Grammars
  Ergebnis: Gleichungssystem
   Auswertungsordn...
Jenseits von Syntax
                                       Attribute Grammars
  S-attributed attribute grammar
   entählt ...
| ‘(’ 〈E〉1 ‘)’   E.val = E1 .val

                                                                                   bdigi...
| ‘(’ 〈E〉1 ‘)’   E.val = E1 .val                  Val (<bit>) ! 0
                                                     | 1...
D
Fazit
        57
Zusammenfassung
                                  Parsergeneratoren
1. Implementierung von Endlichen Automaten
           ...
Zusammenfassung
                                 Parsergeneratoren
2. Implementierung von Kellerautomaten
                ...
Zusammenfassung
                              Parsergeneratoren
 Beispielprogramme + Dokumentation
  im Laufe der Woche au...
E
Fragen
         61
Nächste SlideShare
Wird geladen in …5
×

Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken

1.270 Aufrufe

Veröffentlicht am

Veröffentlicht in: Bildung
0 Kommentare
1 Gefällt mir
Statistik
Notizen
  • Als Erste(r) kommentieren

Keine Downloads
Aufrufe
Aufrufe insgesamt
1.270
Auf SlideShare
0
Aus Einbettungen
0
Anzahl an Einbettungen
3
Aktionen
Geteilt
0
Downloads
11
Kommentare
0
Gefällt mir
1
Einbettungen 0
Keine Einbettungen

Keine Notizen für die Folie

Von Automaten zu Programmen–Parsergeneratoren und Attributgrammatiken

  1. 1. Von Automaten zu Programmen Manuelle und automatische Entwicklung von Parsern Tim Furche Compilerbau, Wintersemester 2008/09, Prof. F. Bry 1
  2. 2. Formale Sprachen: Beispiele aus der Praxis 2
  3. 3. Formale Sprachen: Nicht nur in Compilern! 3
  4. 4. Browser 4
  5. 5. 5
  6. 6. URIs Google Anfrage HTML JavaScript CSS Browser: Formale Sprachen 6
  7. 7. Spreadsheets: Excel/ Numbers/OpenCalc 7
  8. 8. 8
  9. 9. Formeln Format Felder Macros 9
  10. 10. A Endliche Automaten Parser für Reguläre Sprachen z.B.: URIs, Datumsangaben, Gleitpunktzahlen 10
  11. 11. Beispiel: Gleitpunktzahlen 11
  12. 12. -666.797E-14 parsen, normalisieren 12
  13. 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. 14
  15. 15. Wie? z.B. in Java 15
  16. 16. 16
  17. 17. Bibliothek: Double.parseDouble() 17
  18. 18. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher 17
  19. 19. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton 17
  20. 20. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton Manuelle Implementierung 17
  21. 21. Bibliothek: Double.parseDouble() Regulärer Ausdruck über Bibliothek: java.util.regex.Pattern&Matcher Endliche Automaten Bibliothek: dk.brics.automaton Manuelle Implementierung 17
  22. 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. 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. 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. 25. 21
  26. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 40. 32
  41. 41. B Keller- Automaten Parser für kontextfreie Sprachen++ z.B. für arithmetische Ausdrücke und Erweiterungen 33
  42. 42. Beispiel: Arithmetischer Ausdruck 34
  43. 43. 2 + 4 * 11 - 2 * 3 + 2 parsen, ausrechnen 35
  44. 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. 45. 37
  46. 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. 47. 39
  48. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 59. 49
  60. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 71. D Fazit 57
  72. 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. 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. 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. 75. E Fragen 61

×