File: parser.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 (106 lines) | stat: -rw-r--r-- 3,208 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
94
95
96
97
98
99
100
101
102
103
104
105
106
In this section a small demo-parser is developed using polymorphic semantic
values.  Its tt(%polymorphic) directive looks like this:
        verb(
    %polymorphic INT: int; TEXT: std::string;
        )
    Furthermore, the grammar declares tokens tt(INT) and tt(IDENTIFIER), and
pre-associates the tt(TEXT) tag with the tt(identifier) nonterminal,
associates the tt(INT) tag with the tt(int) nonterminal. The tt(combi)
nonterminal is associated with the generic tt(STYPE_) semantic value type:
        verb(
    %type <TEXT>    identifier
    %type <INT>     int
    %type <STYPE_> combi
        )
    
    The parser's grammar is simple, expecting input lines, formatted
according to the following (tt(rule)) production rule:
        verb(
    rule:
        identifier '(' identifier ')' '\n'
    |
        identifier '=' int '\n'
    |
        combi '\n'
    ;
        )
    
    The rules for tt(identifier) and tt(int) return, respectively, text and an
tt(int) value:
        verb(
    identifier:
        IDENTIFIER
        {
            $$ = d_scanner.matched();
        }
    ;
    int:
        INT
        {
            $$ = d_scanner.intValue();
        }
    ;
        )

These simple assignments can be used as tt(int) is pre-associated with the
tt(INT) tag and tt(identifier) is asociated with the tt(TEXT) tag. 

The tt(combi) rule, which is used in one of the production rules of
`tt(rule)', accepts a single tt(int) value, as well as an identifier. So it
cannot be associated with a single polymorphic type. But as it is associated
with the generic tt(STYPE_) type, it can pass on any polymorphic value. In
tt(rule's) production rule the generic semantic value is then simply passed on
to tt(process), expecting a plain tt(STYPE_ const &). The function
tt(process) has to inspect the semantic value's tag to learn what
kind of value is stored inside the received semantic value. Here are the
definition of the tt(combi) nonterminal and action blocks for the tt(rule)
nonterminal:
        verb(
    combi:          
        int
    |
        identifier
    ;
        
    rule:
        identifier '(' identifier ')' '\n'
        {
            cout << $1 << " " << $3 << '\n';
        }
    |
        identifier '=' int '\n'
        {
            cout << $1 << " " << $3 << '\n';
        }
    |
        combi '\n'
        {
            process($1);
        }
    ;
        )

Note that tt(combi's) production rules do not define action blocks. The
standard way to handle these situations is to add tt($$ = $1) action blocks to
non-empty production rules not defining final action blocks. This works well
in the current example, but a tt(default-actions quiet) (or tt(warn)) option
or directive can also be used.

The function tt(process), called from tt(combi's) action block, inspects the
semantic value's tag to select the proper way of handling the received
semantic value. Here is its implementation:
        verb(
    void Parser::process(STYPE_ &semVal) const
    {
        if (semVal.tag() == Tag_::INT)
            cout << "Saw an int-value: " << semVal.get<Tag_::INT>() << '\n';
        else
            cout << "Saw text: " << semVal.get<Tag_::TEXT>() << '\n';
    }
        )