cprover
Loading...
Searching...
No Matches
parse.cpp
Go to the documentation of this file.
1/*******************************************************************\
2
3Module: C++ Language Parsing
4
5Author: Daniel Kroening, kroening@cs.cmu.edu
6
7\*******************************************************************/
8
11
12#include "cpp_parser.h"
13
14#include <map>
15
16#include <util/c_types.h>
17#include <util/std_code.h>
18
19#include <ansi-c/ansi_c_y.tab.h>
20#include <ansi-c/merged_type.h>
21
22#include "cpp_token_buffer.h"
23#include "cpp_member_spec.h"
24#include "cpp_enum_type.h"
25
26#ifdef DEBUG
27#include <iostream>
28
29static unsigned __indent;
30
31struct indenter // NOLINT(readability/identifiers)
32{
33 indenter() { __indent+=2; }
34 ~indenter() { __indent-=2; }
35};
36
37#define TOK_TEXT \
38{ \
39 cpp_tokent _tk; \
40 lex.LookAhead(0, _tk); \
41 std::cout << std::string(__indent, ' ') << "Text [" << _tk.line_no << "]: " \
42 << _tk.text << '\n'; \
43}
44#endif
45
47{
48public:
50 {
51 }
52
53 enum class kindt
54 {
55 NONE,
57 MEMBER,
60 TYPEDEF,
61 TAG,
66 BLOCK,
70 };
71
74
75 bool is_type() const
76 {
77 return kind==kindt::TYPEDEF ||
81 }
82
83 bool is_template() const
84 {
88 }
89
90 bool is_named_scope() const
91 {
92 return kind==kindt::NAMESPACE ||
95 }
96
97 static const char *kind2string(kindt kind)
98 {
99 switch(kind)
100 {
101 case kindt::NONE:
102 return "?";
103 case kindt::TEMPLATE:
104 return "TEMPLATE";
105 case kindt::MEMBER:
106 return "MEMBER";
107 case kindt::FUNCTION:
108 return "FUNCTION";
109 case kindt::VARIABLE:
110 return "VARIABLE";
111 case kindt::TYPEDEF:
112 return "TYPEDEF";
113 case kindt::TAG:
114 return "TAG";
115 case kindt::NAMESPACE:
116 return "NAMESPACE";
118 return "CLASS_TEMPLATE";
120 return "MEMBER_TEMPLATE";
122 return "FUNCTION_TEMPLATE";
123 case kindt::BLOCK:
124 return "BLOCK";
126 return "NON_TYPE_TEMPLATE_PARAMETER";
128 return "TYPE_TEMPLATE_PARAMETER";
130 return "TEMPLATE_TEMPLATE_PARAMETER";
131 default:
132 return "";
133 }
134 }
135
136 typedef std::map<irep_idt, new_scopet> id_mapt;
138
139 std::size_t anon_count;
140
142
143 inline void print(std::ostream &out) const
144 {
145 print_rec(out, 0);
146 }
147
149 {
150 ++anon_count;
151 return "#anon"+std::to_string(anon_count);
152 }
153
154 std::string full_name() const
155 {
156 return (parent==nullptr?"":(parent->full_name()+"::"))+
157 id2string(id);
158 }
159
160protected:
161 void print_rec(std::ostream &, unsigned indent) const;
162};
163
165{
166public:
167 explicit save_scopet(new_scopet *&_scope):
168 scope_ptr(_scope), old_scope(_scope)
169 {
170 }
171
173 {
175 }
176
177protected:
180};
181
182void new_scopet::print_rec(std::ostream &out, unsigned indent) const
183{
184 for(id_mapt::const_iterator
185 it=id_map.begin();
186 it!=id_map.end();
187 it++)
188 {
189 out << std::string(indent, ' ') << it->first << ": "
190 << kind2string(it->second.kind) << '\n';
191 it->second.print_rec(out, indent+2);
192 }
193}
194
195class Parser // NOLINT(readability/identifiers)
196{
197public:
198 explicit Parser(cpp_parsert &_cpp_parser):
199 lex(_cpp_parser.token_buffer),
200 parser(_cpp_parser),
201 max_errors(10)
202 {
205 }
206
207 bool operator()();
208
209protected:
212
213 // scopes
218 void make_sub_scope(const irept &name, new_scopet::kindt);
220
224
225 // rules
226 bool rProgram(cpp_itemt &item);
227
228 bool SyntaxError();
229
230 bool rDefinition(cpp_itemt &);
235 bool rTypeSpecifier(typet &, bool);
236 bool isTypeSpecifier();
239 bool rUsing(cpp_usingt &);
244 bool rTempArgList(irept &);
247
253 typet &,
254 typet &);
260 typet &);
261 bool rCondition(exprt &);
263
264 bool isConstructorDecl();
265 bool isPtrToMember(int);
268 bool optCvQualify(typet &);
269 bool optAlignas(typet &);
270 bool rAttribute(typet &);
271 bool optAttribute(typet &);
273 bool rConstructorDecl(
275 typet &,
276 typet &trailing_return_type);
277 bool optThrowDecl(irept &);
278
279 bool rDeclarators(cpp_declarationt::declaratorst &, bool, bool=false);
280 bool rDeclaratorWithInit(cpp_declaratort &, bool, bool);
281 bool rDeclarator(cpp_declaratort &, DeclKind, bool, bool);
283 bool optPtrOperator(typet &);
285 bool rMemberInit(exprt &);
286
287 bool rName(irept &);
288 bool rOperatorName(irept &);
289 bool rCastOperatorName(irept &);
290 bool rPtrToMember(irept &);
291 bool rTemplateArgs(irept &);
292
293 bool rArgDeclListOrInit(exprt &, bool&, bool);
294 bool rArgDeclList(irept &);
296
298 bool rInitializeExpr(exprt &);
299
300 bool rEnumSpec(typet &);
301 bool rEnumBody(irept &);
302 bool rClassSpec(typet &);
303 bool rBaseSpecifiers(irept &);
304 bool rClassBody(exprt &);
305 bool rClassMember(cpp_itemt &);
307
308 bool rCommaExpression(exprt &);
309
310 bool rExpression(exprt &, bool);
311 bool rConditionalExpr(exprt &, bool);
312 bool rLogicalOrExpr(exprt &, bool);
313 bool rLogicalAndExpr(exprt &, bool);
314 bool rInclusiveOrExpr(exprt &, bool);
315 bool rExclusiveOrExpr(exprt &, bool);
316 bool rAndExpr(exprt &, bool);
317 bool rEqualityExpr(exprt &, bool);
318 bool rRelationalExpr(exprt &, bool);
319 bool rShiftExpr(exprt &, bool);
320 bool rAdditiveExpr(exprt &);
321 bool rMultiplyExpr(exprt &);
322 bool rPmExpr(exprt &);
323 bool rCastExpr(exprt &);
324 bool rTypeName(typet &);
326 bool rUnaryExpr(exprt &);
327 bool rThrowExpr(exprt &);
328 bool rNoexceptExpr(exprt &);
329 bool rSizeofExpr(exprt &);
330 bool rTypeidExpr(exprt &);
331 bool rAlignofExpr(exprt &);
332 bool isAllocateExpr(int);
333 bool rAllocateExpr(exprt &);
334 bool rAllocateType(exprt &, typet &, exprt &);
335 bool rNewDeclarator(typet &);
337 bool rPostfixExpr(exprt &);
338 bool rPrimaryExpr(exprt &);
339 bool rVarName(exprt &);
340 bool rVarNameCore(exprt &);
341 bool maybeTemplateArgs();
342
352
358
360 void SkipTo(int token);
361 bool moreVarName();
362
363 bool rString(cpp_tokent &tk);
364
365 // GCC extensions
367
368 // MSC extensions
373 bool rTypePredicate(exprt &);
374 bool rMSCuuidof(exprt &);
376
377 std::size_t number_of_errors;
379
380 void merge_types(const typet &src, typet &dest);
381
382 void set_location(irept &dest, const cpp_tokent &token)
383 {
384 source_locationt &source_location=
385 static_cast<source_locationt &>(dest.add(ID_C_source_location));
386 source_location.set_file(token.filename);
387 source_location.set_line(token.line_no);
389 source_location.set_function(current_function);
390 }
391
392 void make_subtype(const typet &src, typet &dest)
393 {
394 typet *p=&dest;
395
396 while(!p->id().empty() && p->is_not_nil())
397 {
398 if(p->id()==ID_merged_type)
399 {
400 auto &merged_type = to_merged_type(*p);
401 p = &merged_type.last_type();
402 }
403 else
404 p=&p->subtype();
405 }
406
407 *p=src;
408 }
409
410 unsigned int max_errors;
411};
412
414{
415 irep_idt id;
416
417 if(cpp_name.get_sub().size()==1 &&
418 cpp_name.get_sub().front().id()==ID_name)
419 id=cpp_name.get_sub().front().get(ID_identifier);
420 else
422
423 return add_id(id, kind);
424}
425
427{
429
430 s.kind=kind;
431 s.id=id;
433
434 return s;
435}
436
438{
439 new_scopet &s=add_id(cpp_name, kind);
440 current_scope=&s;
441}
442
444{
445 new_scopet &s=add_id(id, kind);
446 current_scope=&s;
447}
448
450{
451 if(lex.get_token(tk)!=TOK_STRING)
452 return false;
453
454 return true;
455}
456
457void Parser::merge_types(const typet &src, typet &dest)
458{
459 if(src.is_nil())
460 return;
461
462 if(dest.is_nil())
463 dest=src;
464 else
465 {
466 if(dest.id()!=ID_merged_type)
467 {
468 source_locationt location=dest.source_location();
469 merged_typet tmp;
470 tmp.move_to_subtypes(dest);
471 tmp.add_source_location()=location;
472 dest=tmp;
473 }
474
475 // the end of the subtypes container needs to stay the same,
476 // since several analysis functions traverse via the end for
477 // merged_types
478 auto &sub = to_type_with_subtypes(dest).subtypes();
479 sub.emplace(sub.begin(), src);
480 }
481}
482
484{
485#define ERROR_TOKENS 4
486
488
489 for(std::size_t i=0; i<ERROR_TOKENS; i++)
490 lex.LookAhead(i, t[i]);
491
492 if(t[0].kind!='\0')
493 {
494 source_locationt source_location;
495 source_location.set_file(t[0].filename);
496 source_location.set_line(std::to_string(t[0].line_no));
497
498 std::string message = "parse error before '";
499
500 for(std::size_t i=0; i<ERROR_TOKENS; i++)
501 if(t[i].kind!='\0')
502 {
503 if(i!=0)
504 message+=' ';
505 message+=t[i].text;
506 }
507
508 message+="'";
509
510 parser.error().source_location=source_location;
511 parser.error() << message << messaget::eom;
512 }
513
514 return ++number_of_errors < max_errors;
515}
516
518{
519 while(lex.LookAhead(0)!='\0')
520 if(rDefinition(item))
521 return true;
522 else
523 {
524 cpp_tokent tk;
525
526 if(!SyntaxError())
527 return false; // too many errors
528
529 SkipTo(';');
530 lex.get_token(tk); // ignore ';'
531 }
532
533 return false;
534}
535
536/*
537 definition
538 : null.declaration
539 | typedef
540 | template.decl
541 | linkage.spec
542 | namespace.spec
543 | using.declaration
544 | extern.template.decl
545 | declaration
546*/
548{
549 int t=lex.LookAhead(0);
550
551#ifdef DEBUG
552 indenter _i;
553 std::cout << std::string(__indent, ' ') << "Parser::rDefinition 1 " << t
554 << '\n';
555#endif
556
557 if(t==';')
558 return rNullDeclaration(item.make_declaration());
559 else if(t==TOK_TYPEDEF)
560 return rTypedef(item.make_declaration());
561 else if(t==TOK_TEMPLATE)
562 return rTemplateDecl(item.make_declaration());
563 else if(t==TOK_EXTERN && lex.LookAhead(1)==TOK_STRING)
564 return rLinkageSpec(item.make_linkage_spec());
565 else if(t==TOK_EXTERN && lex.LookAhead(1)==TOK_TEMPLATE)
567 else if(t==TOK_NAMESPACE)
568 return rNamespaceSpec(item.make_namespace_spec());
569 else if(t==TOK_INLINE && lex.LookAhead(1)==TOK_NAMESPACE)
570 return rNamespaceSpec(item.make_namespace_spec());
571 else if(t==TOK_USING &&
572 lex.LookAhead(1)==TOK_IDENTIFIER &&
573 lex.LookAhead(2)=='=')
574 return rTypedefUsing(item.make_declaration());
575 else if(t==TOK_USING)
576 return rUsing(item.make_using());
577 else if(t==TOK_STATIC_ASSERT)
578 return rStaticAssert(item.make_static_assert());
579 else
580 return rDeclaration(item.make_declaration());
581}
582
584{
585 cpp_tokent tk;
586
587 if(lex.get_token(tk)!=';')
588 return false;
589
590 set_location(decl, tk);
591
592 return true;
593}
594
595/*
596 typedef
597 : TYPEDEF type.specifier declarators ';'
598*/
600{
601 cpp_tokent tk;
602
603 if(lex.get_token(tk)!=TOK_TYPEDEF)
604 return false;
605
606#ifdef DEBUG
607 indenter _i;
608 std::cout << std::string(__indent, ' ') << "Parser::rTypedef 1\n";
609#endif
610
611 declaration=cpp_declarationt();
612 set_location(declaration, tk);
613 declaration.set_is_typedef();
614
615 if(!rTypeSpecifier(declaration.type(), true))
616 return false;
617
618 if(!rDeclarators(declaration.declarators(), true))
619 return false;
620
621 return true;
622}
623
624/*
625 USING Identifier '=' type.specifier ';'
626*/
628{
629 cpp_tokent tk;
630 typet type_name;
631
632 if(lex.get_token(tk)!=TOK_USING)
633 return false;
634
635#ifdef DEBUG
636 indenter _i;
637 std::cout << std::string(__indent, ' ') << "Parser::rTypedefUsing 1\n";
638#endif
639
640 declaration=cpp_declarationt();
641 set_location(declaration, tk);
642
643 declaration.type()=typet(ID_typedef);
644
645 if(lex.get_token(tk)!=TOK_IDENTIFIER)
646 return false;
647
648 cpp_declaratort name;
649 name.name()=cpp_namet(tk.data.get(ID_C_base_name));
650 name.type().make_nil();
651
652#ifdef DEBUG
653 std::cout << std::string(__indent, ' ') << "Parser::rTypedefUsing 2\n";
654#endif
655
656 if(lex.get_token(tk)!='=')
657 return false;
658
659 if(!rTypeNameOrFunctionType(type_name))
660 return false;
661
662 merge_types(type_name, declaration.type());
663
664 declaration.declarators().push_back(name);
665
666 if(lex.get_token(tk)!=';')
667 return false;
668
669#ifdef DEBUG
670 std::cout << std::string(__indent, ' ') << "Parser::rTypedefUsing 3\n";
671#endif
672
673 return true;
674}
675
677{
678 cpp_declarationt declaration;
679 if(!rTypedef(declaration))
680 return {};
681
682 return code_frontend_declt(
683 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
684}
685
686/*
687 type.specifier
688 : {cv.qualify} (integral.or.class.spec | name) {cv.qualify}
689*/
690bool Parser::rTypeSpecifier(typet &tspec, bool check)
691{
692#ifdef DEBUG
693 indenter _i;
694 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 0\n";
695#endif
696
697 typet cv_q;
698
699 cv_q.make_nil();
700
701 if(!optCvQualify(cv_q))
702 return false;
703
704#ifdef DEBUG
705 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 0.1\n";
706#endif
707
709 return false;
710
711 if(tspec.is_nil())
712 {
713 cpp_tokent tk;
714 lex.LookAhead(0, tk);
715
716#ifdef DEBUG
717 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 1\n";
718#endif
719
720 if(check)
722 return false;
723
724#ifdef DEBUG
725 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 2\n";
726#endif
727
728 if(!rName(tspec))
729 return false;
730 }
731
732#ifdef DEBUG
733 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 3\n";
734#endif
735
736 if(!optCvQualify(cv_q))
737 return false;
738
739 merge_types(cv_q, tspec);
740
741#ifdef DEBUG
742 std::cout << std::string(__indent, ' ') << "Parser::rTypeSpecifier 4\n";
743#endif
744
745 return true;
746}
747
748// isTypeSpecifier() returns true if the next is probably a type specifier.
749
751{
752 int t=lex.LookAhead(0);
753
754 if(t==TOK_IDENTIFIER || t==TOK_SCOPE
755 || t==TOK_CONSTEXPR || t==TOK_CONST || t==TOK_VOLATILE || t==TOK_RESTRICT
756 || t==TOK_CHAR || t==TOK_INT || t==TOK_SHORT || t==TOK_LONG
757 || t==TOK_CHAR16_T || t==TOK_CHAR32_T
758 || t==TOK_WCHAR_T || t==TOK_COMPLEX // new !!!
759 || t==TOK_SIGNED || t==TOK_UNSIGNED || t==TOK_FLOAT || t==TOK_DOUBLE
760 || t==TOK_INT8 || t==TOK_INT16 || t==TOK_INT32 || t==TOK_INT64
761 || t==TOK_GCC_INT128
762 || t==TOK_PTR32 || t==TOK_PTR64
763 || t==TOK_GCC_FLOAT80 || t==TOK_GCC_FLOAT128
764 || t==TOK_VOID || t==TOK_BOOL || t==TOK_CPROVER_BOOL
765 || t==TOK_CLASS || t==TOK_STRUCT || t==TOK_UNION || t==TOK_ENUM
766 || t==TOK_INTERFACE
767 || t==TOK_TYPENAME
768 || t==TOK_TYPEOF
769 || t==TOK_DECLTYPE
770 || t==TOK_UNDERLYING_TYPE
771 )
772 return true;
773
774 return false;
775}
776
777/*
778 linkage.spec
779 : EXTERN String definition
780 | EXTERN String linkage.body
781*/
783{
784 cpp_tokent tk1, tk2;
785
786 if(lex.get_token(tk1)!=TOK_EXTERN)
787 return false;
788
789 if(!rString(tk2))
790 return false;
791
792 linkage_spec=cpp_linkage_spect();
793 set_location(linkage_spec, tk1);
794 linkage_spec.linkage().swap(tk2.data);
795 set_location(linkage_spec.linkage(), tk2);
796
797 if(lex.LookAhead(0)=='{')
798 {
799 if(!rLinkageBody(linkage_spec.items()))
800 return false;
801 }
802 else
803 {
804 cpp_itemt item;
805
806 if(!rDefinition(item))
807 return false;
808
809 linkage_spec.items().push_back(item);
810 }
811
812 return true;
813}
814
815/*
816 namespace.spec
817 : { INLINE } NAMESPACE Identifier definition
818 | { INLINE } NAMESPACE Identifier = name
819 | { INLINE } NAMESPACE { Identifier } linkage.body
820*/
821
823{
824 cpp_tokent tk1, tk2;
825 bool is_inline=false;
826
827 if(lex.LookAhead(0)==TOK_INLINE)
828 {
829 lex.get_token(tk1);
830 is_inline=true;
831 }
832
833 if(lex.get_token(tk1)!=TOK_NAMESPACE)
834 return false;
835
836 irep_idt name;
837
838 // namespace might be anonymous
839 if(lex.LookAhead(0) != '{')
840 {
841 if(lex.get_token(tk2)==TOK_IDENTIFIER)
842 name=tk2.data.get(ID_C_base_name);
843 else
844 return false;
845 }
846
847 namespace_spec=cpp_namespace_spect();
848 set_location(namespace_spec, tk1);
849 namespace_spec.set_namespace(name);
850 namespace_spec.set_is_inline(is_inline);
851
852 // Tolerate constructs such as:
853 // inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
854 // which occurs in glibc. Obviously we need to better than just throw attribs
855 // away like this in the future.
856 if(lex.LookAhead(0)==TOK_GCC_ATTRIBUTE)
857 {
858 cpp_tokent tk;
859 lex.get_token(tk);
860
861 typet discard;
862 if(!rAttribute(discard))
863 return false;
864 }
865
866 switch(lex.LookAhead(0))
867 {
868 case '{':
869 return rLinkageBody(namespace_spec.items());
870
871 case '=': // namespace alias
872 lex.get_token(tk2); // eat =
873 return rName(namespace_spec.alias());
874
875 default:
876 namespace_spec.items().push_back(cpp_itemt());
877 return rDefinition(namespace_spec.items().back());
878 }
879}
880
881/*
882 using.declaration : USING { NAMESPACE } name ';'
883*/
885{
886 cpp_tokent tk;
887
888 if(lex.get_token(tk)!=TOK_USING)
889 return false;
890
891 cpp_using=cpp_usingt();
892 set_location(cpp_using, tk);
893
894 if(lex.LookAhead(0)==TOK_NAMESPACE)
895 {
896 lex.get_token(tk);
897 cpp_using.set_namespace(true);
898 }
899
900 if(!rName(cpp_using.name()))
901 return false;
902
903 if(lex.get_token(tk)!=';')
904 return false;
905
906 return true;
907}
908
909/*
910 static_assert.declaration : STATIC_ASSERT ( expression , expression ) ';'
911*/
913{
914 cpp_tokent tk;
915
916 if(lex.get_token(tk)!=TOK_STATIC_ASSERT)
917 return false;
918
919 if(lex.get_token(tk)!='(')
920 return false;
921
922 exprt cond;
923
924 if(!rExpression(cond, false))
925 return false;
926
927 if(lex.get_token(tk)!=',')
928 return false;
929
930 exprt description;
931
932 if(!rExpression(description, false))
933 return false;
934
935 if(lex.get_token(tk)!=')')
936 return false;
937
938 if(lex.get_token(tk)!=';')
939 return false;
940
941 cpp_static_assert =
942 cpp_static_assertt(std::move(cond), std::move(description));
943 set_location(cpp_static_assert, tk);
944
945 return true;
946}
947
948/*
949 linkage.body : '{' (definition)* '}'
950
951 Note: this is also used to construct namespace.spec
952*/
954{
955 cpp_tokent op, cp;
956
957 if(lex.get_token(op)!='{')
958 return false;
959
960 items.clear();
961 while(lex.LookAhead(0)!='}')
962 {
963 cpp_itemt item;
964
965 if(!rDefinition(item))
966 {
967 if(!SyntaxError())
968 return false; // too many errors
969
970 SkipTo('}');
971 lex.get_token(cp);
972 items.push_back(item);
973 return true; // error recovery
974 }
975
976 items.push_back(item);
977 }
978
979 lex.get_token(cp);
980 return true;
981}
982
983/*
984 template.decl
985 : TEMPLATE '<' temp.arg.list '>' declaration
986 | TEMPLATE declaration
987 | TEMPLATE '<' '>' declaration
988
989 The second case is an explicit template instantiation. declaration must
990 be a class declaration. For example,
991
992 template class Foo<int, char>;
993
994 explicitly instantiates the template Foo with int and char.
995
996 The third case is a specialization of a function template. declaration
997 must be a function template. For example,
998
999 template <> int count(String x) { return x.length; }
1000*/
1002{
1004
1006 current_scope->id_map.clear();
1007
1008 typet template_type;
1009 if(!rTemplateDecl2(template_type, kind))
1010 return false;
1011
1012 cpp_declarationt body;
1013 if(lex.LookAhead(0)==TOK_USING)
1014 {
1015 if(!rTypedefUsing(body))
1016 return false;
1017 }
1018 else if(!rDeclaration(body))
1019 return false;
1020
1021 // Repackage the decl and body depending upon what kind of template
1022 // declaration was observed.
1023 switch(kind)
1024 {
1025 case tdk_decl:
1026#ifdef DEBUG
1027 std::cout << std::string(__indent, ' ') << "BODY: "
1028 << body.pretty() << '\n';
1029 std::cout << std::string(__indent, ' ') << "TEMPLATE_TYPE: "
1030 << template_type.pretty() << '\n';
1031#endif
1032 body.add(ID_template_type).swap(template_type);
1033 body.set(ID_is_template, true);
1034 decl.swap(body);
1035 break;
1036
1037 case tdk_instantiation:
1038 // Repackage the decl
1039 decl=body;
1040 break;
1041
1042 case tdk_specialization:
1043 body.add(ID_template_type).swap(template_type);
1044 body.set(ID_is_template, true);
1045 decl.swap(body);
1046 break;
1047
1048 case num_tdks:
1049 case tdk_unknown:
1051 break;
1052 }
1053
1054 return true;
1055}
1056
1058{
1059 cpp_tokent tk;
1060
1061 if(lex.get_token(tk)!=TOK_TEMPLATE)
1062 return false;
1063
1064 decl=typet(ID_template);
1065 set_location(decl, tk);
1066
1067 if(lex.LookAhead(0)!='<')
1068 {
1069 // template instantiation
1070 kind=tdk_instantiation;
1071 return true; // ignore TEMPLATE
1072 }
1073
1074 if(lex.get_token(tk)!='<')
1075 return false;
1076
1077 irept &template_parameters=decl.add(ID_template_parameters);
1078
1079 if(!rTempArgList(template_parameters))
1080 return false;
1081
1082 if(lex.get_token(tk)!='>')
1083 return false;
1084
1085 // ignore nested TEMPLATE
1086 while(lex.LookAhead(0)==TOK_TEMPLATE)
1087 {
1088 lex.get_token(tk);
1089 if(lex.LookAhead(0)!='<')
1090 break;
1091
1092 lex.get_token(tk);
1093 irept dummy_args;
1094 if(!rTempArgList(dummy_args))
1095 return false;
1096
1097 if(lex.get_token(tk)!='>')
1098 return false;
1099 }
1100
1101 if(template_parameters.get_sub().empty())
1102 // template < > declaration
1103 kind=tdk_specialization;
1104 else
1105 // template < ... > declaration
1106 kind=tdk_decl;
1107
1108 return true;
1109}
1110
1111/*
1112 temp.arg.list
1113 : empty
1114 | temp.arg.declaration (',' temp.arg.declaration)*
1115*/
1117{
1118 if(lex.LookAhead(0)=='>')
1119 return true;
1120
1122 if(!rTempArgDeclaration(a))
1123 return false;
1124
1125 args.get_sub().push_back(get_nil_irep());
1126 args.get_sub().back().swap(a);
1127
1128 while(lex.LookAhead(0)==',')
1129 {
1130 cpp_tokent tk;
1131
1132 lex.get_token(tk);
1133 if(!rTempArgDeclaration(a))
1134 return false;
1135
1136 args.get_sub().push_back(get_nil_irep());
1137 args.get_sub().back().swap(a);
1138 }
1139
1140 return true;
1141}
1142
1143/*
1144 temp.arg.declaration
1145 : CLASS [Identifier] {'=' type.name}
1146 | CLASS Ellipsis [Identifier]
1147 | type.specifier arg.declarator {'=' conditional.expr}
1148 | template.decl2 CLASS Identifier {'=' type.name}
1149*/
1151{
1152#ifdef DEBUG
1153 indenter _i;
1154 std::cout << std::string(__indent, ' ') << "Parser::rTempArgDeclaration 0\n";
1155#endif
1156
1157 int t0=lex.LookAhead(0);
1158
1159 if((t0==TOK_CLASS || t0==TOK_TYPENAME))
1160 {
1162
1163 cpp_tokent tk1;
1164 lex.get_token(tk1);
1165
1166 declaration=cpp_declarationt();
1167 set_location(declaration, tk1);
1168
1169 declaration.set(ID_is_type, true);
1170 declaration.type()=typet("cpp-template-type");
1171
1172 declaration.declarators().resize(1);
1173 cpp_declaratort &declarator=declaration.declarators().front();
1174
1175 declarator=cpp_declaratort();
1176 declarator.name().make_nil();
1177 declarator.type().make_nil();
1178 set_location(declarator, tk1);
1179
1180 bool has_ellipsis=false;
1181
1182 if(lex.LookAhead(0)==TOK_ELLIPSIS)
1183 {
1184 cpp_tokent tk2;
1185 lex.get_token(tk2);
1186
1187 has_ellipsis=true;
1188 }
1189
1190 if(lex.LookAhead(0) == TOK_IDENTIFIER)
1191 {
1192 cpp_tokent tk2;
1193 lex.get_token(tk2);
1194
1195 declarator.name() = cpp_namet(tk2.data.get(ID_C_base_name));
1196 set_location(declarator.name(), tk2);
1197
1199
1200 if(has_ellipsis)
1201 {
1202 // TODO
1203 }
1204 }
1205
1206 if(lex.LookAhead(0)=='=')
1207 {
1208 if(has_ellipsis)
1209 return false;
1210
1211 typet default_type;
1212
1213 lex.get_token(tk1);
1214 if(!rTypeName(default_type))
1215 return false;
1216
1217 declarator.value()=exprt(ID_type);
1218 declarator.value().type().swap(default_type);
1219 }
1220
1221 if(lex.LookAhead(0)==',' ||
1222 lex.LookAhead(0)=='>')
1223 return true;
1224
1225 lex.Restore(pos);
1226 }
1227
1228#ifdef DEBUG
1229 std::cout << std::string(__indent, ' ') << "Parser::rTempArgDeclaration 1\n";
1230#endif
1231
1232 if(t0==TOK_TEMPLATE)
1233 {
1234 TemplateDeclKind kind;
1235
1236 typet template_type;
1237
1238 if(!rTemplateDecl2(template_type, kind))
1239 return false;
1240
1241 // TODO
1242
1243 cpp_tokent tk1, tk2;
1244
1245 if(lex.get_token(tk1)!=TOK_CLASS ||
1246 lex.get_token(tk2)!=TOK_IDENTIFIER)
1247 return false;
1248
1249 // Ptree cspec=new PtreeClassSpec(new LeafReserved(tk1),
1250 // Ptree::Cons(new Leaf(tk2),nil),
1251 // nil);
1252 // decl=Ptree::Snoc(decl, cspec);
1253 if(lex.LookAhead(0)=='=')
1254 {
1255 typet default_type;
1256 lex.get_token(tk1);
1257 if(!rTypeName(default_type))
1258 return false;
1259
1260 // decl=Ptree::Nconc(decl, Ptree::List(new Leaf(tk1),
1261 // default_type));
1262 }
1263 }
1264 else
1265 {
1266#ifdef DEBUG
1267 std::cout << std::string(__indent, ' ')
1268 << "Parser::rTempArgDeclaration 2\n";
1269#endif
1270
1271 declaration=cpp_declarationt();
1272 declaration.set(ID_is_type, false);
1273
1274 if(!rTypeSpecifier(declaration.type(), true))
1275 return false;
1276
1277#ifdef DEBUG
1278 std::cout << std::string(__indent, ' ')
1279 << "Parser::rTempArgDeclaration 3\n";
1280#endif
1281
1282 bool has_ellipsis=false;
1283
1284 if(lex.LookAhead(0)==TOK_ELLIPSIS)
1285 {
1286 cpp_tokent tk2;
1287 lex.get_token(tk2);
1288
1289 has_ellipsis=true;
1290 }
1291
1292 declaration.declarators().resize(1);
1293 cpp_declaratort &declarator=declaration.declarators().front();
1294
1295 if(!rDeclarator(declarator, kArgDeclarator, true, false))
1296 return false;
1297
1298#ifdef DEBUG
1299 std::cout << std::string(__indent, ' ')
1300 << "Parser::rTempArgDeclaration 4\n";
1301#endif
1302
1304
1305 if(has_ellipsis)
1306 {
1307 // TODO
1308 }
1309
1310 exprt &value=declarator.value();
1311
1312 if(lex.LookAhead(0)=='=')
1313 {
1314 if(has_ellipsis)
1315 return false;
1316
1317 cpp_tokent tk;
1318
1319 lex.get_token(tk);
1320 if(!rConditionalExpr(value, true))
1321 return false;
1322 }
1323 else
1324 value.make_nil();
1325 }
1326
1327 return true;
1328}
1329
1330/*
1331 extern.template.decl
1332 : EXTERN TEMPLATE declaration
1333*/
1335{
1336 cpp_tokent tk1, tk2;
1337
1338 if(lex.get_token(tk1)!=TOK_EXTERN)
1339 return false;
1340
1341 if(lex.get_token(tk2)!=TOK_TEMPLATE)
1342 return false;
1343
1344 if(!rDeclaration(decl))
1345 return false;
1346
1347 // decl=new PtreeExternTemplate(new Leaf(tk1),
1348 // Ptree::List(new Leaf(tk2), body));
1349 return true;
1350}
1351
1352/*
1353 declaration
1354 : integral.declaration
1355 | const.declaration
1356 | other.declaration
1357
1358 decl.head
1359 : {member.spec} {storage.spec} {member.spec} {cv.qualify}
1360
1361 integral.declaration
1362 : integral.decl.head declarators (';' | function.body)
1363 | integral.decl.head ';'
1364 | integral.decl.head ':' expression ';'
1365
1366 integral.decl.head
1367 : decl.head integral.or.class.spec {cv.qualify}
1368
1369 other.declaration
1370 : decl.head name {cv.qualify} declarators (';' | function.body)
1371 | decl.head name constructor.decl (';' | function.body)
1372 | FRIEND name ';'
1373
1374 const.declaration
1375 : cv.qualify {'*'} Identifier '=' expression {',' declarators} ';'
1376
1377 Note: if you modify this function, look at declaration.statement, too.
1378 Note: this regards a statement like "T (a);" as a constructor
1379 declaration. See isConstructorDecl().
1380*/
1381
1383{
1384#ifdef DEBUG
1385 indenter _i;
1386 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 0.1 token: "
1387 << lex.LookAhead(0) << '\n';
1388#endif
1389
1390 if(!optAttribute(declaration.type()))
1391 return false;
1392
1393 cpp_member_spect member_spec;
1394 if(!optMemberSpec(member_spec))
1395 return false;
1396
1397#ifdef DEBUG
1398 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 0.2\n";
1399#endif
1400
1401 cpp_storage_spect storage_spec;
1402 if(!optStorageSpec(storage_spec))
1403 return false;
1404
1405#ifdef DEBUG
1406 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 1\n";
1407#endif
1408
1409 if(member_spec.is_empty())
1410 if(!optMemberSpec(member_spec))
1411 return false;
1412
1413#ifdef DEBUG
1414 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 3\n";
1415#endif
1416
1417 typet cv_q, integral;
1418 cv_q.make_nil();
1419
1420 if(!optCvQualify(cv_q))
1421 return false;
1422
1423 // added these two to do "const static volatile int i=1;"
1424 if(!optStorageSpec(storage_spec))
1425 return false;
1426
1427 if(!optCvQualify(cv_q))
1428 return false;
1429
1430#ifdef DEBUG
1431 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 4\n";
1432#endif
1433
1434 if(!optIntegralTypeOrClassSpec(integral))
1435 return false;
1436
1437 // added this one to do "void inline foo();"
1438 if(member_spec.is_empty())
1439 if(!optMemberSpec(member_spec))
1440 return false;
1441
1442 if(integral.is_not_nil())
1443 {
1444#ifdef DEBUG
1445 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 5\n";
1446#endif
1447 return
1449 declaration, storage_spec, member_spec, integral, cv_q);
1450 }
1451 else
1452 {
1453 int t=lex.LookAhead(0);
1454
1455#ifdef DEBUG
1456 std::cout << std::string(__indent, ' ') << "Parser::rDeclaration 6 " << t
1457 << '\n';
1458#endif
1459
1460 if(cv_q.is_not_nil() &&
1461 ((t==TOK_IDENTIFIER && lex.LookAhead(1)=='=') || t=='*'))
1462 return rConstDeclaration(declaration);
1463 else
1464 return rOtherDeclaration(declaration, storage_spec, member_spec, cv_q);
1465 }
1466}
1467
1468/* single declaration, for use in a condition (controlling
1469 expression of switch/while/if) */
1471{
1472 typet cv_q, integral;
1473
1474 /* no member specification permitted here, and no
1475 storage specifier:
1476 type-specifier ::=
1477 simple-type-specifier
1478 class-specifier
1479 enum-specifier
1480 elaborated-type-specifier
1481 cv-qualifier */
1482
1483 cv_q.make_nil();
1484
1485 if(!optCvQualify(cv_q))
1486 return false;
1487
1488 if(!optIntegralTypeOrClassSpec(integral))
1489 return false;
1490
1491 if(integral.is_nil() &&
1492 !rName(integral))
1493 return false;
1494
1495 if(cv_q.is_not_nil() && integral.is_not_nil())
1496 merge_types(cv_q, integral);
1497 else if(cv_q.is_not_nil() && integral.is_nil())
1498 integral.swap(cv_q);
1499
1500 /* no type-specifier so far -> can't be a declaration */
1501 if(integral.is_nil())
1502 return false;
1503
1504 merge_types(cv_q, integral);
1505
1506 declaration.type().swap(integral);
1507
1508 cpp_declaratort declarator;
1509 if(!rDeclarator(declarator, kDeclarator, true, true))
1510 return false;
1511
1512 // there really _has_ to be an initializer!
1513
1514 if(lex.LookAhead(0)!='=')
1515 return false;
1516
1517 cpp_tokent eqs;
1518 lex.get_token(eqs);
1519
1520 if(!rExpression(declarator.value(), false))
1521 return false;
1522
1523 declaration.declarators().push_back(declarator);
1524
1525 return true;
1526}
1527
1529 cpp_declarationt &declaration,
1530 cpp_storage_spect &storage_spec,
1531 cpp_member_spect &member_spec,
1532 typet &integral,
1533 typet &cv_q)
1534{
1535#ifdef DEBUG
1536 indenter _i;
1537 std::cout << std::string(__indent, ' ')
1538 << "Parser::rIntegralDeclaration 1 token: "
1539 << static_cast<char>(lex.LookAhead(0)) << '\n';
1540#endif
1541
1542 if(!optCvQualify(cv_q))
1543 return false;
1544
1545#ifdef DEBUG
1546 std::cout << std::string(__indent, ' ') << "Parser::rIntegralDeclaration 2\n";
1547#endif
1548
1549 merge_types(cv_q, integral);
1550
1551#ifdef DEBUG
1552 std::cout << std::string(__indent, ' ') << "Parser::rIntegralDeclaration 3\n";
1553#endif
1554
1555 declaration.type().swap(integral);
1556 declaration.storage_spec().swap(storage_spec);
1557 declaration.member_spec().swap(member_spec);
1558
1559 cpp_tokent tk;
1560
1561 switch(lex.LookAhead(0))
1562 {
1563 case ';':
1564#ifdef DEBUG
1565 std::cout << std::string(__indent, ' ')
1566 << "Parser::rIntegralDeclaration 4\n";
1567#endif
1568
1569 lex.get_token(tk);
1570 return true;
1571
1572 case ':': // bit field
1573#ifdef DEBUG
1574 std::cout << std::string(__indent, ' ')
1575 << "Parser::rIntegralDeclaration 5\n";
1576#endif
1577
1578 lex.get_token(tk);
1579
1580 {
1581 exprt width;
1582
1583 if(!rExpression(width, false))
1584 return false;
1585
1586 if(lex.get_token(tk)!=';')
1587 return false;
1588
1589 // TODO
1590 }
1591 return true;
1592
1593 default:
1594#ifdef DEBUG
1595 std::cout << std::string(__indent, ' ') << "Parser::rIntegralDeclaration 6 "
1596 << lex.LookAhead(0) << '\n';
1597#endif
1598
1599 if(!rDeclarators(declaration.declarators(), true))
1600 return false;
1601
1602 // handle trailing return type
1603 if(
1604 declaration.type().id() == ID_auto &&
1605 declaration.declarators().size() == 1 &&
1606 declaration.declarators().front().type().id() == ID_function_type &&
1607 declaration.declarators().front().type().subtype().is_not_nil())
1608 {
1609 declaration.type() = declaration.declarators().front().type().subtype();
1610 declaration.declarators().front().type().subtype().make_nil();
1611 }
1612
1613#ifdef DEBUG
1614 std::cout << std::string(__indent, ' ')
1615 << "Parser::rIntegralDeclaration 7\n";
1616#endif
1617
1618 if(lex.LookAhead(0)==';')
1619 {
1620#ifdef DEBUG
1621 std::cout << std::string(__indent, ' ')
1622 << "Parser::rIntegralDeclaration 8 "
1623 << declaration.pretty() << '\n';
1624#endif
1625 lex.get_token(tk);
1626 return true;
1627 }
1628 else
1629 {
1630#ifdef DEBUG
1631 std::cout << std::string(__indent, ' ')
1632 << "Parser::rIntegralDeclaration 9\n";
1633#endif
1634
1635 if(declaration.declarators().size()!=1)
1636 return false;
1637
1638 if(!rFunctionBody(declaration.declarators().front()))
1639 return false;
1640
1641#ifdef DEBUG
1642 std::cout << std::string(__indent, ' ')
1643 << "Parser::rIntegralDeclaration 10\n";
1644#endif
1645
1646 return true;
1647 }
1648 }
1649}
1650
1652{
1653#ifdef DEBUG
1654 indenter _i;
1655 std::cout << std::string(__indent, ' ') << "Parser::rConstDeclaration\n";
1656#endif
1657
1658 if(!rDeclarators(declaration.declarators(), false))
1659 return false;
1660
1661 if(lex.LookAhead(0)!=';')
1662 return false;
1663
1664 cpp_tokent tk;
1665 lex.get_token(tk);
1666
1667 return true;
1668}
1669
1671 cpp_declarationt &declaration,
1672 cpp_storage_spect &storage_spec,
1673 cpp_member_spect &member_spec,
1674 typet &cv_q)
1675{
1676 typet type_name;
1677
1678#ifdef DEBUG
1679 indenter _i;
1680 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 1\n";
1681#endif
1682
1683 if(!rName(type_name))
1684 return false;
1685
1686 merge_types(cv_q, type_name);
1687
1688#ifdef DEBUG
1689 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 2\n";
1690#endif
1691
1692 // added this one to do "typename inline foo();"
1693 if(member_spec.is_empty())
1694 if(!optMemberSpec(member_spec))
1695 return false;
1696
1697 // this allows "typename static foo();"
1698 if(storage_spec.is_empty())
1699 if(!optStorageSpec(storage_spec))
1700 return false;
1701
1702#ifdef DEBUG
1703 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 3\n";
1704#endif
1705
1707 bool is_operator = false;
1708
1709 if(is_constructor)
1710 {
1711#ifdef DEBUG
1712 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 4\n";
1713#endif
1714
1715 assert(!type_name.get_sub().empty());
1716
1717 for(std::size_t i=0; i < type_name.get_sub().size(); i++)
1718 {
1719 if(type_name.get_sub()[i].id() == ID_operator)
1720 {
1721 is_operator = true;
1722 break;
1723 }
1724 }
1725 }
1726
1728 {
1729#ifdef DEBUG
1730 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 5\n";
1731#endif
1732
1733 // it's a conversion operator
1734 typet type = type_name;
1735 type.get_sub().erase(type.get_sub().begin());
1736
1737 cpp_declaratort conv_operator_declarator;
1738 typet trailing_return_type;
1739 if(!rConstructorDecl(
1740 conv_operator_declarator, type_name, trailing_return_type))
1741 return false;
1742
1743 type_name=typet("cpp-cast-operator");
1744
1745 declaration.declarators().push_back(conv_operator_declarator);
1746 }
1747 else if(cv_q.is_nil() && is_constructor)
1748 {
1749#ifdef DEBUG
1750 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 6\n";
1751#endif
1752
1753 assert(!type_name.get_sub().empty());
1754
1755 bool is_destructor=false;
1756 for(const auto &irep : type_name.get_sub())
1757 {
1758 if(irep.id() == "~")
1759 {
1760 is_destructor=true;
1761 break;
1762 }
1763 }
1764
1765 cpp_declaratort constructor_declarator;
1766 typet trailing_return_type;
1767 if(!rConstructorDecl(
1768 constructor_declarator, type_name, trailing_return_type))
1769 return false;
1770
1771#ifdef DEBUG
1772 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 7\n";
1773#endif
1774
1775 // type_name above is the name declarator, not the return type
1776 if(storage_spec.is_auto())
1777 type_name=trailing_return_type;
1778 else
1779 type_name=typet(is_destructor?ID_destructor:ID_constructor);
1780
1781 declaration.declarators().push_back(constructor_declarator);
1782 }
1783 else if(!member_spec.is_empty() && lex.LookAhead(0)==';')
1784 {
1785#ifdef DEBUG
1786 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 8\n";
1787#endif
1788
1789 // FRIEND name ';'
1790 // if(Ptree::Length(member_spec)==1 && member_spec->Car()->What()==FRIEND)
1791 {
1792 cpp_tokent tk;
1793 lex.get_token(tk);
1794 // statement=new PtreeDeclaration(head, Ptree::List(type_name,
1795 // new Leaf(tk)));
1796 return true;
1797 }
1798 // else
1799 // return false;
1800 }
1801 else
1802 {
1803#ifdef DEBUG
1804 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 9\n";
1805#endif
1806
1807 if(!optCvQualify(cv_q))
1808 return false;
1809
1810 merge_types(cv_q, type_name);
1811
1812 if(!rDeclarators(declaration.declarators(), false))
1813 return false;
1814 }
1815
1816 declaration.type().swap(type_name);
1817 declaration.storage_spec().swap(storage_spec);
1818 declaration.member_spec().swap(member_spec);
1819
1820#ifdef DEBUG
1821 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 10\n";
1822#endif
1823
1824 if(lex.LookAhead(0)==';')
1825 {
1826#ifdef DEBUG
1827 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 11\n";
1828#endif
1829
1830 cpp_tokent tk;
1831 lex.get_token(tk);
1832 }
1833 else
1834 {
1835#ifdef DEBUG
1836 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclaration 12\n";
1837#endif
1838
1839 if(declaration.declarators().size()!=1)
1840 return false;
1841
1842 if(!rFunctionBody(declaration.declarators().front()))
1843 return false;
1844 }
1845
1846 return true;
1847}
1848
1849/*
1850 This returns true for an declaration like:
1851 T (a);
1852 even if a is not a type name. This is a bug according to the ANSI
1853 specification, but I believe none says "T (a);" for a variable
1854 declaration.
1855*/
1857{
1858#ifdef DEBUG
1859 indenter _i;
1860 std::cout << std::string(__indent, ' ') << "Parser::isConstructorDecl "
1861 << lex.LookAhead(0) << " " << lex.LookAhead(1) << '\n';
1862#endif
1863
1864 if(lex.LookAhead(0)!='(')
1865 return false;
1866 else
1867 {
1868 int t=lex.LookAhead(1);
1869 if(t=='*' || t=='&' || t=='(')
1870 return false; // it's a declarator
1871 else if(t==TOK_STDCALL || t==TOK_FASTCALL || t==TOK_CLRCALL || t==TOK_CDECL)
1872 return false; // it's a declarator
1873 else if(isPtrToMember(1))
1874 return false; // declarator (::*)
1875 else if(t==TOK_IDENTIFIER)
1876 {
1877 // Ambiguous. Do some more look-ahead.
1878 if(lex.LookAhead(2)==')' &&
1879 lex.LookAhead(3)=='(')
1880 return false; // must be declarator (decl)(...)
1881 }
1882
1883 // maybe constructor
1884 return true;
1885 }
1886}
1887
1888/*
1889 ptr.to.member
1890 : {'::'} (identifier {'<' any* '>'} '::')+ '*'
1891*/
1893{
1894 int t0=lex.LookAhead(i++);
1895
1896 if(t0==TOK_SCOPE)
1897 t0=lex.LookAhead(i++);
1898
1899 while(t0==TOK_IDENTIFIER)
1900 {
1901 int t=lex.LookAhead(i++);
1902 if(t=='<')
1903 {
1904 int n=1;
1905 while(n > 0)
1906 {
1907 int u=lex.LookAhead(i++);
1908 if(u=='<')
1909 ++n;
1910 else if(u=='>')
1911 --n;
1912 else if(u=='(')
1913 {
1914 int m=1;
1915 while(m > 0)
1916 {
1917 int v=lex.LookAhead(i++);
1918 if(v=='(')
1919 ++m;
1920 else if(v==')')
1921 --m;
1922 else if(v=='\0' || v==';' || v=='}')
1923 return false;
1924 }
1925 }
1926 else if(u=='\0' || u==';' || u=='}')
1927 return false;
1928 }
1929
1930 t=lex.LookAhead(i++);
1931 }
1932
1933 if(t!=TOK_SCOPE)
1934 return false;
1935
1936 t0=lex.LookAhead(i++);
1937
1938 if(t0=='*')
1939 return true;
1940 }
1941
1942 return false;
1943}
1944
1945/*
1946 member.spec
1947 : (FRIEND | INLINE | VIRTUAL | EXPLICIT)+
1948*/
1950{
1951 member_spec.clear();
1952
1953 int t=lex.LookAhead(0);
1954
1955 while(
1956 t == TOK_FRIEND || t == TOK_INLINE || t == TOK_VIRTUAL ||
1957 t == TOK_EXPLICIT || t == TOK_MSC_FORCEINLINE)
1958 {
1959 cpp_tokent tk;
1960 lex.get_token(tk);
1961
1962 switch(t)
1963 {
1964 case TOK_INLINE:
1965 case TOK_MSC_FORCEINLINE:
1966 member_spec.set_inline(true);
1967 break;
1968 case TOK_VIRTUAL: member_spec.set_virtual(true); break;
1969 case TOK_FRIEND: member_spec.set_friend(true); break;
1970 case TOK_EXPLICIT: member_spec.set_explicit(true); break;
1971 default: UNREACHABLE;
1972 }
1973
1974 t=lex.LookAhead(0);
1975 }
1976
1977 return true;
1978}
1979
1980/*
1981 storage.spec : STATIC | EXTERN | AUTO | REGISTER | MUTABLE | ASM |
1982 THREAD_LOCAL
1983*/
1985{
1986 int t=lex.LookAhead(0);
1987
1988 if(t==TOK_STATIC ||
1989 t==TOK_EXTERN ||
1990 (t == TOK_AUTO && !ansi_c_parser.cpp11) ||
1991 t==TOK_REGISTER ||
1992 t==TOK_MUTABLE ||
1993 t==TOK_GCC_ASM ||
1994 t==TOK_THREAD_LOCAL)
1995 {
1996 cpp_tokent tk;
1997 lex.get_token(tk);
1998
1999 switch(t)
2000 {
2001 case TOK_STATIC: storage_spec.set_static(); break;
2002 case TOK_EXTERN: storage_spec.set_extern(); break;
2003 case TOK_AUTO: storage_spec.set_auto(); break;
2004 case TOK_REGISTER: storage_spec.set_register(); break;
2005 case TOK_MUTABLE: storage_spec.set_mutable(); break;
2006 case TOK_GCC_ASM: storage_spec.set_asm(); break;
2007 case TOK_THREAD_LOCAL: storage_spec.set_thread_local(); break;
2008 default: UNREACHABLE;
2009 }
2010
2011 set_location(storage_spec, tk);
2012 }
2013
2014 return true;
2015}
2016
2017/*
2018 cv.qualify : (CONSTEXPR | CONST | VOLATILE | RESTRICT)+
2019*/
2021{
2022 for(;;)
2023 {
2024 int t=lex.LookAhead(0);
2025 if(t==TOK_CONSTEXPR ||
2026 t==TOK_CONST || t==TOK_VOLATILE || t==TOK_RESTRICT ||
2027 t==TOK_PTR32 || t==TOK_PTR64 ||
2028 t==TOK_GCC_ATTRIBUTE || t==TOK_GCC_ASM)
2029 {
2030 cpp_tokent tk;
2031 lex.get_token(tk);
2032 typet p;
2033
2034 switch(t)
2035 {
2036 case TOK_CONSTEXPR:
2037 p=typet(ID_constexpr);
2038 set_location(p, tk);
2039 merge_types(p, cv);
2040 break;
2041
2042 case TOK_CONST:
2043 p=typet(ID_const);
2044 set_location(p, tk);
2045 merge_types(p, cv);
2046 break;
2047
2048 case TOK_VOLATILE:
2049 p=typet(ID_volatile);
2050 set_location(p, tk);
2051 merge_types(p, cv);
2052 break;
2053
2054 case TOK_RESTRICT:
2055 p=typet(ID_restrict);
2056 set_location(p, tk);
2057 merge_types(p, cv);
2058 break;
2059
2060 case TOK_PTR32:
2061 p=typet(ID_ptr32);
2062 set_location(p, tk);
2063 merge_types(p, cv);
2064 break;
2065
2066 case TOK_PTR64:
2067 p=typet(ID_ptr64);
2068 set_location(p, tk);
2069 merge_types(p, cv);
2070 break;
2071
2072 case TOK_GCC_ATTRIBUTE:
2073 if(!rAttribute(cv))
2074 return false;
2075 break;
2076
2077 case TOK_GCC_ASM:
2078 // asm post-declarator
2079 // this is stuff like
2080 // int x __asm("asd")=1, y;
2081 if(lex.get_token(tk)!='(')
2082 return false;
2083 if(!rString(tk))
2084 return false;
2085 if(lex.get_token(tk)!=')')
2086 return false;
2087 break;
2088
2089 default:
2091 break;
2092 }
2093 }
2094 else
2095 break;
2096 }
2097
2098 return true;
2099}
2100
2101/*
2102 dcl.align
2103 : ALIGNAS unary.expr
2104 | ALIGNAS '(' type.name ')'
2105*/
2107{
2108 if(lex.LookAhead(0)!=TOK_ALIGNAS)
2109 return true;
2110
2111 cpp_tokent tk;
2112 lex.get_token(tk);
2113
2114 if(lex.LookAhead(0)!='(')
2115 return false;
2116
2117 typet tname;
2118 cpp_tokent op, cp;
2119
2121 lex.get_token(op);
2122
2123 if(rTypeName(tname))
2124 {
2125 if(lex.get_token(cp)==')')
2126 {
2127 exprt exp(ID_alignof);
2128 exp.add(ID_type_arg).swap(tname);
2129 set_location(exp, tk);
2130
2131 typet attr(ID_aligned);
2132 set_location(attr, tk);
2133 attr.add(ID_size, exp);
2134
2135 merge_types(attr, cv);
2136
2137 return true;
2138 }
2139 }
2140
2141 lex.Restore(pos);
2142
2143 exprt exp;
2144
2145 if(!rCommaExpression(exp))
2146 return false;
2147
2148 if(lex.get_token(cp)==')')
2149 {
2150 typet attr(ID_aligned);
2151 set_location(attr, tk);
2152 attr.add(ID_size, exp);
2153
2154 merge_types(attr, cv);
2155
2156 return true;
2157 }
2158
2159 return false;
2160}
2161
2163{
2164#ifdef DEBUG
2165 indenter _i;
2166 std::cout << std::string(__indent, ' ') << "Parser::rAttribute "
2167 << lex.LookAhead(0);
2168#endif
2169 cpp_tokent tk;
2170 lex.get_token(tk);
2171
2172 switch(tk.kind)
2173 {
2174 case '(':
2175 if(lex.LookAhead(0)!=')')
2176 rAttribute(t);
2177
2178 if(lex.LookAhead(0)!=')')
2179 return false;
2180 lex.get_token(tk);
2181 return true;
2182
2183 case TOK_GCC_ATTRIBUTE_PACKED:
2184 {
2185 typet attr(ID_packed);
2186 set_location(attr, tk);
2187 merge_types(attr, t);
2188 break;
2189 }
2190
2191 case TOK_GCC_ATTRIBUTE_TRANSPARENT_UNION:
2192 {
2193 typet attr(ID_transparent_union);
2194 set_location(attr, tk);
2195 merge_types(attr, t);
2196 break;
2197 }
2198
2199 case TOK_GCC_ATTRIBUTE_VECTOR_SIZE:
2200 {
2201 cpp_tokent tk2, tk3;
2202
2203 if(lex.get_token(tk2)!='(')
2204 return false;
2205
2206 exprt exp;
2207 if(!rCommaExpression(exp))
2208 return false;
2209
2210 if(lex.get_token(tk3)!=')')
2211 return false;
2212
2213 type_with_subtypet attr(ID_frontend_vector, uninitialized_typet{});
2214 attr.set(ID_size, exp);
2215 attr.add_source_location()=exp.source_location();
2216 merge_types(attr, t);
2217 break;
2218 }
2219
2220 case TOK_GCC_ATTRIBUTE_ALIGNED:
2221 {
2222 typet attr(ID_aligned);
2223 set_location(attr, tk);
2224
2225 if(lex.LookAhead(0)=='(')
2226 {
2227 cpp_tokent tk2, tk3;
2228
2229 if(lex.get_token(tk2)!='(')
2230 return false;
2231
2232 exprt exp;
2233 if(!rCommaExpression(exp))
2234 return false;
2235
2236 if(lex.get_token(tk3)!=')')
2237 return false;
2238
2239 attr.add(ID_size, exp);
2240 }
2241
2242 merge_types(attr, t);
2243 break;
2244 }
2245
2246 case TOK_GCC_ATTRIBUTE_MODE:
2247 {
2248 cpp_tokent tk2, tk3;
2249
2250 if(lex.get_token(tk2)!='(')
2251 return false;
2252
2253 irept name;
2254 if(!rName(name))
2255 return false;
2256
2257 if(lex.get_token(tk3)!=')')
2258 return false;
2259
2260 typet attr(ID_gcc_attribute_mode);
2261 set_location(attr, tk);
2262 attr.set(ID_size, to_cpp_name(name).get_base_name());
2263 merge_types(attr, t);
2264 break;
2265 }
2266
2267 case TOK_GCC_ATTRIBUTE_GNU_INLINE:
2268 {
2269 typet attr(ID_static);
2270 set_location(attr, tk);
2271 merge_types(attr, t);
2272 break;
2273 }
2274
2275 case TOK_GCC_ATTRIBUTE_WEAK:
2276 {
2277 typet attr(ID_weak);
2278 set_location(attr, tk);
2279 merge_types(attr, t);
2280 break;
2281 }
2282
2283 case TOK_GCC_ATTRIBUTE_ALIAS:
2284 {
2285 cpp_tokent tk2, tk3, tk4;
2286
2287 if(lex.get_token(tk2)!='(')
2288 return false;
2289
2290 if(!rString(tk3))
2291 return false;
2292
2293 if(lex.get_token(tk4)!=')')
2294 return false;
2295
2296 typet attr(ID_alias);
2297 set_location(attr, tk);
2298 attr.move_to_sub(tk3.data);
2299 merge_types(attr, t);
2300 break;
2301 }
2302
2303 case TOK_GCC_ATTRIBUTE_SECTION:
2304 {
2305 cpp_tokent tk2, tk3, tk4;
2306
2307 if(lex.get_token(tk2)!='(')
2308 return false;
2309
2310 if(!rString(tk3))
2311 return false;
2312
2313 if(lex.get_token(tk4)!=')')
2314 return false;
2315
2316 typet attr(ID_section);
2317 set_location(attr, tk);
2318 attr.move_to_sub(tk3.data);
2319 merge_types(attr, t);
2320 break;
2321 }
2322
2323 case TOK_GCC_ATTRIBUTE_NORETURN:
2324 {
2325 typet attr(ID_noreturn);
2326 set_location(attr, tk);
2327 merge_types(attr, t);
2328 break;
2329 }
2330
2331 case TOK_GCC_ATTRIBUTE_CONSTRUCTOR:
2332 {
2333 typet attr(ID_constructor);
2334 set_location(attr, tk);
2335 merge_types(attr, t);
2336 break;
2337 }
2338
2339 case TOK_GCC_ATTRIBUTE_DESTRUCTOR:
2340 {
2341 typet attr(ID_destructor);
2342 set_location(attr, tk);
2343 merge_types(attr, t);
2344 break;
2345 }
2346
2347 case ',':
2348 if(lex.LookAhead(0)==')')
2349 // the scanner ignored an attribute
2350 return true;
2351 break;
2352
2353 default:
2354 return false;
2355 }
2356
2357 if(lex.LookAhead(0)==')')
2358 return true;
2359
2360 return rAttribute(t);
2361}
2362
2364{
2365 if(lex.LookAhead(0)!='[' ||
2366 lex.LookAhead(1)!='[')
2367 return true;
2368
2369 lex.get_token();
2370 lex.get_token();
2371
2372 for(;;)
2373 {
2374 cpp_tokent tk;
2375 lex.get_token(tk);
2376
2377 switch(tk.kind)
2378 {
2379 case ']':
2380 lex.get_token();
2381 return true;
2382
2383 case TOK_NORETURN:
2384 {
2385 typet attr(ID_noreturn);
2386 set_location(attr, tk);
2387 merge_types(attr, t);
2388 break;
2389 }
2390
2391 default:
2392 return false;
2393 }
2394 }
2395}
2396
2397/*
2398
2399 integral.or.class.spec
2400 : (CHAR | CHAR16_T | CHAR32_T | WCHAR_T
2401 | INT | SHORT | LONG | SIGNED | UNSIGNED | FLOAT | DOUBLE
2402 | VOID | BOOLEAN | COMPLEX)+
2403 | class.spec
2404 | enum.spec
2405
2406 Note: if editing this, see also isTypeSpecifier().
2407*/
2409{
2410#ifdef DEBUG
2411 indenter _i;
2412 std::cout << std::string(__indent, ' ')
2413 << "Parser::optIntegralTypeOrClassSpec 0\n";
2414#endif // DEBUG
2415
2416 // This makes no sense, but is used in Visual Studio header files.
2417 if(lex.LookAhead(0)==TOK_TYPENAME)
2418 {
2419 cpp_tokent tk;
2420 lex.get_token(tk);
2421 }
2422
2423 bool is_integral=false;
2424 p.make_nil();
2425
2426 int t;
2427
2428 for(;;)
2429 {
2430 t=lex.LookAhead(0);
2431
2432#ifdef DEBUG
2433 std::cout << std::string(__indent, ' ')
2434 << "Parser::optIntegralTypeOrClassSpec 1\n";
2435#endif // DEBUG
2436
2437 irep_idt type_id;
2438
2439 switch(t)
2440 {
2441 case TOK_CHAR: type_id=ID_char; break;
2442 case TOK_CHAR16_T: type_id=ID_char16_t; break;
2443 case TOK_CHAR32_T: type_id=ID_char32_t; break;
2444 case TOK_INT: type_id=ID_int; break;
2445 case TOK_SHORT: type_id=ID_short; break;
2446 case TOK_LONG: type_id=ID_long; break;
2447 case TOK_SIGNED: type_id=ID_signed; break;
2448 case TOK_WCHAR_T: type_id=ID_wchar_t; break;
2449 case TOK_COMPLEX: type_id=ID_complex; break;
2450 case TOK_UNSIGNED: type_id=ID_unsigned; break;
2451 case TOK_FLOAT: type_id=ID_float; break;
2452 case TOK_DOUBLE: type_id=ID_double; break;
2453 case TOK_VOID: type_id=ID_void; break;
2454 case TOK_INT8: type_id=ID_int8; break;
2455 case TOK_INT16: type_id=ID_int16; break;
2456 case TOK_INT32: type_id=ID_int32; break;
2457 case TOK_INT64: type_id=ID_int64; break;
2458 case TOK_GCC_INT128: type_id=ID_gcc_int128; break;
2459 case TOK_GCC_FLOAT80: type_id=ID_gcc_float80; break;
2460 case TOK_GCC_FLOAT128: type_id=ID_gcc_float128; break;
2461 case TOK_BOOL:
2462 type_id = ID_c_bool;
2463 break;
2464 case TOK_CPROVER_BOOL: type_id=ID_proper_bool; break;
2465 case TOK_AUTO: type_id = ID_auto; break;
2466 default: type_id=irep_idt();
2467 }
2468
2469 if(!type_id.empty())
2470 {
2471 cpp_tokent tk;
2472 typet kw;
2473 lex.get_token(tk);
2474 kw=typet(type_id);
2475 set_location(kw, tk);
2476
2477 merge_types(kw, p);
2478
2479 is_integral=true;
2480 }
2481 else
2482 break;
2483 }
2484
2485#ifdef DEBUG
2486 std::cout << std::string(__indent, ' ')
2487 << "Parser::optIntegralTypeOrClassSpec 2\n";
2488#endif // DEBUG
2489
2490 if(is_integral)
2491 return true;
2492
2493#ifdef DEBUG
2494 std::cout << std::string(__indent, ' ')
2495 << "Parser::optIntegralTypeOrClassSpec 3\n";
2496#endif // DEBUG
2497
2498 if(t==TOK_CLASS || t==TOK_STRUCT || t==TOK_UNION || t==TOK_INTERFACE)
2499 return rClassSpec(p);
2500 else if(t==TOK_ENUM)
2501 return rEnumSpec(p);
2502 else if(t==TOK_TYPEOF)
2503 {
2504#ifdef DEBUG
2505 std::cout << std::string(__indent, ' ')
2506 << "Parser::optIntegralTypeOrClassSpec 4\n";
2507#endif // DEBUG
2508
2509 cpp_tokent typeof_tk;
2510 lex.get_token(typeof_tk);
2511
2512#ifdef DEBUG
2513 std::cout << std::string(__indent, ' ')
2514 << "Parser::optIntegralTypeOrClassSpec 5\n";
2515#endif // DEBUG
2516
2517 p=typet(ID_typeof);
2518 set_location(p, typeof_tk);
2519
2520 cpp_tokent tk;
2521 if(lex.get_token(tk)!='(')
2522 return false;
2523
2524 // the argument can be a type or an expression
2525
2526 {
2527 typet tname;
2529
2530 if(rTypeName(tname))
2531 {
2532 if(lex.get_token(tk)==')')
2533 {
2534 p.add(ID_type_arg).swap(tname);
2535 return true;
2536 }
2537 }
2538
2539 lex.Restore(pos);
2540 }
2541
2542#ifdef DEBUG
2543 std::cout << std::string(__indent, ' ')
2544 << "Parser::optIntegralTypeOrClassSpec 6\n";
2545#endif // DEBUG
2546
2547 exprt expr;
2548 if(!rCommaExpression(expr))
2549 return false;
2550
2551#ifdef DEBUG
2552 std::cout << std::string(__indent, ' ')
2553 << "Parser::optIntegralTypeOrClassSpec 7\n";
2554#endif // DEBUG
2555
2556 if(lex.get_token(tk)!=')')
2557 return false;
2558
2559#ifdef DEBUG
2560 std::cout << std::string(__indent, ' ')
2561 << "Parser::optIntegralTypeOrClassSpec 8\n";
2562#endif // DEBUG
2563
2564 p.add(ID_expr_arg).swap(expr);
2565
2566 return true;
2567 }
2568 else if(t==TOK_DECLTYPE)
2569 {
2570 cpp_tokent decltype_tk;
2571 lex.get_token(decltype_tk);
2572
2573 p=typet(ID_decltype);
2574 set_location(p, decltype_tk);
2575
2576 cpp_tokent tk;
2577 if(lex.get_token(tk)!='(')
2578 return false;
2579
2580 // the argument is always an expression
2581
2582 exprt expr;
2583 if(!rCommaExpression(expr))
2584 return false;
2585
2586 if(lex.get_token(tk)!=')')
2587 return false;
2588
2589 p.add(ID_expr_arg).swap(expr);
2590
2591 return true;
2592 }
2593 else if(t==TOK_UNDERLYING_TYPE)
2594 {
2595 // A Visual Studio extension that returns the underlying
2596 // type of an enum.
2597 cpp_tokent underlying_type_tk;
2598 lex.get_token(underlying_type_tk);
2599
2600 p=typet(ID_msc_underlying_type);
2601 set_location(p, underlying_type_tk);
2602
2603 cpp_tokent tk;
2604 if(lex.get_token(tk)!='(')
2605 return false;
2606
2607 // the argument is always a type
2608
2609 typet tname;
2610
2611 if(!rTypeName(tname))
2612 return false;
2613
2614 if(lex.get_token(tk)!=')')
2615 return false;
2616
2617 p.add(ID_type_arg).swap(tname);
2618
2619 return true;
2620 }
2621 else
2622 {
2623 p.make_nil();
2624 return true;
2625 }
2626}
2627
2628/*
2629 constructor.decl
2630 : '(' {arg.decl.list} ')' {cv.qualify} {throw.decl}
2631 {member.initializers} {'=' Constant}
2632*/
2634 cpp_declaratort &constructor,
2635 typet &type_name,
2636 typet &trailing_return_type)
2637{
2638#ifdef DEBUG
2639 indenter _i;
2640 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 0\n";
2641#endif
2642
2643 trailing_return_type.make_nil();
2644
2645 constructor=cpp_declaratort(typet(ID_function_type));
2646 constructor.type().subtype().make_nil();
2647 constructor.name().swap(type_name);
2648
2649 cpp_tokent op;
2650 if(lex.get_token(op)!='(')
2651 return false;
2652
2653#ifdef DEBUG
2654 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 1\n";
2655#endif
2656
2657 irept &parameters=constructor.type().add(ID_parameters);
2658
2659 if(lex.LookAhead(0)!=')')
2660 if(!rArgDeclList(parameters))
2661 return false;
2662
2663 cpp_tokent cp;
2664 lex.get_token(cp);
2665
2666#ifdef DEBUG
2667 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 2\n";
2668#endif
2669
2670 typet &cv=static_cast<typet &>(constructor.add(ID_method_qualifier));
2671 cv.make_nil();
2672 optCvQualify(cv);
2673
2674 optThrowDecl(constructor.throw_decl());
2675
2676 if(lex.LookAhead(0)==TOK_ARROW)
2677 {
2678#ifdef DEBUG
2679 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 3\n";
2680#endif
2681
2682 // C++11 trailing return type
2683 cpp_tokent arrow;
2684 lex.get_token(arrow);
2685
2686 if(!rTypeSpecifier(trailing_return_type, false))
2687 return false;
2688 }
2689
2690#ifdef DEBUG
2691 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 4\n";
2692#endif
2693
2694 if(lex.LookAhead(0)==':')
2695 {
2696 irept mi;
2697
2698 if(rMemberInitializers(mi))
2699 constructor.member_initializers().swap(mi);
2700 else
2701 return false;
2702 }
2703
2704#ifdef DEBUG
2705 std::cout << std::string(__indent, ' ') << "Parser::rConstructorDecl 5\n";
2706#endif
2707
2708 if(lex.LookAhead(0)=='=')
2709 {
2710 cpp_tokent eq, value;
2711 lex.get_token(eq);
2712
2713 switch(lex.get_token(value))
2714 {
2715 case TOK_INTEGER:
2716 {
2717 constructor.value()=codet("cpp-pure-virtual");
2718 set_location(constructor.value(), value);
2719 }
2720 break;
2721
2722 case TOK_DEFAULT: // C++0x
2723 {
2724 if(!ansi_c_parser.cpp11)
2725 {
2726 SyntaxError();
2727 return false;
2728 }
2729
2730 constructor.value()=codet(ID_default);
2731 set_location(constructor.value(), value);
2732 }
2733 break;
2734
2735 case TOK_DELETE: // C++0x
2736 {
2737 if(!ansi_c_parser.cpp11)
2738 {
2739 SyntaxError();
2740 return false;
2741 }
2742
2743 constructor.value()=codet(ID_cpp_delete);
2744 set_location(constructor.value(), value);
2745 }
2746 break;
2747
2748 default:
2749 return false;
2750 }
2751 }
2752 else
2753 constructor.add(ID_value).make_nil();
2754
2755 return true;
2756}
2757
2758/*
2759 throw.decl : THROW '(' (name {','})* {name} ')'
2760 | THROW '(' '...' ')'
2761 | NOEXCEPT
2762*/
2764{
2765 cpp_tokent tk;
2766 int t;
2767 irept p=get_nil_irep();
2768
2769 if(lex.LookAhead(0)==TOK_THROW)
2770 {
2771 lex.get_token(tk);
2772 // p=Ptree::Snoc(p, new LeafReserved(tk));
2773
2774 if(lex.get_token(tk)!='(')
2775 return false;
2776
2777 // p=Ptree::Snoc(p, new Leaf(tk));
2778
2779 for(;;)
2780 {
2781 irept q;
2782 t=lex.LookAhead(0);
2783 if(t=='\0')
2784 return false;
2785 else if(t==')')
2786 break;
2787 else if(t==TOK_ELLIPSIS)
2788 {
2789 lex.get_token(tk);
2790 }
2791 else if(rName(q))
2792 {
2793 // p=Ptree::Snoc(p, q);
2794 }
2795 else
2796 return false;
2797
2798 if(lex.LookAhead(0)==',')
2799 {
2800 lex.get_token(tk);
2801 // p=Ptree::Snoc(p, new Leaf(tk));
2802 }
2803 else
2804 break;
2805 }
2806
2807 if(lex.get_token(tk)!=')')
2808 return false;
2809
2810 // p=Ptree::Snoc(p, new Leaf(tk));
2811 }
2812 else if(lex.LookAhead(0)==TOK_NOEXCEPT)
2813 {
2814 exprt expr;
2815
2816 if(!rNoexceptExpr(expr))
2817 return false;
2818
2819 // TODO
2820 }
2821
2822 throw_decl=p;
2823 return true;
2824}
2825
2826/*
2827 declarators : declarator.with.init (',' declarator.with.init)*
2828
2829 is_statement changes the behavior of rArgDeclListOrInit().
2830*/
2832 cpp_declarationt::declaratorst &declarators,
2833 bool should_be_declarator,
2834 bool is_statement)
2835{
2836 cpp_tokent tk;
2837
2838 for(;;)
2839 {
2840 cpp_declaratort declarator;
2841 if(!rDeclaratorWithInit(declarator, should_be_declarator, is_statement))
2842 return false;
2843
2844 declarators.push_back(declarator);
2845
2846 if(lex.LookAhead(0)==',')
2847 lex.get_token(tk);
2848 else
2849 return true;
2850 }
2851}
2852
2853/*
2854 declarator.with.init
2855 : ':' expression
2856 | declarator
2857 {'=' initialize.expr |
2858 ':' expression}
2859*/
2861 cpp_declaratort &dw,
2862 bool should_be_declarator,
2863 bool is_statement)
2864{
2865 if(lex.LookAhead(0)==':')
2866 {
2867 // This is an anonymous bit field.
2868 cpp_tokent tk;
2869 lex.get_token(tk); // get :
2870
2871 exprt e;
2872 if(!rExpression(e, false))
2873 return false;
2874
2875 typet bit_field_type(ID_c_bit_field);
2876 bit_field_type.set(ID_size, e);
2877 bit_field_type.subtype().make_nil();
2878 set_location(bit_field_type, tk);
2879
2880 merge_types(bit_field_type, dw.type());
2881
2882 return true;
2883 }
2884 else
2885 {
2886 cpp_declaratort declarator;
2887
2888 if(!rDeclarator(
2889 declarator, kDeclarator, should_be_declarator, is_statement))
2890 return false;
2891
2892 int t=lex.LookAhead(0);
2893 if(t=='=')
2894 {
2895 // initializer
2896 cpp_tokent tk;
2897 lex.get_token(tk);
2898
2899 if(lex.LookAhead(0)==TOK_DEFAULT) // C++0x
2900 {
2901 if(!ansi_c_parser.cpp11)
2902 {
2903 SyntaxError();
2904 return false;
2905 }
2906
2907 lex.get_token(tk);
2908 declarator.value()=codet(ID_default);
2909 set_location(declarator.value(), tk);
2910 }
2911 else if(lex.LookAhead(0)==TOK_DELETE) // C++0x
2912 {
2913 if(!ansi_c_parser.cpp11)
2914 {
2915 SyntaxError();
2916 return false;
2917 }
2918
2919 lex.get_token(tk);
2920 declarator.value()=codet(ID_cpp_delete);
2921 set_location(declarator.value(), tk);
2922 }
2923 else
2924 {
2925 if(!rInitializeExpr(declarator.value()))
2926 return false;
2927 }
2928 }
2929 else if(t=='{')
2930 {
2931 // Possibly a C++11 list initializer;
2932 // or a function body.
2933
2934 if(declarator.type().id()!=ID_function_type)
2935 {
2936 if(!rInitializeExpr(declarator.value()))
2937 return false;
2938 }
2939 }
2940 else if(t==':')
2941 {
2942 // bit field
2943 cpp_tokent tk;
2944 lex.get_token(tk); // get :
2945
2946 exprt e;
2947 if(!rExpression(e, false))
2948 return false;
2949
2950 typet bit_field_type(ID_c_bit_field);
2951 bit_field_type.set(ID_size, e);
2952 bit_field_type.subtype().make_nil();
2953 set_location(bit_field_type, tk);
2954
2955 merge_types(bit_field_type, declarator.type());
2956 }
2957
2958 dw.swap(declarator);
2959 return true;
2960 }
2961}
2962
2963/* __stdcall, __fastcall, __clrcall, __cdecl
2964
2965 These are Visual-Studio specific.
2966
2967*/
2968
2970{
2971 int t=lex.LookAhead(0);
2972
2973 // we just eat these
2974
2975 while(t==TOK_STDCALL || t==TOK_FASTCALL || t==TOK_CLRCALL || t==TOK_CDECL)
2976 {
2977 cpp_tokent op;
2978 lex.get_token(op);
2979 t=lex.LookAhead(0);
2980 }
2981
2982 return true;
2983}
2984
2985/*
2986 declarator
2987 : (ptr.operator)* (name | '(' declarator ')')
2988 ('[' comma.expression ']')* {func.args.or.init}
2989
2990 func.args.or.init
2991 : '(' arg.decl.list.or.init ')' {cv.qualify} {throw.decl}
2992 {member.initializers}
2993
2994 Note: We assume that '(' declarator ')' is followed by '(' or '['.
2995 This is to avoid accepting a function call F(x) as a pair of
2996 a type F and a declarator x. This assumption is ignored
2997 if should_be_declarator is true.
2998
2999 Note: is_statement changes the behavior of rArgDeclListOrInit().
3000*/
3001
3003 cpp_declaratort &declarator,
3004 DeclKind kind,
3005 bool should_be_declarator,
3006 bool is_statement)
3007{
3008 int t;
3009
3010#ifdef DEBUG
3011 indenter _i;
3012 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 1\n";
3013#endif
3014
3015 // we can have one or more declarator qualifiers
3017 return false;
3018
3019 typet d_outer, d_inner;
3020 irept name;
3021
3022 name.make_nil();
3023 d_outer.make_nil();
3024 d_inner.make_nil();
3025
3026 if(!optPtrOperator(d_outer))
3027 return false;
3028
3029 // we can have another sequence of declarator qualifiers
3031 return false;
3032
3033#ifdef DEBUG
3034 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 2\n";
3035#endif
3036
3037 t=lex.LookAhead(0);
3038
3039 if(t=='(')
3040 {
3041#ifdef DEBUG
3042 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 3\n";
3043#endif
3044
3045 cpp_tokent op;
3046 lex.get_token(op);
3047
3048 cpp_declaratort declarator2;
3049 if(!rDeclarator(declarator2, kind, true, false))
3050 return false;
3051
3052#ifdef DEBUG
3053 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 4\n";
3054#endif
3055
3056 cpp_tokent cp;
3057
3058 if(lex.get_token(cp)!=')')
3059 return false;
3060
3061 if(!should_be_declarator)
3062 {
3063 if((kind==kDeclarator || kind==kCastDeclarator) && d_outer.is_nil())
3064 {
3065 t=lex.LookAhead(0);
3066 if(t!='[' && t!='(')
3067 return false;
3068 }
3069 }
3070
3071#ifdef DEBUG
3072 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 5\n";
3073#endif
3074
3075 d_inner.swap(declarator2.type());
3076 name.swap(declarator2.name());
3077 }
3078 else if(kind!=kCastDeclarator &&
3079 (kind==kDeclarator || t==TOK_IDENTIFIER || t==TOK_SCOPE))
3080 {
3081#ifdef DEBUG
3082 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 6\n";
3083#endif
3084
3085 // if this is an argument declarator, "int (*)()" is valid.
3086 if(!rName(name))
3087 return false;
3088 }
3089
3090#ifdef DEBUG
3091 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 7\n";
3092#endif
3093
3094 exprt init_args(static_cast<const exprt &>(get_nil_irep()));
3095 // const...
3096 typet method_qualifier(static_cast<const typet &>(get_nil_irep()));
3097
3098 for(;;)
3099 {
3100 t=lex.LookAhead(0);
3101 if(t=='(') // function
3102 {
3103#ifdef DEBUG
3104 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 8\n";
3105#endif
3106
3107 cpp_tokent op, cp;
3108 exprt args;
3109 bool is_args=true;
3110
3111 lex.get_token(op);
3112
3113 if(lex.LookAhead(0)==')')
3114 args.clear();
3115 else
3116 if(!rArgDeclListOrInit(args, is_args, is_statement))
3117 return false;
3118
3119 if(lex.get_token(cp)!=')')
3120 return false;
3121
3122 if(is_args)
3123 {
3124 typet function_type(ID_function_type);
3125 function_type.subtype().swap(d_outer);
3126 function_type.add(ID_parameters).swap(args);
3127
3128 // make this subtype of d_inner
3129 make_subtype(function_type, d_inner);
3130 d_outer.swap(d_inner);
3131
3132 optCvQualify(method_qualifier);
3133 }
3134 else
3135 {
3136 init_args.swap(args);
3137 // loop should end here
3138 }
3139
3140#ifdef DEBUG
3141 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 9\n";
3142#endif
3143
3144 irept throw_decl;
3145 optThrowDecl(throw_decl); // ignore in this version
3146
3147 if(lex.LookAhead(0)==TOK_ARROW)
3148 {
3149#ifdef DEBUG
3150 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 10\n";
3151#endif
3152
3153 // C++11 trailing return type, but we already have
3154 // a return type. We should report this as an error.
3155 cpp_tokent arrow;
3156 lex.get_token(arrow);
3157
3158 typet return_type;
3159 if(!rTypeSpecifier(return_type, false))
3160 return false;
3161
3162 if(d_outer.subtype().is_not_nil())
3163 return false;
3164
3165 d_outer.subtype().swap(return_type);
3166 }
3167
3168 if(lex.LookAhead(0)==':')
3169 {
3170#ifdef DEBUG
3171 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 11\n";
3172#endif
3173
3174 irept mi;
3175 if(rMemberInitializers(mi))
3176 {
3177 // TODO: these are only meant to show up in a
3178 // constructor!
3179 }
3180 else
3181 return false;
3182 }
3183
3184 break; // "T f(int)(char)" is invalid.
3185 }
3186 else if(t=='[') // array
3187 {
3188#ifdef DEBUG
3189 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 12\n";
3190#endif
3191
3192 cpp_tokent ob, cb;
3193 exprt expr;
3194 lex.get_token(ob);
3195 if(lex.LookAhead(0)==']')
3196 expr.make_nil();
3197 else
3198 if(!rCommaExpression(expr))
3199 return false;
3200
3201 if(lex.get_token(cb)!=']')
3202 return false;
3203
3204 std::list<typet> tl;
3205 tl.push_back(d_outer);
3206 while(tl.back().id() == ID_array)
3207 {
3208 tl.push_back(tl.back().subtype());
3209 }
3210
3211 array_typet array_type(tl.back(), expr);
3212 tl.pop_back();
3213 d_outer.swap(array_type);
3214 while(!tl.empty())
3215 {
3216 tl.back().subtype().swap(d_outer);
3217 d_outer.swap(tl.back());
3218 tl.pop_back();
3219 }
3220 }
3221 else
3222 break;
3223 }
3224
3225 optCvQualify(d_outer);
3226 if(d_outer.is_not_nil() && !d_outer.has_subtypes())
3227 {
3228 merged_typet merged_type;
3229 merged_type.move_to_subtypes(d_outer);
3230 typet nil;
3231 nil.make_nil();
3232 merged_type.move_to_sub(nil);
3233 d_outer.swap(merged_type);
3234 }
3235
3236#ifdef DEBUG
3237 std::cout << std::string(__indent, ' ') << "Parser::rDeclarator2 13\n";
3238#endif
3239
3240 declarator=cpp_declaratort();
3241
3242 declarator.name().swap(name);
3243
3244 if(init_args.is_not_nil())
3245 declarator.init_args().swap(init_args);
3246
3247 if(method_qualifier.is_not_nil())
3248 declarator.method_qualifier().swap(method_qualifier);
3249
3250 declarator.type().swap(d_outer);
3251
3252 return true;
3253}
3254
3255/*
3256 ptr.operator
3257 : (('*' | ptr.to.member)['&'] {cv.qualify})+
3258*/
3260{
3261#ifdef DEBUG
3262 indenter _i;
3263 std::cout << std::string(__indent, ' ') << "Parser::optPtrOperator 1\n";
3264#endif // DEBUG
3265
3266 std::list<typet> t_list;
3267
3268 for(;;)
3269 {
3270 int t=lex.LookAhead(0);
3271
3272#ifdef DEBUG
3273 std::cout << std::string(__indent, ' ') << "Parser::optPtrOperator 2 " << t
3274 << '\n';
3275#endif
3276
3277 if(t=='*')
3278 {
3279 typet op(ID_frontend_pointer); // width gets set during conversion
3280 cpp_tokent tk;
3281 lex.get_token(tk);
3282 set_location(op, tk);
3283
3284 typet cv;
3285 cv.make_nil();
3286 optCvQualify(cv); // the qualifier is for the pointer
3287 if(cv.is_not_nil())
3288 merge_types(cv, op);
3289
3290 t_list.push_back(op);
3291 }
3292 else if(t=='^')
3293 {
3294 // this is an Apple extension called 'block pointer' or 'closure pointer'
3295 typet op(ID_block_pointer);
3296 cpp_tokent tk;
3297 lex.get_token(tk);
3298 set_location(op, tk);
3299
3300 typet cv;
3301 cv.make_nil();
3302 optCvQualify(cv); // the qualifier is for the pointer
3303 if(cv.is_not_nil())
3304 merge_types(cv, op);
3305
3306 t_list.push_back(op);
3307 }
3308 else if(isPtrToMember(0))
3309 {
3310 typet op;
3311 if(!rPtrToMember(op))
3312 return false;
3313
3314 typet cv;
3315 cv.make_nil();
3316 optCvQualify(cv); // the qualifier is for the pointer
3317 if(cv.is_not_nil())
3318 {
3319 merge_types(op, cv);
3320 t_list.push_back(cv);
3321 }
3322 else
3323 t_list.push_back(op);
3324 }
3325 else
3326 break;
3327 }
3328
3329 {
3330 int t=lex.LookAhead(0);
3331
3332 if(t=='&')
3333 {
3334 cpp_tokent tk;
3335 lex.get_token(tk);
3336 typet op(ID_frontend_pointer); // width gets set during conversion
3337 op.set(ID_C_reference, true);
3338 set_location(op, tk);
3339 t_list.push_front(op);
3340 }
3341 else if(t==TOK_ANDAND) // &&, these are C++0x rvalue refs
3342 {
3343 cpp_tokent tk;
3344 lex.get_token(tk);
3345 typet op(ID_frontend_pointer); // width gets set during conversion
3346 op.set(ID_C_rvalue_reference, true);
3347 set_location(op, tk);
3348 t_list.push_front(op);
3349 }
3350 }
3351
3352 for(std::list<typet>::reverse_iterator
3353 it=t_list.rbegin();
3354 it!=t_list.rend();
3355 it++)
3356 {
3357 if(it->id()==ID_merged_type)
3358 {
3359 auto &merged_type = to_merged_type(*it);
3360 merged_type.last_type().subtype().swap(ptrs);
3361 }
3362 else
3363 {
3364 assert(it->is_not_nil());
3365 it->subtype().swap(ptrs);
3366 }
3367
3368 ptrs.swap(*it);
3369 }
3370
3371 return true;
3372}
3373
3374/*
3375 member.initializers
3376 : ':' member.init (',' member.init)*
3377*/
3379{
3380 cpp_tokent tk;
3381
3382 if(lex.get_token(tk)!=':')
3383 return false;
3384
3385 init=irept(ID_member_initializers);
3386 set_location(init, tk);
3387
3388 exprt m;
3389 if(!rMemberInit(m))
3390 return false;
3391
3392 init.move_to_sub(m);
3393
3394 while(lex.LookAhead(0)==',')
3395 {
3396 lex.get_token(tk);
3397 if(!rMemberInit(m))
3398 return false;
3399
3400 init.move_to_sub(m);
3401 }
3402
3403 return true;
3404}
3405
3406/*
3407 member.init
3408 : name '(' function.arguments ')'
3409 : name '(' '{' initialize.expr ... '}' ')'
3410*/
3412{
3413#ifdef DEBUG
3414 indenter _i;
3415 std::cout << std::string(__indent, ' ') << "Parser::rMemberInit 1\n";
3416#endif
3417
3418 irept name;
3419
3420 if(!rName(name))
3421 return false;
3422
3423#ifdef DEBUG
3424 std::cout << std::string(__indent, ' ') << "Parser::rMemberInit 2\n";
3425#endif
3426
3427 init=codet(ID_member_initializer);
3428 init.add(ID_member).swap(name);
3429
3430 cpp_tokent tk1, tk2;
3431 lex.get_token(tk1);
3432 set_location(init, tk1);
3433
3434 if(tk1.kind=='{' ||
3435 (tk1.kind=='(' && lex.LookAhead(0)=='{'))
3436 {
3437#ifdef DEBUG
3438 std::cout << std::string(__indent, ' ') << "Parser::rMemberInit 3\n";
3439#endif
3440 exprt exp;
3441 if(!rInitializeExpr(exp))
3442 return false;
3443
3444 init.operands().push_back(exp);
3445
3446 // read closing parenthesis
3447 lex.get_token(tk2);
3448 if(tk2.kind!='}' && tk2.kind!=')')
3449 return false;
3450 }
3451 else
3452 {
3453 if(tk1.kind!='(')
3454 return false;
3455
3456#ifdef DEBUG
3457 std::cout << std::string(__indent, ' ') << "Parser::rMemberInit 4\n";
3458#endif
3459
3460 exprt args;
3461
3462 if(!rFunctionArguments(args))
3463 return false;
3464
3465 init.operands().swap(args.operands());
3466
3467 // read closing parenthesis
3468 if(lex.get_token(tk2)!=')')
3469 return false;
3470 }
3471
3472 if(lex.LookAhead(0)==TOK_ELLIPSIS)
3473 {
3474 lex.get_token();
3475
3476 // TODO
3477 }
3478
3479 return true;
3480}
3481
3482/*
3483 name : {'::'} name2 ('::' name2)*
3484
3485 name2
3486 : Identifier {template.args}
3487 | '~' Identifier
3488 | OPERATOR operator.name {template.args}
3489
3490 Don't use this function for parsing an expression
3491 It always regards '<' as the beginning of template arguments.
3492*/
3494{
3495#ifdef DEBUG
3496 indenter _i;
3497 std::cout << std::string(__indent, ' ') << "Parser::rName 0\n";
3498#endif
3499
3500 name=cpp_namet();
3501 irept::subt &components=name.get_sub();
3502
3503 if(lex.LookAhead(0)==TOK_TYPENAME)
3504 {
3505 cpp_tokent tk;
3506 lex.get_token(tk);
3507 name.set(ID_typename, true);
3508 }
3509
3510 {
3511 cpp_tokent tk;
3512 lex.LookAhead(0, tk);
3513 set_location(name, tk);
3514 }
3515
3516#ifdef DEBUG
3517 std::cout << std::string(__indent, ' ') << "Parser::rName 1\n";
3518#endif
3519
3520 for(;;)
3521 {
3522 cpp_tokent tk;
3523
3524#ifdef DEBUG
3525 std::cout << std::string(__indent, ' ') << "Parser::rName 2 "
3526 << lex.LookAhead(0) << '\n';
3527#endif
3528
3529 switch(lex.LookAhead(0))
3530 {
3531 case TOK_TEMPLATE:
3532#ifdef DEBUG
3533 std::cout << std::string(__indent, ' ') << "Parser::rName 3\n";
3534#endif
3535 lex.get_token(tk);
3536 // Skip template token, next will be identifier
3537 if(lex.LookAhead(0)!=TOK_IDENTIFIER)
3538 return false;
3539 break;
3540
3541 case '<':
3542#ifdef DEBUG
3543 std::cout << std::string(__indent, ' ') << "Parser::rName 4\n";
3544#endif
3545 {
3546 irept args;
3547 if(!rTemplateArgs(args))
3548 return false;
3549
3550 components.push_back(irept(ID_template_args));
3551 components.back().add(ID_arguments).swap(args);
3552
3553 // done unless scope is next
3554 if(lex.LookAhead(0)!=TOK_SCOPE)
3555 return true;
3556 }
3557 break;
3558
3559 case TOK_IDENTIFIER:
3560#ifdef DEBUG
3561 std::cout << std::string(__indent, ' ') << "Parser::rName 5\n";
3562#endif
3563 lex.get_token(tk);
3564 components.push_back(cpp_namet::namet(tk.data.get(ID_C_base_name)));
3565 set_location(components.back(), tk);
3566
3567 {
3568 int t=lex.LookAhead(0);
3569 // done unless scope or template args is next
3570 if(t!=TOK_SCOPE && t!='<')
3571 return true;
3572 }
3573 break;
3574
3575 case TOK_SCOPE:
3576#ifdef DEBUG
3577 std::cout << std::string(__indent, ' ') << "Parser::rName 6\n";
3578#endif
3579 lex.get_token(tk);
3580 components.push_back(irept("::"));
3581 set_location(components.back(), tk);
3582 break;
3583
3584 case '~':
3585#ifdef DEBUG
3586 std::cout << std::string(__indent, ' ') << "Parser::rName 7\n";
3587#endif
3588 lex.get_token(tk);
3589
3590 // identifier must be next
3591 if(lex.LookAhead(0)!=TOK_IDENTIFIER)
3592 return false;
3593
3594 components.push_back(irept("~"));
3595 set_location(components.back(), tk);
3596 break;
3597
3598 case TOK_OPERATOR:
3599#ifdef DEBUG
3600 std::cout << std::string(__indent, ' ') << "Parser::rName 8\n";
3601#endif
3602 lex.get_token(tk);
3603 {
3604 components.push_back(irept(ID_operator));
3605 set_location(components.back(), tk);
3606
3607 components.push_back(irept());
3608
3609 if(!rOperatorName(components.back()))
3610 return false;
3611 }
3612
3613 // done unless template args are next
3614 if(lex.LookAhead(0)!='<')
3615 return true;
3616 break;
3617
3618 default:
3619 return false;
3620 }
3621 }
3622}
3623
3624/*
3625 operator.name
3626 : '+' | '-' | '*' | '/' | '%' | '^' | '&' | '|' | '~'
3627 | '!' | '=' | '<' | '>' | AssignOp | ShiftOp | EqualOp
3628 | RelOp | LogAndOp | LogOrOp | IncOp | ',' | DOTPM | ARROWPM | ArrowOp
3629 | NEW {'[' ']'}
3630 | DELETE {'[' ']'}
3631 | '(' ')'
3632 | '[' ']'
3633 | cast.operator.name
3634*/
3635
3637{
3638 cpp_tokent tk;
3639
3640 int t=lex.LookAhead(0);
3641
3642 irep_idt operator_id;
3643
3644 switch(t)
3645 {
3646 case '+':
3647 case '-':
3648 case '*':
3649 case '/':
3650 case '%':
3651 case '^':
3652 case '&':
3653 case '|':
3654 case '~':
3655 case '!':
3656 case '=':
3657 case '<':
3658 case '>':
3659 case ',':
3660 operator_id = std::string(1, static_cast<char>(t));
3661 break;
3662
3663 case TOK_MULTASSIGN: operator_id="*="; break;
3664 case TOK_DIVASSIGN: operator_id="/="; break;
3665 case TOK_MODASSIGN: operator_id="%="; break;
3666 case TOK_PLUSASSIGN: operator_id="+="; break;
3667 case TOK_MINUSASSIGN: operator_id="-="; break;
3668 case TOK_SHLASSIGN: operator_id="<<="; break;
3669 case TOK_SHRASSIGN: operator_id=">>="; break;
3670 case TOK_ANDASSIGN: operator_id="&="; break;
3671 case TOK_XORASSIGN: operator_id="^="; break;
3672 case TOK_ORASSIGN: operator_id="|="; break;
3673 case TOK_SHIFTLEFT: operator_id="<<"; break;
3674 case TOK_SHIFTRIGHT: operator_id=">>"; break;
3675 case TOK_EQ: operator_id="=="; break;
3676 case TOK_NE: operator_id="!="; break;
3677 case TOK_LE: operator_id="<="; break;
3678 case TOK_GE: operator_id=">="; break;
3679 case TOK_ANDAND: operator_id="&&"; break;
3680 case TOK_OROR: operator_id="||"; break;
3681 case TOK_INCR: operator_id="++"; break;
3682 case TOK_DECR: operator_id="--"; break;
3683 case TOK_DOTPM: operator_id=".*"; break;
3684 case TOK_ARROWPM: operator_id="->*"; break;
3685 case TOK_ARROW: operator_id="->"; break;
3686
3687 case TOK_NEW:
3688 case TOK_DELETE:
3689 {
3690 lex.get_token(tk);
3691
3692 if(lex.LookAhead(0)!='[')
3693 {
3694 name=irept(t==TOK_NEW?ID_cpp_new:ID_cpp_delete);
3695 set_location(name, tk);
3696 }
3697 else
3698 {
3699 name=irept(t==TOK_NEW?ID_cpp_new_array:ID_cpp_delete_array);
3700 set_location(name, tk);
3701
3702 lex.get_token(tk);
3703
3704 if(lex.get_token(tk)!=']')
3705 return false;
3706 }
3707 }
3708 return true;
3709
3710 case '(':
3711 lex.get_token(tk);
3712 name=irept("()");
3713 set_location(name, tk);
3714 return lex.get_token(tk)==')';
3715
3716 case '[':
3717 lex.get_token(tk);
3718 name=irept("[]");
3719 set_location(name, tk);
3720 return lex.get_token(tk)==']';
3721
3722 default:
3723 return rCastOperatorName(name);
3724 }
3725
3726 assert(!operator_id.empty());
3727 lex.get_token(tk);
3728 name=irept(operator_id);
3729 set_location(name, tk);
3730
3731 return true;
3732}
3733
3734/*
3735 cast.operator.name
3736 : {cv.qualify} (integral.or.class.spec | name) {cv.qualify}
3737 {(ptr.operator)*}
3738*/
3739
3741{
3742 typet cv1, cv2, type_name, ptr;
3743
3744 cv1.make_nil();
3745 cv2.make_nil();
3746 type_name.make_nil();
3747 ptr.make_nil();
3748
3749 if(!optCvQualify(cv1))
3750 return false;
3751
3752 if(!optIntegralTypeOrClassSpec(type_name))
3753 return false;
3754
3755 if(type_name.is_nil())
3756 {
3757 if(!rName(type_name))
3758 return false;
3759 }
3760
3761 merge_types(cv1, type_name);
3762
3763 if(!optCvQualify(cv2))
3764 return false;
3765
3766 if(!optPtrOperator(ptr))
3767 return false;
3768
3769 make_subtype(type_name, ptr);
3770 merge_types(cv2, ptr);
3771 name = ptr;
3772
3773 return true;
3774}
3775
3776/*
3777 ptr.to.member
3778 : {'::'} (identifier {template.args} '::')+ '*'
3779*/
3781{
3782#ifdef DEBUG
3783 indenter _i;
3784 std::cout << std::string(__indent, ' ') << "Parser::rPtrToMember 0\n";
3785#endif
3786
3787 typet ptm(ID_frontend_pointer); // width gets set during conversion
3788 irept &name = ptm.add(ID_to_member);
3789 name=cpp_namet();
3790 irept::subt &components=name.get_sub();
3791
3792 {
3793 cpp_tokent tk;
3794 lex.LookAhead(0, tk);
3795 set_location(name, tk);
3796 }
3797
3798 bool loop_cond = true;
3799 while(loop_cond)
3800 {
3801 cpp_tokent tk;
3802
3803 switch(lex.LookAhead(0))
3804 {
3805 case TOK_TEMPLATE:
3806 lex.get_token(tk);
3807 // Skip template token, next will be identifier
3808 if(lex.LookAhead(0)!=TOK_IDENTIFIER)
3809 return false;
3810 break;
3811
3812 case '<':
3813 {
3814 irept args;
3815 if(!rTemplateArgs(args))
3816 return false;
3817
3818 components.push_back(irept(ID_template_args));
3819 components.back().add(ID_arguments).swap(args);
3820
3821 if(lex.LookAhead(0)!=TOK_SCOPE)
3822 return false;
3823 }
3824 break;
3825
3826 case TOK_IDENTIFIER:
3827 lex.get_token(tk);
3828 components.push_back(cpp_namet::namet(tk.data.get(ID_C_base_name)));
3829 set_location(components.back(), tk);
3830
3831 {
3832 int t=lex.LookAhead(0);
3833 if(t!=TOK_SCOPE && t!='<')
3834 return false;
3835 }
3836 break;
3837
3838 case TOK_SCOPE:
3839 lex.get_token(tk);
3840 components.push_back(irept("::"));
3841 set_location(components.back(), tk);
3842
3843 // done if next token is '*'
3844 if(lex.LookAhead(0) == '*')
3845 {
3846 lex.get_token(tk);
3847 ptr_to_mem.swap(ptm);
3848
3849#ifdef DEBUG
3850 std::cout << std::string(__indent, ' ') << "Parser::rPtrToMember 1\n";
3851#endif
3852
3853 return true;
3854 }
3855
3856 if(lex.LookAhead(0) != TOK_IDENTIFIER)
3857 return false;
3858
3859 break;
3860
3861 default:
3862 return false;
3863 }
3864 }
3865 return false;
3866}
3867
3868/*
3869 template.args
3870 : '<' '>'
3871 | '<' template.argument {',' template.argument} '>'
3872
3873 template.argument
3874 : type.name
3875 | logical.or.expr
3876*/
3877bool Parser::rTemplateArgs(irept &template_args)
3878{
3879#ifdef DEBUG
3880 indenter _i;
3881 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 0\n";
3882#endif
3883
3884 cpp_tokent tk1;
3885
3886 if(lex.get_token(tk1)!='<')
3887 return false;
3888
3889 set_location(template_args, tk1);
3890
3891#ifdef DEBUG
3892 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 1\n";
3893#endif
3894
3895 // in case of Foo<>
3896 if(lex.LookAhead(0)=='>')
3897 {
3898 cpp_tokent tk2;
3899 lex.get_token(tk2);
3900 return true;
3901 }
3902
3903#ifdef DEBUG
3904 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 2\n";
3905#endif
3906
3907 for(;;)
3908 {
3909 exprt exp;
3911
3912#ifdef DEBUG
3913 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 3\n";
3914#endif
3915
3916 typet a;
3917
3918 // try type name first
3920 ((lex.LookAhead(0) == '>' || lex.LookAhead(0) == ',' ||
3921 lex.LookAhead(0)==TOK_SHIFTRIGHT) ||
3922 (lex.LookAhead(0)==TOK_ELLIPSIS &&
3923 (lex.LookAhead(1) == '>' ||
3924 lex.LookAhead(1)==TOK_SHIFTRIGHT)))
3925 )
3926 {
3927#ifdef DEBUG
3928 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 4\n";
3929#endif
3930
3931 // ok
3932 exp=exprt(ID_type);
3934 exp.type().swap(a);
3935
3936 // but could also be an expr
3937 lex.Restore(pos);
3938 exprt tmp;
3939 if(rConditionalExpr(tmp, true))
3940 exp.id(ID_ambiguous);
3941#ifdef DEBUG
3942 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 4.1\n";
3943#endif
3944 lex.Restore(pos);
3946
3947 if(lex.LookAhead(0)==TOK_ELLIPSIS)
3948 {
3949 lex.get_token(tk1);
3950
3951 // TODO
3952 }
3953#ifdef DEBUG
3954 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 4.2\n";
3955#endif
3956 }
3957 else
3958 {
3959 // parsing failed, try expression
3960#ifdef DEBUG
3961 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 5\n";
3962#endif
3963
3964 lex.Restore(pos);
3965
3966
3967 if(!rConditionalExpr(exp, true))
3968 return false;
3969
3970 if(lex.LookAhead(0)==TOK_ELLIPSIS)
3971 {
3972 lex.get_token(tk1);
3973
3974 // TODO
3975 }
3976 }
3977
3978#ifdef DEBUG
3979 std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 6\n";
3980#endif
3981
3982 template_args.get_sub().push_back(irept(irep_idt()));
3983 template_args.get_sub().back().swap(exp);
3984
3985 pos=lex.Save();
3986 cpp_tokent tk2;
3987 switch(lex.get_token(tk2))
3988 {
3989 case '>':
3990 return true;
3991
3992 case ',':
3993 break;
3994
3995 case TOK_SHIFTRIGHT: // turn >> into > >
3996 lex.Restore(pos);
3997 tk2.kind='>';
3998 tk2.text='>';
3999 lex.Replace(tk2);
4000 lex.Insert(tk2);
4001 assert(lex.LookAhead(0)=='>');
4002 assert(lex.LookAhead(1)=='>');
4003 return true;
4004
4005 default:
4006 return false;
4007 }
4008 }
4009}
4010
4011/*
4012 arg.decl.list.or.init
4013 : arg.decl.list
4014 | function.arguments
4015
4016 This rule accepts function.arguments to parse declarations like:
4017 Point p(1, 3);
4018 "(1, 3)" is arg.decl.list.or.init.
4019
4020 If maybe_init is true, we first examine whether tokens construct
4021 function.arguments. This ordering is significant if tokens are
4022 Point p(s, t);
4023 s and t can be type names or variable names.
4024*/
4026 exprt &arglist,
4027 bool &is_args,
4028 bool maybe_init)
4029{
4031 if(maybe_init)
4032 {
4033 if(rFunctionArguments(arglist))
4034 if(lex.LookAhead(0)==')')
4035 {
4036 is_args=false;
4037 // encode.Clear();
4038 return true;
4039 }
4040
4041 lex.Restore(pos);
4042 return(is_args=rArgDeclList(arglist));
4043 }
4044 else
4045 {
4046 is_args = rArgDeclList(arglist);
4047
4048 if(is_args)
4049 return true;
4050 else
4051 {
4052 lex.Restore(pos);
4053 // encode.Clear();
4054 return rFunctionArguments(arglist);
4055 }
4056 }
4057}
4058
4059/*
4060 arg.decl.list
4061 : empty
4062 | arg.declaration ( ',' arg.declaration )* {{ ',' } Ellipses}
4063*/
4065{
4066 irept list;
4067
4068 list.clear();
4069 for(;;)
4070 {
4071 cpp_declarationt declaration;
4072
4073 int t=lex.LookAhead(0);
4074 if(t==')')
4075 break;
4076 else if(t==TOK_ELLIPSIS)
4077 {
4078 cpp_tokent tk;
4079 lex.get_token(tk);
4080 list.get_sub().push_back(irept(ID_ellipsis));
4081 break;
4082 }
4083 else if(rArgDeclaration(declaration))
4084 {
4085 cpp_tokent tk;
4086
4087 list.get_sub().push_back(irept(irep_idt()));
4088 list.get_sub().back().swap(declaration);
4089 t=lex.LookAhead(0);
4090 if(t==',')
4091 lex.get_token(tk);
4092 else if(t==TOK_ELLIPSIS)
4093 {
4094 lex.get_token(tk);
4095 list.get_sub().push_back(irept(ID_ellipsis));
4096 }
4097 else if(t!=')' && t!=TOK_ELLIPSIS)
4098 return false;
4099 }
4100 else
4101 {
4102 arglist.clear();
4103 return false;
4104 }
4105 }
4106
4107 arglist.swap(list);
4108
4109 return true;
4110}
4111
4112/*
4113 arg.declaration
4114 : {userdef.keyword | REGISTER} type.specifier arg.declarator
4115 {'=' expression}
4116*/
4118{
4119 typet header;
4120 cpp_tokent tk;
4121
4122 switch(lex.LookAhead(0))
4123 {
4124 case TOK_REGISTER:
4125 lex.get_token(tk);
4126 header=typet(ID_register);
4127 break;
4128
4129 default:
4130 header.make_nil();
4131 break;
4132 }
4133
4134 if(!rTypeSpecifier(declaration.type(), true))
4135 return false;
4136
4137 cpp_declaratort arg_declarator;
4138
4139 if(!rDeclarator(arg_declarator, kArgDeclarator, true, false))
4140 return false;
4141
4142 arg_declarator.set_is_parameter(true);
4143
4144 declaration.declarators().push_back(arg_declarator);
4145
4146 int t=lex.LookAhead(0);
4147 if(t=='=')
4148 {
4149 lex.get_token(tk);
4150 if(!rInitializeExpr(declaration.declarators().back().value()))
4151 return false;
4152 }
4153
4154 return true;
4155}
4156
4157/*
4158 initialize.expr
4159 : expression
4160 | '{' initialize.expr (',' initialize.expr)* {','} '}'
4161*/
4163{
4164 if(lex.LookAhead(0)!='{')
4165 return rExpression(expr, false);
4166
4167 // we want { initialize_expr, ... }
4168
4169 cpp_tokent tk;
4170 lex.get_token(tk);
4171
4172 exprt e;
4173
4174 expr.id(ID_initializer_list);
4175 set_location(expr, tk);
4176
4177 int t=lex.LookAhead(0);
4178
4179 while(t!='}')
4180 {
4181 exprt tmp;
4182
4183 if(t==TOK_MSC_IF_EXISTS ||
4184 t==TOK_MSC_IF_NOT_EXISTS)
4185 {
4186 // TODO
4187 exprt name;
4188 lex.get_token(tk);
4189 if(lex.get_token(tk)!='(')
4190 return false;
4191 if(!rVarName(name))
4192 return false;
4193 if(lex.get_token(tk)!=')')
4194 return false;
4195 if(lex.get_token(tk)!='{')
4196 return false;
4197 if(!rInitializeExpr(name))
4198 return false;
4199 if(lex.LookAhead(0)==',')
4200 lex.get_token(tk);
4201 if(lex.get_token(tk)!='}')
4202 return false;
4203 }
4204
4205 if(!rInitializeExpr(tmp))
4206 {
4207 if(!SyntaxError())
4208 return false; // too many errors
4209
4210 SkipTo('}');
4211 lex.get_token(tk);
4212 return true; // error recovery
4213 }
4214
4215 expr.add_to_operands(std::move(tmp));
4216
4217 t=lex.LookAhead(0);
4218 if(t=='}')
4219 {
4220 // done!
4221 }
4222 else if(t==',')
4223 {
4224 lex.get_token(tk);
4225 t=lex.LookAhead(0);
4226 }
4227 else
4228 {
4229 if(!SyntaxError())
4230 return false; // too many errors
4231
4232 SkipTo('}');
4233 lex.get_token(tk);
4234 return true; // error recovery
4235 }
4236 }
4237
4238 lex.get_token(tk);
4239
4240 return true;
4241}
4242
4243/*
4244 function.arguments
4245 : empty
4246 | expression (',' expression)*
4247
4248 This assumes that the next token following function.arguments is ')'.
4249*/
4251{
4252 exprt exp;
4253 cpp_tokent tk;
4254
4255 args=exprt(irep_idt());
4256 if(lex.LookAhead(0)==')')
4257 return true;
4258
4259 for(;;)
4260 {
4261 if(!rExpression(exp, false))
4262 return false;
4263
4264 args.add_to_operands(std::move(exp));
4265
4266 if(lex.LookAhead(0)==TOK_ELLIPSIS &&
4267 (lex.LookAhead(1)==')' || lex.LookAhead(1)==','))
4268 {
4269 lex.get_token(tk);
4270 // TODO
4271
4272 if(lex.LookAhead(0)==')')
4273 return true;
4274 lex.get_token();
4275 }
4276 else if(lex.LookAhead(0)!=',')
4277 return true;
4278 else
4279 lex.get_token(tk);
4280 }
4281}
4282
4283/*
4284 enum.spec
4285 : ENUM Identifier
4286 | ENUM {Identifier} '{' {enum.body} '}'
4287 | ENUM CLASS Identifier '{' {enum.body} '}'
4288 | ENUM CLASS Identifier ':' Type '{' {enum.body} '}'
4289*/
4291{
4292#ifdef DEBUG
4293 indenter _i;
4294 std::cout << std::string(__indent, ' ') << "Parser::rEnumSpec 1\n";
4295#endif
4296
4297 cpp_tokent tk;
4298
4299 if(lex.get_token(tk)!=TOK_ENUM)
4300 return false;
4301
4302 spec=cpp_enum_typet();
4303 set_location(spec, tk);
4304
4305 spec.subtype().make_nil();
4306
4307 // C++11 enum classes
4308 if(lex.LookAhead(0)==TOK_CLASS)
4309 {
4310 lex.get_token(tk);
4311 spec.set(ID_C_class, true);
4312 }
4313
4314 if(lex.LookAhead(0)!='{' &&
4315 lex.LookAhead(0)!=':')
4316 {
4317 // Visual Studio allows full names for the tag,
4318 // not just an identifier
4319 irept name;
4320
4321 if(!rName(name))
4322 return false;
4323
4324 spec.add(ID_tag).swap(name);
4325 }
4326
4327#ifdef DEBUG
4328 std::cout << std::string(__indent, ' ') << "Parser::rEnumSpec 2\n";
4329#endif
4330
4331 // C++11 enums have an optional underlying type
4332 if(lex.LookAhead(0)==':')
4333 {
4334 lex.get_token(tk); // read the colon
4335 if(!rTypeName(spec.subtype()))
4336 return false;
4337 }
4338
4339#ifdef DEBUG
4340 std::cout << std::string(__indent, ' ') << "Parser::rEnumSpec 3\n";
4341#endif
4342
4343 if(lex.LookAhead(0)!='{')
4344 return true; // ok, no body
4345
4346 lex.get_token(tk);
4347
4348 if(lex.LookAhead(0)=='}')
4349 {
4350 // there is still a body, just an empty one!
4351 spec.add(ID_body);
4352 }
4353 else
4354 if(!rEnumBody(spec.add(ID_body)))
4355 return false;
4356
4357 // there must be closing '}'
4358
4359 if(lex.get_token(tk)!='}')
4360 return false;
4361
4362#ifdef DEBUG
4363 std::cout << std::string(__indent, ' ') << "Parser::rEnumSpec 4\n";
4364#endif
4365
4366 return true;
4367}
4368
4369/*
4370 enum.body
4371 : Identifier {'=' expression} (',' Identifier {'=' expression})* {','}
4372*/
4374{
4375 body.clear();
4376
4377 for(;;)
4378 {
4379 cpp_tokent tk, tk2;
4380
4381 if(lex.LookAhead(0)=='}')
4382 return true;
4383
4384 if(lex.get_token(tk)!=TOK_IDENTIFIER)
4385 return false;
4386
4387 body.get_sub().push_back(irept());
4388 irept &n=body.get_sub().back();
4389 set_location(n, tk);
4390 n.set(ID_name, tk.data.get(ID_C_base_name));
4391
4392 if(lex.LookAhead(0, tk2)=='=') // set the constant
4393 {
4394 lex.get_token(tk2); // read the '='
4395
4396 exprt exp;
4397
4398 if(!rExpression(exp, false))
4399 {
4400 if(!SyntaxError())
4401 return false; // too many errors
4402
4403 SkipTo('}');
4404 body.clear(); // empty
4405 return true; // error recovery
4406 }
4407
4408 n.add(ID_value).swap(exp);
4409 }
4410 else
4411 n.add(ID_value).make_nil();
4412
4413 if(lex.LookAhead(0)!=',')
4414 return true;
4415
4416 lex.get_token(tk);
4417 }
4418}
4419
4420/*
4421 class.spec
4422 : {userdef.keyword} class.key class.body
4423 | {userdef.keyword} class.key name {class.body}
4424 | {userdef.keyword} class.key name ':' base.specifiers class.body
4425
4426 class.key
4427 : CLASS | STRUCT | UNION | INTERFACE
4428*/
4430{
4431 cpp_tokent tk;
4432
4433#ifdef DEBUG
4434 indenter _i;
4435 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 1\n";
4436#endif
4437
4438 int t=lex.get_token(tk);
4439 if(t!=TOK_CLASS && t!=TOK_STRUCT &&
4440 t!=TOK_UNION && t!=TOK_INTERFACE)
4441 return false;
4442
4443#ifdef DEBUG
4444 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 2\n";
4445#endif
4446
4447 if(t==TOK_CLASS)
4448 {
4449 spec=typet(ID_struct);
4450 spec.set(ID_C_class, true);
4451 }
4452 else if(t==TOK_INTERFACE) // MS-specific
4453 {
4454 spec=typet(ID_struct);
4455 spec.set(ID_C_interface, true);
4456 }
4457 else if(t==TOK_STRUCT)
4458 spec=typet(ID_struct);
4459 else if(t==TOK_UNION)
4460 spec=typet(ID_union);
4461 else
4463
4464 set_location(spec, tk);
4465
4466#ifdef DEBUG
4467 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 3\n";
4468#endif
4469
4470 if(lex.LookAhead(0)=='{')
4471 {
4472 // no tag
4473#ifdef DEBUG
4474 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 4\n";
4475#endif
4476 }
4477 else
4478 {
4479 if(!optAlignas(spec))
4480 return false;
4481
4482 if(lex.LookAhead(0)==TOK_GCC_ATTRIBUTE)
4483 {
4484 lex.get_token(tk);
4485
4486 if(!rAttribute(spec))
4487 return false;
4488 }
4489
4490 irept name;
4491
4492 if(!rName(name))
4493 return false;
4494
4495 spec.add(ID_tag).swap(name);
4496
4497#ifdef DEBUG
4498 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 5\n";
4499#endif
4500
4501 t=lex.LookAhead(0);
4502
4503 if(t==':')
4504 {
4505 if(!rBaseSpecifiers(spec.add(ID_bases)))
4506 return false;
4507 }
4508 else if(t=='{')
4509 {
4510 }
4511 else
4512 {
4513 return true;
4514 }
4515 }
4516
4517#ifdef DEBUG
4518 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 6\n";
4519#endif
4520
4521 save_scopet saved_scope(current_scope);
4523
4524 exprt body;
4525
4526 if(!rClassBody(body))
4527 return false;
4528
4529#ifdef DEBUG
4530 std::cout << std::string(__indent, ' ') << "Parser::rClassSpec 7\n";
4531#endif
4532
4533 ((exprt&)spec.add(ID_body)).operands().swap(body.operands());
4534 return true;
4535}
4536
4537/*
4538 base.specifiers
4539 : ':' base.specifier (',' base.specifier)*
4540
4541 base.specifier
4542 : {{VIRTUAL} (PUBLIC | PROTECTED | PRIVATE) {VIRTUAL}} name
4543*/
4545{
4546 cpp_tokent tk;
4547
4548 if(lex.get_token(tk)!=':')
4549 return false;
4550
4551 for(;;)
4552 {
4553 int t=lex.LookAhead(0);
4554 irept base(ID_base);
4555
4556 if(t==TOK_VIRTUAL)
4557 {
4558 lex.get_token(tk);
4559 base.set(ID_virtual, true);
4560 t=lex.LookAhead(0);
4561 }
4562
4563 if(t==TOK_PUBLIC || t==TOK_PROTECTED || t==TOK_PRIVATE)
4564 {
4565 switch(lex.get_token(tk))
4566 {
4567 case TOK_PUBLIC:
4568 base.set(ID_protection, ID_public);
4569 break;
4570
4571 case TOK_PROTECTED:
4572 base.set(ID_protection, ID_protected);
4573 break;
4574
4575 case TOK_PRIVATE:
4576 base.set(ID_protection, ID_private);
4577 break;
4578
4579 default:
4581 }
4582
4583 t=lex.LookAhead(0);
4584 }
4585
4586 if(t==TOK_VIRTUAL)
4587 {
4588 lex.get_token(tk);
4589 base.set(ID_virtual, true);
4590 }
4591
4592 if(!rName(base.add(ID_name)))
4593 return false;
4594
4595 if(lex.LookAhead(0)==TOK_ELLIPSIS)
4596 {
4597 lex.get_token();
4598
4599 // TODO
4600 }
4601
4602 bases.get_sub().push_back(irept());
4603 bases.get_sub().back().swap(base);
4604
4605 if(lex.LookAhead(0)!=',')
4606 return true;
4607 else
4608 lex.get_token(tk);
4609 }
4610}
4611
4612/*
4613 class.body : '{' (class.members)* '}'
4614*/
4616{
4617 cpp_tokent tk;
4618
4619#ifdef DEBUG
4620 indenter _i;
4621 std::cout << std::string(__indent, ' ') << "Parser::rClassBody 0\n";
4622#endif
4623
4624 if(lex.get_token(tk)!='{')
4625 return false;
4626
4627 exprt members=exprt("cpp-class-body");
4628
4629 set_location(members, tk);
4630
4631 while(lex.LookAhead(0)!='}')
4632 {
4633 cpp_itemt member;
4634
4635 if(!rClassMember(member))
4636 {
4637 if(!SyntaxError())
4638 return false; // too many errors
4639
4640 SkipTo('}');
4641 lex.get_token(tk);
4642 // body=Ptree::List(ob, nil, new Leaf(tk));
4643 return true; // error recovery
4644 }
4645#ifdef DEBUG
4646 std::cout << std::string(__indent, ' ') << "Parser::rClassBody "
4647 << member.pretty() << '\n';
4648#endif
4649
4650 members.add_to_operands(
4651 std::move(static_cast<exprt &>(static_cast<irept &>(member))));
4652 }
4653
4654 lex.get_token(tk);
4655 body.swap(members);
4656 return true;
4657}
4658
4659/*
4660 class.member
4661 : (PUBLIC | PROTECTED | PRIVATE) ':'
4662 | user.access.spec
4663 | ';'
4664 | type.def
4665 | template.decl
4666 | using.declaration
4667 | metaclass.decl
4668 | declaration
4669 | access.decl
4670 | static_assert
4671
4672 Note: if you modify this function, see ClassWalker::TranslateClassSpec()
4673 as well.
4674*/
4676{
4677 cpp_tokent tk1, tk2;
4678
4679 int t=lex.LookAhead(0);
4680
4681#ifdef DEBUG
4682 indenter _i;
4683 std::cout << std::string(__indent, ' ') << "Parser::rClassMember 0 " << t
4684 << '\n';
4685#endif // DEBUG
4686
4687 if(t==TOK_PUBLIC || t==TOK_PROTECTED || t==TOK_PRIVATE)
4688 {
4689 switch(lex.get_token(tk1))
4690 {
4691 case TOK_PUBLIC:
4692 member.id("cpp-public");
4693 break;
4694
4695 case TOK_PROTECTED:
4696 member.id("cpp-protected");
4697 break;
4698
4699 case TOK_PRIVATE:
4700 member.id("cpp-private");
4701 break;
4702
4703 default:
4705 }
4706
4707 set_location(member, tk1);
4708
4709 if(lex.get_token(tk2)!=':')
4710 return false;
4711
4712 return true;
4713 }
4714 else if(t==';')
4715 return rNullDeclaration(member.make_declaration());
4716 else if(t==TOK_TYPEDEF)
4717 return rTypedef(member.make_declaration());
4718 else if(t==TOK_TEMPLATE)
4719 return rTemplateDecl(member.make_declaration());
4720 else if(t==TOK_USING &&
4721 lex.LookAhead(1)==TOK_IDENTIFIER &&
4722 lex.LookAhead(2)=='=')
4723 return rTypedefUsing(member.make_declaration());
4724 else if(t==TOK_USING)
4725 return rUsing(member.make_using());
4726 else if(t==TOK_STATIC_ASSERT)
4727 return rStaticAssert(member.make_static_assert());
4728 else
4729 {
4731 if(rDeclaration(member.make_declaration()))
4732 return true;
4733
4734 lex.Restore(pos);
4735 return rAccessDecl(member.make_declaration());
4736 }
4737}
4738
4739/*
4740 access.decl
4741 : name ';' e.g. <qualified class>::<member name>;
4742*/
4744{
4745 cpp_namet name;
4746 cpp_tokent tk;
4747
4748 if(!rName(name))
4749 return false;
4750
4751 if(lex.get_token(tk)!=';')
4752 return false;
4753
4754 cpp_declaratort name_decl;
4755 name_decl.name() = name;
4756 mem.declarators().push_back(name_decl);
4757
4758 // mem=new PtreeAccessDecl(new PtreeName(name, encode),
4759 // Ptree::List(new Leaf(tk)));
4760 return true;
4761}
4762
4763/*
4764 comma.expression
4765 : expression
4766 | comma.expression ',' expression (left-to-right)
4767*/
4769{
4770#ifdef DEBUG
4771 indenter _i;
4772 std::cout << std::string(__indent, ' ') << "Parser::rCommaExpression 0\n";
4773#endif
4774
4775 if(!rExpression(exp, false))
4776 return false;
4777
4778#ifdef DEBUG
4779 std::cout << std::string(__indent, ' ') << "Parser::rCommaExpression 1\n";
4780#endif
4781
4782 while(lex.LookAhead(0)==',')
4783 {
4784 cpp_tokent tk;
4785
4786 lex.get_token(tk);
4787
4788 exprt right;
4789 if(!rExpression(right, false))
4790 return false;
4791
4792 exprt left;
4793 left.swap(exp);
4794
4795 exp=exprt(ID_comma);
4796 exp.add_to_operands(std::move(left), std::move(right));
4797 set_location(exp, tk);
4798 }
4799
4800#ifdef DEBUG
4801 std::cout << std::string(__indent, ' ') << "Parser::rCommaExpression 2\n";
4802#endif
4803
4804 return true;
4805}
4806
4807/*
4808 expression
4809 : conditional.expr {(AssignOp | '=') expression} right-to-left
4810*/
4811bool Parser::rExpression(exprt &exp, bool template_args)
4812{
4813 cpp_tokent tk;
4814
4815#ifdef DEBUG
4816 indenter _i;
4817 std::cout << std::string(__indent, ' ') << "Parser::rExpression 0\n";
4818#endif
4819
4820 if(!rConditionalExpr(exp, template_args))
4821 return false;
4822
4823#ifdef DEBUG
4824 std::cout << std::string(__indent, ' ') << "Parser::rExpression 1\n";
4825#endif
4826
4827 int t=lex.LookAhead(0);
4828
4829 if(t=='=' ||
4830 t==TOK_MULTASSIGN || t==TOK_DIVASSIGN || t==TOK_MODASSIGN ||
4831 t==TOK_PLUSASSIGN || t==TOK_MINUSASSIGN || t==TOK_SHLASSIGN ||
4832 t==TOK_SHRASSIGN || t==TOK_ANDASSIGN ||
4833 t==TOK_XORASSIGN || t==TOK_ORASSIGN)
4834 {
4835 lex.get_token(tk);
4836
4837#ifdef DEBUG
4838 std::cout << std::string(__indent, ' ') << "Parser::rExpression 2\n";
4839#endif
4840
4841 exprt right;
4842 if(!rExpression(right, template_args))
4843 return false;
4844
4845#ifdef DEBUG
4846 std::cout << std::string(__indent, ' ') << "Parser::rExpression 3\n";
4847#endif
4848
4849 exprt left;
4850 left.swap(exp);
4851
4852 exp=exprt(ID_side_effect);
4853
4854 if(t=='=')
4855 exp.set(ID_statement, ID_assign);
4856 else if(t==TOK_PLUSASSIGN)
4857 exp.set(ID_statement, ID_assign_plus);
4858 else if(t==TOK_MINUSASSIGN)
4859 exp.set(ID_statement, ID_assign_minus);
4860 else if(t==TOK_MULTASSIGN)
4861 exp.set(ID_statement, ID_assign_mult);
4862 else if(t==TOK_DIVASSIGN)
4863 exp.set(ID_statement, ID_assign_div);
4864 else if(t==TOK_MODASSIGN)
4865 exp.set(ID_statement, ID_assign_mod);
4866 else if(t==TOK_SHLASSIGN)
4867 exp.set(ID_statement, ID_assign_shl);
4868 else if(t==TOK_SHRASSIGN)
4869 exp.set(ID_statement, ID_assign_shr);
4870 else if(t==TOK_ANDASSIGN)
4871 exp.set(ID_statement, ID_assign_bitand);
4872 else if(t==TOK_XORASSIGN)
4873 exp.set(ID_statement, ID_assign_bitxor);
4874 else if(t==TOK_ORASSIGN)
4875 exp.set(ID_statement, ID_assign_bitor);
4876
4877 exp.add_to_operands(std::move(left), std::move(right));
4878 set_location(exp, tk);
4879 }
4880
4881#ifdef DEBUG
4882 std::cout << std::string(__indent, ' ') << "Parser::rExpression 4\n";
4883#endif
4884
4885 return true;
4886}
4887
4888/*
4889 conditional.expr
4890 : logical.or.expr {'?' comma.expression ':' conditional.expr} right-to-left
4891*/
4892bool Parser::rConditionalExpr(exprt &exp, bool template_args)
4893{
4894#ifdef DEBUG
4895 indenter _i;
4896 std::cout << std::string(__indent, ' ') << "Parser::rConditionalExpr 0\n";
4897#endif
4898
4899 if(!rLogicalOrExpr(exp, template_args))
4900 return false;
4901
4902#ifdef DEBUG
4903 std::cout << std::string(__indent, ' ') << "Parser::rConditionalExpr 1\n";
4904#endif
4905
4906 if(lex.LookAhead(0)=='?')
4907 {
4908 cpp_tokent tk1, tk2;
4909 exprt then, otherwise;
4910
4911 lex.get_token(tk1);
4912 if(!rCommaExpression(then))
4913 return false;
4914
4915#ifdef DEBUG
4916 std::cout << std::string(__indent, ' ') << "Parser::rConditionalExpr 2\n";
4917#endif
4918
4919 if(lex.get_token(tk2)!=':')
4920 return false;
4921
4922 if(!rExpression(otherwise, template_args))
4923 return false;
4924
4925 exprt cond;
4926 cond.swap(exp);
4927
4928 exp =
4929 if_exprt(std::move(cond), std::move(then), std::move(otherwise), typet());
4930 set_location(exp, tk1);
4931 }
4932
4933 return true;
4934}
4935
4936/*
4937 logical.or.expr
4938 : logical.and.expr
4939 | logical.or.expr LogOrOp logical.and.expr left-to-right
4940*/
4941bool Parser::rLogicalOrExpr(exprt &exp, bool template_args)
4942{
4943#ifdef DEBUG
4944 indenter _i;
4945 std::cout << std::string(__indent, ' ') << "Parser::rLogicalOrExpr 0\n";
4946#endif
4947
4948 if(!rLogicalAndExpr(exp, template_args))
4949 return false;
4950
4951#ifdef DEBUG
4952 std::cout << std::string(__indent, ' ') << "Parser::rLogicalOrExpr 1\n";
4953#endif
4954
4955 while(lex.LookAhead(0)==TOK_OROR)
4956 {
4957 cpp_tokent tk;
4958 lex.get_token(tk);
4959
4960 exprt right;
4961 if(!rLogicalAndExpr(right, template_args))
4962 return false;
4963
4964 exprt left;
4965 left.swap(exp);
4966
4967 exp=exprt(ID_or);
4968 exp.add_to_operands(std::move(left), std::move(right));
4969 set_location(exp, tk);
4970 }
4971
4972 return true;
4973}
4974
4975/*
4976 logical.and.expr
4977 : inclusive.or.expr
4978 | logical.and.expr LogAndOp inclusive.or.expr
4979*/
4980bool Parser::rLogicalAndExpr(exprt &exp, bool template_args)
4981{
4982#ifdef DEBUG
4983 indenter _i;
4984 std::cout << std::string(__indent, ' ') << "Parser::rLogicalAndExpr 1\n";
4985#endif
4986
4987 if(!rInclusiveOrExpr(exp, template_args))
4988 return false;
4989
4990#ifdef DEBUG
4991 std::cout << std::string(__indent, ' ') << "Parser::rLogicalAndExpr 1\n";
4992#endif
4993
4994 while(lex.LookAhead(0)==TOK_ANDAND)
4995 {
4996 cpp_tokent tk;
4997 lex.get_token(tk);
4998
4999 exprt right;
5000 if(!rInclusiveOrExpr(right, template_args))
5001 return false;
5002
5003 exprt left;
5004 left.swap(exp);
5005
5006 exp=exprt(ID_and);
5007 exp.add_to_operands(std::move(left), std::move(right));
5008 set_location(exp, tk);
5009 }
5010
5011 return true;
5012}
5013
5014/*
5015 inclusive.or.expr
5016 : exclusive.or.expr
5017 | inclusive.or.expr '|' exclusive.or.expr
5018*/
5019bool Parser::rInclusiveOrExpr(exprt &exp, bool template_args)
5020{
5021#ifdef DEBUG
5022 indenter _i;
5023 std::cout << std::string(__indent, ' ') << "Parser::rInclusiveOrExpr 0\n";
5024#endif
5025
5026 if(!rExclusiveOrExpr(exp, template_args))
5027 return false;
5028
5029#ifdef DEBUG
5030 std::cout << std::string(__indent, ' ') << "Parser::rInclusiveOrExpr 1\n";
5031#endif
5032
5033 while(lex.LookAhead(0)=='|')
5034 {
5035 cpp_tokent tk;
5036 lex.get_token(tk);
5037
5038 exprt right;
5039 if(!rExclusiveOrExpr(right, template_args))
5040 return false;
5041
5042 exprt left;
5043 left.swap(exp);
5044
5045 exp=exprt(ID_bitor);
5046 exp.add_to_operands(std::move(left), std::move(right));
5047 set_location(exp, tk);
5048 }
5049
5050 return true;
5051}
5052
5053/*
5054 exclusive.or.expr
5055 : and.expr
5056 | exclusive.or.expr '^' and.expr
5057*/
5058bool Parser::rExclusiveOrExpr(exprt &exp, bool template_args)
5059{
5060#ifdef DEBUG
5061 indenter _i;
5062 std::cout << std::string(__indent, ' ') << "Parser::rExclusiveOrExpr 0\n";
5063#endif
5064
5065 if(!rAndExpr(exp, template_args))
5066 return false;
5067
5068#ifdef DEBUG
5069 std::cout << std::string(__indent, ' ') << "Parser::rExclusiveOrExpr 1\n";
5070#endif
5071
5072 while(lex.LookAhead(0)=='^')
5073 {
5074 cpp_tokent tk;
5075 lex.get_token(tk);
5076
5077 exprt right;
5078 if(!rAndExpr(right, template_args))
5079 return false;
5080
5081 exprt left;
5082 left.swap(exp);
5083
5084 exp=exprt(ID_bitxor);
5085 exp.add_to_operands(std::move(left), std::move(right));
5086 set_location(exp, tk);
5087 }
5088
5089 return true;
5090}
5091
5092/*
5093 and.expr
5094 : equality.expr
5095 | and.expr '&' equality.expr
5096*/
5097bool Parser::rAndExpr(exprt &exp, bool template_args)
5098{
5099#ifdef DEBUG
5100 indenter _i;
5101 std::cout << std::string(__indent, ' ') << "Parser::rAndExpr 0\n";
5102#endif
5103
5104 if(!rEqualityExpr(exp, template_args))
5105 return false;
5106
5107#ifdef DEBUG
5108 std::cout << std::string(__indent, ' ') << "Parser::rAndExpr 1\n";
5109#endif
5110
5111 while(lex.LookAhead(0)=='&')
5112 {
5113 cpp_tokent tk;
5114 lex.get_token(tk);
5115
5116 exprt right;
5117 if(!rEqualityExpr(right, template_args))
5118 return false;
5119
5120 exprt left;
5121 left.swap(exp);
5122
5123 exp=exprt(ID_bitand);
5124 exp.add_to_operands(std::move(left), std::move(right));
5125 set_location(exp, tk);
5126 }
5127
5128 return true;
5129}
5130
5131/*
5132 equality.expr
5133 : relational.expr
5134 | equality.expr EqualOp relational.expr
5135*/
5136bool Parser::rEqualityExpr(exprt &exp, bool template_args)
5137{
5138#ifdef DEBUG
5139 indenter _i;
5140 std::cout << std::string(__indent, ' ') << "Parser::rEqualityExpr 0\n";
5141#endif
5142
5143 if(!rRelationalExpr(exp, template_args))
5144 return false;
5145
5146#ifdef DEBUG
5147 std::cout << std::string(__indent, ' ') << "Parser::rEqualityExpr 1\n";
5148#endif
5149
5150 while(lex.LookAhead(0)==TOK_EQ ||
5151 lex.LookAhead(0)==TOK_NE)
5152 {
5153 cpp_tokent tk;
5154 lex.get_token(tk);
5155
5156 exprt right;
5157 if(!rRelationalExpr(right, template_args))
5158 return false;
5159
5160 exprt left;
5161 left.swap(exp);
5162
5163 exp=exprt(tk.kind==TOK_EQ?ID_equal:ID_notequal);
5164 exp.add_to_operands(std::move(left), std::move(right));
5165 set_location(exp, tk);
5166 }
5167
5168 return true;
5169}
5170
5171/*
5172 relational.expr
5173 : shift.expr
5174 | relational.expr (RelOp | '<' | '>') shift.expr
5175*/
5176bool Parser::rRelationalExpr(exprt &exp, bool template_args)
5177{
5178#ifdef DEBUG
5179 indenter _i;
5180 std::cout << std::string(__indent, ' ') << "Parser::rRelationalExpr 0\n";
5181#endif
5182
5183 if(!rShiftExpr(exp, template_args))
5184 return false;
5185
5186#ifdef DEBUG
5187 std::cout << std::string(__indent, ' ') << "Parser::rRelationalExpr 1\n";
5188#endif
5189
5190 int t;
5191
5192 while(t=lex.LookAhead(0),
5193 (t==TOK_LE || t==TOK_GE || t=='<' || (t=='>' && !template_args)))
5194 {
5195 cpp_tokent tk;
5196 lex.get_token(tk);
5197
5198 exprt right;
5199 if(!rShiftExpr(right, template_args))
5200 return false;
5201
5202 exprt left;
5203 left.swap(exp);
5204
5205 irep_idt id;
5206
5207 switch(t)
5208 {
5209 case TOK_LE: id=ID_le; break;
5210 case TOK_GE: id=ID_ge; break;
5211 case '<': id=ID_lt; break;
5212 case '>': id=ID_gt; break;
5213 }
5214
5215 exp=exprt(id);
5216 exp.add_to_operands(std::move(left), std::move(right));
5217 set_location(exp, tk);
5218 }
5219
5220 return true;
5221}
5222
5223/*
5224 shift.expr
5225 : additive.expr
5226 | shift.expr ShiftOp additive.expr
5227*/
5228bool Parser::rShiftExpr(exprt &exp, bool template_args)
5229{
5230#ifdef DEBUG
5231 indenter _i;
5232 std::cout << std::string(__indent, ' ') << "Parser::rShiftExpr 0\n";
5233#endif
5234
5235 if(!rAdditiveExpr(exp))
5236 return false;
5237
5238#ifdef DEBUG
5239 std::cout << std::string(__indent, ' ') << "Parser::rShiftExpr 1\n";
5240#endif
5241
5242 while(lex.LookAhead(0)==TOK_SHIFTLEFT ||
5243 (lex.LookAhead(0)==TOK_SHIFTRIGHT && !template_args))
5244 {
5245 cpp_tokent tk;
5246 lex.get_token(tk);
5247
5248 exprt right;
5249 if(!rAdditiveExpr(right))
5250 return false;
5251
5252 exprt left;
5253 left.swap(exp);
5254
5255 exp=exprt((tk.kind==TOK_SHIFTRIGHT)?ID_shr:ID_shl);
5256 exp.add_to_operands(std::move(left), std::move(right));
5257 set_location(exp, tk);
5258 }
5259
5260 return true;
5261}
5262
5263/*
5264 additive.expr
5265 : multiply.expr
5266 | additive.expr ('+' | '-') multiply.expr
5267*/
5269{
5270#ifdef DEBUG
5271 indenter _i;
5272 std::cout << std::string(__indent, ' ') << "Parser::rAdditiveExpr 0\n";
5273#endif
5274
5275 if(!rMultiplyExpr(exp))
5276 return false;
5277
5278#ifdef DEBUG
5279 std::cout << std::string(__indent, ' ') << "Parser::rAdditiveExpr 1\n";
5280#endif
5281
5282 int t;
5283 while(t=lex.LookAhead(0), (t=='+' || t=='-'))
5284 {
5285 cpp_tokent tk;
5286 lex.get_token(tk);
5287
5288 exprt right;
5289 if(!rMultiplyExpr(right))
5290 return false;
5291
5292 exprt left;
5293 left.swap(exp);
5294
5295 irep_idt id;
5296 switch(t)
5297 {
5298 case '+': id=ID_plus; break;
5299 case '-': id=ID_minus; break;
5300 }
5301
5302 exp=exprt(id);
5303 exp.add_to_operands(std::move(left), std::move(right));
5304 set_location(exp, tk);
5305 }
5306
5307 return true;
5308}
5309
5310/*
5311 multiply.expr
5312 : pm.expr
5313 | multiply.expr ('*' | '/' | '%') pm.expr
5314*/
5316{
5317#ifdef DEBUG
5318 indenter _i;
5319 std::cout << std::string(__indent, ' ') << "Parser::rMultiplyExpr 0\n";
5320#endif
5321
5322 if(!rPmExpr(exp))
5323 return false;
5324
5325#ifdef DEBUG
5326 std::cout << std::string(__indent, ' ') << "Parser::rMultiplyExpr 1\n";
5327#endif
5328
5329 int t;
5330 while(t=lex.LookAhead(0), (t=='*' || t=='/' || t=='%'))
5331 {
5332 cpp_tokent tk;
5333 lex.get_token(tk);
5334
5335 exprt right;
5336 if(!rPmExpr(right))
5337 return false;
5338
5339 exprt left;
5340 left.swap(exp);
5341
5342 irep_idt id;
5343 switch(t)
5344 {
5345 case '*': id=ID_mult; break;
5346 case '/': id=ID_div; break;
5347 case '%': id=ID_mod; break;
5348 }
5349
5350 exp=exprt(id);
5351 exp.add_to_operands(std::move(left), std::move(right));
5352 set_location(exp, tk);
5353 }
5354
5355#ifdef DEBUG
5356 std::cout << std::string(__indent, ' ') << "Parser::rMultiplyExpr 2\n";
5357#endif
5358
5359 return true;
5360}
5361
5362/*
5363 pm.expr (pointer to member .*, ->*)
5364 : cast.expr
5365 | pm.expr DOTPM cast.expr
5366 | pm.expr ARROWPM cast.expr
5367*/
5369{
5370#ifdef DEBUG
5371 indenter _i;
5372 std::cout << std::string(__indent, ' ') << "Parser::rPmExpr 0\n";
5373#endif
5374
5375 if(!rCastExpr(exp))
5376 return false;
5377
5378#ifdef DEBUG
5379 std::cout << std::string(__indent, ' ') << "Parser::rPmExpr 1\n";
5380#endif
5381
5382 while(lex.LookAhead(0)==TOK_DOTPM ||
5383 lex.LookAhead(0)==TOK_ARROWPM)
5384 {
5385 cpp_tokent tk;
5386 lex.get_token(tk);
5387
5388 exprt right;
5389 if(!rCastExpr(right))
5390 return false;
5391
5392 exprt left;
5393 left.swap(exp);
5394
5395 exp = exprt(ID_pointer_to_member);
5396 exp.add_to_operands(std::move(left), std::move(right));
5397 set_location(exp, tk);
5398 }
5399
5400#ifdef DEBUG
5401 std::cout << std::string(__indent, ' ') << "Parser::rPmExpr 2\n";
5402#endif
5403
5404 return true;
5405}
5406
5407/*
5408 cast.expr
5409 : unary.expr
5410 | '(' type.name ')' cast.expr
5411*/
5413{
5414#ifdef DEBUG
5415 indenter _i;
5416 std::cout << std::string(__indent, ' ') << "Parser::rCastExpr 0\n";
5417#endif
5418
5419 if(lex.LookAhead(0)!='(')
5420 return rUnaryExpr(exp);
5421 else
5422 {
5423 // There is an ambiguity in the C++ grammar as follows:
5424 // (TYPENAME) + expr (typecast of unary plus) vs.
5425 // (expr) + expr (sum of two expressions)
5426 // Same issue with the operators & and - and *
5427
5428 cpp_tokent tk1, tk2;
5429 typet tname;
5430
5431#ifdef DEBUG
5432 std::cout << std::string(__indent, ' ') << "Parser::rCastExpr 1\n";
5433#endif
5434
5436 lex.get_token(tk1);
5437
5438 if(rTypeName(tname))
5439 {
5440 if(lex.get_token(tk2)==')')
5441 {
5442 if(lex.LookAhead(0)=='&' &&
5443 lex.LookAhead(1)==TOK_INTEGER)
5444 {
5445 // we have (x) & 123
5446 // This is likely a binary bit-wise 'and'
5447 }
5448 else if(rCastExpr(exp))
5449 {
5450 exprt op;
5451 op.swap(exp);
5452
5453 exp=exprt("explicit-typecast");
5454 exp.type().swap(tname);
5455 exp.add_to_operands(std::move(op));
5456 set_location(exp, tk1);
5457
5458 return true;
5459 }
5460 }
5461 }
5462
5463 lex.Restore(pos);
5464 return rUnaryExpr(exp);
5465 }
5466}
5467
5468/*
5469 type.name
5470 : type.specifier cast.declarator
5471*/
5473{
5474#ifdef DEBUG
5475 indenter _i;
5476 std::cout << std::string(__indent, ' ') << "Parser::rTypeName 0\n";
5477#endif
5478
5479 typet type_name;
5480
5481 if(!rTypeSpecifier(type_name, true))
5482 return false;
5483
5484#ifdef DEBUG
5485 std::cout << std::string(__indent, ' ') << "Parser::rTypeName 1\n";
5486#endif
5487
5488 cpp_declaratort declarator;
5489
5490 if(!rDeclarator(declarator, kCastDeclarator, false, false))
5491 return false;
5492
5493 if(!declarator.method_qualifier().id().empty())
5494 {
5495 tname.swap(declarator.method_qualifier());
5496 merge_types(declarator.type(), tname);
5497 }
5498 else
5499 tname.swap(declarator.type());
5500
5501 // make type_name subtype of arg
5502 make_subtype(type_name, tname);
5503
5504#ifdef DEBUG
5505 std::cout << std::string(__indent, ' ') << "Parser::rTypeName 2\n";
5506#endif
5507
5508 return true;
5509}
5510
5511/*
5512 type.name
5513 | type.specifier { '(' type.specifier ( ',' type.specifier )*
5514 { {,} Ellipsis } ')' } {cv.qualify} {(ptr.operator)*}
5515*/
5517{
5518#ifdef DEBUG
5519 indenter _i;
5520 std::cout << std::string(__indent, ' ')
5521 << "Parser::rTypeNameOrFunctionType 0\n";
5522#endif
5523
5525
5526 if(rTypeName(tname) && lex.LookAhead(0)!='(')
5527 {
5528#ifdef DEBUG
5529 std::cout << std::string(__indent, ' ')
5530 << "Parser::rTypeNameOrFunctionType 1\n";
5531#endif
5532
5533 if(!optPtrOperator(tname))
5534 return false;
5535
5536 return true;
5537 }
5538
5539 lex.Restore(pos);
5540
5541#ifdef DEBUG
5542 std::cout << std::string(__indent, ' ')
5543 << "Parser::rTypeNameOrFunctionType 2\n";
5544#endif
5545
5546 typet return_type;
5547 if(!rCastOperatorName(return_type))
5548 return false;
5549
5550#ifdef DEBUG
5551 std::cout << std::string(__indent, ' ')
5552 << "Parser::rTypeNameOrFunctionType 3\n";
5553#endif
5554
5555 if(lex.LookAhead(0)!='(')
5556 {
5557 tname.swap(return_type);
5558
5559 if(!optPtrOperator(tname))
5560 return false;
5561
5562 return true;
5563 }
5564
5565#ifdef DEBUG
5566 std::cout << std::string(__indent, ' ')
5567 << "Parser::rTypeNameOrFunctionType 4\n";
5568#endif
5569
5570 code_typet type({}, return_type);
5571 cpp_tokent op;
5572 lex.get_token(op);
5573
5574 // TODO -- cruel hack for Clang's type_traits:
5575 // struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...),
5576 // true, false>
5577 if(lex.LookAhead(0)==TOK_IDENTIFIER &&
5578 lex.LookAhead(1)==TOK_SCOPE &&
5579 lex.LookAhead(2)=='*' &&
5580 lex.LookAhead(3)==')' &&
5581 lex.LookAhead(4)=='(')
5582 {
5583 lex.get_token();
5584 lex.get_token();
5585 lex.get_token();
5586 lex.get_token();
5587 lex.get_token();
5588 }
5589 else if(lex.LookAhead(0)==TOK_IDENTIFIER &&
5590 lex.LookAhead(1)==')' &&
5591 lex.LookAhead(2)=='(')
5592 {
5593 lex.get_token(op);
5594 type.set(ID_identifier, op.data.get(ID_C_base_name));
5595 lex.get_token();
5596 lex.get_token();
5597 }
5598 else if(lex.LookAhead(0)=='*' &&
5599 lex.LookAhead(1)==TOK_IDENTIFIER &&
5600 lex.LookAhead(2)==')' &&
5601 lex.LookAhead(3)=='(')
5602 {
5603 lex.get_token(op);
5604 lex.get_token(op);
5605 type.set(ID_identifier, op.data.get(ID_C_base_name));
5606 lex.get_token();
5607 lex.get_token();
5608 }
5609
5610 for(;;)
5611 {
5612 // function type parameters
5613
5614#ifdef DEBUG
5615 std::cout << std::string(__indent, ' ')
5616 << "Parser::rTypeNameOrFunctionType 5\n";
5617#endif
5618
5619 int t=lex.LookAhead(0);
5620 if(t==')')
5621 break;
5622 else if(t==TOK_ELLIPSIS)
5623 {
5624 cpp_tokent tk;
5625 lex.get_token(tk);
5626 type.make_ellipsis();
5627 }
5628 else
5629 {
5630 cpp_declarationt parameter_declaration;
5631 if(!rArgDeclaration(parameter_declaration))
5632 return false;
5633
5634 code_typet::parametert parameter(typet{});
5635 parameter.swap(parameter_declaration);
5636 type.parameters().push_back(parameter);
5637
5638 t=lex.LookAhead(0);
5639 if(t==',')
5640 {
5641 cpp_tokent tk;
5642 lex.get_token(tk);
5643 }
5644 else if(t==TOK_ELLIPSIS)
5645 {
5646 // TODO -- this is actually ambiguous as it could refer to a
5647 // template parameter pack or declare a variadic function
5648 cpp_tokent tk;
5649 lex.get_token(tk);
5650 type.make_ellipsis();
5651 }
5652 else if(t==')')
5653 break;
5654 }
5655 }
5656
5657#ifdef DEBUG
5658 std::cout << std::string(__indent, ' ')
5659 << "Parser::rTypeNameOrFunctionType 6\n";
5660#endif
5661
5662 cpp_tokent cp;
5663 lex.get_token(cp);
5664
5665 // not sure where this one belongs
5666 if(!optCvQualify(type))
5667 return false;
5668
5669#ifdef DEBUG
5670 std::cout << std::string(__indent, ' ')
5671 << "Parser::rTypeNameOrFunctionType 7\n";
5672#endif
5673
5674 // not sure where this one belongs
5675 if(!optPtrOperator(type))
5676 return false;
5677
5678 tname.swap(type);
5679
5680#ifdef DEBUG
5681 std::cout << std::string(__indent, ' ')
5682 << "Parser::rTypeNameOrFunctionType 8\n";
5683#endif
5684
5685 return true;
5686}
5687
5688/*
5689 unary.expr
5690 : postfix.expr
5691 | ('*' | '&' | '+' | '-' | '!' | '~' | IncOp) cast.expr
5692 | sizeof.expr
5693 | allocate.expr
5694 | throw.expression
5695 | noexcept.expr
5696*/
5697
5699{
5700 int t=lex.LookAhead(0);
5701
5702#ifdef DEBUG
5703 indenter _i;
5704 std::cout << std::string(__indent, ' ') << "Parser::rUnaryExpr 0\n";
5705#endif
5706
5707 if(t=='*' || t=='&' || t=='+' ||
5708 t=='-' || t=='!' || t=='~' ||
5709 t==TOK_INCR || t==TOK_DECR)
5710 {
5711 cpp_tokent tk;
5712 lex.get_token(tk);
5713
5714#ifdef DEBUG
5715 std::cout << std::string(__indent, ' ') << "Parser::rUnaryExpr 1\n";
5716#endif
5717
5718 exprt right;
5719 if(!rCastExpr(right))
5720 return false;
5721
5722#ifdef DEBUG
5723 std::cout << std::string(__indent, ' ') << "Parser::rUnaryExpr 2\n";
5724#endif
5725
5726 switch(t)
5727 {
5728 case '*':
5729 exp=exprt(ID_dereference);
5730 break;
5731
5732 case '&':
5733 exp=exprt(ID_address_of);
5734 break;
5735
5736 case '+':
5737 exp=exprt(ID_unary_plus);
5738 break;
5739
5740 case '-':
5741 exp=exprt(ID_unary_minus);
5742 break;
5743
5744 case '!':
5745 exp=exprt(ID_not);
5746 break;
5747
5748 case '~':
5749 exp=exprt(ID_bitnot);
5750 break;
5751
5752 case TOK_INCR:
5753 exp=exprt(ID_side_effect);
5754 exp.set(ID_statement, ID_preincrement);
5755 break;
5756
5757 case TOK_DECR:
5758 exp=exprt(ID_side_effect);
5759 exp.set(ID_statement, ID_predecrement);
5760 break;
5761
5762 default:
5764 }
5765
5766 exp.add_to_operands(std::move(right));
5767 set_location(exp, tk);
5768
5769 return true;
5770 }
5771 else if(t==TOK_SIZEOF)
5772 return rSizeofExpr(exp);
5773 else if(t==TOK_ALIGNOF)
5774 return rAlignofExpr(exp);
5775 else if(t==TOK_THROW)
5776 return rThrowExpr(exp);
5777 else if(t==TOK_NOEXCEPT)
5778 return rNoexceptExpr(exp);
5779 else if(t==TOK_REAL || t==TOK_IMAG)
5780 {
5781 // a GCC extension for complex floating-point arithmetic
5782 cpp_tokent tk;
5783 lex.get_token(tk);
5784
5785 exprt unary;
5786
5787 if(!rUnaryExpr(unary))
5788 return false;
5789
5790 exp=exprt(t==TOK_REAL?ID_complex_real:ID_complex_imag);
5791 exp.add_to_operands(std::move(unary));
5792 set_location(exp, tk);
5793 return true;
5794 }
5795 else if(isAllocateExpr(t))
5796 return rAllocateExpr(exp);
5797 else
5798 return rPostfixExpr(exp);
5799}
5800
5801/*
5802 throw.expression
5803 : THROW {expression}
5804*/
5806{
5807 cpp_tokent tk;
5808
5809#ifdef DEBUG
5810 indenter _i;
5811 std::cout << std::string(__indent, ' ') << "Parser::rThrowExpr 0\n";
5812#endif
5813
5814 if(lex.get_token(tk)!=TOK_THROW)
5815 return false;
5816
5817 int t=lex.LookAhead(0);
5818
5820 set_location(exp, tk);
5821
5822 if(t==':' || t==';')
5823 {
5824 // done
5825 }
5826 else
5827 {
5828 exprt e;
5829
5830 if(!rExpression(e, false))
5831 return false;
5832
5833 exp.add_to_operands(std::move(e));
5834 }
5835
5836 return true;
5837}
5838
5839/*
5840 typeid.expr
5841 : TYPEID '(' expression ')'
5842 | TYPEID '(' type.name ')'
5843*/
5845{
5846 cpp_tokent tk;
5847
5848#ifdef DEBUG
5849 indenter _i;
5850 std::cout << std::string(__indent, ' ') << "Parser::rTypeidExpr 0\n";
5851#endif
5852
5853 if(lex.get_token(tk)!=TOK_TYPEID)
5854 return false;
5855
5856 if(lex.LookAhead(0)=='(')
5857 {
5858 typet tname;
5859 exprt subexp;
5860 cpp_tokent op, cp;
5861
5863 lex.get_token(op);
5864 if(rTypeName(tname))
5865 {
5866 if(lex.get_token(cp)==')')
5867 {
5868 // exp=new PtreeTypeidExpr(new Leaf(tk),
5869 // Ptree::List(new Leaf(op), tname,
5870 // new Leaf(cp)));
5871
5872 exp = exprt(ID_typeid);
5873 set_location(exp, tk);
5874 return true;
5875 }
5876 }
5877
5878 lex.Restore(pos);
5879 lex.get_token(op);
5880
5881 if(rExpression(subexp, false))
5882 {
5883 if(lex.get_token(cp)==')')
5884 {
5885 // exp=new PtreeTypeidExpr(
5886 // new Leaf(tk),
5887 // Ptree::List(
5888 // Ptree::List(new Leaf(op), subexp, new Leaf(cp))
5889 // ));
5890
5891 exp = exprt(ID_typeid);
5892 set_location(exp, tk);
5893 return true;
5894 }
5895 }
5896
5897 lex.Restore(pos);
5898 }
5899
5900 return false;
5901}
5902
5903/*
5904 sizeof.expr
5905 : SIZEOF unary.expr
5906 | SIZEOF '(' type.name ')'
5907 | SIZEOF Ellipsis '(' Identifier ')'
5908*/
5909
5911{
5912 cpp_tokent tk;
5913
5914#ifdef DEBUG
5915 indenter _i;
5916 std::cout << std::string(__indent, ' ') << "Parser::rSizeofExpr 0\n";
5917#endif
5918
5919 if(lex.get_token(tk)!=TOK_SIZEOF)
5920 return false;
5921
5922 if(lex.LookAhead(0)=='(')
5923 {
5924 typet tname;
5925 cpp_tokent op, cp;
5926
5928 lex.get_token(op);
5929
5930 if(rTypeName(tname))
5931 {
5932 if(lex.get_token(cp)==')')
5933 {
5934 exp=exprt(ID_sizeof);
5935 exp.add(ID_type_arg).swap(tname);
5936 set_location(exp, tk);
5937 return true;
5938 }
5939 }
5940
5941 lex.Restore(pos);
5942 }
5943 else if(lex.LookAhead(0)==TOK_ELLIPSIS)
5944 {
5945 typet tname;
5946 cpp_tokent ell, op, cp;
5947
5948 lex.get_token(ell);
5949
5950 lex.get_token(op);
5951
5952 if(rTypeName(tname))
5953 {
5954 if(lex.get_token(cp)==')')
5955 {
5956 exp=exprt(ID_sizeof);
5957 exp.add(ID_type_arg).swap(tname);
5958 set_location(exp, tk);
5959 return true;
5960 }
5961 }
5962
5963 return false;
5964 }
5965
5966 exprt unary;
5967
5968 if(!rUnaryExpr(unary))
5969 return false;
5970
5971 exp=exprt(ID_sizeof);
5972 exp.add_to_operands(std::move(unary));
5973 set_location(exp, tk);
5974 return true;
5975}
5976
5977/*
5978 alignof.expr
5979 | ALIGNOF '(' type.name ')'
5980*/
5981
5983{
5984 cpp_tokent tk;
5985
5986 if(lex.get_token(tk)!=TOK_ALIGNOF)
5987 return false;
5988
5989 typet tname;
5990 cpp_tokent op, cp;
5991
5992 lex.get_token(op);
5993
5994 if(!rTypeName(tname))
5995 return false;
5996
5997 if(lex.get_token(cp)!=')')
5998 return false;
5999
6000 exp=exprt(ID_alignof);
6001 exp.add(ID_type_arg).swap(tname);
6002 set_location(exp, tk);
6003 return true;
6004}
6005
6006/*
6007 noexcept.expr
6008 : NOEXCEPT '(' expression ')'
6009*/
6011{
6012 cpp_tokent tk;
6013
6014#ifdef DEBUG
6015 indenter _i;
6016 std::cout << std::string(__indent, ' ') << "Parser::rNoexceptExpr 0\n";
6017#endif
6018
6019 if(lex.get_token(tk)!=TOK_NOEXCEPT)
6020 return false;
6021
6022 if(lex.LookAhead(0)=='(')
6023 {
6024 exprt subexp;
6025 cpp_tokent op, cp;
6026
6027 lex.get_token(op);
6028
6029 if(rExpression(subexp, false))
6030 {
6031 if(lex.get_token(cp)==')')
6032 {
6033 // TODO
6034 exp=exprt(ID_noexcept);
6035 exp.add_to_operands(std::move(subexp));
6036 set_location(exp, tk);
6037 return true;
6038 }
6039 }
6040 }
6041 else
6042 return true;
6043
6044 return false;
6045}
6046
6048{
6049 if(t==TOK_SCOPE)
6050 t=lex.LookAhead(1);
6051
6052 return t==TOK_NEW || t==TOK_DELETE;
6053}
6054
6055/*
6056 allocate.expr
6057 : {Scope | userdef.keyword} NEW allocate.type
6058 | {Scope} DELETE {'[' ']'} cast.expr
6059*/
6061{
6062 cpp_tokent tk;
6063 irept head=get_nil_irep();
6064
6065#ifdef DEBUG
6066 indenter _i;
6067 std::cout << std::string(__indent, ' ') << "Parser::rAllocateExpr 0\n";
6068#endif
6069
6070 int t=lex.LookAhead(0);
6071 if(t==TOK_SCOPE)
6072 {
6073 lex.get_token(tk);
6074 // TODO one can put 'new'/'delete' into a namespace!
6075 }
6076
6077#ifdef DEBUG
6078 std::cout << std::string(__indent, ' ') << "Parser::rAllocateExpr 1\n";
6079#endif
6080
6081 t=lex.get_token(tk);
6082
6083#ifdef DEBUG
6084 std::cout << std::string(__indent, ' ') << "Parser::rAllocateExpr 2\n";
6085#endif
6086
6087 if(t==TOK_DELETE)
6088 {
6089 exprt obj;
6090
6091 if(lex.LookAhead(0)=='[')
6092 {
6093 lex.get_token(tk);
6094
6095 if(lex.get_token(tk)!=']')
6096 return false;
6097
6098 exp=exprt(ID_side_effect);
6099 exp.set(ID_statement, ID_cpp_delete_array);
6100 }
6101 else
6102 {
6103 exp=exprt(ID_side_effect);
6104 exp.set(ID_statement, ID_cpp_delete);
6105 }
6106
6107 set_location(exp, tk);
6108
6109 if(!rCastExpr(obj))
6110 return false;
6111
6112 exp.add_to_operands(std::move(obj));
6113
6114 return true;
6115 }
6116 else if(t==TOK_NEW)
6117 {
6118#ifdef DEBUG
6119 std::cout << std::string(__indent, ' ') << "Parser::rAllocateExpr 3\n";
6120#endif
6121
6122 exp=exprt(ID_side_effect);
6123 exp.set(ID_statement, ID_cpp_new);
6124 set_location(exp, tk);
6125
6126 exprt arguments, initializer;
6127
6128 if(!rAllocateType(arguments, exp.type(), initializer))
6129 return false;
6130
6131#ifdef DEBUG
6132 std::cout << std::string(__indent, ' ') << "Parser::rAllocateExpr 4\n";
6133#endif
6134
6135 exp.add(ID_initializer).swap(initializer);
6136 exp.operands().swap(arguments.operands());
6137 return true;
6138 }
6139 else
6140 return false;
6141}
6142
6143/*
6144 allocate.type
6145 : {'(' function.arguments ')'} type.specifier new.declarator
6146 {allocate.initializer}
6147 | {'(' function.arguments ')'} '(' type.name ')' {allocate.initializer}
6148*/
6149
6151 exprt &arguments,
6152 typet &atype,
6153 exprt &initializer)
6154{
6155 if(lex.LookAhead(0)!='(')
6156 {
6157 atype.make_nil();
6158 }
6159 else
6160 {
6161 // reads the '('
6162 lex.get_token();
6163
6164 // we may need to backtrack
6166
6167 if(rTypeName(atype))
6168 {
6169 if(lex.get_token()==')')
6170 {
6171 // we have "( type.name )"
6172
6173 if(lex.LookAhead(0)!='(')
6174 {
6175 if(!isTypeSpecifier())
6176 return true;
6177 }
6178 else if(rAllocateInitializer(initializer))
6179 {
6180 // the next token cannot be '('
6181 if(lex.LookAhead(0)!='(')
6182 return true;
6183 }
6184 }
6185 }
6186
6187 // if we reach here, it's not '(' type.name ')',
6188 // and we have to process '(' function.arguments ')'.
6189
6190 lex.Restore(pos);
6191 if(!rFunctionArguments(arguments))
6192 return false;
6193
6194 if(lex.get_token()!=')')
6195 return false;
6196 }
6197
6198 if(lex.LookAhead(0)=='(')
6199 {
6200 lex.get_token();
6201
6202 typet tname;
6203
6204 if(!rTypeName(tname))
6205 return false;
6206
6207 if(lex.get_token()!=')')
6208 return false;
6209
6210 atype.swap(tname);
6211 }
6212 else
6213 {
6214 typet tname;
6215
6216 if(!rTypeSpecifier(tname, false))
6217 return false;
6218
6219 if(!rNewDeclarator(tname))
6220 return false;
6221
6222 atype.swap(tname);
6223 }
6224
6225 if(lex.LookAhead(0)=='(')
6226 {
6227 if(!rAllocateInitializer(initializer))
6228 return false;
6229 }
6230 else if(lex.LookAhead(0)=='{')
6231 {
6232 // this is a C++11 extension
6233 if(!rInitializeExpr(initializer))
6234 return false;
6235 }
6236
6237 return true;
6238}
6239
6240/*
6241 new.declarator
6242 : empty
6243 | ptr.operator
6244 | {ptr.operator} ('[' comma.expression ']')+
6245*/
6247{
6248 if(lex.LookAhead(0)!='[')
6249 if(!optPtrOperator(decl))
6250 return false;
6251
6252 while(lex.LookAhead(0)=='[')
6253 {
6254 cpp_tokent ob, cb;
6255 exprt expr;
6256
6257 lex.get_token(ob);
6258 if(!rCommaExpression(expr))
6259 return false;
6260
6261 if(lex.get_token(cb)!=']')
6262 return false;
6263
6264 array_typet array_type(decl, expr);
6265 set_location(array_type, ob);
6266
6267 decl.swap(array_type);
6268 }
6269
6270 return true;
6271}
6272
6273/*
6274 allocate.initializer
6275 : '(' {initialize.expr (',' initialize.expr)* } ')'
6276*/
6278{
6279 if(lex.get_token()!='(')
6280 return false;
6281
6282 init.clear();
6283
6284 if(lex.LookAhead(0)==')')
6285 {
6286 lex.get_token();
6287 return true;
6288 }
6289
6290 for(;;)
6291 {
6292 exprt exp;
6293 if(!rInitializeExpr(exp))
6294 return false;
6295
6296 init.add_to_operands(std::move(exp));
6297
6298 if(lex.LookAhead(0)==TOK_ELLIPSIS)
6299 {
6300 lex.get_token();
6301 // TODO
6302 }
6303
6304 if(lex.LookAhead(0)==',')
6305 lex.get_token();
6306 else if(lex.LookAhead(0)==')')
6307 {
6308 lex.get_token();
6309 break;
6310 }
6311 else
6312 return false;
6313 }
6314
6315 return true;
6316}
6317
6318/*
6319 postfix.exp
6320 : primary.exp
6321 | postfix.expr '[' comma.expression ']'
6322 | postfix.expr '(' function.arguments ')'
6323 | postfix.expr '.' var.name
6324 | postfix.expr ArrowOp var.name
6325 | postfix.expr IncOp
6326 | openc++.postfix.expr
6327
6328 openc++.postfix.expr
6329 : postfix.expr '.' userdef.statement
6330 | postfix.expr ArrowOp userdef.statement
6331
6332 Note: function-style casts are accepted as function calls.
6333*/
6335{
6336#ifdef DEBUG
6337 indenter _i;
6338 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 0\n";
6339#endif
6340
6341 if(!rPrimaryExpr(exp))
6342 return false;
6343
6344#ifdef DEBUG
6345 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 1\n";
6346#endif
6347
6348 exprt e;
6349 cpp_tokent cp, op;
6350 int t2;
6351
6352 for(;;)
6353 {
6354 switch(lex.LookAhead(0))
6355 {
6356 case '[':
6357 lex.get_token(op);
6358 if(!rCommaExpression(e))
6359 return false;
6360
6361#ifdef DEBUG
6362 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 2\n";
6363#endif
6364
6365 if(lex.get_token(cp)!=']')
6366 return false;
6367
6368 {
6369 exprt left;
6370 left.swap(exp);
6371
6372 exp=exprt(ID_index);
6373 exp.add_to_operands(std::move(left), std::move(e));
6374 set_location(exp, op);
6375 }
6376 break;
6377
6378 case '(':
6379#ifdef DEBUG
6380 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 3\n";
6381#endif
6382
6383 lex.get_token(op);
6384 if(!rFunctionArguments(e))
6385 return false;
6386
6387 if(lex.get_token(cp)!=')')
6388 return false;
6389
6390#ifdef DEBUG
6391 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 4\n";
6392#endif
6393
6394 {
6396 std::move(exp), {}, typet{}, source_locationt{});
6397 fc.arguments().reserve(e.operands().size());
6398 set_location(fc, op);
6399
6400 Forall_operands(it, e)
6401 fc.arguments().push_back(*it);
6402 e.operands().clear(); // save some
6403 exp.swap(fc);
6404 }
6405 break;
6406
6407 case TOK_INCR:
6408 lex.get_token(op);
6409
6410 {
6411 side_effect_exprt tmp(ID_postincrement, typet(), source_locationt());
6412 tmp.add_to_operands(std::move(exp));
6413 set_location(tmp, op);
6414 exp.swap(tmp);
6415 }
6416 break;
6417
6418 case TOK_DECR:
6419 lex.get_token(op);
6420
6421 {
6423 ID_postdecrement, {std::move(exp)}, typet(), source_locationt());
6424 set_location(tmp, op);
6425 exp.swap(tmp);
6426 }
6427 break;
6428
6429 case '.':
6430 case TOK_ARROW:
6431 t2=lex.get_token(op);
6432
6433#ifdef DEBUG
6434 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 5\n";
6435#endif
6436
6437 if(!rVarName(e))
6438 return false;
6439
6440#ifdef DEBUG
6441 std::cout << std::string(__indent, ' ') << "Parser::rPostfixExpr 6\n";
6442#endif
6443
6444 {
6445 exprt left;
6446 left.swap(exp);
6447
6448 if(t2=='.')
6449 exp=exprt(ID_member);
6450 else // ARROW
6451 exp=exprt(ID_ptrmember);
6452
6453 exp.add_to_operands(std::move(left));
6454 set_location(exp, op);
6455 }
6456
6457 exp.add(ID_component_cpp_name).swap(e);
6458
6459 break;
6460
6461 default:
6462 return true;
6463 }
6464 }
6465}
6466
6467/*
6468 __uuidof( expression )
6469 __uuidof( type )
6470 This is a Visual Studio Extension.
6471*/
6472
6474{
6475 cpp_tokent tk;
6476
6477 if(lex.get_token(tk)!=TOK_MSC_UUIDOF)
6478 return false;
6479
6480 if(lex.get_token(tk)!='(')
6481 return false;
6482
6483 {
6484 typet tname;
6485 cpp_tokent cp;
6486
6488
6489 if(rTypeName(tname))
6490 {
6491 if(lex.get_token(cp)==')')
6492 {
6493 expr=exprt(ID_msc_uuidof);
6494 expr.add(ID_type_arg).swap(tname);
6495 set_location(expr, tk);
6496 return true;
6497 }
6498 }
6499
6500 lex.Restore(pos);
6501 }
6502
6503 exprt unary;
6504
6505 if(!rUnaryExpr(unary))
6506 return false;
6507
6508 if(lex.get_token(tk)!=')')
6509 return false;
6510
6511 expr=exprt(ID_msc_uuidof);
6512 expr.add_to_operands(std::move(unary));
6513 set_location(expr, tk);
6514 return true;
6515}
6516
6517/*
6518 __if_exists ( identifier ) { token stream }
6519 __if_not_exists ( identifier ) { token stream }
6520*/
6521
6523{
6524 cpp_tokent tk1;
6525
6526 lex.get_token(tk1);
6527
6528 if(tk1.kind!=TOK_MSC_IF_EXISTS &&
6529 tk1.kind!=TOK_MSC_IF_NOT_EXISTS)
6530 return false;
6531
6532 cpp_tokent tk2;
6533
6534 if(lex.get_token(tk2)!='(')
6535 return false;
6536
6537 exprt name;
6538
6539 if(!rVarName(name))
6540 return false;
6541
6542 if(lex.get_token(tk2)!=')')
6543 return false;
6544
6545 if(lex.get_token(tk2)!='{')
6546 return false;
6547
6548 exprt op;
6549
6550 if(!rUnaryExpr(op))
6551 return false;
6552
6553 if(lex.get_token(tk2)!='}')
6554 return false;
6555
6556 expr=exprt(
6557 tk1.kind==TOK_MSC_IF_EXISTS?ID_msc_if_exists:
6558 ID_msc_if_not_exists);
6559
6560 expr.add_to_operands(std::move(name), std::move(op));
6561
6562 set_location(expr, tk1);
6563
6564 return true;
6565}
6566
6568{
6569 cpp_tokent tk1;
6570
6571 lex.get_token(tk1);
6572
6573 if(tk1.kind != TOK_MSC_IF_EXISTS && tk1.kind != TOK_MSC_IF_NOT_EXISTS)
6574 return {};
6575
6576 cpp_tokent tk2;
6577
6578 if(lex.get_token(tk2)!='(')
6579 return {};
6580
6581 exprt name;
6582
6583 if(!rVarName(name))
6584 return {};
6585
6586 if(lex.get_token(tk2)!=')')
6587 return {};
6588
6589 if(lex.get_token(tk2)!='{')
6590 return {};
6591
6592 code_blockt block;
6593
6594 while(lex.LookAhead(0)!='}')
6595 {
6596 if(auto statement = rStatement())
6597 block.add(std::move(*statement));
6598 else
6599 return {};
6600 }
6601
6602 if(lex.get_token(tk2)!='}')
6603 return {};
6604
6605 codet code(
6606 tk1.kind == TOK_MSC_IF_EXISTS ? ID_msc_if_exists : ID_msc_if_not_exists);
6607
6608 code.add_to_operands(std::move(name), std::move(block));
6609
6610 set_location(code, tk1);
6611
6612 return std::move(code);
6613}
6614
6615/*
6616 __is_base_of ( base, derived )
6617 __is_convertible_to ( from, to )
6618 __is_class ( t )
6619 __is_... (t)
6620*/
6621
6623{
6624 cpp_tokent tk;
6625
6626 lex.get_token(tk);
6627
6628 expr.id(irep_idt(tk.text));
6629 set_location(expr, tk);
6630
6631 typet tname1, tname2;
6632
6633 switch(tk.kind)
6634 {
6635 case TOK_UNARY_TYPE_PREDICATE:
6636 if(lex.get_token(tk)!='(')
6637 return false;
6638 if(!rTypeName(tname1))
6639 return false;
6640 if(lex.get_token(tk)!=')')
6641 return false;
6642 expr.add(ID_type_arg).swap(tname1);
6643 break;
6644
6645 case TOK_BINARY_TYPE_PREDICATE:
6646 if(lex.get_token(tk)!='(')
6647 return false;
6648 if(!rTypeName(tname1))
6649 return false;
6650 if(lex.get_token(tk)!=',')
6651 return false;
6652 if(!rTypeName(tname2))
6653 return false;
6654 if(lex.get_token(tk)!=')')
6655 return false;
6656 expr.add("type_arg1").swap(tname1);
6657 expr.add("type_arg2").swap(tname2);
6658 break;
6659
6660 default:
6662 }
6663
6664 return true;
6665}
6666
6667/*
6668 primary.exp
6669 : Constant
6670 | CharConst
6671 | WideCharConst !!! new
6672 | String
6673 | WideStringL !!! new
6674 | THIS
6675 | var.name
6676 | '(' comma.expression ')'
6677 | integral.or.class.spec '(' function.arguments ')'
6678 | integral.or.class.spec initializer
6679 | typeid.expr
6680 | true
6681 | false
6682 | nullptr
6683*/
6685{
6686 cpp_tokent tk, tk2;
6687
6688#ifdef DEBUG
6689 indenter _i;
6690 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 0 "
6691 << lex.LookAhead(0) << ' ' << lex.current_token().text << '\n';
6692#endif
6693
6694 switch(lex.LookAhead(0))
6695 {
6696 case TOK_INTEGER:
6697 case TOK_CHARACTER:
6698 case TOK_FLOATING:
6699 lex.get_token(tk);
6700 exp.swap(tk.data);
6701 set_location(exp, tk);
6702#ifdef DEBUG
6703 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 1\n";
6704#endif
6705 return true;
6706
6707 case TOK_STRING:
6708 rString(tk);
6709 exp.swap(tk.data);
6710 set_location(exp, tk);
6711#ifdef DEBUG
6712 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 2\n";
6713#endif
6714 return true;
6715
6716 case TOK_THIS:
6717 lex.get_token(tk);
6718 exp=exprt("cpp-this");
6719 set_location(exp, tk);
6720#ifdef DEBUG
6721 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 3\n";
6722#endif
6723 return true;
6724
6725 case TOK_TRUE:
6726 lex.get_token(tk);
6728 set_location(exp, tk);
6729#ifdef DEBUG
6730 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 4\n";
6731#endif
6732 return true;
6733
6734 case TOK_FALSE:
6735 lex.get_token(tk);
6737 set_location(exp, tk);
6738#ifdef DEBUG
6739 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 5\n";
6740#endif
6741 return true;
6742
6743 case TOK_NULLPTR:
6744 lex.get_token(tk);
6745 // as an exception, we set the width of pointer
6746 exp = null_pointer_exprt{pointer_type(typet(ID_nullptr))};
6747 set_location(exp, tk);
6748#ifdef DEBUG
6749 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 6\n";
6750#endif
6751 return true;
6752
6753 case '(':
6754#ifdef DEBUG
6755 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 7\n";
6756#endif
6757 lex.get_token(tk);
6758
6759 if(lex.LookAhead(0)=='{') // GCC extension
6760 {
6761 if(auto code = rCompoundStatement())
6762 {
6763 exp = exprt(ID_side_effect);
6764 exp.set(ID_statement, ID_statement_expression);
6765 set_location(exp, tk);
6766 exp.add_to_operands(std::move(*code));
6767 }
6768 else
6769 return false;
6770
6771 if(lex.get_token(tk2)!=')')
6772 return false;
6773 }
6774 else
6775 {
6776 exprt exp2;
6777
6778 if(!rCommaExpression(exp2))
6779 return false;
6780
6781#ifdef DEBUG
6782 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 8\n";
6783#endif
6784
6785 if(lex.get_token(tk2)!=')')
6786 return false;
6787
6788 exp.swap(exp2);
6789 }
6790
6791#ifdef DEBUG
6792 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 9\n";
6793#endif
6794 return true;
6795
6796 case '{': // C++11 initialisation expression
6797#ifdef DEBUG
6798 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 10\n";
6799#endif
6800 return rInitializeExpr(exp);
6801
6802 case TOK_TYPEID:
6803 return rTypeidExpr(exp);
6804
6805 case TOK_UNARY_TYPE_PREDICATE:
6806 case TOK_BINARY_TYPE_PREDICATE:
6807#ifdef DEBUG
6808 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 11\n";
6809#endif
6810 return rTypePredicate(exp);
6811
6812 case TOK_MSC_UUIDOF:
6813#ifdef DEBUG
6814 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 12\n";
6815#endif
6816 return rMSCuuidof(exp);
6817
6818 // not quite appropriate: these allow more general
6819 // token streams, not just expressions
6820 case TOK_MSC_IF_EXISTS:
6821 case TOK_MSC_IF_NOT_EXISTS:
6822#ifdef DEBUG
6823 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 13\n";
6824#endif
6825 return rMSC_if_existsExpr(exp);
6826
6827 default:
6828#ifdef DEBUG
6829 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 14\n";
6830#endif
6831 {
6832 typet type;
6833
6835 return false;
6836
6837#ifdef DEBUG
6838 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 15\n";
6839#endif
6840
6841 if(type.is_not_nil() && lex.LookAhead(0)==TOK_SCOPE)
6842 {
6843 lex.get_token(tk);
6844 lex.get_token(tk);
6845
6846 // TODO
6847 }
6848 else if(type.is_not_nil())
6849 {
6850#ifdef DEBUG
6851 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 16\n";
6852#endif
6853 if(lex.LookAhead(0)=='{')
6854 {
6855 lex.LookAhead(0, tk);
6856
6857 exprt exp2;
6858 if(!rInitializeExpr(exp2))
6859 return false;
6860
6861 exp=exprt("explicit-constructor-call");
6862 exp.type().swap(type);
6863 exp.add_to_operands(std::move(exp2));
6864 set_location(exp, tk);
6865 }
6866 else if(lex.LookAhead(0)=='(')
6867 {
6868 lex.get_token(tk);
6869
6870 exprt exp2;
6871 if(!rFunctionArguments(exp2))
6872 return false;
6873
6874 if(lex.get_token(tk2)!=')')
6875 return false;
6876
6877 exp=exprt("explicit-constructor-call");
6878 exp.type().swap(type);
6879 exp.operands().swap(exp2.operands());
6880 set_location(exp, tk);
6881 }
6882 else
6883 return false;
6884 }
6885 else
6886 {
6887 if(!rVarName(exp))
6888 return false;
6889
6890 if(lex.LookAhead(0)==TOK_SCOPE)
6891 {
6892 lex.get_token(tk);
6893
6894 // exp=new PtreeStaticUserStatementExpr(exp,
6895 // Ptree::Cons(new Leaf(tk), exp2));
6896 // TODO
6897 }
6898 }
6899 }
6900#ifdef DEBUG
6901 std::cout << std::string(__indent, ' ') << "Parser::rPrimaryExpr 17\n";
6902#endif
6903
6904 return true;
6905 }
6906}
6907
6908/*
6909 var.name : {'::'} name2 ('::' name2)*
6910
6911 name2
6912 : Identifier {template.args}
6913 | '~' Identifier
6914 | OPERATOR operator.name
6915
6916 if var.name ends with a template type, the next token must be '('
6917*/
6919{
6920#ifdef DEBUG
6921 indenter _i;
6922 std::cout << std::string(__indent, ' ') << "Parser::rVarName 0\n";
6923#endif
6924
6925 if(rVarNameCore(name))
6926 return true;
6927 else
6928 return false;
6929}
6930
6932{
6933#ifdef DEBUG
6934 indenter _i;
6935 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 0\n";
6936#endif
6937
6938 name = cpp_namet().as_expr();
6939 irept::subt &components=name.get_sub();
6940
6941 if(lex.LookAhead(0)==TOK_TYPENAME)
6942 {
6943 cpp_tokent tk;
6944 lex.get_token(tk);
6945 name.set(ID_typename, true);
6946 }
6947
6948 {
6949 cpp_tokent tk;
6950 lex.LookAhead(0, tk);
6951 set_location(name, tk);
6952 }
6953
6954#ifdef DEBUG
6955 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 1\n";
6956#endif
6957
6958 for(;;)
6959 {
6960 cpp_tokent tk;
6961
6962#ifdef DEBUG
6963 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 1.1 "
6964 << lex.LookAhead(0)
6965 << '\n';
6966#endif
6967
6968 switch(lex.LookAhead(0))
6969 {
6970 case TOK_TEMPLATE:
6971 // this may be a template member function, for example
6972#ifdef DEBUG
6973 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 2\n";
6974#endif
6975 lex.get_token(tk);
6976 // Skip template token, next will be identifier
6977 if(lex.LookAhead(0)!=TOK_IDENTIFIER)
6978 return false;
6979 break;
6980
6981 case TOK_IDENTIFIER:
6982#ifdef DEBUG
6983 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 3\n";
6984#endif
6985
6986 lex.get_token(tk);
6987 components.push_back(cpp_namet::namet(tk.data.get(ID_C_base_name)));
6988 set_location(components.back(), tk);
6989
6990 // may be followed by template arguments
6991 if(maybeTemplateArgs())
6992 {
6994
6995#ifdef DEBUG
6996 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 4\n";
6997#endif
6998
6999 irept args;
7000 if(!rTemplateArgs(args))
7001 {
7002 lex.Restore(pos);
7003 return true;
7004 }
7005
7006 components.push_back(irept(ID_template_args));
7007 components.back().add(ID_arguments).swap(args);
7008 }
7009
7010 if(!moreVarName())
7011 return true;
7012 break;
7013
7014 case TOK_SCOPE:
7015#ifdef DEBUG
7016 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 5\n";
7017#endif
7018
7019 lex.get_token(tk);
7020 components.push_back(irept("::"));
7021 set_location(components.back(), tk);
7022 break;
7023
7024 case '~':
7025#ifdef DEBUG
7026 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 6\n";
7027#endif
7028
7029 lex.get_token(tk);
7030
7031 if(lex.LookAhead(0)!=TOK_IDENTIFIER)
7032 return false;
7033
7034 components.push_back(irept("~"));
7035 set_location(components.back(), tk);
7036 break;
7037
7038 case TOK_OPERATOR:
7039#ifdef DEBUG
7040 std::cout << std::string(__indent, ' ') << "Parser::rVarNameCore 7\n";
7041#endif
7042
7043 lex.get_token(tk);
7044
7045 components.push_back(irept(ID_operator));
7046 set_location(components.back(), tk);
7047
7048 {
7049 irept op;
7050 if(!rOperatorName(op))
7051 return false;
7052
7053 components.push_back(op);
7054 }
7055 return true;
7056
7057 default:
7058 return false;
7059 }
7060 }
7061}
7062
7064{
7065 if(lex.LookAhead(0)==TOK_SCOPE)
7066 {
7067 int t=lex.LookAhead(1);
7068 if(t==TOK_IDENTIFIER || t=='~' || t==TOK_OPERATOR || t==TOK_TEMPLATE)
7069 return true;
7070 }
7071
7072 return false;
7073}
7074
7075/*
7076 template.args : '<' any* '>'
7077
7078 template.args must be followed by '(' or '::'
7079*/
7081{
7082 int i=0;
7083 int t=lex.LookAhead(i++);
7084
7085#ifdef DEBUG
7086 indenter _i;
7087 std::cout << std::string(__indent, ' ') << "Parser::maybeTemplateArgs 0\n";
7088#endif
7089
7090 if(t=='<')
7091 {
7092#if 1
7093 for(;;)
7094 {
7095 int u=lex.LookAhead(i++);
7096 if(u=='\0' || u==';' || u=='}')
7097 return false;
7098 else if((u=='>' || u==TOK_SHIFTRIGHT) &&
7099 (lex.LookAhead(i)==TOK_SCOPE || lex.LookAhead(i)=='(' ||
7100 lex.LookAhead(i)==')'))
7101 return true;
7102 }
7103#else
7104 int n=1;
7105
7106 while(n>0)
7107 {
7108#ifdef DEBUG
7109 std::cout << std::string(__indent, ' ')
7110 << "Parser::maybeTemplateArgs 1\n";
7111#endif
7112
7113 int u=lex.LookAhead(i++);
7114
7115#ifdef DEBUG
7116 std::cout << std::string(__indent, ' ')
7117 << "Parser::maybeTemplateArgs 2\n";
7118#endif
7119
7120 if(u=='<')
7121 ++n;
7122 else if(u=='>')
7123 --n;
7124 else if(u=='(')
7125 {
7126 int m=1;
7127 while(m>0)
7128 {
7129 int v=lex.LookAhead(i++);
7130
7131#ifdef DEBUG
7132 std::cout << std::string(__indent, ' ')
7133 << "Parser::maybeTemplateArgs 3\n";
7134#endif
7135
7136 if(v=='(')
7137 ++m;
7138 else if(v==')')
7139 --m;
7140 else if(v=='\0' || v==';' || v=='}')
7141 return false;
7142 }
7143 }
7144 else if(u=='\0' || u==';' || u=='}')
7145 return false;
7146 else if(u==TOK_SHIFTRIGHT && n>=2)
7147 n-=2;
7148
7149#ifdef DEBUG
7150 std::cout << std::string(__indent, ' ')
7151 << "Parser::maybeTemplateArgs 4\n";
7152#endif
7153 }
7154
7155#ifdef DEBUG
7156 std::cout << std::string(__indent, ' ') << "Parser::maybeTemplateArgs 5\n";
7157#endif
7158
7159 t=lex.LookAhead(i);
7160
7161#ifdef DEBUG
7162 std::cout << std::string(__indent, ' ') << "Parser::maybeTemplateArgs 6\n";
7163#endif
7164
7165 return t==TOK_SCOPE || t=='(';
7166#endif
7167 }
7168
7169#ifdef DEBUG
7170 std::cout << std::string(__indent, ' ') << "Parser::maybeTemplateArgs 7\n";
7171#endif
7172
7173 return false;
7174}
7175
7176/*
7177 function.body : compound.statement
7178 | { asm }
7179*/
7180
7182{
7183 // The following is an extension in GCC,
7184 // ARMCC, CodeWarrior...
7185
7186 if(lex.LookAhead(0)=='{' &&
7187 lex.LookAhead(1)==TOK_ASM_STRING)
7188 {
7189 cpp_tokent ob, tk, cb;
7190 lex.get_token(ob);
7191
7192 codet body=code_blockt();
7193 set_location(body, ob);
7194
7195 lex.get_token(tk);
7196 // TODO: add to body
7197
7198 if(lex.get_token(cb)!='}')
7199 return false;
7200
7201 declarator.value()=body;
7202 return true;
7203 }
7204 else
7205 {
7206 // this is for the benefit of set_location
7207 const cpp_namet &cpp_name=declarator.name();
7209
7210 if(auto body = rCompoundStatement())
7211 declarator.value() = std::move(*body);
7212 else
7213 {
7215 return false;
7216 }
7217
7219
7220 return true;
7221 }
7222}
7223
7224/*
7225 compound.statement
7226 : '{' (statement)* '}'
7227*/
7229{
7230 cpp_tokent ob, cb;
7231
7232#ifdef DEBUG
7233 indenter _i;
7234 std::cout << std::string(__indent, ' ') << "Parser::rCompoundStatement 1\n";
7235#endif
7236
7237 if(lex.get_token(ob)!='{')
7238 return {};
7239
7240#ifdef DEBUG
7241 std::cout << std::string(__indent, ' ') << "Parser::rCompoundStatement 2\n";
7242#endif
7243
7244 code_blockt statement;
7245 set_location(statement, ob);
7246
7247 while(lex.LookAhead(0)!='}')
7248 {
7249 if(auto statement2 = rStatement())
7250 statement.add(std::move(*statement2));
7251 else
7252 {
7253 if(!SyntaxError())
7254 return {}; // too many errors
7255
7256 SkipTo('}');
7257 lex.get_token(cb);
7258 return std::move(statement); // error recovery
7259 }
7260 }
7261
7262 if(lex.get_token(cb)!='}')
7263 return {};
7264
7265 return std::move(statement);
7266}
7267
7268/*
7269 statement
7270 : compound.statement
7271 | typedef
7272 | if.statement
7273 | switch.statement
7274 | while.statement
7275 | do.statement
7276 | for.statement
7277 | try.statement
7278 | BREAK ';'
7279 | CONTINUE ';'
7280 | RETURN { comma.expression } ';'
7281 | GOTO Identifier ';'
7282 | CASE expression ':' statement
7283 | DEFAULT ':' statement
7284 | Identifier ':' statement
7285 | expr.statement
7286 | USING { NAMESPACE } identifier ';'
7287 | STATIC_ASSERT ( expression ',' expression ) ';'
7288*/
7290{
7291 cpp_tokent tk1, tk2, tk3;
7292 int k;
7293
7294#ifdef DEBUG
7295 indenter _i;
7296 std::cout << std::string(__indent, ' ') << "Parser::rStatement 0 "
7297 << lex.LookAhead(0) << '\n';
7298#endif
7299
7300 switch(k=lex.LookAhead(0))
7301 {
7302 case '{':
7303 return rCompoundStatement();
7304
7305 case TOK_TYPEDEF:
7306 return rTypedefStatement();
7307
7308 case TOK_IF:
7309 return rIfStatement();
7310
7311 case TOK_SWITCH:
7312 return rSwitchStatement();
7313
7314 case TOK_WHILE:
7315 return rWhileStatement();
7316
7317 case TOK_DO:
7318 return rDoStatement();
7319
7320 case TOK_FOR:
7321 return rForStatement();
7322
7323 case TOK_TRY:
7324 return rTryStatement();
7325
7326 case TOK_MSC_TRY:
7327 return rMSC_tryStatement();
7328
7329 case TOK_MSC_LEAVE:
7330 return rMSC_leaveStatement();
7331
7332 case TOK_BREAK:
7333 case TOK_CONTINUE:
7334 {
7335 lex.get_token(tk1);
7336
7337 codet statement(k == TOK_BREAK ? ID_break : ID_continue);
7338 set_location(statement, tk1);
7339
7340 if(lex.get_token(tk2)!=';')
7341 return {};
7342
7343 return std::move(statement);
7344 }
7345 case TOK_RETURN:
7346 {
7347#ifdef DEBUG
7348 std::cout << std::string(__indent, ' ') << "Parser::rStatement RETURN 0\n";
7349#endif
7350
7351 lex.get_token(tk1);
7352
7353 code_frontend_returnt statement;
7354 set_location(statement, tk1);
7355
7356 if(lex.LookAhead(0)==';')
7357 {
7358#ifdef DEBUG
7359 std::cout << std::string(__indent, ' ')
7360 << "Parser::rStatement RETURN 1\n";
7361#endif
7362 lex.get_token(tk2);
7363 }
7364 else
7365 {
7366#ifdef DEBUG
7367 std::cout << std::string(__indent, ' ')
7368 << "Parser::rStatement RETURN 2\n";
7369#endif
7370
7371 if(!rCommaExpression(statement.return_value()))
7372 return {};
7373
7374#ifdef DEBUG
7375 std::cout << std::string(__indent, ' ')
7376 << "Parser::rStatement RETURN 3\n";
7377#endif
7378
7379 if(lex.get_token(tk2)!=';')
7380 return {};
7381 }
7382
7383 return std::move(statement);
7384 }
7385 case TOK_GOTO:
7386 {
7387 lex.get_token(tk1);
7388
7389 if(lex.get_token(tk2)!=TOK_IDENTIFIER)
7390 return {};
7391
7392 if(lex.get_token(tk3)!=';')
7393 return {};
7394
7395 code_gotot statement(tk2.data.get(ID_C_base_name));
7396 set_location(statement, tk1);
7397
7398 return std::move(statement);
7399 }
7400 case TOK_CASE:
7401 {
7402 lex.get_token(tk1);
7403
7404 exprt case_expr;
7405 if(!rExpression(case_expr, false))
7406 return {};
7407
7408 if(lex.LookAhead(0)==TOK_ELLIPSIS)
7409 {
7410 // This is a gcc extension for case ranges.
7411 // Should really refuse in non-GCC modes.
7412 lex.get_token(tk2);
7413
7414 exprt range_end;
7415 if(!rExpression(range_end, false))
7416 return {};
7417
7418 if(lex.get_token(tk2)!=':')
7419 return {};
7420
7421 if(auto statement2 = rStatement())
7422 {
7424 std::move(case_expr), std::move(range_end), std::move(*statement2));
7425 set_location(code, tk1);
7426 return std::move(code);
7427 }
7428 else
7429 return {};
7430 }
7431 else
7432 {
7433 if(lex.get_token(tk2)!=':')
7434 return {};
7435
7436 if(auto statement2 = rStatement())
7437 {
7438 code_switch_caset statement(
7439 std::move(case_expr), std::move(*statement2));
7440 set_location(statement, tk1);
7441 return std::move(statement);
7442 }
7443 else
7444 return {};
7445 }
7446 }
7447
7448 case TOK_DEFAULT:
7449 {
7450 lex.get_token(tk1);
7451
7452 if(lex.get_token(tk2)!=':')
7453 return {};
7454
7455 if(auto statement2 = rStatement())
7456 {
7457 code_switch_caset statement(exprt{}, std::move(*statement2));
7458 statement.set_default();
7459 set_location(statement, tk1);
7460 return std::move(statement);
7461 }
7462 else
7463 return {};
7464 }
7465
7466 case TOK_GCC_ASM:
7467 return rGCCAsmStatement();
7468
7469 case TOK_MSC_ASM:
7470 return rMSCAsmStatement();
7471
7472 case TOK_MSC_IF_EXISTS:
7473 case TOK_MSC_IF_NOT_EXISTS:
7474 return rMSC_if_existsStatement();
7475
7476 case TOK_IDENTIFIER:
7477 if(lex.LookAhead(1)==':') // label statement
7478 {
7479 // the label
7480 lex.get_token(tk1);
7481 // the colon
7482 lex.get_token(tk2);
7483
7484 if(auto statement2 = rStatement())
7485 {
7486 code_labelt label(tk1.data.get(ID_C_base_name), std::move(*statement2));
7487 set_location(label, tk1);
7488 return std::move(label);
7489 }
7490 else
7491 return {};
7492 }
7493
7494 return rExprStatement();
7495
7496 case TOK_USING:
7497 {
7498 if(lex.LookAhead(1)==TOK_IDENTIFIER &&
7499 lex.LookAhead(2)=='=')
7500 {
7501 cpp_declarationt declaration;
7502 if(!rTypedefUsing(declaration))
7503 return {};
7504 code_frontend_declt statement(
7505 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
7506 statement.add_source_location() = declaration.source_location();
7507 return std::move(statement);
7508 }
7509
7510 cpp_usingt cpp_using;
7511
7512 if(!rUsing(cpp_using))
7513 return {};
7514
7516 }
7517
7518 case TOK_STATIC_ASSERT:
7519 {
7520 cpp_static_assertt cpp_static_assert{nil_exprt(), nil_exprt()};
7521
7522 if(!rStaticAssert(cpp_static_assert))
7523 return {};
7524
7525 codet statement(ID_static_assert);
7526 statement.add_source_location()=cpp_static_assert.source_location();
7527 statement.operands().swap(cpp_static_assert.operands());
7528
7529 return std::move(statement);
7530 }
7531
7532 default:
7533 return rExprStatement();
7534 }
7535}
7536
7537/*
7538 if.statement
7539 : IF '(' comma.expression ')' statement { ELSE statement }
7540*/
7542{
7543 cpp_tokent tk1, tk2, tk3, tk4;
7544
7545 if(lex.get_token(tk1)!=TOK_IF)
7546 return {};
7547
7548 if(lex.get_token(tk2)!='(')
7549 return {};
7550
7551 exprt exp;
7552 if(!rCondition(exp))
7553 return {};
7554
7555 if(lex.get_token(tk3)!=')')
7556 return {};
7557
7558 auto then = rStatement();
7559 if(!then.has_value())
7560 return {};
7561
7562 if(lex.LookAhead(0)==TOK_ELSE)
7563 {
7564 lex.get_token(tk4);
7565
7566 if(auto otherwise = rStatement())
7567 {
7568 code_ifthenelset statement(
7569 std::move(exp), std::move(*then), std::move(*otherwise));
7570 set_location(statement, tk1);
7571 return std::move(statement);
7572 }
7573 else
7574 return {};
7575 }
7576 else
7577 {
7578 code_ifthenelset statement(std::move(exp), std::move(*then));
7579 set_location(statement, tk1);
7580 return std::move(statement);
7581 }
7582}
7583
7584/*
7585 switch.statement
7586 : SWITCH '(' comma.expression ')' statement
7587*/
7589{
7590 cpp_tokent tk1, tk2, tk3;
7591
7592 if(lex.get_token(tk1)!=TOK_SWITCH)
7593 return {};
7594
7595 if(lex.get_token(tk2)!='(')
7596 return {};
7597
7598 exprt exp;
7599 if(!rCondition(exp))
7600 return {};
7601
7602 if(lex.get_token(tk3)!=')')
7603 return {};
7604
7605 if(auto body = rStatement())
7606 {
7607 code_switcht statement(std::move(exp), std::move(*body));
7608 set_location(statement, tk1);
7609 return std::move(statement);
7610 }
7611 else
7612 return {};
7613}
7614
7615/*
7616 while.statement
7617 : WHILE '(' comma.expression ')' statement
7618*/
7620{
7621 cpp_tokent tk1, tk2, tk3;
7622
7623 if(lex.get_token(tk1)!=TOK_WHILE)
7624 return {};
7625
7626 if(lex.get_token(tk2)!='(')
7627 return {};
7628
7629 exprt exp;
7630 if(!rCondition(exp))
7631 return {};
7632
7633 if(lex.get_token(tk3)!=')')
7634 return {};
7635
7636 if(auto body = rStatement())
7637 {
7638 code_whilet statement(std::move(exp), std::move(*body));
7639 set_location(statement, tk1);
7640 return std::move(statement);
7641 }
7642 else
7643 return {};
7644}
7645
7646/*
7647 do.statement
7648 : DO statement WHILE '(' comma.expression ')' ';'
7649*/
7651{
7652 cpp_tokent tk0, tk1, tk2, tk3, tk4;
7653
7654 if(lex.get_token(tk0)!=TOK_DO)
7655 return {};
7656
7657 auto body = rStatement();
7658 if(!body.has_value())
7659 return {};
7660
7661 if(lex.get_token(tk1)!=TOK_WHILE)
7662 return {};
7663
7664 if(lex.get_token(tk2)!='(')
7665 return {};
7666
7667 exprt exp;
7668 if(!rCommaExpression(exp))
7669 return {};
7670
7671 if(lex.get_token(tk3)!=')')
7672 return {};
7673
7674 if(lex.get_token(tk4)!=';')
7675 return {};
7676
7677 code_dowhilet statement(std::move(exp), std::move(*body));
7678 set_location(statement, tk0);
7679 return std::move(statement);
7680}
7681
7682/*
7683 for.statement
7684 : FOR '(' expr.statement {comma.expression} ';' {comma.expression} ')'
7685 statement
7686*/
7688{
7689 cpp_tokent tk1, tk2, tk3, tk4;
7690
7691 if(lex.get_token(tk1)!=TOK_FOR)
7692 return {};
7693
7694 if(lex.get_token(tk2)!='(')
7695 return {};
7696
7697 auto exp1 = rExprStatement();
7698
7699 if(!exp1.has_value())
7700 return {};
7701
7702 exprt exp2;
7703
7704 if(lex.LookAhead(0)==';')
7705 exp2.make_nil();
7706 else
7707 if(!rCommaExpression(exp2))
7708 return {};
7709
7710 if(lex.get_token(tk3)!=';')
7711 return {};
7712
7713 exprt exp3;
7714
7715 if(lex.LookAhead(0)==')')
7716 exp3.make_nil();
7717 else
7718 {
7719 if(!rCommaExpression(exp3))
7720 return {};
7721 }
7722
7723 if(lex.get_token(tk4)!=')')
7724 return {};
7725
7726 if(auto body = rStatement())
7727 {
7728 code_fort statement(
7729 std::move(*exp1), std::move(exp2), std::move(exp3), std::move(*body));
7730 set_location(statement, tk1);
7731 return std::move(statement);
7732 }
7733 else
7734 return {};
7735}
7736
7737/*
7738 try.statement
7739 : TRY compound.statement (exception.handler)+ ';'
7740
7741 exception.handler
7742 : CATCH '(' (arg.declaration | Ellipsis) ')' compound.statement
7743*/
7745{
7746 cpp_tokent try_token;
7747
7748 // The 'try' block
7749 if(lex.get_token(try_token) != TOK_TRY)
7750 return {};
7751
7752 auto try_body = rCompoundStatement();
7753 if(!try_body.has_value())
7754 return {};
7755
7756 code_try_catcht statement(std::move(*try_body));
7757 set_location(statement, try_token);
7758
7759 // iterate while there are catch clauses
7760 do
7761 {
7762 cpp_tokent catch_token, op_token, cp_token;
7763
7764 if(lex.get_token(catch_token)!=TOK_CATCH)
7765 return {};
7766
7767 if(lex.get_token(op_token)!='(')
7768 return {};
7769
7770 optionalt<codet> catch_op;
7771
7772 if(lex.LookAhead(0)==TOK_ELLIPSIS)
7773 {
7774 cpp_tokent ellipsis_token;
7775 lex.get_token(ellipsis_token);
7776 codet ellipsis(ID_ellipsis);
7777 set_location(ellipsis, ellipsis_token);
7778 catch_op = std::move(ellipsis);
7779 }
7780 else
7781 {
7782 cpp_declarationt declaration;
7783
7784 if(!rArgDeclaration(declaration))
7785 return {};
7786
7787 // No name in the declarator? Make one.
7788 assert(declaration.declarators().size()==1);
7789
7790 if(declaration.declarators().front().name().is_nil())
7791 declaration.declarators().front().name() = cpp_namet("#anon");
7792
7793 code_frontend_declt code_decl(
7794 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
7795 set_location(code_decl, catch_token);
7796
7797 catch_op = std::move(code_decl);
7798 }
7799
7800 if(lex.get_token(cp_token)!=')')
7801 return {};
7802
7803 if(auto body = rCompoundStatement())
7804 {
7805 code_blockt &block = to_code_block(*body);
7806
7807 block.statements().insert(block.statements().begin(), *catch_op);
7808
7809 statement.add_to_operands(std::move(*body));
7810 }
7811 else
7812 return {};
7813 }
7814 while(lex.LookAhead(0)==TOK_CATCH);
7815
7816 return std::move(statement);
7817}
7818
7820{
7821 // These are for 'structured exception handling',
7822 // and are a relic from Visual C.
7823
7824 cpp_tokent tk, tk2, tk3;
7825
7826 if(lex.get_token(tk)!=TOK_MSC_TRY)
7827 return {};
7828
7829 auto body1 = rCompoundStatement();
7830
7831 if(!body1.has_value())
7832 return {};
7833
7834 if(lex.LookAhead(0)==TOK_MSC_EXCEPT)
7835 {
7836 codet statement(ID_msc_try_except);
7837 set_location(statement, tk);
7838
7839 lex.get_token(tk);
7840
7841 // get '(' comma.expression ')'
7842
7843 if(lex.get_token(tk2)!='(')
7844 return {};
7845
7846 exprt exp;
7847 if(!rCommaExpression(exp))
7848 return {};
7849
7850 if(lex.get_token(tk3)!=')')
7851 return {};
7852
7853 if(auto body2 = rCompoundStatement())
7854 {
7855 statement.add_to_operands(
7856 std::move(*body1), std::move(exp), std::move(*body2));
7857 return std::move(statement);
7858 }
7859 else
7860 return {};
7861 }
7862 else if(lex.LookAhead(0)==TOK_MSC_FINALLY)
7863 {
7864 codet statement(ID_msc_try_finally);
7865 set_location(statement, tk);
7866
7867 lex.get_token(tk);
7868
7869 if(auto body2 = rCompoundStatement())
7870 {
7871 statement.add_to_operands(std::move(*body1), std::move(*body2));
7872 return std::move(statement);
7873 }
7874 else
7875 return {};
7876 }
7877 else
7878 return {};
7879}
7880
7882{
7883 // These are for 'structured exception handling',
7884 // and are a relic from Visual C.
7885
7886 cpp_tokent tk;
7887
7888 if(lex.get_token(tk)!=TOK_MSC_LEAVE)
7889 return {};
7890
7891 codet statement(ID_msc_leave);
7892 set_location(statement, tk);
7893
7894 return std::move(statement);
7895}
7896
7898{
7899 cpp_tokent tk;
7900
7901#ifdef DEBUG
7902 indenter _i;
7903 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 1\n";
7904#endif // DEBUG
7905
7906 // asm [volatile] ("stuff" [ : ["=S" [(__res)], ... ]]) ;
7907
7908 if(lex.get_token(tk)!=TOK_GCC_ASM)
7909 return {};
7910
7911 code_asm_gcct statement;
7912 set_location(statement, tk);
7913
7914 if(lex.LookAhead(0)==TOK_VOLATILE)
7915 lex.get_token(tk);
7916
7917#ifdef DEBUG
7918 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 3\n";
7919#endif // DEBUG
7920
7921 if(lex.get_token(tk)!='(')
7922 return {};
7923 if(!rString(tk))
7924 return {};
7925
7926 statement.asm_text() = tk.data;
7927
7928#ifdef DEBUG
7929 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 3\n";
7930#endif // DEBUG
7931
7932 while(lex.LookAhead(0)!=')')
7933 {
7934#ifdef DEBUG
7935 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 4\n";
7936#endif // DEBUG
7937
7938 // get ':'
7939 if(lex.get_token(tk)!=':')
7940 return {};
7941
7942 for(;;)
7943 {
7944 if(lex.LookAhead(0)!=TOK_STRING)
7945 break;
7946
7947 // get String
7948 rString(tk);
7949
7950 if(lex.LookAhead(0)=='(')
7951 {
7952 // get '('
7953 lex.get_token(tk);
7954
7955#ifdef DEBUG
7956 std::cout << std::string(__indent, ' ')
7957 << "Parser::rGCCAsmStatement 5\n";
7958#endif // DEBUG
7959
7960 exprt expr;
7961 if(!rCommaExpression(expr))
7962 return {};
7963
7964#ifdef DEBUG
7965 std::cout << std::string(__indent, ' ')
7966 << "Parser::rGCCAsmStatement 6\n";
7967#endif // DEBUG
7968
7969 if(lex.get_token(tk)!=')')
7970 return {};
7971 }
7972
7973 // more?
7974 if(lex.LookAhead(0)!=',')
7975 break;
7976 lex.get_token(tk);
7977 }
7978 }
7979
7980#ifdef DEBUG
7981 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 7\n";
7982#endif // DEBUG
7983
7984 if(lex.get_token(tk)!=')')
7985 return {};
7986 if(lex.get_token(tk)!=';')
7987 return {};
7988
7989#ifdef DEBUG
7990 std::cout << std::string(__indent, ' ') << "Parser::rGCCAsmStatement 8\n";
7991#endif // DEBUG
7992
7993 return std::move(statement);
7994}
7995
7997{
7998 cpp_tokent tk;
7999
8000#ifdef DEBUG
8001 indenter _i;
8002 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 1\n";
8003#endif // DEBUG
8004
8005 // asm "STUFF"
8006 // asm { "STUFF" }
8007
8008 if(lex.get_token(tk)!=TOK_MSC_ASM)
8009 return {};
8010
8011 code_asmt statement;
8012 statement.set_flavor(ID_msc);
8013 set_location(statement, tk);
8014
8015#ifdef DEBUG
8016 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 2\n";
8017#endif // DEBUG
8018
8019 if(lex.LookAhead(0)=='{')
8020 {
8021 lex.get_token(tk); // eat the '{'
8022
8023#ifdef DEBUG
8024 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 3\n";
8025#endif // DEBUG
8026
8027 if(lex.LookAhead(0)!=TOK_ASM_STRING)
8028 return {};
8029
8030 lex.get_token(tk);
8031
8032 statement.add_to_operands(std::move(tk.data));
8033 if(lex.get_token(tk)!='}')
8034 return {};
8035
8036#ifdef DEBUG
8037 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 4\n";
8038#endif // DEBUG
8039 }
8040 else
8041 {
8042#ifdef DEBUG
8043 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 5\n";
8044#endif // DEBUG
8045
8046 if(lex.LookAhead(0)!=TOK_ASM_STRING)
8047 return std::move(statement);
8048
8049 lex.get_token(tk);
8050 statement.add_to_operands(std::move(tk.data));
8051
8052#ifdef DEBUG
8053 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 6\n";
8054#endif // DEBUG
8055 }
8056
8057#ifdef DEBUG
8058 std::cout << std::string(__indent, ' ') << "Parser::rMSCAsmStatement 7\n";
8059#endif // DEBUG
8060
8061 return std::move(statement);
8062}
8063
8064/*
8065 expr.statement
8066 : ';'
8067 | declaration.statement
8068 | comma.expression ';'
8069 | openc++.postfix.expr
8070 | openc++.primary.exp
8071*/
8073{
8074 cpp_tokent tk;
8075
8076#ifdef DEBUG
8077 indenter _i;
8078 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 0\n";
8079#endif
8080
8081 if(lex.LookAhead(0)==';')
8082 {
8083#ifdef DEBUG
8084 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 1\n";
8085#endif
8086
8087 lex.get_token(tk);
8088 code_skipt statement;
8089 set_location(statement, tk);
8090 return std::move(statement);
8091 }
8092 else
8093 {
8094#ifdef DEBUG
8095 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 2\n";
8096#endif
8097
8099
8100 if(auto statement = rDeclarationStatement())
8101 {
8102#ifdef DEBUG
8103 std::cout << std::string(__indent, ' ') << "rDe " << statement->pretty()
8104 << '\n';
8105#endif
8106 return statement;
8107 }
8108 else
8109 {
8110 exprt exp;
8111
8112 lex.Restore(pos);
8113
8114#ifdef DEBUG
8115 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 3\n";
8116#endif
8117
8118 if(!rCommaExpression(exp))
8119 return {};
8120
8121#ifdef DEBUG
8122 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 4\n";
8123#endif
8124
8125#ifdef DEBUG
8126 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 5 "
8127 << lex.LookAhead(0) << '\n';
8128#endif
8129
8130 if(lex.get_token(tk)!=';')
8131 return {};
8132
8133#ifdef DEBUG
8134 std::cout << std::string(__indent, ' ') << "Parser::rExprStatement 6\n";
8135#endif
8136
8137 code_expressiont expr_statement(exp);
8138 expr_statement.add_source_location() = exp.source_location();
8139 return std::move(expr_statement);
8140 }
8141 }
8142}
8143
8145{
8147
8148 // C++ conditions can be a declaration!
8149
8150 cpp_declarationt declaration;
8151
8152 if(rSimpleDeclaration(declaration))
8153 {
8154 statement=codet(ID_decl);
8155 statement.add_to_operands(std::move(declaration));
8156 return true;
8157 }
8158 else
8159 {
8160 lex.Restore(pos);
8161
8162 if(!rCommaExpression(statement))
8163 return false;
8164
8165 return true;
8166 }
8167}
8168
8169/*
8170 declaration.statement
8171 : decl.head integral.or.class.spec {cv.qualify} {declarators} ';'
8172 | decl.head name {cv.qualify} declarators ';'
8173 | const.declaration
8174
8175 decl.head
8176 : {storage.spec} {cv.qualify}
8177
8178 const.declaration
8179 : cv.qualify {'*'} Identifier '=' expression {',' declarators} ';'
8180
8181 Note: if you modify this function, take a look at rDeclaration(), too.
8182*/
8184{
8185 cpp_storage_spect storage_spec;
8186 typet cv_q, integral;
8187 cpp_member_spect member_spec;
8188
8189#ifdef DEBUG
8190 indenter _i;
8191 std::cout << std::string(__indent, ' ')
8192 << "Parser::rDeclarationStatement 1\n";
8193#endif
8194
8195 if(!optStorageSpec(storage_spec))
8196 return {};
8197
8198 cv_q.make_nil();
8199
8200 if(!optCvQualify(cv_q))
8201 return {};
8202
8203 // added for junk like const volatile static ...
8204 if(!optStorageSpec(storage_spec))
8205 return {};
8206
8207 if(!optCvQualify(cv_q))
8208 return {};
8209
8210 if(!optIntegralTypeOrClassSpec(integral))
8211 return {};
8212
8213#ifdef DEBUG
8214 std::cout << std::string(__indent, ' ')
8215 << "Parser::rDeclarationStatement 2\n";
8216#endif
8217
8218 if(integral.is_not_nil())
8219 return rIntegralDeclStatement(storage_spec, integral, cv_q);
8220 else
8221 {
8222 int t=lex.LookAhead(0);
8223
8224#ifdef DEBUG
8225 std::cout << std::string(__indent, ' ')
8226 << "Parser::rDeclarationStatement 3 " << t << '\n';
8227#endif
8228
8229 if(cv_q.is_not_nil() &&
8230 ((t==TOK_IDENTIFIER && lex.LookAhead(1)=='=') || t=='*'))
8231 {
8232#ifdef DEBUG
8233 std::cout << std::string(__indent, ' ')
8234 << "Parser::rDeclarationStatement 4\n";
8235#endif
8236
8237 cpp_declarationt declaration;
8238 if(!rConstDeclaration(declaration))
8239 return {};
8240 return code_frontend_declt(
8241 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
8242 }
8243 else
8244 return rOtherDeclStatement(storage_spec, cv_q);
8245 }
8246}
8247
8248/*
8249 integral.decl.statement
8250 : decl.head integral.or.class.spec {cv.qualify} {declarators} ';'
8251*/
8253 cpp_storage_spect &storage_spec,
8254 typet &integral,
8255 typet &cv_q)
8256{
8257 cpp_tokent tk;
8258
8259 if(!optCvQualify(cv_q))
8260 return {};
8261
8262 merge_types(cv_q, integral);
8263
8264 cpp_declarationt declaration;
8265 declaration.type().swap(integral);
8266 declaration.storage_spec().swap(storage_spec);
8267
8268 if(lex.LookAhead(0)==';')
8269 {
8270 lex.get_token(tk);
8271 code_frontend_declt statement(
8272 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
8273 set_location(statement, tk);
8274 return std::move(statement);
8275 }
8276 else
8277 {
8278 if(!rDeclarators(declaration.declarators(), false, true))
8279 return {};
8280
8281 if(lex.get_token(tk)!=';')
8282 return {};
8283
8284 code_frontend_declt statement(
8285 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
8286 set_location(statement, tk);
8287 return std::move(statement);
8288 }
8289}
8290
8291/*
8292 other.decl.statement
8293 :decl.head name {cv.qualify} declarators ';'
8294*/
8297{
8298 typet type_name;
8299 cpp_tokent tk;
8300
8301#ifdef DEBUG
8302 indenter _i;
8303 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclStatement 1\n";
8304#endif // DEBUG
8305
8306 if(!rName(type_name))
8307 return {};
8308
8309#ifdef DEBUG
8310 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclStatement 2\n";
8311#endif // DEBUG
8312
8313 if(!optCvQualify(cv_q))
8314 return {};
8315
8316#ifdef DEBUG
8317 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclStatement 3\n";
8318#endif // DEBUG
8319
8320 merge_types(cv_q, type_name);
8321
8322 cpp_declarationt declaration;
8323 declaration.type().swap(type_name);
8324 declaration.storage_spec().swap(storage_spec);
8325
8326 if(!rDeclarators(declaration.declarators(), false, true))
8327 return {};
8328
8329#ifdef DEBUG
8330 std::cout << std::string(__indent, ' ') << "Parser::rOtherDeclStatement 4\n";
8331#endif // DEBUG
8332
8333 if(lex.get_token(tk)!=';')
8334 return {};
8335
8336 code_frontend_declt statement(
8337 static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
8338 set_location(statement, tk);
8339 return std::move(statement);
8340}
8341
8343{
8344 return true;
8345}
8346
8347void Parser::SkipTo(int token)
8348{
8349 cpp_tokent tk;
8350
8351 for(;;)
8352 {
8353 int t=lex.LookAhead(0);
8354 if(t==token || t=='\0')
8355 break;
8356 else
8357 lex.get_token(tk);
8358 }
8359}
8360
8362{
8364 max_errors=10;
8365
8366 cpp_itemt item;
8367
8368 while(rProgram(item))
8369 {
8370 parser.parse_tree.items.push_back(item);
8371 item.clear();
8372 }
8373
8374#if 0
8375 root_scope.print(std::cout);
8376#endif
8377
8378 return number_of_errors!=0;
8379}
8380
8382{
8383 Parser parser(cpp_parser);
8384 return parser();
8385}
ansi_c_parsert ansi_c_parser
pointer_typet pointer_type(const typet &subtype)
Definition c_types.cpp:253
typet c_bool_type()
Definition c_types.cpp:118
bool optCvQualify(typet &)
Definition parse.cpp:2020
bool rDeclaratorQualifier()
Definition parse.cpp:2969
bool rShiftExpr(exprt &, bool)
Definition parse.cpp:5228
optionalt< codet > rStatement()
Definition parse.cpp:7289
bool rThrowExpr(exprt &)
Definition parse.cpp:5805
bool rPostfixExpr(exprt &)
Definition parse.cpp:6334
bool rIntegralDeclaration(cpp_declarationt &, cpp_storage_spect &, cpp_member_spect &, typet &, typet &)
Definition parse.cpp:1528
bool MaybeTypeNameOrClassTemplate(cpp_tokent &)
Definition parse.cpp:8342
bool rClassMember(cpp_itemt &)
Definition parse.cpp:4675
bool rDefinition(cpp_itemt &)
Definition parse.cpp:547
bool rTypedefUsing(cpp_declarationt &)
Definition parse.cpp:627
bool rAllocateExpr(exprt &)
Definition parse.cpp:6060
bool rMSC_if_existsExpr(exprt &)
Definition parse.cpp:6522
bool rClassBody(exprt &)
Definition parse.cpp:4615
bool rCastExpr(exprt &)
Definition parse.cpp:5412
bool rBaseSpecifiers(irept &)
Definition parse.cpp:4544
bool rPtrToMember(irept &)
Definition parse.cpp:3780
bool optMemberSpec(cpp_member_spect &)
Definition parse.cpp:1949
void make_sub_scope(const irept &name, new_scopet::kindt)
Definition parse.cpp:437
bool rLinkageBody(cpp_linkage_spect::itemst &)
Definition parse.cpp:953
bool rTypePredicate(exprt &)
Definition parse.cpp:6622
void SkipTo(int token)
Definition parse.cpp:8347
bool rAndExpr(exprt &, bool)
Definition parse.cpp:5097
bool optPtrOperator(typet &)
Definition parse.cpp:3259
Parser(cpp_parsert &_cpp_parser)
Definition parse.cpp:198
bool rAttribute(typet &)
Definition parse.cpp:2162
bool rLogicalAndExpr(exprt &, bool)
Definition parse.cpp:4980
bool rExpression(exprt &, bool)
Definition parse.cpp:4811
optionalt< codet > rTypedefStatement()
Definition parse.cpp:676
bool isTypeSpecifier()
Definition parse.cpp:750
bool rString(cpp_tokent &tk)
Definition parse.cpp:449
bool isConstructorDecl()
Definition parse.cpp:1856
bool moreVarName()
Definition parse.cpp:7063
bool rOtherDeclaration(cpp_declarationt &, cpp_storage_spect &, cpp_member_spect &, typet &)
Definition parse.cpp:1670
optionalt< codet > rWhileStatement()
Definition parse.cpp:7619
bool optAttribute(typet &)
Definition parse.cpp:2363
bool rAdditiveExpr(exprt &)
Definition parse.cpp:5268
bool rMemberInit(exprt &)
Definition parse.cpp:3411
optionalt< codet > rExprStatement()
Definition parse.cpp:8072
bool rConstDeclaration(cpp_declarationt &)
Definition parse.cpp:1651
bool rCondition(exprt &)
Definition parse.cpp:8144
bool rSimpleDeclaration(cpp_declarationt &)
Definition parse.cpp:1470
bool rInclusiveOrExpr(exprt &, bool)
Definition parse.cpp:5019
bool rAllocateInitializer(exprt &)
Definition parse.cpp:6277
bool rPrimaryExpr(exprt &)
Definition parse.cpp:6684
bool rStaticAssert(cpp_static_assertt &)
Definition parse.cpp:912
optionalt< codet > rDoStatement()
Definition parse.cpp:7650
bool rArgDeclListOrInit(exprt &, bool &, bool)
Definition parse.cpp:4025
bool rNewDeclarator(typet &)
Definition parse.cpp:6246
void make_subtype(const typet &src, typet &dest)
Definition parse.cpp:392
optionalt< codet > rIntegralDeclStatement(cpp_storage_spect &, typet &, typet &)
Definition parse.cpp:8252
optionalt< codet > rTryStatement()
Definition parse.cpp:7744
bool rAccessDecl(cpp_declarationt &)
Definition parse.cpp:4743
optionalt< codet > rDeclarationStatement()
Definition parse.cpp:8183
bool rRelationalExpr(exprt &, bool)
Definition parse.cpp:5176
bool rMSCuuidof(exprt &)
Definition parse.cpp:6473
bool rNoexceptExpr(exprt &)
Definition parse.cpp:6010
new_scopet root_scope
Definition parse.cpp:214
bool rNamespaceSpec(cpp_namespace_spect &)
Definition parse.cpp:822
cpp_token_buffert & lex
Definition parse.cpp:210
bool rArgDeclaration(cpp_declarationt &)
Definition parse.cpp:4117
bool rTypeName(typet &)
Definition parse.cpp:5472
optionalt< codet > rCompoundStatement()
Definition parse.cpp:7228
bool operator()()
Definition parse.cpp:8361
new_scopet & add_id(const irept &name, new_scopet::kindt)
Definition parse.cpp:413
bool rVarNameCore(exprt &)
Definition parse.cpp:6931
bool rDeclarators(cpp_declarationt::declaratorst &, bool, bool=false)
Definition parse.cpp:2831
bool rLinkageSpec(cpp_linkage_spect &)
Definition parse.cpp:782
bool rDeclarator(cpp_declaratort &, DeclKind, bool, bool)
Definition parse.cpp:3002
bool rAllocateType(exprt &, typet &, exprt &)
Definition parse.cpp:6150
bool rTypeSpecifier(typet &, bool)
Definition parse.cpp:690
bool optThrowDecl(irept &)
Definition parse.cpp:2763
bool rExclusiveOrExpr(exprt &, bool)
Definition parse.cpp:5058
optionalt< codet > rIfStatement()
Definition parse.cpp:7541
bool rEqualityExpr(exprt &, bool)
Definition parse.cpp:5136
bool rVarName(exprt &)
Definition parse.cpp:6918
bool rCommaExpression(exprt &)
Definition parse.cpp:4768
bool rTempArgList(irept &)
Definition parse.cpp:1116
optionalt< codet > rMSC_leaveStatement()
Definition parse.cpp:7881
TemplateDeclKind
Definition parse.cpp:222
@ tdk_decl
Definition parse.cpp:222
@ tdk_instantiation
Definition parse.cpp:222
@ num_tdks
Definition parse.cpp:223
@ tdk_specialization
Definition parse.cpp:223
@ tdk_unknown
Definition parse.cpp:222
bool rArgDeclList(irept &)
Definition parse.cpp:4064
bool rMultiplyExpr(exprt &)
Definition parse.cpp:5315
optionalt< codet > rMSC_if_existsStatement()
Definition parse.cpp:6567
optionalt< codet > rMSCAsmStatement()
Definition parse.cpp:7996
bool rTypedef(cpp_declarationt &)
Definition parse.cpp:599
bool rTemplateArgs(irept &)
Definition parse.cpp:3877
bool rSizeofExpr(exprt &)
Definition parse.cpp:5910
optionalt< codet > rGCCAsmStatement()
Definition parse.cpp:7897
bool rTypeNameOrFunctionType(typet &)
Definition parse.cpp:5516
bool rMemberInitializers(irept &)
Definition parse.cpp:3378
bool rDeclaratorWithInit(cpp_declaratort &, bool, bool)
Definition parse.cpp:2860
unsigned int max_errors
Definition parse.cpp:410
bool SyntaxError()
Definition parse.cpp:483
bool isPtrToMember(int)
Definition parse.cpp:1892
optionalt< codet > rForStatement()
Definition parse.cpp:7687
bool rFunctionArguments(exprt &)
Definition parse.cpp:4250
cpp_parsert & parser
Definition parse.cpp:211
optionalt< codet > rOtherDeclStatement(cpp_storage_spect &, typet &)
Definition parse.cpp:8296
irep_idt current_function
Definition parse.cpp:378
new_scopet * current_scope
Definition parse.cpp:215
bool optIntegralTypeOrClassSpec(typet &)
Definition parse.cpp:2408
bool isAllocateExpr(int)
Definition parse.cpp:6047
bool rPmExpr(exprt &)
Definition parse.cpp:5368
bool rTempArgDeclaration(cpp_declarationt &)
Definition parse.cpp:1150
@ kArgDeclarator
Definition parse.cpp:221
@ kDeclarator
Definition parse.cpp:221
@ kCastDeclarator
Definition parse.cpp:221
bool rEnumBody(irept &)
Definition parse.cpp:4373
bool rLogicalOrExpr(exprt &, bool)
Definition parse.cpp:4941
bool rProgram(cpp_itemt &item)
Definition parse.cpp:517
bool rName(irept &)
Definition parse.cpp:3493
optionalt< codet > rSwitchStatement()
Definition parse.cpp:7588
bool rTemplateDecl2(typet &, TemplateDeclKind &kind)
Definition parse.cpp:1057
bool optAlignas(typet &)
Definition parse.cpp:2106
bool rEnumSpec(typet &)
Definition parse.cpp:4290
bool rTypeidExpr(exprt &)
Definition parse.cpp:5844
void merge_types(const typet &src, typet &dest)
Definition parse.cpp:457
bool rAlignofExpr(exprt &)
Definition parse.cpp:5982
optionalt< codet > rMSC_tryStatement()
Definition parse.cpp:7819
bool rCastOperatorName(irept &)
Definition parse.cpp:3740
bool rInitializeExpr(exprt &)
Definition parse.cpp:4162
bool rFunctionBody(cpp_declaratort &)
Definition parse.cpp:7181
bool optStorageSpec(cpp_storage_spect &)
Definition parse.cpp:1984
bool rDeclaration(cpp_declarationt &)
Definition parse.cpp:1382
bool rUsing(cpp_usingt &)
Definition parse.cpp:884
void set_location(irept &dest, const cpp_tokent &token)
Definition parse.cpp:382
std::size_t number_of_errors
Definition parse.cpp:377
bool rClassSpec(typet &)
Definition parse.cpp:4429
bool rUnaryExpr(exprt &)
Definition parse.cpp:5698
bool rOperatorName(irept &)
Definition parse.cpp:3636
bool rExternTemplateDecl(cpp_declarationt &)
Definition parse.cpp:1334
bool maybeTemplateArgs()
Definition parse.cpp:7080
bool rNullDeclaration(cpp_declarationt &)
Definition parse.cpp:583
bool rTemplateDecl(cpp_declarationt &)
Definition parse.cpp:1001
bool rConstructorDecl(cpp_declaratort &, typet &, typet &trailing_return_type)
Definition parse.cpp:2633
bool rConditionalExpr(exprt &, bool)
Definition parse.cpp:4892
Arrays with given size.
Definition std_types.h:763
codet representation of an inline assembler statement, for the gcc flavor.
Definition std_code.h:1297
exprt & asm_text()
Definition std_code.h:1305
codet representation of an inline assembler statement.
Definition std_code.h:1253
void set_flavor(const irep_idt &f)
Definition std_code.h:1268
A codet representing sequential composition of program statements.
Definition std_code.h:130
code_operandst & statements()
Definition std_code.h:138
void add(const codet &code)
Definition std_code.h:168
codet representation of a do while statement.
Definition std_code.h:672
codet representation of an expression statement.
Definition std_code.h:1394
codet representation of a for statement.
Definition std_code.h:734
A codet representing the declaration of a local variable.
Definition std_code.h:347
codet representation of a "return from a function" statement.
Definition std_code.h:893
const exprt & return_value() const
Definition std_code.h:903
codet representation of a switch-case, i.e. a case statement within a switch.
Definition std_code.h:1097
codet representation of a goto statement.
Definition std_code.h:841
codet representation of an if-then-else statement.
Definition std_code.h:460
codet representation of a label for branch targets.
Definition std_code.h:959
A codet representing a skip statement.
Definition std_code.h:322
codet representation of a switch-case, i.e. a case statement within a switch.
Definition std_code.h:1023
codet representing a switch statement.
Definition std_code.h:548
codet representation of a try/catch block.
Definition std_code.h:1986
Base type of functions.
Definition std_types.h:539
codet representing a while statement.
Definition std_code.h:610
Data structure for representing an arbitrary statement in a program.
const declaratorst & declarators() const
const cpp_member_spect & member_spec() const
const cpp_storage_spect & storage_spec() const
std::vector< cpp_declaratort > declaratorst
irept & throw_decl()
void set_is_parameter(bool is_parameter)
irept & member_initializers()
cpp_namet & name()
irept & method_qualifier()
exprt & init_args()
cpp_static_assertt & make_static_assert()
Definition cpp_item.h:126
cpp_linkage_spect & make_linkage_spec()
Definition cpp_item.h:51
cpp_namespace_spect & make_namespace_spec()
Definition cpp_item.h:76
cpp_usingt & make_using()
Definition cpp_item.h:101
cpp_declarationt & make_declaration()
Definition cpp_item.h:26
std::vector< class cpp_itemt > itemst
const itemst & items() const
void set_inline(bool value)
bool is_empty() const
void set_virtual(bool value)
void set_friend(bool value)
void set_explicit(bool value)
const itemst & items() const
void set_namespace(const irep_idt &_namespace)
void set_is_inline(bool value)
const exprt & as_expr() const
Definition cpp_name.h:137
irep_idt get_base_name() const
Definition cpp_name.cpp:16
cpp_parse_treet parse_tree
Definition cpp_parser.h:25
bool is_empty() const
int LookAhead(unsigned offset)
int get_token(cpp_tokent &token)
void Replace(const cpp_tokent &token)
cpp_tokent & current_token()
void Insert(const cpp_tokent &token)
exprt data
Definition cpp_token.h:23
irep_idt filename
Definition cpp_token.h:26
void clear()
Definition cpp_token.h:28
unsigned line_no
Definition cpp_token.h:25
std::string text
Definition cpp_token.h:24
void set_namespace(bool value)
Definition cpp_using.h:39
cpp_namet & name()
Definition cpp_using.h:24
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition dstring.h:37
bool empty() const
Definition dstring.h:88
void clear()
Definition dstring.h:142
Base class for all expressions.
Definition expr.h:54
typet & type()
Return the type of the expression.
Definition expr.h:82
operandst & operands()
Definition expr.h:92
const source_locationt & source_location() const
Definition expr.h:230
source_locationt & add_source_location()
Definition expr.h:235
void add_to_operands(const exprt &expr)
Add the given argument to the end of exprt's operands.
Definition expr.h:136
The Boolean constant false.
Definition std_expr.h:2865
The trinary if-then-else operator.
Definition std_expr.h:2226
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition irep.h:372
std::string pretty(unsigned indent=0, unsigned max_indent=0) const
Definition irep.cpp:495
const irept & find(const irep_idt &name) const
Definition irep.cpp:106
const irep_idt & get(const irep_idt &name) const
Definition irep.cpp:45
void set(const irep_idt &name, const irep_idt &value)
Definition irep.h:420
void clear()
Definition irep.h:452
bool is_not_nil() const
Definition irep.h:380
subt & get_sub()
Definition irep.h:456
void make_nil()
Definition irep.h:454
void move_to_sub(irept &irep)
Definition irep.cpp:36
void swap(irept &irep)
Definition irep.h:442
const irep_idt & id() const
Definition irep.h:396
irept & add(const irep_idt &name)
Definition irep.cpp:116
bool is_nil() const
Definition irep.h:376
holds a combination of types
Definition merged_type.h:16
source_locationt source_location
Definition message.h:247
mstreamt & error() const
Definition message.h:399
static eomt eom
Definition message.h:297
void print_rec(std::ostream &, unsigned indent) const
Definition parse.cpp:182
id_mapt id_map
Definition parse.cpp:137
new_scopet * parent
Definition parse.cpp:141
irep_idt id
Definition parse.cpp:73
kindt kind
Definition parse.cpp:72
std::string full_name() const
Definition parse.cpp:154
std::map< irep_idt, new_scopet > id_mapt
Definition parse.cpp:136
void print(std::ostream &out) const
Definition parse.cpp:143
bool is_named_scope() const
Definition parse.cpp:90
std::size_t anon_count
Definition parse.cpp:139
new_scopet()
Definition parse.cpp:49
static const char * kind2string(kindt kind)
Definition parse.cpp:97
irep_idt get_anon_id()
Definition parse.cpp:148
bool is_template() const
Definition parse.cpp:83
bool is_type() const
Definition parse.cpp:75
The NIL expression.
Definition std_expr.h:2874
The null pointer constant.
new_scopet * old_scope
Definition parse.cpp:179
new_scopet *& scope_ptr
Definition parse.cpp:178
save_scopet(new_scopet *&_scope)
Definition parse.cpp:167
A side_effect_exprt representation of a function call side effect.
Definition std_code.h:1692
exprt::operandst & arguments()
Definition std_code.h:1718
A side_effect_exprt representation of a side effect that throws an exception.
Definition std_code.h:1757
An expression containing a side effect.
Definition std_code.h:1450
void set_file(const irep_idt &file)
void set_line(const irep_idt &line)
void set_function(const irep_idt &function)
Expression to hold a symbol (variable)
Definition std_expr.h:80
The Boolean constant true.
Definition std_expr.h:2856
void move_to_subtypes(typet &type)
Move the provided type to the subtypes of this type.
Definition type.cpp:25
subtypest & subtypes()
Definition type.h:206
Type with a single subtype.
Definition type.h:149
Semantic type conversion.
Definition std_expr.h:1920
The type of an expression, extends irept.
Definition type.h:29
const typet & subtype() const
Definition type.h:48
source_locationt & add_source_location()
Definition type.h:79
bool has_subtypes() const
Definition type.h:63
const source_locationt & source_location() const
Definition type.h:74
C++ Language Type Checking.
cpp_namet & to_cpp_name(irept &cpp_name)
Definition cpp_name.h:148
cpp_parsert cpp_parser
C++ Parser.
C++ Parser: Token Buffer.
static bool is_operator(const ctokent &t)
Definition ctoken.h:78
#define Forall_operands(it, expr)
Definition expr.h:25
std::string get_base_name(const std::string &in, bool strip_suffix)
cleans a filename from path and extension
const irept & get_nil_irep()
Definition irep.cpp:20
dstringt irep_idt
Definition irep.h:37
const std::string & id2string(const irep_idt &d)
Definition irep.h:47
static bool is_constructor(const irep_idt &method_name)
literalt pos(literalt a)
Definition literal.h:194
const merged_typet & to_merged_type(const typet &type)
conversion to merged_typet
Definition merged_type.h:29
nonstd::optional< T > optionalt
Definition optional.h:35
bool cpp_parse()
Definition parse.cpp:8381
#define ERROR_TOKENS
#define UNREACHABLE
This should be used to mark dead code.
Definition invariant.h:503
#define UNIMPLEMENTED
Definition invariant.h:525
const code_blockt & to_code_block(const codet &code)
Definition std_code.h:203
const type_with_subtypest & to_type_with_subtypes(const typet &type)
Definition type.h:221