File: polymorphictype.OBS

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 (348 lines) | stat: -rw-r--r-- 13,538 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
    tt(%type) directives is used to associate (non-)terminals with semantic
value types.  E.g., after:
        verb(
    %polymorphic INT: int; TEXT: std::string
    %type <INT> expr
        )
    the tt(expr) nonterminal returns tt(int) semantic values. In a
rule like:
        verb(
    expr:
        expr '+' expr
        {
            // Action block: C++ statements here.
        }
        )
    Inside action blocks $-notations can be used to retrieve and assign values
from/to the elements of production rules. Type directives are used to
associates $-notations with polymorphic semantic types. In the example $$, $1
and $3 are automatically associated with tt(int) values. $$ is associated with
the rule (here:, `tt(expr:)'; it is the semantic value that becomes available
once the production rule has been recognized), while $1 and $3 are tt(int)
values which are associated with, resp., the first and third element (the
tt(expr) nonterminals) in the production rule tt(expr '+' expr).

    Negative dollar indices can also be used (like $-1), but then pre-defined
associations between nonterminals and semantic types are not available, and
must explicitly be specified to access their polymorphic value types.  Blanks
cannot be used for type-specifications (so $<INT>-1 is OK, $< INT >-1 is not).

Various $-constructions are available to indicate values of rule-elements. $$
constructions refer to values of nonterminals, $1 constructions refer to
values of numbered elements of production rules (the examples use $1, but in
general the positive number must be less than the element number of the action
block in which it is used. Likewise, $-1 constructions refer to values of
elements of production rules that are specified before the current rule's
nonterminal, and in theory any negative number could be used.

The term `value of' indicates the generic tt(STYPE_) value of an
element. When a rule element is associated with a polymorphic type, then the
term `semantic value of' is used.

Here is an overview of the various possibilities:

itemization(
    itt($$ = ) 

    A semantic value is assigned to the rule. The right-hand side (rhs) of
the assignment expression must be an expression of the type that is associated
with $$. This assignment operation assumes that the type of the rhs-expression
equals $$'s semantic value type. If the types don't match the compiler issues
a compilation error when compiling tt(parse.cc). Casting the rhs to the
correct value type is possible, but in that case the function call operator is
preferred, which does not require casting. If no semantic value type was
associated with $$ then the assignment tt($$ = STYPE_{}) can be used.

    itt($$(expr))

    A semantic value is assigned to the rule. tt(Expr) must be of a type that
can statically be cast to $$'s semantic value type. The required
tt(static_cast) is generated by bic() and doesn't have to be specified for
tt(expr).

    itt(_$$)

    This refers to the rule's return value (i.e., tt(d_val_)). No allowance
is made for associated types.

    itt($$)

    If no semantic value was associated with $$ then this is shorthand for a
reference to the rule's value. If a semantic value type was associated with $$
then a reference to the rule's semantic value is returned.

    itt($$.)

    If no semantic value was associated with $$ then this is shorthand for the
member selector operator, applied to a reference to the rule's return
value. If a semantic value type was associated with $$ then the member
selector operator is applied to the rule's semantic value.

    itt($$->)

    If no semantic value was associated with $$ then this is shorthand for the
pointer to member operator, applied to the rule's return value. If a semantic
value type was associated with $$ then the pointer to member operator is
applied to the rule's semantic value.


    itt(_$1)

    This refers to the variable containing the semantic value of the current
production rule's first element. No allowance is made for associated types.

    itt($1)

    This construction refers to the semantic value of the production rule's
first element. If no semantic value was associated with $1 then this is
shorthand for the tt(STYPE_) value that's available for the production rule's
element 1.  If a semantic value was associated with $1 then $1 refers to the
semantic value associated with the production rule's element 1.

    itt($1.)

    If no semantic value was associated with $1 then this is shorthand for the
member selector operator, applied to the semantic value of the production
rule's element 1. If a semantic value was associated with $1 then the member
selector operator is applied to the semantic value associated with the
production rule's element 1.

    itt($1->)

    If no semantic value was associated with $1 then this is shorthand for the
pointer to member operator, applied to the semantic value of the production
rule's element 1. If a semantic value was associated with $1 then the pointer
to member operator is applied to the semantic value associated with the
production rule's element 1.

    itt(_$-1)

    This refers to the value of some production rule element, 1 element before
the current rule's nonterminal. No allowance is made for associated semantic
types.

    itt($-1)

    Same: this refers to the value of some production rule element, 1 element
before the current rule's nonterminal. No allowance is made for associated
semantic types.
 
    itt($-1.)

    This is shorthand for the member selector operator applied to to the value
of some production rule element, 1 element before the current rule's
nonterminal. No allowance is made for associated semantic types.

    itt($1->)

    This is shorthand for the pointer to member operator applied to to the
value of some production rule element, 1 element before the current rule's
nonterminal. No allowance is made for associated semantic types.

    itt($<tag>-1)

    This refers to the semantic value of a polymorphic type (associated with
tt(tag)) of some production rule element, 1 element before the current rule's
nonterminal.

If the semantic value type of that element doesn't match the type that is
associated with tt(tag) then a run-time fatal error results. If that happens,
and the tt(debug) option/directive was specified when bic() wrote the
program's tt(parse) member, then the program can be rerun after specifying
tt(parser.setDebug(Parser::ACTIONCASES)) to locate the tt(parse) function's
action block where the fatal error was encountered.
 
    itt($<tag>-1.)

    This refers to the member selector operator applied to the semantic value
of a polymorphic type (associated with tt(tag)) of some production rule
element, 1 element before the current rule's nonterminal.

If the semantic value type of that element doesn't match the type that is
associated with tt(tag) then a run-time fatal error results. The procedure
suggested at the previous tt($<tag>-1) item for solving such errors can be
applied here as well.

 
    itt($<tag>-1->)

    This refers to the pointer to member operator applied to the semantic
value of a polymorphic type (associated with tt(tag)) of some production rule
element, 1 element before the current rule's nonterminal.

If the semantic value type of that element doesn't match the type that is
associated with tt(tag) then a run-time fatal error results. The procedure
suggested at the previous tt($<tag>-1) item for solving such errors can be
applied here as well.
    )

COMMENT(
whenhtml(
center(
table(1)(l)(
rowline()
row(cell(center(includefile(polytable))))
))
includefile(polytablenotes)
rowline()
)

whenman(
bf(%type<TAG> and $$ or $1 specifications:)
includefile(polytable)
includefile(polytablenotes)
)


bf(Direct semantic value assignments) (`$$(args)'):

    Production rules associated with polymorphic tags and production rules
associated with tt(%type <STYPE_>) should assign values of matching types to
the rules' semantic values. If a matching value type is available from a
production rule's component it can directly be used to assign the semantic
value of the rule's left-hand side nonterminal. E.g., $$ = $1 returns the
semantic value of the production rule's first component. 

However, often production rules receiving tokens from the lexical scanner
cannot refer to semantic values of components of their production rules, as
the scanner merely returns the token and matching text, as in the following
production rule:
        verb(
    number:         // assume %type<NUMBER> number
        NUMBER
        {
            // convert text to a numeric value
        }
    ;
        )
    In such cases the appropriate semantic value must be initialized. 

Bic() translates phrases like tt($$ = xyz) into tt(d_val_.get<tag>() =
xyz) (where tt(tag) is the production rule's left-hand side nonterminal's
polymorphic tag, and tt(d_val_) (see below) is the parser's data member
containing the action block's semantic value). The function tt(get) returns a
reference to a value of the type matching tt(tag), but that value isn't
available yet: in this case it is the action block's duty to initialize it.
Unless there's comment at either side of the assignment operator, bic() 
recognizes such situations, and issues a warning, and such warnings should be
prevented lest the generated tt(parse) function produce a segmentation
fault.

Fortunately, prevention is easy.  To initialize a rule's semantic value a
tt($$(args)) expression should be used (no blanks are allowed between
tt($$) and the open-parenthesis). tt(Args) are at least one, comma-separated
arguments. For tagged nonterminals bic() translates a tt($$(args))
expression into
        verb(
    d_val_.assign<tag>(args).
        )
    where `tt(tag)' is the tag associated with the production rule's left-hand
side nonterminal. For nonterminals that are associated with a
tt(%type<STYPE_>) specification only one argument can be passed to
tt($$(arg)), which translates to
        verb(
    d_val_ = (arg);
        )
    The tt($$(args)) syntax cannot be used for untagged production rules.

If a nonterminal is associated with tt(%type<STYPE_>) and its production
rule calls a function returning a value of a known tagged type, then an
explicit tt(assign) call can be used. E.g.,
        verb(
    Symbol useSymbol();             // available function

    %polymorphic SYMBOL: Symbol;    // directives
    %type<STYPE_> rule
    
    rule:                           // grammar rule
        IDENTIFIER
        {
            $$.assign<Tag_::SYMBOL>(useSymbol());
        }
    ;
        
bf(Member calls) (`$$.', `$1.', `($$)', `($1)', etc.):)

    When `$$.' or `$1.' is used default tags are ignored. A warning is issued
that the default tag is ignored. This syntax allows members of the semantic
value type (tt(STYPE_)) to be called explicitly. The default tag is only
ignored if there are no additional characters (e.g., blanks, closing
parentheses) between the dollar-expressions and the member selector operator
(e.g., no tags are used with $1.member(), but tags are used with
tt(($1).member())). In fact, notations like tt(($$), ($1)), etc. are synonym
to using tt($$.get<Tag_::TYPE>(), $1.get<Tag_::TYPE>())

The opposite, overriding default tag associations, is
accomplished using constructions like $<STYPE_>$ and $<STYPE_>1.

When negative dollar indices are used, the appropriate tag must explicitly be
specified. The next example shows how this is realized in the grammar
specification file itself:
        verb(
    %polymorphic INT: int
    %type <INT> ident
    %%
    
    type:
        ident arg
    ;
    
    arg:
        {
            call($-1.get<Tag_::INT>());
        }
    ;
        )
    In this example tt(call) may define an tt(int) or tt(int &) parameter. 

It is also possible to delegate specification of the semantic value to the
function tt(call) itself, as shown next:
        verb(
    %polymorphic INT: int
    %type <INT> ident
    %%
    
    type:
        ident arg
    ;
    
    arg:
        {
            call($-1);
        }
    ;
        )
    Here, the function tt(call) could be implemented like this:
        verb(
    void call(STYPE_ &st)
    {
        st.get<Tag_::INT>() = 5;
    }
        )

Semantic values may also directly be associated with terminal tokens. In that
case it is the lexical scanner's responsibility to assign a properly typed
value to the parser's tt(STYPE_ d_val_) data member. When the lexical
scanner receives a pointer to the parser's tt(d_val_) data member (using,
e.g., a member tt(setSval(STYPE_ *dval)))
    IFDEF(manual)((cf. section ref(PRIVDATA)))(), 
then the lecical scanner must use em(tagged assignment) as shown in the above
example to reach the different polymorphic types. The lexical scanner, having
defined a tt(Parser::STYPE_ *d_val) data member could then use statements
like
        verb(
    d_val.assign<Tag_::INT>(stoi(matched()));
        )
    to assign an tt(int) value to the parser's semantic value, which is then
available to the parser when the lexical scanner's tt(lex) function returns as
the semantic value (e.g., $1) of the production rule's element specifying the
terminal token. Note, however that this requires the scanner to harbor some
intelligence about the meaning of a tt(Parser::INT) token. It can be argued
that this intelligence should only be available to the parser, and that the
scanner should merely recognize regular expressions and return tokens and
their corresponding matched text.

END)