source: NonGTP/Boost/boost/wave/grammars/cpp_expression_value.hpp @ 857

Revision 857, 26.5 KB checked in by igarcia, 18 years ago (diff)
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3
4    http://www.boost.org/
5
6    Copyright (c) 2001-2005 Hartmut Kaiser. Distributed under the Boost
7    Software License, Version 1.0. (See accompanying file
8    LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9=============================================================================*/
10
11#if !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
12#define CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED
13
14#if defined (BOOST_SPIRIT_DEBUG)
15#include <iostream>
16#endif // defined(BOOST_SPIRIT_DEBUG)
17
18///////////////////////////////////////////////////////////////////////////////
19namespace boost {
20namespace wave {
21namespace grammars {
22namespace closures {
23
24///////////////////////////////////////////////////////////////////////////////
25//
26//  The closure_value class represents the closure type, which is used for the
27//  expression grammar.
28//
29//      This class was introduced to allow the expression grammar to respect
30//      the numeric type of a numeric literal or expression result.
31//
32///////////////////////////////////////////////////////////////////////////////
33class closure_value {
34public:
35
36    enum value_type {
37        is_int = 1,
38        is_uint = 2,
39        is_bool = 3
40    };
41   
42    enum value_error {
43        error_noerror = 0x0,
44        error_division_by_zero = 0x1,
45        error_overflow = 0x2
46    };
47   
48    closure_value(value_error valid_ = error_noerror)
49    : type(is_int), valid(valid_)
50    { value.i = 0; }
51    explicit closure_value(int i, value_error valid_ = error_noerror)
52    : type(is_int), valid(valid_)
53    { value.i = i; }
54    explicit closure_value(unsigned int ui, value_error valid_ = error_noerror)
55    : type(is_uint), valid(valid_)
56    { value.ui = ui; }
57    explicit closure_value(long i, value_error valid_ = error_noerror)
58    : type(is_int), valid(valid_)
59    { value.i = i; }
60    explicit closure_value(unsigned long ui, value_error valid_ = error_noerror)
61    : type(is_uint), valid(valid_)
62    { value.ui = ui; }
63    explicit closure_value(bool b, value_error valid_ = error_noerror)
64    : type(is_bool), valid(valid_)
65    { value.b = b; }
66
67    value_type get_type() const { return type; }
68    value_error is_valid() const { return valid; }
69   
70// implicit conversion
71    operator int() const
72    {
73        switch (type) {
74        case is_uint:   return value.ui;
75        case is_bool:   return value.b ? 1 : 0;
76        case is_int:    break;
77        }
78        return value.i;
79    }
80    operator unsigned int() const
81    {
82        switch (type) {
83        case is_uint:   return value.ui;
84        case is_bool:   return value.b ? 1 : 0;
85        case is_int:    break;
86        }
87        return value.i;
88    }
89    operator long() const
90    {
91        switch (type) {
92        case is_uint:   return value.ui;
93        case is_bool:   return value.b ? 1 : 0;
94        case is_int:    break;
95        }
96        return value.i;
97    }
98    operator unsigned long() const
99    {
100        switch (type) {
101        case is_uint:   return value.ui;
102        case is_bool:   return value.b ? 1 : 0;
103        case is_int:    break;
104        }
105        return value.i;
106    }
107    operator bool() const
108    {
109        switch (type) {
110        case is_uint:   return value.ui != 0;
111        case is_bool:   return value.b;
112        case is_int:    break;
113        }
114        return value.i != 0.0;
115    }
116
117// assignment   
118    closure_value &operator= (closure_value const &rhs)
119    {
120        switch (rhs.get_type()) {
121        case is_int:   
122            value.i = long(rhs);
123            type = is_int;
124            break;
125       
126        case is_uint:   
127            value.ui = (unsigned long)(rhs);
128            type = is_uint;
129            break;
130       
131        case is_bool:   
132            value.b = bool(rhs);
133            type = is_bool;
134            break;
135        }
136        valid = rhs.valid;
137        return *this;
138    }
139    closure_value &operator= (int rhs)
140    {
141        type = is_int;
142        value.i = rhs;
143        valid = error_noerror;
144        return *this;
145    }
146    closure_value &operator= (unsigned int rhs)
147    {
148        type = is_uint;
149        value.ui = rhs;
150        valid = error_noerror;
151        return *this;
152    }
153    closure_value &operator= (long rhs)
154    {
155        type = is_int;
156        value.i = rhs;
157        valid = error_noerror;
158        return *this;
159    }
160    closure_value &operator= (unsigned long rhs)
161    {
162        type = is_uint;
163        value.ui = rhs;
164        valid = error_noerror;
165        return *this;
166    }
167    closure_value &operator= (bool rhs)
168    {
169        type = is_bool;
170        value.b = rhs;
171        valid = error_noerror;
172        return *this;
173    }
174
175// arithmetics
176    closure_value &operator+= (closure_value const &rhs)
177    {
178        switch (type) {
179        case is_int:   
180            switch(rhs.type) {
181            case is_bool:
182                {
183                    long result = value.i + long(rhs);
184                    if (rhs.value.i > 0L && value.i > result ||
185                        rhs.value.i < 0L && value.i < result)
186                    {
187                        valid = error_overflow;
188                    }
189                    else {
190                        value.i = result;
191                    }
192                }
193                break;
194               
195            case is_int:
196                {
197                    long result = value.i + rhs.value.i;
198                    if (rhs.value.i > 0L && value.i > result ||
199                        rhs.value.i < 0L && value.i < result)
200                    {
201                        valid = error_overflow;
202                    }
203                    else {
204                        value.i = result;
205                    }
206                }
207                break;
208               
209            case is_uint:
210                {
211                    unsigned long result = value.ui + rhs.value.ui;
212                    if (result < value.ui) {
213                        valid = error_overflow;
214                    }
215                    else {
216                        value.ui = result;
217                        type = is_uint;
218                    }
219                }
220                break;
221            }
222            break;
223           
224        case is_uint:
225            {
226                unsigned long result = value.ui + (unsigned long)(rhs);
227                if (result < value.ui) {
228                    valid = error_overflow;
229                }
230                else {
231                    value.ui = result;
232                }
233            }
234            break;
235           
236        case is_bool:   
237            value.i = value.b + bool(rhs);
238            type = is_int;
239        }
240        valid = (value_error)(valid | rhs.valid);
241        return *this;
242    }
243    closure_value &operator-= (closure_value const &rhs)
244    {
245        switch (type) {
246        case is_int:
247            switch(rhs.type) {
248            case is_bool:
249                {
250                    long result = value.i - long(rhs);
251                    if (rhs.value.i > 0L && result > value.i ||
252                        rhs.value.i < 0L && result < value.i)
253                    {
254                        valid = error_overflow;
255                    }
256                    else {
257                        value.i = result;
258                    }
259                }
260                break;
261
262            case is_int:
263                {
264                    long result = value.i - rhs.value.i;
265                    if (rhs.value.i > 0L && result > value.i ||
266                        rhs.value.i < 0L && result < value.i)
267                    {
268                        valid = error_overflow;
269                    }
270                    else {
271                        value.i = result;
272                    }
273                }
274                break;
275               
276            case is_uint:
277                {
278                    unsigned long result = value.ui - rhs.value.ui;
279                    if (result > value.ui) {
280                        valid = error_overflow;
281                    }
282                    else {
283                        value.ui = result;
284                        type = is_uint;
285                    }
286                }
287                break;
288            }
289            break;
290           
291        case is_uint:
292            switch(rhs.type) {
293            case is_bool:
294                {
295                    unsigned long result = value.ui - (unsigned long)(rhs);
296                    if (result > value.ui)
297                    {
298                        valid = error_overflow;
299                    }
300                    else {
301                        value.ui = result;
302                    }
303                }
304                break;
305
306            case is_int:
307                {
308                    unsigned long result = value.ui - rhs.value.i;
309                    if (rhs.value.i > 0L && result > value.ui ||
310                        rhs.value.i < 0L && result < value.ui)
311                    {
312                        valid = error_overflow;
313                    }
314                    else {
315                        value.ui = result;
316                    }
317                }
318                break;
319               
320            case is_uint:
321                {
322                    unsigned long result = value.ui - rhs.value.ui;
323                    if (result > value.ui) {
324                        valid = error_overflow;
325                    }
326                    else {
327                        value.ui = result;
328                    }
329                }
330                break;
331            }
332            break;
333
334        case is_bool:   
335            value.i = value.b - bool(rhs);
336            type = is_int;
337        }
338        valid = (value_error)(valid | rhs.valid);
339        return *this;
340    }
341    closure_value &operator*= (closure_value const &rhs)
342    {
343        switch (type) {
344        case is_int:   
345            switch(rhs.type) {
346            case is_bool:   value.i *= long(rhs); break;
347            case is_int:
348                {
349                    long result = value.i * rhs.value.i;
350                    if (0 != value.i && 0 != rhs.value.i &&
351                        (result / value.i != rhs.value.i ||
352                         result / rhs.value.i != value.i)
353                       )
354                    {
355                        valid = error_overflow;
356                    }
357                    else {
358                        value.i = result;
359                    }
360                }
361                break;
362               
363            case is_uint:
364                {
365                    unsigned long result = value.ui * rhs.value.ui;
366                    if (0 != value.ui && 0 != rhs.value.ui &&
367                        (result / value.ui != rhs.value.ui ||
368                         result / rhs.value.ui != value.ui)
369                       )
370                    {
371                        valid = error_overflow;
372                    }
373                    else {
374                        value.ui = result;
375                        type = is_uint;
376                    }
377                }
378                break;
379            }
380            break;
381           
382        case is_uint:
383            {
384                unsigned long rhs_val = (unsigned long)(rhs);
385                unsigned long result = value.ui * rhs_val;
386                if (0 != value.ui && 0 != rhs_val &&
387                    (result / value.ui != rhs_val ||
388                      result / rhs_val != value.ui)
389                    )
390                {
391                    valid = error_overflow;
392                }
393                else {
394                    value.ui = result;
395                    type = is_uint;
396                }
397            }
398            break;
399           
400        case is_bool:
401            switch (rhs.type) {
402            case is_int:
403                value.i = (value.b ? 1 : 0) * rhs.value.i;
404                type = is_int;
405                break;
406               
407            case is_uint:
408                value.ui = (value.b ? 1 : 0) * rhs.value.ui;
409                type = is_uint;
410                break;
411               
412            case is_bool:
413                value.b = 0 != ((value.b ? 1 : 0) * (rhs.value.b ? 1 : 0));
414                break;
415            }
416        }
417        valid = (value_error)(valid | rhs.valid);
418        return *this;
419    }
420    closure_value &operator/= (closure_value const &rhs)
421    {
422        switch (type) {
423        case is_int:   
424            switch(rhs.type) {
425            case is_bool:   
426            case is_int:
427                if (long(rhs) != 0) {
428                    if (value.i == -value.i && -1 == rhs.value.i) {
429                    // LONG_MIN / -1 on two's complement
430                        valid = error_overflow;
431                    }
432                    else {
433                        value.i /= long(rhs);
434                    }
435                }
436                else {
437                    valid = error_division_by_zero;   // division by zero
438                }
439                break;
440               
441            case is_uint:
442                if (rhs.value.ui != 0) {
443                    value.ui /= rhs.value.ui;
444                    type = is_uint;
445                }
446                else {
447                    valid = error_division_by_zero;      // division by zero
448                }
449                break;
450            }
451            break;
452           
453        case is_uint:
454            if ((unsigned long)(rhs) != 0)
455                value.ui /= (unsigned long)(rhs);
456            else
457                valid = error_division_by_zero;         // division by zero
458            break;
459
460        case is_bool: 
461            if (bool(rhs)) {
462                switch(rhs.type) {
463                case is_int:
464                    value.i = (value.b ? 1 : 0) / rhs.value.i;
465                    type = is_int;
466                    break;
467                   
468                case is_uint:
469                    value.i = (value.b ? 1 : 0) / rhs.value.ui;
470                    type = is_int;
471                    break;
472                   
473                case is_bool:
474                    break;
475                }
476            }
477            else {
478                valid = error_division_by_zero;         // division by zero
479            }
480        }
481        return *this;
482    }
483    closure_value &operator%= (closure_value const &rhs)
484    {
485        switch (type) {
486        case is_int:   
487            switch(rhs.type) {
488            case is_bool:   
489            case is_int:
490                if (long(rhs) != 0) {
491                    if (value.i == -value.i && -1 == rhs.value.i) {
492                    // LONG_MIN % -1 on two's complement
493                        valid = error_overflow;
494                    }
495                    else {
496                        value.i %= long(rhs);
497                    }
498                }
499                else {
500                    valid = error_division_by_zero;      // division by zero
501                }
502                break;
503               
504            case is_uint:
505                if (rhs.value.ui != 0) {
506                    value.ui %= rhs.value.ui;
507                    type = is_uint;
508                }
509                else {
510                    valid = error_division_by_zero;      // division by zero
511                }
512                break;
513            }
514            break;
515           
516        case is_uint:
517            if ((unsigned long)(rhs) != 0)
518                value.ui %= (unsigned long)(rhs);
519            else
520                valid = error_division_by_zero;      // division by zero
521            break;
522
523        case is_bool: 
524            if (bool(rhs)) {
525                switch(rhs.type) {
526                case is_int:
527                    value.i = (value.b ? 1 : 0) % rhs.value.i;
528                    type = is_int;
529                    break;
530                   
531                case is_uint:
532                    value.i = (value.b ? 1 : 0) % rhs.value.ui;
533                    type = is_int;
534                    break;
535                   
536                case is_bool:
537                    break;
538                }                   
539            }
540            else {
541                valid = error_division_by_zero;      // division by zero
542            }
543        }
544        return *this;
545    }
546
547    friend closure_value
548    operator- (closure_value const &rhs)
549    {
550        switch (rhs.type) {
551        case is_int:
552            {
553                long value = long(rhs);
554                if (value != 0 && value == -value)
555                    return closure_value(-value, error_overflow);
556                return closure_value(-value, rhs.valid);
557            }
558           
559        case is_bool:   return closure_value(-long(rhs), rhs.valid);
560        case is_uint:   break;
561        }
562
563        long value = (unsigned long)(rhs);
564        if (value != 0 && value == -value)
565            return closure_value(-value, error_overflow);
566        return closure_value(-value, rhs.valid);
567    }
568    friend closure_value
569    operator~ (closure_value const &rhs)
570    {
571        return closure_value(~(unsigned long)(rhs), rhs.valid);
572    }
573    friend closure_value
574    operator! (closure_value const &rhs)
575    {
576        switch (rhs.type) {
577        case is_int:    return closure_value(!long(rhs), rhs.valid);
578        case is_bool:   return closure_value(!bool(rhs), rhs.valid);
579        case is_uint:   break;
580        }
581        return closure_value(!(unsigned long)(rhs), rhs.valid);
582    }
583   
584// comparison
585    friend closure_value
586    operator== (closure_value const &lhs, closure_value const &rhs)
587    {
588        bool cmp = false;
589        switch (lhs.type) {
590        case is_int:
591            switch(rhs.type) {
592            case is_bool:   cmp = bool(lhs) == rhs.value.b; break;
593            case is_int:    cmp = lhs.value.i == rhs.value.i; break;
594            case is_uint:   cmp = lhs.value.ui == rhs.value.ui; break;
595            }
596            break;
597           
598        case is_uint:   cmp = lhs.value.ui == (unsigned long)(rhs); break;
599        case is_bool:   cmp = lhs.value.b == bool(rhs); break;
600        }
601        return closure_value(cmp, (value_error)(lhs.valid & rhs.valid));
602    }
603    friend closure_value
604    operator!= (closure_value const &lhs, closure_value const &rhs)
605    {
606        return closure_value(!bool(lhs == rhs), (value_error)(lhs.valid & rhs.valid));
607    }
608    friend closure_value
609    operator> (closure_value const &lhs, closure_value const &rhs)
610    {
611        bool cmp = false;
612        switch (lhs.type) {
613        case is_int:
614            switch(rhs.type) {
615            case is_bool:   cmp = lhs.value.i > long(rhs); break;
616            case is_int:    cmp = lhs.value.i > rhs.value.i; break;
617            case is_uint:   cmp = lhs.value.ui > rhs.value.ui; break;
618            }
619            break;
620           
621        case is_uint:   cmp = lhs.value.ui > (unsigned long)(rhs); break;
622        case is_bool:   cmp = lhs.value.b > bool(rhs); break;
623        }
624        return closure_value(cmp, (value_error)(lhs.valid & rhs.valid));
625    }
626    friend closure_value
627    operator< (closure_value const &lhs, closure_value const &rhs)
628    {
629        bool cmp = false;
630        switch (lhs.type) {
631        case is_int:    cmp = long(lhs) < long(rhs); break;
632            switch(rhs.type) {
633            case is_bool:   cmp = lhs.value.i < long(rhs); break;
634            case is_int:    cmp = lhs.value.i < rhs.value.i; break;
635            case is_uint:   cmp = lhs.value.ui < rhs.value.ui; break;
636            }
637            break;
638           
639        case is_uint:   cmp = lhs.value.ui < (unsigned long)(rhs); break;
640        case is_bool:   cmp = bool(lhs) < bool(rhs); break;
641        }
642        return closure_value(cmp, (value_error)(lhs.valid & rhs.valid));
643    }
644    friend closure_value
645    operator<= (closure_value const &lhs, closure_value const &rhs)
646    {
647        return closure_value(!bool(lhs > rhs), (value_error)(lhs.valid & rhs.valid));
648    }
649    friend closure_value
650    operator>= (closure_value const &lhs, closure_value const &rhs)
651    {
652        return closure_value(!bool(lhs < rhs), (value_error)(lhs.valid & rhs.valid));
653    }
654
655    closure_value &
656    operator<<= (closure_value const &rhs)
657    {
658        switch (type) {
659        case is_bool:
660        case is_int:
661            switch (rhs.type) {
662            case is_bool:
663            case is_int:
664                {
665                long shift_by = long(rhs);
666                   
667                    if (shift_by > 64)
668                        shift_by = 64;
669                    else if (shift_by < -64)
670                        shift_by = -64;
671                    value.i <<= shift_by;
672                }
673                break;
674               
675            case is_uint:
676                {
677                unsigned long shift_by = (unsigned long)(rhs);
678                   
679                    if (shift_by > 64)
680                        shift_by = 64;
681                    value.ui <<= shift_by;
682               
683                // Note: The usual arithmetic conversions are not performed on
684                //       bit shift operations.
685                }
686                break;
687            }
688            break;
689
690        case is_uint:
691            switch (rhs.type) {
692            case is_bool:
693            case is_int:
694                {
695                long shift_by = long(rhs);
696                   
697                    if (shift_by > 64)
698                        shift_by = 64;
699                    else if (shift_by < -64)
700                        shift_by = -64;
701                    value.ui <<= shift_by;
702                }
703                break;
704               
705            case is_uint:
706                {
707                unsigned long shift_by = (unsigned long)(rhs);
708                   
709                    if (shift_by > 64)
710                        shift_by = 64;
711                    value.ui <<= shift_by;
712                }
713                break;
714            }
715        }
716        valid = (value_error)(valid | rhs.valid);
717        return *this;
718    }
719
720    closure_value &
721    operator>>= (closure_value const &rhs)
722    {
723        switch (type) {
724        case is_bool:
725        case is_int:
726            switch (rhs.type) {
727            case is_bool:
728            case is_int:
729                {
730                long shift_by = long(rhs);
731                   
732                    if (shift_by > 64)
733                        shift_by = 64;
734                    else if (shift_by < -64)
735                        shift_by = -64;
736                    value.i >>= shift_by;
737                }
738                break;
739               
740            case is_uint:
741                {
742                unsigned long shift_by = (unsigned long)(rhs);
743                   
744                    if (shift_by > 64)
745                        shift_by = 64;
746                    value.ui >>= shift_by;
747               
748                // Note: The usual arithmetic conversions are not performed on
749                //       bit shift operations.
750                }
751                break;
752            }
753            break;
754           
755        case is_uint:
756            switch (rhs.type) {
757            case is_bool:
758            case is_int:
759                {
760                long shift_by = long(rhs);
761                   
762                    if (shift_by > 64)
763                        shift_by = 64;
764                    else if (shift_by < -64)
765                        shift_by = -64;
766                    value.ui >>= shift_by;
767                }
768                break;
769               
770            case is_uint:
771                {
772                unsigned long shift_by = (unsigned long)(rhs);
773                   
774                    if (shift_by > 64)
775                        shift_by = 64;
776                    value.ui >>= shift_by;
777                }
778                break;
779            }
780            break;
781        }
782        valid = (value_error)(valid | rhs.valid);
783        return *this;
784    }
785
786    friend closure_value
787    operator|| (closure_value const &lhs, closure_value const &rhs)
788    {
789        bool result = bool(lhs) || bool(rhs);
790        return closure_value(result, (value_error)(lhs.valid & rhs.valid));
791    }
792   
793    friend closure_value
794    operator&& (closure_value const &lhs, closure_value const &rhs)
795    {
796        bool result = bool(lhs) && bool(rhs);
797        return closure_value(result, (value_error)(lhs.valid & rhs.valid));
798    }
799
800    // handle the ?: operator
801    closure_value &
802    handle_questionmark(closure_value const &cond, closure_value const &val2)
803    {
804        switch (type) {
805        case is_int:
806            switch (val2.type) {
807            case is_bool: value.b = bool(cond) ? value.b : bool(val2); break;
808            case is_int:  value.i = bool(cond) ? value.i : long(val2); break;
809            case is_uint:
810                value.ui = bool(cond) ? value.ui : (unsigned long)(val2);
811                type = is_uint;   // changing type!
812                break;
813            }
814            break;
815           
816        case is_uint:   value.ui = bool(cond) ? value.ui : (unsigned long)(val2); break;
817        case is_bool:   value.b = bool(cond) ? value.b : bool(val2); break;
818        }
819        valid = bool(cond) ? valid : val2.valid;
820        return *this;
821    }
822   
823#if defined (BOOST_SPIRIT_DEBUG)
824    friend std::ostream&
825    operator<< (std::ostream &o, closure_value const &val)
826    {
827        switch (val.type) {
828        case is_int:    o << "int(" << long(val) << ")"; break;
829        case is_uint:   o << "unsigned int(" << (unsigned long)(val) << ")"; break;
830        case is_bool:   o << "bool(" << bool(val) << ")"; break;
831        }
832        return o;
833    }
834#endif // defined(BOOST_SPIRIT_DEBUG)
835
836private:
837    value_type type;
838    union {
839        long i;
840        unsigned long ui;
841        bool b;
842    } value;
843    value_error valid;
844};
845
846///////////////////////////////////////////////////////////////////////////////
847}   // namespace closures
848}   // namespace grammars
849}   // namespace wave
850}   // namespace boost
851
852#endif // !defined(CPP_EXPRESSION_VALUE_HPP_452FE66D_8754_4107_AF1E_E42255A0C18A_INCLUDED)
Note: See TracBrowser for help on using the repository browser.