COMS W4115
Programming Languages and Translators
Lecture 12: Parsing Action Conflicts
March 3, 2008
Lecture Outline
- Review
- Parsing action conflicts
- Resolving shift/reduce conflicts
- Using Yacc to generate LALR(1) parsers
- Using Yacc with ambiguous grammars
- Reading
1. Review
- LR(1) parsing
- Constructing simple LR(1) parsers
- DFA for viable prefixes
2. Parsing Action Conflicts
- If a grammar is not SLR(1), the SLR parsing table construction produces one or more
multiply defined entries in the parsing table action function.
- These entries are either shift/reduce conflicts or
reduce/reduce conflicts.
3. Resolving Shift/Reduce Conflicts
- Example. Given the augmented grammar G'
(0) E' → E
(1) E → E+E
(2) E → E*E
(3) E → id
Note that this grammar does not specify the relative precedence
of the +
and *
operators
nor their associativities.
C, the canonical collection of sets of LR(0) items for G', is
I0: E' → ·E
E → ·E+E
E → ·E*E
E → ·id
I1: E' → E·
E → E·+E
E → E·*E
I2: E → id·
I3: E → E+·E
E → ·E+E
E → ·E*E
E → ·id
I4: E → E*·E
E → ·E+E
E → ·E*E
E → ·id
I5: E → E+E·
E → E·+E
E → E·*E
I6: E → E*E·
E → E·+E
E → E·*E
SLR(1) parsing table for G':
State |
Action |
Goto |
id |
+ |
* |
$ |
S |
0 |
s2 |
|
|
|
1 |
1 |
|
s3 |
s4 |
acc |
|
2 |
|
r3 |
r3 |
r3 |
|
3 |
s2 |
|
|
|
5 |
4 |
s2 |
|
|
|
6 |
5 |
|
s3
r1 |
s4
r1 |
r1 |
|
6 |
|
s3
r2 |
s4
r2 |
r2 |
|
Notes
- There is a shift/reduce conflict in
action[5,+]
between
"shift 3
" and "reduce by E → E+E
"
because the associativity of the operator +
is not defined
by the grammar. This conflict can be resolved in favor of
"reduce by E → E+E
" if we want +
to be left associative.
- There is a shift/reduce conflict in
action[5,*]
between "shift 4
" and "reduce by E → E+E
"
because the relative precedence of the operators +
and
*
is not defined by the grammar. This conflict can be
resolved in favor of "shift 4
" if we want *
to have higher precedence than +
.
- Analogously, there is a shift/reduce conflict in
action[6,+]
between "shift 3
" and "reduce by E → E*E
"
because the relative precedence of the operators +
and
*
is not defined by the grammar. This conflict can be
resolved in favor of "reduce by E → E*E
" if we want
*
to have higher precedence than +
.
- There is a shift/reduce conflict in
action[6,*]
between
"shift 4
" and "reduce by E → E*E
"
because the associativity of the operator *
is not defined
by the grammar. This conflict can be resolved in favor of
"reduce by E → E*E
" if we want *
to be
left associative.
4. Using Yacc to Generate LALR(1) Parsers
- Consider the yacc program
expr1.y
:
%token id
%%
E : E '+' E
| E '*' E
| id
;
Invoking yacc -v expr1.y
, we can see the kernels of the
sets of items for this grammar in the yacc output file y.output
.
The parsing action conflicts are shown for states 5 and 6.
state 0
$accept : _E $end
id shift 2
. error
E goto 1
state 1
$accept : E_$end
E : E_+ E
E : E_* E
$end accept
+ shift 3
* shift 4
. error
state 2
E : id_ (3)
. reduce 3
state 3
E : E +_E
id shift 2
. error
E goto 5
state 4
E : E *_E
id shift 2
. error
E goto 6
5: shift/reduce conflict (shift 3, red'n 1) on +
5: shift/reduce conflict (shift 4, red'n 1) on *
state 5
E : E_+ E
E : E + E_ (1)
E : E_* E
+ shift 3
* shift 4
. reduce 1
6: shift/reduce conflict (shift 3, red'n 2) on +
6: shift/reduce conflict (shift 4, red'n 2) on *
state 6
E : E_+ E
E : E_* E
E : E * E_ (2)
+ shift 3
* shift 4
. reduce 2
5/127 terminals, 1/600 nonterminals
4/300 grammar rules, 7/1000 states
4 shift/reduce, 0 reduce/reduce conflicts reported
4/601 working sets used
memory: states,etc. 17/2000, parser 2/4000
3/3001 distinct lookahead sets
0 extra closures
9 shift entries, 1 exceptions
3 goto entries
0 entries saved by goto default
Optimizer space used: input 25/2000, output 9/4000
9 table entries, 3 zero
maximum spread: 257, maximum offset: 257
5. Using Yacc with Ambiguous Grammars
- We can specify the associativities and relative precedence
of the
+
and *
operators in the
declarations sections of a yacc program.
- Consider the yacc program
expr2.y
:
- The statement
%left '+'
makes +
left associative.
- The statement
%left '*'
makes *
left associative.
- Since the statement for
+
comes before the statement for
*
, +
has lower precedence than *
.
%token id
%left '+'
%left '*'
%%
E : E '+' E
| E '*' E
| id
;
Invoking yacc -v expr2.y
, we can now see that
no shift-reduce conflicts have been generated in
the yacc output file y.output
.
state 0
$accept : _E $end
id shift 2
. error
E goto 1
state 1
$accept : E_$end
E : E_+ E
E : E_* E
$end accept
+ shift 3
* shift 4
. error
state 2
E : id_ (3)
. reduce 3
state 3
E : E +_E
id shift 2
. error
E goto 5
state 4
E : E *_E
id shift 2
. error
E goto 6
state 5
E : E_+ E
E : E + E_ (1)
E : E_* E
* shift 4
. reduce 1
state 6
E : E_+ E
E : E_* E
E : E * E_ (2)
. reduce 2
5/127 terminals, 1/600 nonterminals
4/300 grammar rules, 7/1000 states
0 shift/reduce, 0 reduce/reduce conflicts reported
4/601 working sets used
memory: states,etc. 17/2000, parser 2/4000
3/3001 distinct lookahead sets
0 extra closures
6 shift entries, 1 exceptions
3 goto entries
0 entries saved by goto default
Optimizer space used: input 19/2000, output 10/4000
10 table entries, 3 zero
maximum spread: 257, maximum offset: 257
Unless otherwise instructed, Yacc resolves all parsing
action conflicts using the following two rules:
- A reduce/reduce conflict is resolved by chossing the
conflicting production listed first in the Yacc
specification.
- A shift/reduce conflict is resolved in favor of shift.
Note that this rule correctly resolves the shift/reduce conflict
arising from the dangling-else ambiguity.
6. Reading
- ALSU, Sects. 4.8 and 4.9
- The first line in the Lex specification in Fig. 4.60
should not have an
e
after the two
backslashes:
number [0-9]+\.?|[0-9]*\.[0-9]+
aho@cs.columbia.edu