scanning and parsing
1/57
rij karakters scanner (filteren separatoren)
rij tokens (+ add. inform.)
(niet expliciet geconstrueerd)
parser (contextvrije analyse)
ontleedboom (parse tree) representeert syntactische structuur programma
concrete versus abstracte syntax I
2/57
concrete syntax if B then St else Se fi als B dan St anders Se sla
I
abstracte syntax (boom) (AST ) if2 (AST(B), AST(St ), AST(Se ))
if2
B
St
Se
beschrijving syntactische structuur
I
reguliere expressies niet geschikt I I
I
geen nesting (n id)n klasse van programma’s (n > 0) |[ var an : int | read(an ) ]| niet regulier
contextvrije grammatica’s I I I
grotere klasse van talen nesting klasse van programma’s (n > 0) |[ var an : int | read(an ); write(an ) ]| niet contextvrij
3/57
contextvrije ontleding (parsing)
I
contextvrije grammatica G
I
acceptor: nondeterministische stapelautomaat (hoge mate van nondeterminisme)
I
algemene ontleedmetode Earley’s algoritme tijd: O(N 3 ) geheugen (tabel): O(N 2 · |G |)
I
eisen aan grammatica/taal −→ deterministische stapelautomaat I I
LALR(1) (meeste programmeertalen) LL(1) (stringenter, eenvoudiger parser)
4/57
LL(1)-grammatica/taal
I
LL(1)-grammatica/taal I
I
I
acceptor: recursive descent parser (stelsel recursieve procedures corresponderend met productieregels) parse tree expliciet opgebouwd (als synthesized attribuut) nog geen contextcondities
5/57
contextvrije grammatica
I
contextvrije grammatica G = (N, Σ, P, S) I
I
I I
I
I
N eindige, niet lege verzameling (nonterminals) Σ eindige, niet lege verzameling (terminals) N ∩Σ=∅ P ⊂ N × (N ∪ Σ)∗ , P eindig (productieregels) (A, α) ∈ P notatie: A → α S ∈ N, start symbol
vocabulaire grammtica: V = N ∪ Σ
6/57
afleidingen en taal contextvrije grammatica I
⇒ (“leidt af in 1 stap”) G
α ⇒ β als G
I
α = δ1 C δ2 en β = δ1 γδ2 met δ1 , δ2 ∈ V ∗ en C → γ ∈P ∗ ⇒ leidt af in 0 of meer stappen G +
⇒ leidt af in 1 of meer stappen G
I
afleiding (derivation) met lengte k α0 ⇒ α1 ⇒ α2 ⇒ · · · ⇒ αk
I
verzameling terminal strings afleidbaar uit α ∈ V ∗ ∗
L(α) = {x ∈ Σ∗ | α ⇒ x} G
I
taal gegenereerd door contextvrije grammatica G ∗
L(G ) = L(S) = {x ∈ Σ∗ | S ⇒ x} G
7/57
voorbeeld contextvrije grammatica en afleidingen G = ({EXPR, OP}, {p, q, (, ), +, ∗}, P, EXPR) P: EXPR → p OP → + EXPR → q OP → ∗ EXPR → (EXPR OP EXPR) verkorte notatie EXPR → p | q | (EXPR OP EXPR) OP → + | ∗ EXPR
⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒
EXPR
⇒
∗
+
(⇒)
(EXPR OP EXPR ) ( EXPR OP (EXPR OP EXPR)) (p OP ( EXPR OP EXPR)) (p OP (q OP EXPR)) (p OP (q ∗ EXPR )) (p OP (q ∗ p)) (p + (q ∗ p)) (p + (q ∗ p))
8/57
voorbeeld linkspreferente afleiding/taal linkspreferente afleiding (uniek) EXPR → p | q | (EXPR OP EXPR) OP → + | ∗ EXPR
⇒ ⇒ ⇒ ⇒ ⇒ ⇒ ⇒
( EXPR OP EXPR) (p OP EXPR) (p + EXPR ) (p + ( EXPR OP EXPR)) (p + (q OP EXPR)) (p + (q ∗ EXPR )) (p + (q ∗ p))
taal L(G ) = L(S) = {p, q, (p + q), (p ∗ q), (p + p), (p ∗ p), . . . , (p + (q ∗ p)), . . .}
9/57
voorbeeld bouwstenen concrete syntaxboom
10/57
A → u1 u2 . . . un
A
u1
u2
...
A→ε
A
ε
un
voorbeeld concrete syntaxboom
11/57
EXPR
(
EXPR
OP
p
+
EXPR
(
EXPR → p | q | (EXPR OP EXPR) OP → + | ∗
)
EXPR
OP
EXPR
q
∗
p
)
voorbeeld goedgehaakte rijen
12/57
S →BS |ε B → (S) linkspreferente afleiding S ⇒ B S ⇒ ( S )S ⇒ () S ⇒ () B S ⇒ ()( S )S ⇒ ()() S ⇒ ()() niet links- of rechtspreferente afleiding S ⇒ B S ⇒ B B S ⇒ B(S) S ⇒ B (S) ⇒ ( S )(S) ⇒ ()( S ) ⇒ ()() dezelfde afleidingsboom S B (
S ε
S )
B (
S ε
S )
ε
dangling else (ambigue grammatica)
I
S → if b then S else S S → if b then S S →a
I
if b then if b then a else a 2 afleidingsbomen
13/57
S
S
if
b
if
then
S
b
then
if S a
else
S a
b
if
then
S
else
S
b
then
S
a
a
2 afleidingsbomen/geen betekenisverschil
14/57
E →p |q |E +E |E ∗E p+q+q E
E p
E
E
+
E
E
+
E
+
E
q
p
E
+
q (p + q) + q
q p + (q + q)
2 afleidingsbomen, geen verschil in “betekenis”
E q
2 afleidingsbomen/betekenisverschil
15/57
E →p |q |E +E |E ∗E p∗q+q E
E p
E
E
+
E
E
∗
E
∗
E
q
p
E
+
q
(p ∗ q) + q (gebruikelijke prioriteiten) +∗ pqq pq ∗ q+
q
E q
p ∗ (q + q) (ongebruikelijk) ∗p + qq pqq+∗
2 afleidingsbomen, wel “betekenis”-verschil
prioriteiten
16/57
∗ hogere prioriteit dan + E :expressie (som van termen) T :term (product van factoren) F :factor F ∗ ··· ∗ F + F ∗ ··· ∗ F +··· + F ∗ ··· ∗ F | {z } | {z } | {z } T T T | {z } E
T + T + T + T = ((T + T ) + T ) + T F ∗ F ∗ F ∗ F = ((F ∗ F ) ∗ F ) ∗ F E E T T F F F
→ → → → → → →
E +T (linksassociativiteit) T T ∗F F p q (E ) (doorbreken prioriteiten)
prioriteiten (vervolg)
17/57
→ E +T |T → T ∗F |F → p | q | (E )
E T F
p ∗ q + q wordt ontleed als (p ∗ q) + q E E
+
T T F p
∗
T F
F q
q
BINEXPR BINEXPR VAREXPR p
∗
+
VAREXPR q
VAREXPR q
syntax / acceptor / parser I I
I
18/57
beschrijving syntax programmeertaal: contextvrije grammatica G = (N, Σ, P, S) acceptor voor L(G ): beslist voor x ∈ Σ∗ of x ∈ L(G ) (ja/nee-antwoord) parser voor L(G ) (nuttiger): beslist voor x ∈ Σ∗ of x ∈ L(G ) en levert, als het antwoord ja is, een afleidingsboom van x S
(te construeren)
x1
x2
xm
constructie parser
19/57
1. stapelautomaten contextvrije grammatica G
stapelautomaat (LL(0)) (nondeterministisch)
stapelautomaat (LL(1)) ((minder non)determ.) implementatie indien determ. recursive descent parsing procedures
2. dominospel
syntactisch dominospel (beginsituatie/dominostenen) I
beginsituatie (invoer x1 x2 . . . xm ) S
boven
bovenkant x1 I
onderkant x2
xm
onder
dominostenen A → u1 u2 . . . un
u1
boven
A
flexibel
u2
···
vaste volgorde
A→ε A
ε
un
onder
20/57
syntactisch dominospel (spelregels/doel)
I
aanleggen stenen I I I
I
21/57
goede ori¨entatie geen kruisende verbindingen gelijk gelabelde vlakke kanten tegen elkaar
doel bord volleggen volgens regels zodat er geen vlakke kanten meer over zijn (indien mogelijk)
syntactisch dominospel (voorbeeld) S
S → BS | ε B B → (S) invoerstring: ()()
22/57
S
S
ε
B (
S
)
syntactisch dominospel (voorbeeld) S
22/57
S
S → BS | ε B B → (S) invoerstring: ()()
B
ε
S
(
)
S
S S
B B
( (
S S
S S
B B
S S
ε
S S
ε
) )
( (
ε
) )
strategie dominospel
23/57
I
geen backtracking (“eenmaal gelegd blijft gelegd”)
I
aansluiten
I
legrichting horizontaal: links −→ rechts
I
legrichting verticaal: van boven naar beneden (top-down, LL-strategie)
strategie behandel steeds de meest linkse, vrije, vlakke onderkant
LL(1)-strategie
24/57 S S ···
v1 x1 x1
···
xn xn
y1
v2
···
meest linkse vrije vlakke onderkant
v1 ∈ Σ:
vl
···
yk (
···
ym
)
v1 = y1 : vlakke kanten samenvoegen
v1 6= y1 : afbreken (foutmelding) v1 ∈ N: plaats tegen deze onderkant een domino met een bovenkant gelabeld v1 welke domino? gebruik k invoersymbolen lookahead LL(k)-strategie (k ≥ 1) (hier LL(1)-strategie)
uitgebreide grammatica
25/57
nieuwe symbolen S 0 en ⊥ uitgebreide grammatica G 0 G 0 = (N ∪ {S 0 }, Σ ∪ {⊥}, P ∪ {S 0 → S⊥}, S 0 ) S0 S0
⊥
S S ···
v1 x1 x1
···
xn xn
y1
v2
···
meest linkse vrije vlakke onderkant
vl
···
yk (
··· )
ym
⊥
dominoselectie
26/57 S
0
⊥
Aβ x
⊥
y
∗
aaneengesloten stuk S 0 ⇒ S⊥ ⇒ xAβ⊥ rij vrije onderkanten v1 v2 · · · vl ⊥ = Aβ⊥ rij vrije bovenkanten y1 y2 · · · ym ⊥ = y ⊥ Aβ⊥
⇒ spelen A → α
I I
αβ⊥
∗
⇒
y⊥
spel is te voltooien
noodzakelijke voorwaarde: el1 (y ⊥) is 1e element van een eindproductie van αβ⊥ criterium dominoselectie: kies een domino A → α zodat el1 (y ⊥) 1e element van een eindproductie van αβ⊥ is (β te specifiek)
lookaheadset/selectiecriterium domino
∗
∗
S 0 ⇒ S⊥ ⇒ xAβ⊥ ⇒ xαβ⊥ ⇒ xy ⊥ strings x en β⊥ specifiek voor deze afleiding • lookaheadset productieregel A → α LA(A → α) = {a ∈ Σ ∪ {⊥} | (∃w , γ, δ : w ∈ Σ∗ ∧ γ, aδ ∈ V ∗ ⊥ : ∗ ∗ S 0 ⇒ S⊥ ⇒ wAγ ⇒ w αγ ⇒ waδ)} • selectiecriterium el1 (y ⊥) ∈ LA(A → α)
27/57
berekening lookaheadsets
∗
28/57
∗
I
S 0 ⇒ S⊥ ⇒ wAγ ⇒ w αγ ⇒ waδ
I
α ⇒ ε?
I
First(α) = ∗ {a ∈ Σ ∪ {⊥} | (∃β : β ∈ V ∗ : α ⇒ aβ)}
I
Follow (A) = {a ∈ Σ ∪ {⊥} | ∗ (∃α, β : α, β ∈ V ∗ : S 0 ⇒ αAaβ)}
I
LA(A → α)( =
∗
First(α) ∪ I
∗
Follow (A) als α ⇒ ε ∗ ∅ als ¬(α ⇒ ε)
lookaheadsets eenvoudige grammatica’s kunnen bepalen
transitive closure / Warshall’s algorithm (1)
29/57
R : V × V → B binary relation on V xR + y ≡ there is a non-empty directed path from x to y with all intermediate nodes on the path in V (x, y ∈ V ) U⊆V xRU y ≡ there is a non-empty directed path from x to y with all intermediate nodes on the path in U (x, y ∈ V ) R∅ RV
= R = R+
transitive closure / Warshall’s algorithm (2)
v ∈V \U xRU+{v } y ≡ xRU y ∨ (xRU v ∧ vRU y ) xRU+{v } v ≡ {property RU+{v } } xRU v ∨ (xRU v ∧ vRU v ) ≡
{absorption} xRU v
vRU+{v } y ≡ vRU y
30/57
transitive closure / Warshall’s algorithm (3) |[ var r : array(V × V )of bool; U : set of V | U : = ∅; for x, y : x, y ∈ V do r [x, y ] : = xRy od; { invariant: ∅ ⊆ U ⊆ V ∧ r = RU } do U 6= V → |[ var v : V ; | v : v ∈ V \ U; for x, y : x, y ∈ V do r [x, y ] : = r [x, y ] ∨ (r [x, v ] ∧ r [v , y ]) od; { r = RU+{v } } U : = U + {v } ]| od { r = RV = R + } ]|
31/57
transitive closure / Warshall’s algorithm (4) fR (x) = {y ∈ V | xRy }
(x ∈ V )
fRU+{v } (x) definition fRU+{v } = {y ∈ V | xRU+{v } y } = {property RU+{v } } {y ∈ V | xRU y ∨ (xRU v ∧ vRU y )} {set calculus} {y ∈ V | xRU y } ∪ {y ∈ V | xRU v ∧ vRU y } = {definition fRU } =
fRU (x) ∪ {y ∈ V | (v ∈ fRU (x)) ∧ vRU y } = {set calculus, definition fRU } fRU (v ) if v ∈ fRU (x) fRU (x) ∪ ∅ if v ∈ / fRU (x) fRU+{v } (v ) = fRU (v )
32/57
transitive closure / Warshall’s algorithm (5) |[ var fr : array(V )of set of V | for x : x ∈ V do fr [x] : = ∅; for y : v ∈ V do if xRy → fr [x] : = fr [x] ∪ {y } [] ¬(xRy ) → skip fi od od; { fr = fR } for v : v ∈ V do for x : x ∈ V do if v ∈ fr [x] → fr [x] : = fr [x] ∪ fr [v ] [] v ∈ / fr [x] → skip fi od od { fr = fR + } ]|
33/57
First as reflexive and transitive closure
34/57
for all x, y ∈ V ∗
xFy ≡ h∃α, β : α, β ∈ V ∗ : x → αy β ∈ P ∧ α ⇒ εi ∗
xF ∗ y ≡ h∃β : β ∈ V ∗ : x ⇒ y βi for all x ∈ V ∗
First1 (x) = {y ∈ V | h∃α, β : α, β ∈ V ∗ : x → αy β ∈ P∧α ⇒ εi} ∗
First(x) = {y ∈ V | h∃β : β ∈ V ∗ : x ⇒ y βi}
voorbeeld lookaheadsets (1)
S 0 → S⊥ S → BS | ε B → (S) FOLLOW (S) = { ) , ⊥ } symbool ) uit regel B → (S) symbool ⊥ uit regel S 0 → S⊥ regel S → BS levert geen bijdrage LA(S 0 → S⊥) = First(S⊥) = { ( , ⊥ } LA(S → BS) = First(BS) = { ( } ∗ ¬(BS ⇒ ε) LA(S → ε) = Follow (S) = { ) , ⊥ } LA(B → (S)) = First( (S) ) = { ( } LA(S → BS) en LA(S → ε) zijn disjunct
35/57
voorbeeld lookaheadsets (2)
S0 E E T T F F F
→ → → → → → → →
E⊥ E +T T T ∗F F p q (E )
LA(S 0 → E ⊥) = {p, q, (} LA(E → E + T ) = { p , q , ( } LA(E → T ) = {p, q, (} laatste 2 lookaheadsets zijn niet disjunct
36/57
LL(1)-strategie / LL(1)-voorwaarde
37/57
rij vrije onderkanten v1 v2 · · · vl ⊥ rij vrije bovenkanten y1 y2 · · · ym ⊥ I meest linkse vrije onderkant v1 I I
I I
I
blokkade I I
I
v1 ∈ Σ ∧ v1 = y1 : voeg samen v1 = A ∈ N: speel A → α met y1 ∈ LA(A → α) v1 = ⊥ = y1 : voeg samen en klaar anders blokkade
invoer ∈ / L(G ) verkeerde domino gespeeld
geen verkeerde keuze te spelen domino LL(1)-voorwaarde voor alle A → α ∈ P, A → β ∈ P en α 6= β geldt LA(A → α) ∩ LA(A → β) = ∅
implementatie LL(1)-strategie
38/57
stelsel recursieve procedures symbool X ∈ V = N ∪ Σ ↓ procedure PX construeert een parse tree met wortel X voor een prefix van de resterende invoer
X
···
···
w
∗
X ⇒w
(NB als X ∈ Σ, dan X = w )
···
tokens en terminals
STAT STAT
39/57
→ ifsym EXPR thensym STATS elsesym STATS fisym → if EXPR then STATS else STATS fi
STAT STAT
→ idsym becomessym EXPR → ID := EXPR
ID
→ n
ID pseudoterminal
voor alle n ∈ L(eidsym )
recursive descent parsing procedures (terminals)
a∈Σ proc Pa = (if sym = a → “voeg a en ; NEXTSYM fi )
sym
samen”
huidige token sym: meest linkse vrije bovenkant meest recente aanroep parsing procedure: meest linkse vrije onderkant
40/57
recursive descent parsing procedures (nonterminals) A ∈ N met productieregels A → α1 , A → α2 , . . . , A → αk proc PA = (if sym ∈ LA(A → α1 ) → “speel A → α1 ”; Qα1 [] sym ∈ LA(A → α2 ) → “speel A → α2 ”; Qα2 .. . [] sym ∈ LA(A → αk ) → “speel A → αk ”; Qαk fi ) waarin Qv1 v2 ···vn = Pv1 ; Pv2 ; · · · ; Pvn
41/57
analyse van invoerstring x⊥
42/57
NEXTSYM { sym = el1 (x⊥) } ; “speel S 0 → S⊥” ;PS ;if sym = ⊥ → “voeg
⊥
en
⊥
samen”
fi (NB geen procedure P⊥ : na ⊥ volgen geen symbolen meer) • abortie (blokkade): x ∈ / L(G ) • be¨eindiging: x ∈ L(G ) • parse tree: - expliciet construeren (als uitvoerparameter parsing procedures) - stapel actieve recursieve procedure-aanroepen ≈ wortelpad in parse tree
voorbeeld recursive descent parsing procedures (1) S0 S S S X X
→ → → → → →
S⊥ aSa bSb cX ε cX
lookaheadset {a, b, c} {a} {b} {c} {a, b, ⊥} {c}
proc PS = (if sym ∈ {a} → Pa ; PS ; Pa [] sym ∈ {b} → Pb ; PS ; Pb [] sym ∈ {c} → Pc ; PX fi) proc PX = (if sym ∈ {c} → Pc ; PX [] sym ∈ {a, b, ⊥} → skip fi) proc Pa = (if sym = a → NEXTSYM fi) proc Pb = (if sym = b → NEXTSYM fi) proc Pc = (if sym = c → NEXTSYM fi)
43/57
voorbeeld recursive descent parsing procedures (2) lookaheadset → S⊥ {(, ⊥} S → BS {(} S → ε {), ⊥} B → (S) {(}
S0
proc PS = (if sym ∈ {(} → PB ; PS [] sym ∈ {), ⊥} → skip fi) proc PB = (if sym ∈ {(} → P( ; PS ; P) fi) proc P( = (if sym = ( → NEXTSYM fi) proc P) = (if sym =) → NEXTSYM fi)
44/57
vereenvoudiging recursive descent parsing procedures (1)
proc Pa = (if sym = a → NEXTSYM fi) ↓ TERM(a) met
(a ∈ Σ)
proc TERM = (↓ a : Σ | if sym = a → NEXTSYM fi)
A → α enige regel met A in linkerlid proc PA = (if sym ∈ LA(A → α) → Qα fi) ↓ proc PA = (Qα )
45/57
vereenvoudiging recursive descent parsing procedures (2)
A → α1 , . . . , A → αk , A → ε alle regels met A in linkerlid proc PA = (if sym ∈ LA(A → α1 ) → Qα1 [] sym ∈ LA(A → α2 ) → Qα2 .. . [] sym ∈ LA(A S → α k ) → Q αk [] sym ∈ / ( i : 1 ≤ i ≤ k : LA(A → αi )) → skip fi)
46/57
staartrecursie
47/57
A → βA A → ε LA(A → βA) = LA(A → ε)
First(β)
∗
¬(β ⇒ ε)
∗ First(β) ∪ First(A) ∪ Follow (A) β ⇒ ε
= Follow (A) ∗
LL(1)-conditie leidt tot de eisen ¬(β ⇒ ε) First(β) ∩ Follow (A) = ∅ proc PA = (if sym ∈ First(β) → Qβ ; PA [] sym ∈ / First(β) → skip fi) ↓ equivalente procedure (β bevat geen A) proc PA0 = (do sym ∈ First(β) → Qβ od) andere notatie productieregels A → {β}
ambigu
48/57
STATS STATS
→ STAT → STATS; STATS
STATS
STATS
STATS
STAT
STATS
STATS
STATS
STATS
;
STAT
STATS
STATS
;
STAT
STAT
;
STAT
STATS
;
STAT
niet ambigu, niet LL(1)
49/57 STATS
STATS
STATS STATS
→ STAT → STATS; STAT
STATS
;
;
;
STAT
STAT
STAT STATS
STAT
STATS STATS
→ STAT → STAT ; STATS
;
STAT
STATS
;
STAT
STATS
;
expressies en prioriteiten
50/57
ambigu E E E E
→ → → →
E +E E ∗E (E ) 3
3+3∗3 2 afleidingsbomen
niet ambigu (prioriteiten) E E T T F F
→ → → → → →
T E +T F T ∗F (E ) 3
(E → T {+T }) (T → F {∗F })
algemeen (prioriteiten) Ei Ei EiMAX
→ Ei+1 (1 ≤ i < iMAX ) → Ei OPi Ei+1 → ID | NUMBER | (E1 ) | · · ·
factoriseren naar LL(1)-vorm
A → αβ A → αγ
LA(A → αβ) = First(αβ) ∪ . . . LA(A → αβ) = First(αγ) ∪ . . .
(α 6= ε) niet disjunct als First(α) 6= ∅ factoriseren A → αA0 A0 → β A0 → γ nieuwe LL(1)-conditie LA(A0 → β) ∩ LA(A0 → γ) = ∅
51/57
voorbeeld factoriseren STATS STATS
→ STAT → STAT ; STATS
52/57 α = STAT
β=ε γ =; STATS
↓ STATS RSTATS RSTATS
→ STAT RSTATS → ε → ; STATS
LL(1)-conditie:
First(STAT ) Follow (STATS) { semicolonsym }
{semicolonsym} ∩ Follow (STATS) = ∅
alternatief RSTATS →; STAT RSTATS eenvoudiger: STATS → STAT { ; STAT } proc PSTATS = (PSTAT ; do sym = semicolonsym → NEXTSYM; PSTAT od)
eliminatie linksrecursie (1)
53/57
A → γ LA(A → γ) = First(γ) ∪ . . . A → Aβ LA(A → Aβ) = First(Aβ) ∪ . . . First(γ) ⊆ First(Aβ) niet disjunt als First(γ) 6= ∅ A
γββ
β
A A
β
(γβ)β (linksassociatief)
γ
eliminatie linksrecursie (2)
54/57
A → γA0 A → γA0 A → γ{β} A0 → {β} A0 → ε 0 0 A → βA ∗
LL(1)-conditie: ¬(β ⇒ ε) First(β) ∩ Follow (A0 ) = ∅ (Follow (A0 ) = Follow (A)) A
γββ
γ(ββ) γ
A’ β
A’ β
A’ ε
eliminatie linksrecursie (3)
55/57
A t A
γ
γ
γ
A’ t β
β
A A
β
A’
γ
t β
β
A β
A
t:
A
A’
β
γ
ε
array variabelen (1)
a[i + j][2 ∗ k]
56/57
interpretatie: (a[i + j]) [2 ∗ k]
VAR → ID VAR → VAR [ EXPR ] LA(VAR → ID) = {idsym} LA(VAR → VAR [ EXPR ]) = {idsym} LL(1)-vorm VAR → ID RVAR RVAR → ε RVAR → [ EXPR ] RVAR LA(RVAR → ε) = Follow (VAR) LA(RVAR → [ EXPR ] RVAR) = {lsqbrsym} LL(1)-conditie: lsqbrsym ∈ / Follow (VAR)
array variabelen (2)
compacter VAR → ID { [ EXPR ] } PVAR = (PID ; do sym = lsqbrsym → NEXTSYM; PEXPR ; TERM(rsqbrsym) od)
57/57