File: reduce.yo

package info (click to toggle)
bisonc%2B%2B 6.09.02-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 5,984 kB
  • sloc: cpp: 9,375; ansic: 1,505; fortran: 1,134; makefile: 1,062; sh: 526; yacc: 84; lex: 60
file content (93 lines) | stat: -rw-r--r-- 2,893 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
A em(reduce/reduce conflict) occurs if there are two or more rules that apply
to the same sequence of input. This usually indicates a serious error in the
grammar.

For example, here is an erroneous attempt to define a sequence of zero or more
words:
        verbinsert(-as4 demos/rr1)
    The error is an ambiguity: there is more than one way to parse a single
word into a sequence. It could be reduced to a maybeword and then into a
sequence via the second rule. Alternatively, nothing-at-all could be reduced
into a sequence via the first rule, and this could be combined with the word
using the third rule for sequence.

There is also more than one way to reduce nothing-at-all into a sequence. This
can be done directly via the first rule, or indirectly via maybeword and then
the second rule.

You might think that this is a distinction without a difference, because it
does not change whether any particular input is valid or not. But it does
affect which actions are run. One parsing order runs the second rule's action;
the other runs the first rule's action and the third rule's action. In this
example, the output of the program changes.

B() resolves a reduce/reduce conflict by choosing to use the rule that appears
first in the grammar, but it is very risky to rely on this. Every
reduce/reduce conflict must be studied and usually eliminated. Here is the
proper way to define sequence:
    verb(
    sequence: 
        // empty 
        { printf ("empty sequence\n"); }
    | sequence word
        { printf ("added word %s\n", $2); }
    ;
    )

Here is another common error that yields a reduce/reduce conflict:
    verb( 
    sequence: 
        // empty 
        | sequence words
        | sequence redirects
    ;

    words:    
        // empty 
        | words word
    ;

    redirects:
        // empty
        | redirects redirect
    ;
    )

The intention here is to define a sequence containing either tt(word) or
tt(redirect) nonterminals. The individual definitions of sequence, words and
redirects are error-free, but the three together make a subtle ambiguity: even
an empty input can be parsed in infinitely many ways!

Consider: nothing-at-all could be a words. Or it could be two words in a row,
or three, or any number. It could equally well be a redirects, or two, or any
number. Or it could be a words followed by three redirects and another
words. And so on.

Here are two ways to correct these rules. First, to make it a single level of
sequence:
    verb(
    sequence: 
        // empty
        | sequence word
        | sequence redirect
    ;
    )

Second, to prevent either a words or a redirects from being empty:
    verb(
    sequence: 
        // empty
        | sequence words
        | sequence redirects
    ;

    words:    
        word
        | words word
    ;

    redirects:
        redirect
        | redirects redirect
    ;
    )