Parsing 1
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 2
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 3
Situering 4
Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 5
Contextvrije grammatica’s Afleidingen staan centraal Beschouw volgende regels: 6 “S”, “E” en “L” zijn non-terminals “id”, “print”, “num”, enz. zijn terminals
Afleiding van een zin: id := num; id := id + (id := num + num, id) 7
Ambiguïteiten 8
Elimineren van ambiguïteit: Lukt niet voor alle contextvrije talen! 9
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 10
Predictive (of recursive-descent) parsing 11
FIRST en FOLLOW sets FIRST(γ): alle terminals die aan het begin van een afleiding uit γ kunnen staan FOLLOW(X): alle terminals die direct kunnen volgen op een afleiding uit X – zij X een non-terminal en a een terminal – in S -> αXaβ is a ∈ FOLLOW[X] 12
Initialiseer voor elke terminal Z: FIRST[Z] = {Z} for alle afleidingsregels X -> Y 1 Y 2 … Y k for i = 1..k for j = i+1..k if alle Y i zijn nullable then nullable[X] = true if Y 1 … Y i-1 zijn nullable then FIRST[X] = FIRST[X] ∪ FIRST[Y i ] if Y i+1 … Y k zijn nullable then FOLLOW[Y i ] = FOLLOW[Y i ] ∪ FOLLOW[X] if Y i+1 … Y j-1 zijn nullable then FOLLOW[Y i ] = FOLLOW[Y i ] ∪ FIRST[Y j ] Herhaal tot FIRST, FOLLOW en nullable niet zijn veranderd tijdens deze iteratie 13
Predictive parsing table voorgaande grammatica: 14 Voer regel X -> γ in: in rij X, kolom T voor alle T ∈ FIRST(γ) als γ de lege string kan afleiden, dan ook in rij X kolom T voor alle T ∈ FOLLOW[X] Indien er in elke cel maar één regel staat, is de grammatica LL(1)
Error recovery voor predictive parsing Door invoegen van geldige token – Gevaar voor oneindig lange foutherstel Door verwijderen – Sla tokens over tot een token in FOLLOW bereikt is 15
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 16
LR-parsing LR(k)-parsing: onderhoud een stack, kijk k tokens vooruit in de input Terminologie: Shift: duw token van input op de stack Reduce: neem exact die tokens van de rechterzijde van een regel weg van de stack, duw symbool van linkerzijde van die regel op stack 17
18
19
LR(0) parser generator Gegeven grammatica: 20
Beschouw: 21 S’ ->.S$ S ->.x S ->.(L) Dit is een toestand: Een productieregel is een item Punt: huidige positive van de parser
Zij I een toestand en X een symbool aan de rechterzijde van een productieregel: Closure(I) = repeat for alle items A -> α.Xβ in I for alle productieregels X -> γ I.γ } until I verandert niet return I Goto(I,X) = J <- { } for alle items A -> α.Xβ in I J αX.β } return Closure(J) 22
Zij T een verzameling toestanden ComputeR(T) = R <- { } for elke toestand I in T for elke item A -> α. in I R α) } Voeg de acties in R toe aan T 23
Volledig algoritme Zij T de toestanden en E de bogen T.S$ } ) } E <- { } repeat for elke toestand I in T for alle items A -> α.Xβ in I J <- Goto(I,X) T <- T ∪ { J } E x J } until E en T veranderen niet in deze iteratie Voer ComputeR(T) uit 24
25
26
LR(1) parser generator Uitbreiding concept van item: – (A -> α.β, x) – α bovenaan de stack, x is lookahead symbool 27
Closure(I) = repeat for alle items (A -> α.Xβ, z) in I for alle productieregels X -> γ for alle w ∈ FIRST(βz) I.γ, w) } until I verandert niet return I Goto(I,X) = J <- { } for alle items (A -> α.Xβ, z) in I J αX.β, z) } return Closure(J) 28
ComputeR(T) = R <- { } for elke toestand I in T for elke item (A -> α., z) in I R α) } Voeg de acties in R toe aan T 29
30
LR(1) en ambiguïteiten Beschouw: S -> if E then S else S S -> if E then S S -> other Hoe het volgende interpreteren? if a then if b then s1 else s2 31
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 32
Parser generator: Yacc parser declarations % grammar rules % programs 33
34
35
Operator precedentie 36 Bovenaan de stack: E * E, lookahead: + Shift leidt tot E * (E + E) Reduce leidt tot (E * E) + E -> wenselijk Dus: los conflict op door voorkeur aan reduce
Associativeit Indien links-associativiteit gewenst: reduce Indien de programmeur expliciet moet zijn: non-associativiteit Yacc-directieven voor precedentie: %nonassoc EQ NEQ %left PLUS MINUS %left TIMES DIV %right EXP Volgorde van directieven van belang! 37
38
Syntax vs semantiek 39
Conflict: booleaanse variabele of arithmetische variabele? Semantische analyse moet uitsluitsel geven 40
Situering Contextvrije grammatica’s Predictive (of recursive-descent) parsing LR-parsing Parser generator: Yacc Error recovery 41
Error recovery Local error recovery: introduceer error- recovery productions, bv. in: exp -> ID exp -> exp + exp exp -> ( exps ) exps -> exp exps -> exps ; exp Voeg toe: exp -> ( error ) exps -> error ; exp 42
Globaal foutherstel Doel: vind kleinste set toevoegingen en verwijderingen om bronstring om te vormen tot syntactisch correcte string 43
Burke-Fisher foutherstel Bij foutdetectie op positie A: probeer alle mogelijke herstellingen van token A – K tot A Herstel dat toelaat het verste te parsen na de fout is de beste (men neemt vaak genoegen met 4 posities na de fout) 44
45
Voorstel examenvragen Leg uit hoe Burke-Fisher foutherstel werkt. Wat zou een mogelijke reden kunnen zijn om dit te verkiezen boven lokaal foutherstel? (gegeven output in de vorm van een toestandsmachine door Yacc met een shift/reduce-conflict; er is ook gegeven aan welke precedentieregels alle operatoren moeten voldoen) Hoe zou jij het conflict gesignaleerd in onderstaande toestandsmachine oplossen? Leg je redenering uit. (gegeven een contextvrije grammatica) Is de volgende contextvrije grammatica LL(1)? Beargumenteer je antwoord. 46