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