1 // -*- mode: C++ -*-
2 //
3 // Copyright (c) 2007, 2008, 2009, 2010, 2011, 2013, 2015, 2016, 2017 The University of Utah
4 // All rights reserved.
5 //
6 // This file is part of `csmith', a random generator of C programs.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions are met:
10 //
11 // * Redistributions of source code must retain the above copyright notice,
12 // this list of conditions and the following disclaimer.
13 //
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29
30 #if HAVE_CONFIG_H
31 # include <config.h>
32 #endif
33
34 #include <cassert>
35 #include <iostream>
36 #include "CVQualifiers.h"
37 #include "Type.h"
38 #include "Effect.h"
39 #include "CGContext.h"
40 #include "CGOptions.h"
41 #include "random.h"
42 #include "Error.h"
43 #include "Probabilities.h"
44 #include "DepthSpec.h"
45 #include "Enumerator.h"
46
47 //////////////////////////////////////////////////////////////////////
48 // Construction/Destruction
49 //////////////////////////////////////////////////////////////////////
CVQualifiers(void)50 CVQualifiers::CVQualifiers(void)
51 : wildcard(false),
52 accept_stricter(false)
53 {
54 // nothing else to do
55 }
56
CVQualifiers(bool wild,bool accept_stricter)57 CVQualifiers::CVQualifiers(bool wild, bool accept_stricter)
58 : wildcard(wild),
59 accept_stricter(accept_stricter)
60 {
61 // nothing else to do
62 }
63
CVQualifiers(const vector<bool> & isConsts,const vector<bool> & isVolatiles)64 CVQualifiers::CVQualifiers(const vector<bool>& isConsts, const vector<bool>& isVolatiles)
65 : wildcard(false),
66 accept_stricter(false),
67 is_consts(isConsts),
68 is_volatiles(isVolatiles)
69 {
70 // nothing else to do
71 }
72
CVQualifiers(const CVQualifiers & qfer)73 CVQualifiers::CVQualifiers(const CVQualifiers &qfer)
74 : wildcard(qfer.wildcard),
75 accept_stricter(qfer.accept_stricter),
76 is_consts(qfer.get_consts()),
77 is_volatiles(qfer.get_volatiles())
78 {
79 // nothing else to do
80 }
81
~CVQualifiers()82 CVQualifiers::~CVQualifiers()
83 {
84 }
85
86 CVQualifiers &
operator =(const CVQualifiers & qfer)87 CVQualifiers::operator=(const CVQualifiers &qfer)
88 {
89 if (this == &qfer) {
90 return *this;
91 }
92 wildcard = qfer.wildcard;
93 accept_stricter = qfer.accept_stricter;
94 is_consts = qfer.get_consts();
95 is_volatiles = qfer.get_volatiles();
96 return *this;
97 }
98
99 // --------------------------------------------------------------
100 /* return true if this variable is more const-volatile qualified than v
101 * some examples are:
102 * const is more qualified than none
103 * volatile is more qualified than none
104 * const volatile is more qualified than const
105 * const is NOT more qualified than volatile
106 * ...
107 * notice "const int**" is not convertable from "int**"
108 * as explained in
109 * http://www.embedded.com/columns/programmingpointers/180205632?_requestid=488055
110 **************************************************************/
111 bool
stricter_than(const CVQualifiers & qfer) const112 CVQualifiers::stricter_than(const CVQualifiers& qfer) const
113 {
114 size_t i;
115 assert(is_consts.size() == is_volatiles.size());
116 const vector<bool>& v_consts = qfer.get_consts();
117 const vector<bool>& v_volatiles = qfer.get_volatiles();
118 if (is_consts.size() != v_consts.size() || is_volatiles.size() != v_volatiles.size()) {
119 return false;
120 }
121
122 size_t depth = is_consts.size();
123 // check "const" qualifier first
124 for (i=0; i<depth; i++) {
125 // for special rule: "const int**" is not convertable from "int**"
126 // actually for a level that is followed by two "*"s, we have to match
127 // "const" qualifier
128 if (depth - i > 2 && is_consts[i] != v_consts[i]) {
129 return false;
130 }
131 if (v_consts[i] && !is_consts[i]) {
132 return false;
133 }
134 }
135
136 // check "volatile" qualifier second
137 // special rule: the volatile property on storage (1st in vector) must match
138 // can be relaxed???
139 if (depth > 1 && is_volatiles[0] != v_volatiles[0]) {
140 return false;
141 }
142 for (i=0; i<depth; i++) {
143 // similiar to const: "volatile int**" is not convertable from "int**"
144 // actually for a level that is followed by two "*"s, we have to match
145 if (depth - i > 2 && is_volatiles[i] != v_volatiles[i]) {
146 return false;
147 }
148 if (v_volatiles[i] && !is_volatiles[i]) {
149 return false;
150 }
151 }
152 return true;
153 }
154
155 bool
match(const CVQualifiers & qfer) const156 CVQualifiers::match(const CVQualifiers& qfer) const
157 {
158 if (wildcard) {
159 return true;
160 }
161 if (CGOptions::match_exact_qualifiers()) {
162 return is_consts == qfer.get_consts() && is_volatiles == qfer.get_volatiles();
163 }
164 // return true if both variables are non-pointer (has only one level qualifier)
165 if (is_consts.size() == qfer.get_consts().size() && is_consts.size()==1) {
166 assert(is_consts.size() == is_volatiles.size());
167 return true;
168 }
169 return (!accept_stricter && stricter_than(qfer)) || (accept_stricter && qfer.stricter_than(*this));
170 }
171
172 bool
match_indirect(const CVQualifiers & qfer) const173 CVQualifiers::match_indirect(const CVQualifiers& qfer) const
174 {
175 if (wildcard) {
176 return true;
177 }
178 if (is_consts.size() == qfer.get_consts().size()) {
179 return match(qfer);
180 }
181 int deref = qfer.get_consts().size() - is_consts.size();
182 if (deref < -1) {
183 return false;
184 }
185 return match(qfer.indirect_qualifiers(deref));
186 }
187
188 /*
189 * make sure no volatile-pointers if volatile-pointers is false
190 */
191 void
make_scalar_volatiles(std::vector<bool> & volatiles)192 CVQualifiers::make_scalar_volatiles(std::vector<bool> &volatiles)
193 {
194 if (!CGOptions::volatile_pointers() || !CGOptions::global_variables()) {
195 for (size_t i=1; i<volatiles.size(); i++)
196 volatiles[i] = false;
197 }
198 }
199
200 /*
201 * make sure no const-pointers if const_pointers is false
202 */
203 void
make_scalar_consts(std::vector<bool> & consts)204 CVQualifiers::make_scalar_consts(std::vector<bool> &consts)
205 {
206 if (!CGOptions::const_pointers()) {
207 for (size_t i=1; i<consts.size(); i++)
208 consts[i] = false;
209 }
210 }
211
212 /*
213 * generate a random CV qualifier vector that is looser or stricter than this one
214 */
215 CVQualifiers
random_qualifiers(bool no_volatile,Effect::Access access,const CGContext & cg_context) const216 CVQualifiers::random_qualifiers(bool no_volatile, Effect::Access access, const CGContext &cg_context) const
217 {
218 std::vector<bool> volatiles;
219 std::vector<bool> consts;
220 if (wildcard) {
221 return CVQualifiers(true, accept_stricter);
222 }
223 // use non-volatile for all levels if requested
224 if (no_volatile) {
225 for (size_t i=0; i<is_volatiles.size(); i++) {
226 volatiles.push_back(false);
227 }
228 }
229 else {
230 volatiles = !accept_stricter ? random_looser_volatiles() : random_stricter_volatiles();
231 ERROR_GUARD(CVQualifiers(consts, volatiles));
232 if (!cg_context.get_effect_context().is_side_effect_free()) {
233 volatiles[volatiles.size() - 1] = false;
234 }
235 }
236
237 ERROR_GUARD(CVQualifiers(consts, volatiles));
238 make_scalar_volatiles(volatiles);
239 consts = !accept_stricter ? random_looser_consts() : random_stricter_consts();
240 make_scalar_consts(consts);
241 ERROR_GUARD(CVQualifiers(consts, volatiles));
242 if (access == Effect::WRITE) {
243 consts[consts.size() - 1] = false;
244 }
245 return CVQualifiers(consts, volatiles);
246 }
247
248 /*
249 * generate a random CV qualifier vector that is looser than this one
250 */
251 CVQualifiers
random_loose_qualifiers(bool no_volatile,Effect::Access access,const CGContext & cg_context) const252 CVQualifiers::random_loose_qualifiers(bool no_volatile, Effect::Access access, const CGContext &cg_context) const
253 {
254 std::vector<bool> volatiles;
255 std::vector<bool> consts;
256 if (wildcard) {
257 return CVQualifiers(true, accept_stricter);
258 }
259 // use non-volatile for all levels if requested
260 if (no_volatile) {
261 for (size_t i=0; i<is_volatiles.size(); i++) {
262 volatiles.push_back(false);
263 }
264 }
265 else {
266 volatiles = random_looser_volatiles();
267 ERROR_GUARD(CVQualifiers(consts, volatiles));
268 if (!cg_context.get_effect_context().is_side_effect_free()) {
269 volatiles[volatiles.size() - 1] = false;
270 }
271 }
272 ERROR_GUARD(CVQualifiers(consts, volatiles));
273 make_scalar_volatiles(volatiles);
274
275 consts = random_looser_consts();
276 make_scalar_consts(consts);
277 ERROR_GUARD(CVQualifiers(consts, volatiles));
278 if (access == Effect::WRITE) {
279 consts[consts.size() - 1] = false;
280 }
281 return CVQualifiers(consts, volatiles);
282 }
283
284 CVQualifiers
random_qualifiers(const Type * t,Effect::Access access,const CGContext & cg_context,bool no_volatile)285 CVQualifiers::random_qualifiers(const Type* t, Effect::Access access,
286 const CGContext &cg_context, bool no_volatile)
287 {
288 return random_qualifiers(t, access, cg_context, no_volatile, RegularConstProb, RegularVolatileProb);
289 }
290
is_volatile_ok_on_one_level(const Type * t)291 static bool is_volatile_ok_on_one_level(const Type* t)
292 {
293 if (!CGOptions::lang_cpp()) return true;
294 if (t->eType != eStruct && t->eType != eUnion) return true;
295
296 if (!t->has_assign_ops()) return false;
297 if (t->eType == eStruct) return true;
298
299 // Union with a struct field: we can't make it volatile, or we won't be able to assign to/from that field
300 for (size_t i = 0; i < t->fields.size(); ++i) {
301 const Type* field = t->fields[i];
302
303 if (field->eType == eStruct)
304 return false;
305 if (field->eType == eUnion){
306 if (!is_volatile_ok_on_one_level(field))
307 return false;
308 }
309 }
310 return true;
311 }
312
313 CVQualifiers
random_qualifiers(const Type * t,Effect::Access access,const CGContext & cg_context,bool no_volatile,unsigned int const_prob,unsigned int volatile_prob)314 CVQualifiers::random_qualifiers(const Type* t, Effect::Access access, const CGContext &cg_context, bool no_volatile,
315 unsigned int const_prob, unsigned int volatile_prob)
316 {
317 CVQualifiers ret_qfer;
318 if (t==0) {
319 return ret_qfer;
320 }
321 bool isVolatile = false;
322 bool isConst = false;
323 std::vector<bool> is_consts, is_volatiles;
324 const Effect &effect_context = cg_context.get_effect_context();
325
326 // set random volatile/const properties for each level of indirection for pointers
327 // First set up the vectors with correct number of qualifiers:
328 unsigned level = 0;
329 const Type* tmp = t->ptr_type;
330 while (tmp) {
331 ++level;
332 is_consts.push_back(false);
333 is_volatiles.push_back(false);
334 tmp = tmp->ptr_type;
335 }
336 // Then make the random properties (properties need to be in reverse order):
337 tmp = t->ptr_type;
338 while (tmp) {
339 bool volatile_ok = is_volatile_ok_on_one_level(tmp);
340 isVolatile = volatile_ok? rnd_flipcoin(volatile_prob): false;
341 isConst = rnd_flipcoin(const_prob);
342 if (isVolatile && isConst && !CGOptions::allow_const_volatile()) {
343 isConst = false;
344 }
345 assert(level > 0);
346 is_consts[level-1] = isConst;
347 is_volatiles[level-1] = isVolatile;
348 --level;
349 tmp = tmp->ptr_type;
350 }
351
352 // set random volatile/const properties for variable itself
353 bool volatile_ok = effect_context.is_side_effect_free() && is_volatile_ok_on_one_level(t);
354 bool const_ok = (access != Effect::WRITE);
355
356 isVolatile = volatile_ok ? rnd_flipcoin(volatile_prob) : false;
357 isConst = const_ok ? rnd_flipcoin(const_prob) : false;
358 if (isVolatile && isConst && !CGOptions::allow_const_volatile()) {
359 isConst = false;
360 }
361 is_consts.push_back(isConst);
362 is_volatiles.push_back(isVolatile);
363 // use non-volatile for all levels if requested
364 if (no_volatile) {
365 for (size_t i=0; i<is_volatiles.size(); i++) {
366 is_volatiles[i] = false;
367 }
368 }
369 make_scalar_volatiles(is_volatiles);
370 make_scalar_consts(is_consts);
371 return CVQualifiers(is_consts, is_volatiles);
372 }
373
374 /*
375 * make a random qualifier for type t, assuming non context,
376 * and no volatile allowed
377 */
378 CVQualifiers
random_qualifiers(const Type * t)379 CVQualifiers::random_qualifiers(const Type* t)
380 {
381 return random_qualifiers(t, Effect::READ, CGContext::get_empty_context(), true);
382 }
383
384 /*
385 * be careful to use it because it will generate volatile without knowing the context.
386 * Only used to generate qulifiers for struct/unions
387 */
388 CVQualifiers
random_qualifiers(const Type * t,unsigned int const_prob,unsigned int volatile_prob)389 CVQualifiers::random_qualifiers(const Type* t, unsigned int const_prob, unsigned int volatile_prob)
390 {
391 return random_qualifiers(t, Effect::READ, CGContext::get_empty_context(), false, const_prob, volatile_prob);
392 }
393
394 vector<bool>
random_stricter_consts(void) const395 CVQualifiers::random_stricter_consts(void) const
396 {
397 vector<bool> consts;
398 size_t i;
399 size_t depth = is_consts.size();
400 if (CGOptions::match_exact_qualifiers()) return is_consts;
401 for (i=0; i<depth; i++) {
402 // special case
403 // const int** is not stricter than int**
404 // int * const ** is not stricter than int***
405 // and so on...
406 if (is_consts[i] || (depth - i > 2)) {
407 consts.push_back(is_consts[i]);
408 }
409 else if (is_volatiles[i] && !CGOptions::allow_const_volatile()) {
410 consts.push_back(false);
411 }
412 else {
413 DEPTH_GUARD_BY_DEPTH_RETURN(1, consts);
414 bool index = rnd_flipcoin(StricterConstProb);
415 ERROR_GUARD(consts);
416 consts.push_back(index);
417 }
418 }
419 return consts;
420 }
421
422 vector<bool>
random_stricter_volatiles(void) const423 CVQualifiers::random_stricter_volatiles(void) const
424 {
425 vector<bool> volatiles;
426 size_t i;
427 size_t depth = is_volatiles.size();
428 if (CGOptions::match_exact_qualifiers()) return is_volatiles;
429 for (i=0; i<depth; i++) {
430 // first one (storage must match, any level followed by at least two more
431 // indirections must match
432 if (is_volatiles[i] || (i==0 && depth>1) || (depth - i > 2)) {
433 volatiles.push_back(is_volatiles[i]);
434 }
435 else if (is_consts[i] && !CGOptions::allow_const_volatile()) {
436 volatiles.push_back(false);
437 }
438 else {
439 DEPTH_GUARD_BY_DEPTH_RETURN(1, volatiles);
440 bool index = rnd_flipcoin(RegularVolatileProb);
441 ERROR_GUARD(volatiles);
442 volatiles.push_back(index);
443 }
444 }
445 make_scalar_volatiles(volatiles);
446 return volatiles;
447 }
448
449 vector<bool>
random_looser_consts(void) const450 CVQualifiers::random_looser_consts(void) const
451 {
452 vector<bool> consts;
453 size_t i;
454 size_t depth = is_consts.size();
455 if (CGOptions::match_exact_qualifiers()) return is_consts;
456 for (i=0; i<depth; i++) {
457 // special case
458 if (!is_consts[i] || (depth - i > 2)) {
459 consts.push_back(is_consts[i]);
460 }
461 else {
462 DEPTH_GUARD_BY_DEPTH_RETURN(1, consts);
463 bool index = rnd_flipcoin(LooserConstProb);
464 ERROR_GUARD(consts);
465 consts.push_back(index);
466 }
467 }
468 return consts;
469 }
470
471 vector<bool>
random_looser_volatiles(void) const472 CVQualifiers::random_looser_volatiles(void) const
473 {
474 vector<bool> volatiles;
475 size_t i;
476 size_t depth = is_volatiles.size();
477 if (CGOptions::match_exact_qualifiers()) return is_volatiles;
478 for (i=0; i<depth; i++) {
479 if (!is_volatiles[i] || (i==0 && depth>1) || (depth - i > 2)) {
480 volatiles.push_back(is_volatiles[i]);
481 }
482 else {
483 DEPTH_GUARD_BY_DEPTH_RETURN(1, volatiles);
484 bool index = rnd_flipcoin(RegularVolatileProb);
485 ERROR_GUARD(volatiles);
486 volatiles.push_back(index);
487 }
488 }
489 make_scalar_volatiles(volatiles);
490 return volatiles;
491 }
492
493 void
add_qualifiers(bool is_const,bool is_volatile)494 CVQualifiers::add_qualifiers(bool is_const, bool is_volatile)
495 {
496 is_consts.push_back(is_const);
497 is_volatiles.push_back(is_volatile);
498 }
499
500
501 // actually add qualifiers to pointers
502 CVQualifiers
random_add_qualifiers(bool no_volatile) const503 CVQualifiers::random_add_qualifiers(bool no_volatile) const
504 {
505 CVQualifiers qfer = *this;
506 if (CGOptions::match_exact_qualifiers()) {
507 qfer.add_qualifiers(false, false);
508 return qfer;
509 }
510 //bool is_const = rnd_upto(50);
511 if (no_volatile) {
512 DEPTH_GUARD_BY_DEPTH_RETURN(1, qfer);
513 }
514 else {
515 DEPTH_GUARD_BY_DEPTH_RETURN(2, qfer);
516 }
517
518 bool is_const;
519 if (!CGOptions::const_pointers())
520 is_const = false;
521 else
522 is_const = rnd_flipcoin(RegularConstProb);
523 ERROR_GUARD(qfer);
524 //bool is_volatile = no_volatile ? false : rnd_upto(RegularVolatileProb);
525 bool is_volatile;
526 if (no_volatile || !CGOptions::volatile_pointers())
527 is_volatile = false;
528 else
529 is_volatile = rnd_flipcoin(RegularVolatileProb);
530
531 ERROR_GUARD(qfer);
532 qfer.add_qualifiers(is_const, is_volatile);
533 return qfer;
534 }
535
536 void
remove_qualifiers(int len)537 CVQualifiers::remove_qualifiers(int len)
538 {
539 int i;
540 for (i=0; i<len; i++) {
541 is_consts.pop_back();
542 is_volatiles.pop_back();
543 }
544 }
545
546 CVQualifiers
indirect_qualifiers(int level) const547 CVQualifiers::indirect_qualifiers(int level) const
548 {
549 if (level == 0 || wildcard) {
550 return *this;
551 }
552 // taking address
553 else if (level < 0) {
554 assert(level == -1);
555 CVQualifiers qfer = *this;
556 qfer.add_qualifiers(false, false);
557 return qfer;
558 }
559 // dereference
560 else {
561 CVQualifiers qfer = *this;
562 qfer.remove_qualifiers(level);
563 return qfer;
564 }
565 }
566
567 /*
568 * check if the indirect depth of type matches qualifier size
569 */
570 bool
sanity_check(const Type * t) const571 CVQualifiers::sanity_check(const Type* t) const
572 {
573 assert(t);
574 int level = t->get_indirect_level();
575 assert(level >= 0);
576 return wildcard || (is_consts.size() == is_volatiles.size() && (static_cast<size_t>(level)+1) == is_consts.size());
577 }
578
579 void
output_qualified_type(const Type * t,std::ostream & out) const580 CVQualifiers::output_qualified_type(const Type* t, std::ostream &out) const
581 {
582 assert(t);
583 assert(sanity_check(t));
584 size_t i;
585 const Type* base = t->get_base_type();
586 for (i=0; i<is_consts.size(); i++) {
587 if (i>0) {
588 out << "*";
589 }
590 if (is_consts[i]) {
591 if (!CGOptions::consts())
592 assert(0);
593 if (i > 0) out << " ";
594 out << "const ";
595 }
596 if (is_volatiles[i]) {
597 if (!CGOptions::volatiles())
598 assert(0);
599 if (i > 0) out << " ";
600 out << "volatile ";
601 }
602 if (i==0) {
603 base->Output(out);
604 out << " ";
605 }
606 }
607 }
608
609 bool
is_const_after_deref(int deref_level) const610 CVQualifiers::is_const_after_deref(int deref_level) const
611 {
612 if (deref_level < 0) {
613 return false;
614 }
615 size_t len = is_consts.size();
616 assert(len > static_cast<size_t>(deref_level));
617 return is_consts[len - deref_level - 1];
618 }
619
620 bool
is_volatile_after_deref(int deref_level) const621 CVQualifiers::is_volatile_after_deref(int deref_level) const
622 {
623 if (deref_level < 0) {
624 return false;
625 }
626 size_t len = is_volatiles.size();
627 assert(len > static_cast<size_t>(deref_level));
628 /*
629 if (len <= static_cast<size_t>(deref_level)) {
630 cout << "len = " << len << ", deref_level = " << deref_level << std::endl;
631 assert(0);
632 }
633 */
634 return is_volatiles[len - deref_level - 1];
635 }
636
637 void
set_const(bool is_const,int pos)638 CVQualifiers::set_const(bool is_const, int pos)
639 {
640 int len = is_consts.size();
641 if (len > 0) {
642 is_consts[len - pos - 1] = is_const;
643 }
644 }
645
646 void
set_volatile(bool is_volatile,int pos)647 CVQualifiers::set_volatile(bool is_volatile, int pos)
648 {
649 int len = is_volatiles.size();
650 if (len > 0) {
651 is_volatiles[len - pos - 1] = is_volatile;
652 }
653 }
654
655 void
656 CVQualifiers::restrict(Effect::Access access, const CGContext& cg_context)
657 {
658 if (access == Effect::WRITE) {
659 set_const(false);
660 }
661 if (!cg_context.get_effect_context().is_side_effect_free()) {
662 set_volatile(false);
663 }
664 }
665
666 /*
667 * For now, only used to generate all qualifiers for struct fields.
668 * Also, since we don't support fields with pointer types, we only
669 * enumerate the first level of qualifiers.
670 */
671 void
get_all_qualifiers(vector<CVQualifiers> & quals,unsigned int const_prob,unsigned int volatile_prob)672 CVQualifiers::get_all_qualifiers(vector<CVQualifiers> &quals, unsigned int const_prob, unsigned int volatile_prob)
673 {
674 Enumerator<string> qual_enumerator;
675 qual_enumerator.add_bool_elem("const_prob", const_prob);
676 qual_enumerator.add_bool_elem("volatile_prob", volatile_prob);
677 Enumerator<string> *i;
678 for (i = qual_enumerator.begin(); i != qual_enumerator.end(); i = i->next()) {
679 bool isConst = i->get_elem("const_prob") != 0;
680 bool isVolatile = i->get_elem("volatile_prob") != 0;
681
682 vector<bool> consts;
683 vector<bool> volatiles;
684
685 consts.push_back(isConst);
686 volatiles.push_back(isVolatile);
687 CVQualifiers qual(consts, volatiles);
688
689 quals.push_back(qual);
690 }
691 }
692
693 void
OutputFirstQuals(std::ostream & out) const694 CVQualifiers::OutputFirstQuals(std::ostream &out) const
695 {
696 if (is_consts.size() > 0 && is_consts[0]) {
697 if (!CGOptions::consts())
698 assert(0);
699 out << "const ";
700 }
701
702 if (is_volatiles.size() > 0 && is_volatiles[0]) {
703 if (!CGOptions::volatiles())
704 assert(0);
705 out << "volatile ";
706 }
707 }
708
709 void
output() const710 CVQualifiers::output() const
711 {
712 size_t i;
713 for (i=0; i<is_consts.size(); i++) {
714 cout << is_consts[i] << " ";
715 }
716 cout << ", ";
717 for (i=0; i<is_volatiles.size(); i++) {
718 cout << is_volatiles[i] << " ";
719 }
720 cout << endl;
721 }
722