CBMC
parse.cpp
Go to the documentation of this file.
1 /*******************************************************************\
2 
3 Module: C++ Language Parsing
4 
5 Author: 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 
29 static unsigned __indent;
30 
31 struct 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 {
48 public:
50  {
51  }
52 
53  enum class kindt
54  {
55  NONE,
56  TEMPLATE,
57  MEMBER,
58  FUNCTION,
59  VARIABLE,
60  TYPEDEF,
61  TAG,
62  NAMESPACE,
66  BLOCK,
70  };
71 
74 
75  bool is_type() const
76  {
77  return kind==kindt::TYPEDEF ||
79  kind==kindt::TAG ||
81  }
82 
83  bool is_template() const
84  {
88  }
89 
90  bool is_named_scope() const
91  {
92  return kind==kindt::NAMESPACE ||
93  kind==kindt::TAG ||
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 
160 protected:
161  void print_rec(std::ostream &, unsigned indent) const;
162 };
163 
165 {
166 public:
167  explicit save_scopet(new_scopet *&_scope):
168  scope_ptr(_scope), old_scope(_scope)
169  {
170  }
171 
172  inline ~save_scopet()
173  {
175  }
176 
177 protected:
180 };
181 
182 void 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 
195 class Parser // NOLINT(readability/identifiers)
196 {
197 public:
199  : lex(_cpp_parser.token_buffer),
200  parse_tree(_cpp_parser.parse_tree),
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 
214 protected:
218 
219  // scopes
222  new_scopet &add_id(const irept &name, new_scopet::kindt);
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 &);
238  bool rTypedef(cpp_declarationt &);
240  std::optional<codet> rTypedefStatement();
241  bool rTypeSpecifier(typet &, bool);
242  bool isTypeSpecifier();
245  bool rUsing(cpp_usingt &);
246  bool rUsingOrTypedef(cpp_itemt &);
250  bool rTemplateDecl2(typet &, TemplateDeclKind &kind);
251  bool rTempArgList(irept &);
254 
260  typet &,
261  typet &);
263  bool rOtherDeclaration(
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(
281  cpp_declaratort &,
282  typet &,
283  typet &trailing_return_type);
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);
289  bool rDeclaratorQualifier();
290  bool optPtrOperator(typet &);
291  bool rMemberInitializers(irept &);
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 
304  bool rFunctionArguments(exprt &);
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 &);
343  bool rAllocateInitializer(exprt &);
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 &);
382  bool rMSC_if_existsExpr(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);
395  if(!current_function.empty())
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 
421 static 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 
450 void Parser::make_sub_scope(const irept &cpp_name, new_scopet::kindt kind)
451 {
452  new_scopet &s=add_id(cpp_name, kind);
453  current_scope=&s;
454 }
455 
457 {
458  new_scopet &s=add_id(id, kind);
459  current_scope=&s;
460 }
461 
463 {
464  if(lex.get_token(tk)!=TOK_STRING)
465  return false;
466 
467  return true;
468 }
469 
470 void 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();
482  merged_typet tmp;
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  {
538  cpp_tokent tk;
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 {
595  cpp_tokent tk;
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 {
611  cpp_tokent tk;
612 
613  if(lex.get_token(tk)!=TOK_TYPEDEF)
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 {
639  cpp_tokent tk;
640  typet type_name;
641 
642  if(lex.get_token(tk)!=TOK_USING)
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 
655  if(!is_identifier(lex.get_token(tk)))
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 
672  if(!rTypeNameOrFunctionType(type_name))
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 
689 std::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 */
703 bool Parser::rTypeSpecifier(typet &tspec, bool check)
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 
721  if(!optIntegralTypeOrClassSpec(tspec))
722  return false;
723 
724  if(tspec.is_nil())
725  {
726  cpp_tokent tk;
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 
752  merge_types(cv_q, tspec);
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 ||
780  t == TOK_UNDERLYING_TYPE;
781 }
782 
783 /*
784  linkage.spec
785  : EXTERN String definition
786  | EXTERN String linkage.body
787 */
789 {
790  cpp_tokent tk1, tk2;
791 
792  if(lex.get_token(tk1)!=TOK_EXTERN)
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  {
810  cpp_itemt item;
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 {
830  cpp_tokent tk1, tk2;
831  bool is_inline=false;
832 
833  if(lex.LookAhead(0)==TOK_INLINE)
834  {
835  lex.get_token(tk1);
836  is_inline=true;
837  }
838 
839  if(lex.get_token(tk1)!=TOK_NAMESPACE)
840  return false;
841 
842  irep_idt name;
843 
844  // namespace might be anonymous
845  if(lex.LookAhead(0) != '{')
846  {
847  if(is_identifier(lex.get_token(tk2)))
848  name=tk2.data.get(ID_C_base_name);
849  else
850  return false;
851  }
852 
853  namespace_spec=cpp_namespace_spect();
854  set_location(namespace_spec, tk1);
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.
862  typet discard;
863  if(!optAttribute(discard))
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 */
884 bool Parser::rUsing(cpp_usingt &cpp_using)
885 {
886  cpp_tokent tk;
887 
888  if(lex.get_token(tk)!=TOK_USING)
889  return false;
890 
891  cpp_using=cpp_usingt();
892  set_location(cpp_using, tk);
893 
894  if(lex.LookAhead(0)==TOK_NAMESPACE)
895  {
896  lex.get_token(tk);
897  cpp_using.set_namespace(true);
898  }
899 
900  if(!rName(cpp_using.name()))
901  return false;
902 
903  // We will eventually need to record this attribute as Clang's
904  // __using_if_exists__ affects type checking.
905  typet discard;
906  if(!optAttribute(discard))
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 
923  cpp_tokent tk;
924  if(lex.get_token(tk) != TOK_USING)
925  return false;
926 
927  typet discard;
928  if(
929  is_identifier(lex.get_token(tk)) && optAttribute(discard) &&
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 {
945  cpp_tokent tk;
946 
947  if(lex.get_token(tk)!=TOK_STATIC_ASSERT)
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 
972  cpp_static_assert =
973  cpp_static_assertt(std::move(cond), std::move(description));
974  set_location(cpp_static_assert, tk);
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  {
994  cpp_itemt item;
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:
1081  UNREACHABLE;
1082  break;
1083  }
1084 
1085  return true;
1086 }
1087 
1089 {
1090  cpp_tokent tk;
1091 
1092  if(lex.get_token(tk)!=TOK_TEMPLATE)
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);
1124  irept dummy_args;
1125  if(!rTempArgList(dummy_args))
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 
1152  cpp_declarationt a;
1153  if(!rTempArgDeclaration(a))
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);
1164  if(!rTempArgDeclaration(a))
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 
1194  cpp_tokent tk1;
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  {
1215  cpp_tokent tk2;
1216  lex.get_token(tk2);
1217 
1218  has_ellipsis=true;
1219  }
1220 
1221  if(is_identifier(lex.LookAhead(0)))
1222  {
1223  cpp_tokent tk2;
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 
1242  typet default_type;
1243 
1244  lex.get_token(tk1);
1245  if(!rTypeName(default_type))
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 
1274  cpp_tokent tk1, tk2;
1275 
1276  if(lex.get_token(tk1) != TOK_CLASS || !is_identifier(lex.get_token(tk2)))
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  {
1285  typet default_type;
1286  lex.get_token(tk1);
1287  if(!rTypeName(default_type))
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  {
1316  cpp_tokent tk2;
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 {
1366  cpp_tokent tk1, tk2;
1367 
1368  if(lex.get_token(tk1)!=TOK_EXTERN)
1369  return false;
1370 
1371  if(lex.get_token(tk2)!=TOK_TEMPLATE)
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 
1447  typet cv_q, integral;
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 
1468  if(!optIntegralTypeOrClassSpec(integral))
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 {
1509  typet cv_q, integral;
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 
1525  if(!optIntegralTypeOrClassSpec(integral))
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())
1533  merge_types(cv_q, integral);
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 
1541  merge_types(cv_q, integral);
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 
1554  cpp_tokent eqs;
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 
1586  merge_types(cv_q, integral);
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 {
1715  typet type_name;
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 
1725  merge_types(cv_q, type_name);
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 
1776  cpp_declaratort conv_operator_declarator;
1777  typet trailing_return_type;
1778  if(!rConstructorDecl(
1779  conv_operator_declarator, type_name, trailing_return_type))
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 
1804  cpp_declaratort constructor_declarator;
1805  typet trailing_return_type;
1806  if(!rConstructorDecl(
1807  constructor_declarator, type_name, trailing_return_type))
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())
1816  type_name=trailing_return_type;
1817  else
1818  type_name=typet(is_destructor?ID_destructor:ID_constructor);
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 
1849  merge_types(cv_q, type_name);
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:
2004  case TOK_MSC_FORCEINLINE:
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 ||
2064  t==TOK_GCC_ATTRIBUTE || t==TOK_GCC_ASM)
2065  {
2066  cpp_tokent tk;
2067  lex.get_token(tk);
2068  typet p;
2069 
2070  switch(t)
2071  {
2072  case TOK_CONSTEXPR:
2073  p=typet(ID_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:
2126  UNREACHABLE;
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  {
2162  exprt exp(ID_alignof);
2163  exp.add(ID_type_arg).swap(tname);
2164  set_location(exp, tk);
2165 
2166  typet attr(ID_aligned);
2167  set_location(attr, tk);
2168  attr.add(ID_size, exp);
2169 
2170  merge_types(attr, cv);
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  {
2185  typet attr(ID_aligned);
2186  set_location(attr, tk);
2187  attr.add(ID_size, exp);
2188 
2189  merge_types(attr, cv);
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 
2218  case TOK_GCC_ATTRIBUTE_PACKED:
2219  {
2220  typet attr(ID_packed);
2221  set_location(attr, tk);
2222  merge_types(attr, t);
2223  break;
2224  }
2225 
2226  case TOK_GCC_ATTRIBUTE_TRANSPARENT_UNION:
2227  {
2228  typet attr(ID_transparent_union);
2229  set_location(attr, tk);
2230  merge_types(attr, t);
2231  break;
2232  }
2233 
2234  case TOK_GCC_ATTRIBUTE_VECTOR_SIZE:
2235  {
2236  cpp_tokent tk2, tk3;
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 
2248  type_with_subtypet attr(ID_frontend_vector, uninitialized_typet{});
2249  attr.set(ID_size, exp);
2250  attr.add_source_location()=exp.source_location();
2251  merge_types(attr, t);
2252  break;
2253  }
2254 
2255  case TOK_GCC_ATTRIBUTE_ALIGNED:
2256  {
2257  typet attr(ID_aligned);
2258  set_location(attr, tk);
2259 
2260  if(lex.LookAhead(0)=='(')
2261  {
2262  cpp_tokent tk2, tk3;
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 
2281  case TOK_GCC_ATTRIBUTE_MODE:
2282  {
2283  cpp_tokent tk2, tk3;
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 
2295  typet attr(ID_gcc_attribute_mode);
2296  set_location(attr, tk);
2297  attr.set(ID_size, to_cpp_name(name).get_base_name());
2298  merge_types(attr, t);
2299  break;
2300  }
2301 
2302  case TOK_GCC_ATTRIBUTE_GNU_INLINE:
2303  {
2304  typet attr(ID_static);
2305  set_location(attr, tk);
2306  merge_types(attr, t);
2307  break;
2308  }
2309 
2310  case TOK_GCC_ATTRIBUTE_WEAK:
2311  {
2312  typet attr(ID_weak);
2313  set_location(attr, tk);
2314  merge_types(attr, t);
2315  break;
2316  }
2317 
2318  case TOK_GCC_ATTRIBUTE_ALIAS:
2319  {
2320  cpp_tokent tk2, tk3, tk4;
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 
2331  typet attr(ID_alias);
2332  set_location(attr, tk);
2333  attr.move_to_sub(tk3.data);
2334  merge_types(attr, t);
2335  break;
2336  }
2337 
2338  case TOK_GCC_ATTRIBUTE_SECTION:
2339  {
2340  cpp_tokent tk2, tk3, tk4;
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 
2351  typet attr(ID_section);
2352  set_location(attr, tk);
2353  attr.move_to_sub(tk3.data);
2354  merge_types(attr, t);
2355  break;
2356  }
2357 
2358  case TOK_GCC_ATTRIBUTE_NORETURN:
2359  {
2360  typet attr(ID_noreturn);
2361  set_location(attr, tk);
2362  merge_types(attr, t);
2363  break;
2364  }
2365 
2366  case TOK_GCC_ATTRIBUTE_CONSTRUCTOR:
2367  {
2368  typet attr(ID_constructor);
2369  set_location(attr, tk);
2370  merge_types(attr, t);
2371  break;
2372  }
2373 
2374  case TOK_GCC_ATTRIBUTE_DESTRUCTOR:
2375  {
2376  typet attr(ID_destructor);
2377  set_location(attr, tk);
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 {
2400  if(lex.LookAhead(0) == TOK_GCC_ATTRIBUTE)
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  {
2430  typet attr(ID_noreturn);
2431  set_location(attr, tk);
2432  merge_types(attr, t);
2433  break;
2434  }
2435 
2436  case TOK_NODISCARD:
2437  {
2438  typet attr(ID_nodiscard);
2439  set_location(attr, tk);
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 
2492  irep_idt type_id;
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;
2513  case TOK_GCC_INT128: type_id=ID_gcc_int128; break;
2514  case TOK_GCC_FLOAT16:
2515  type_id = ID_gcc_float16;
2516  break;
2517  case TOK_GCC_FLOAT80: type_id=ID_gcc_float80; break;
2518  case TOK_GCC_FLOAT128: type_id=ID_gcc_float128; break;
2519  case TOK_BOOL:
2520  type_id = ID_c_bool;
2521  break;
2522  case TOK_CPROVER_BOOL: type_id=ID_proper_bool; 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 
2567  cpp_tokent typeof_tk;
2568  lex.get_token(typeof_tk);
2569 
2570 #ifdef DEBUG
2571  std::cout << std::string(__indent, ' ')
2572  << "Parser::optIntegralTypeOrClassSpec 5\n";
2573 #endif // DEBUG
2574 
2575  p=typet(ID_typeof);
2576  set_location(p, typeof_tk);
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  {
2592  p.add(ID_type_arg).swap(tname);
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  {
2628  cpp_tokent decltype_tk;
2629  lex.get_token(decltype_tk);
2630 
2631  p=typet(ID_decltype);
2632  set_location(p, decltype_tk);
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.
2655  cpp_tokent underlying_type_tk;
2656  lex.get_token(underlying_type_tk);
2657 
2658  p=typet(ID_msc_underlying_type);
2659  set_location(p, underlying_type_tk);
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 
2675  p.add(ID_type_arg).swap(tname);
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,
2693  typet &type_name,
2694  typet &trailing_return_type)
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 
2703  constructor=cpp_declaratort(typet(ID_function_type));
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();
2730  optCvQualify(cv);
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
2741  cpp_tokent arrow;
2742  lex.get_token(arrow);
2743 
2744  if(!rTypeSpecifier(trailing_return_type, false))
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 
2756  if(rMemberInitializers(mi))
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 */
2821 bool Parser::optThrowDecl(irept &throw_decl)
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,
2891  bool should_be_declarator,
2892  bool is_statement)
2893 {
2894  cpp_tokent tk;
2895 
2896  for(;;)
2897  {
2898  cpp_declaratort declarator;
2899  if(!rDeclaratorWithInit(declarator, should_be_declarator, is_statement))
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 */
2919  cpp_declaratort &dw,
2920  bool should_be_declarator,
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 
2933  typet bit_field_type(ID_c_bit_field);
2934  bit_field_type.set(ID_size, e);
2935  bit_field_type.add_subtype().make_nil();
2936  set_location(bit_field_type, tk);
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(
2947  declarator, kDeclarator, should_be_declarator, is_statement))
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 
3008  typet bit_field_type(ID_c_bit_field);
3009  bit_field_type.set(ID_size, e);
3010  bit_field_type.add_subtype().make_nil();
3011  set_location(bit_field_type, tk);
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,
3063  bool should_be_declarator,
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
3074  if(!rDeclaratorQualifier())
3075  return false;
3076 
3077  typet d_outer, d_inner;
3078  irept name;
3079 
3080  name.make_nil();
3081  d_outer.make_nil();
3082  d_inner.make_nil();
3083 
3084  if(!optPtrOperator(d_outer))
3085  return false;
3086 
3087  // we can have another sequence of declarator qualifiers
3088  if(!rDeclaratorQualifier())
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 
3106  cpp_declaratort declarator2;
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 
3119  if(!should_be_declarator)
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
3175  if(!rArgDeclListOrInit(args, is_args, is_statement))
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.
3214  cpp_tokent arrow;
3215  lex.get_token(arrow);
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;
3234  if(rMemberInitializers(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 
3284  optCvQualify(d_outer);
3285  if(d_outer.is_not_nil() && !d_outer.has_subtypes())
3286  {
3287  merged_typet merged_type;
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'
3354  typet op(ID_block_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 
3444  init=irept(ID_member_initializers);
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 
3486  init=codet(ID_member_initializer);
3487  init.add(ID_member).swap(name);
3488 
3489  cpp_tokent tk1, tk2;
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 
3702  irep_idt operator_id;
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  {
3754  name=irept(t==TOK_NEW?ID_cpp_new:ID_cpp_delete);
3755  set_location(name, tk);
3756  }
3757  else
3758  {
3759  name=irept(t==TOK_NEW?ID_cpp_new_array:ID_cpp_delete_array);
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 
3812  if(!optIntegralTypeOrClassSpec(type_name))
3813  return false;
3814 
3815  if(type_name.is_nil())
3816  {
3817  if(!rName(type_name))
3818  return false;
3819  }
3820 
3821  merge_types(cv1, type_name);
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 */
3840 bool Parser::rPtrToMember(irept &ptr_to_mem)
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 */
3940 bool Parser::rTemplateArgs(irept &template_args)
3941 {
3942 #ifdef DEBUG
3943  indenter _i;
3944  std::cout << std::string(__indent, ' ') << "Parser::rTemplateArgs 0\n";
3945 #endif
3946 
3947  cpp_tokent tk1;
3948 
3949  if(lex.get_token(tk1)!='<')
3950  return false;
3951 
3952  set_location(template_args, tk1);
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  {
3961  cpp_tokent tk2;
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
3982  if(rTypeNameOrFunctionType(a) &&
3983  ((lex.LookAhead(0) == '>' || lex.LookAhead(0) == ',' ||
3984  lex.LookAhead(0)==TOK_SHIFTRIGHT) ||
3985  (lex.LookAhead(0)==TOK_ELLIPSIS &&
3986  (lex.LookAhead(1) == '>' ||
3987  lex.LookAhead(1)==TOK_SHIFTRIGHT)))
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();
4049  cpp_tokent tk2;
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  {
4096  if(rFunctionArguments(arglist))
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  {
4109  is_args = rArgDeclList(arglist);
4110 
4111  if(is_args)
4112  return true;
4113  else
4114  {
4115  lex.Restore(pos);
4116  // encode.Clear();
4117  return rFunctionArguments(arglist);
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);
4189  header=typet(ID_register);
4190  break;
4191 
4192  default:
4193  header.make_nil();
4194  break;
4195  }
4196 
4197  if(!rTypeSpecifier(declaration.type(), true))
4198  return false;
4199 
4200  cpp_declaratort arg_declarator;
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 ||
4247  t==TOK_MSC_IF_NOT_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 
4447  if(!is_identifier(lex.get_token(tk)))
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
4525  UNREACHABLE;
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:
4626  base.set(ID_protection, ID_public);
4627  break;
4628 
4629  case TOK_PROTECTED:
4630  base.set(ID_protection, ID_protected);
4631  break;
4632 
4633  case TOK_PRIVATE:
4634  base.set(ID_protection, ID_private);
4635  break;
4636 
4637  default:
4638  UNREACHABLE;
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 {
4735  cpp_tokent tk1, tk2;
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:
4762  UNREACHABLE;
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 
4808  cpp_declaratort name_decl;
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 
4849  exp=exprt(ID_comma);
4850  exp.add_to_operands(std::move(left), std::move(right));
4851  set_location(exp, tk);
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 */
4865 bool Parser::rExpression(exprt &exp, bool template_args)
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 
4874  if(!rConditionalExpr(exp, template_args))
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=='=' ||
4884  t==TOK_MULTASSIGN || t==TOK_DIVASSIGN || t==TOK_MODASSIGN ||
4885  t==TOK_PLUSASSIGN || t==TOK_MINUSASSIGN || t==TOK_SHLASSIGN ||
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 
4906  exp=exprt(ID_side_effect);
4907 
4908  if(t=='=')
4909  exp.set(ID_statement, ID_assign);
4910  else if(t==TOK_PLUSASSIGN)
4911  exp.set(ID_statement, ID_assign_plus);
4912  else if(t==TOK_MINUSASSIGN)
4913  exp.set(ID_statement, ID_assign_minus);
4914  else if(t==TOK_MULTASSIGN)
4915  exp.set(ID_statement, ID_assign_mult);
4916  else if(t==TOK_DIVASSIGN)
4917  exp.set(ID_statement, ID_assign_div);
4918  else if(t==TOK_MODASSIGN)
4919  exp.set(ID_statement, ID_assign_mod);
4920  else if(t==TOK_SHLASSIGN)
4921  exp.set(ID_statement, ID_assign_shl);
4922  else if(t==TOK_SHRASSIGN)
4923  exp.set(ID_statement, ID_assign_shr);
4924  else if(t==TOK_ANDASSIGN)
4925  exp.set(ID_statement, ID_assign_bitand);
4926  else if(t==TOK_XORASSIGN)
4927  exp.set(ID_statement, ID_assign_bitxor);
4928  else if(t==TOK_ORASSIGN)
4929  exp.set(ID_statement, ID_assign_bitor);
4930 
4931  exp.add_to_operands(std::move(left), std::move(right));
4932  set_location(exp, tk);
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 */
4946 bool Parser::rConditionalExpr(exprt &exp, bool template_args)
4947 {
4948 #ifdef DEBUG
4949  indenter _i;
4950  std::cout << std::string(__indent, ' ') << "Parser::rConditionalExpr 0\n";
4951 #endif
4952 
4953  if(!rLogicalOrExpr(exp, template_args))
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  {
4962  cpp_tokent tk1, tk2;
4963  exprt then, otherwise;
4964 
4965  lex.get_token(tk1);
4966  if(!rCommaExpression(then))
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 
4976  if(!rExpression(otherwise, template_args))
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());
4984  set_location(exp, tk1);
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 */
4995 bool Parser::rLogicalOrExpr(exprt &exp, bool template_args)
4996 {
4997 #ifdef DEBUG
4998  indenter _i;
4999  std::cout << std::string(__indent, ' ') << "Parser::rLogicalOrExpr 0\n";
5000 #endif
5001 
5002  if(!rLogicalAndExpr(exp, template_args))
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));
5023  set_location(exp, tk);
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 */
5034 bool Parser::rLogicalAndExpr(exprt &exp, bool template_args)
5035 {
5036 #ifdef DEBUG
5037  indenter _i;
5038  std::cout << std::string(__indent, ' ') << "Parser::rLogicalAndExpr 1\n";
5039 #endif
5040 
5041  if(!rInclusiveOrExpr(exp, template_args))
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));
5062  set_location(exp, tk);
5063  }
5064 
5065  return true;
5066 }
5067 
5068 /*
5069  inclusive.or.expr
5070  : exclusive.or.expr
5071  | inclusive.or.expr '|' exclusive.or.expr
5072 */
5073 bool Parser::rInclusiveOrExpr(exprt &exp, bool template_args)
5074 {
5075 #ifdef DEBUG
5076  indenter _i;
5077  std::cout << std::string(__indent, ' ') << "Parser::rInclusiveOrExpr 0\n";
5078 #endif
5079 
5080  if(!rExclusiveOrExpr(exp, template_args))
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 
5099  exp=exprt(ID_bitor);
5100  exp.add_to_operands(std::move(left), std::move(right));
5101  set_location(exp, tk);
5102  }
5103 
5104  return true;
5105 }
5106 
5107 /*
5108  exclusive.or.expr
5109  : and.expr
5110  | exclusive.or.expr '^' and.expr
5111 */
5112 bool Parser::rExclusiveOrExpr(exprt &exp, bool template_args)
5113 {
5114 #ifdef DEBUG
5115  indenter _i;
5116  std::cout << std::string(__indent, ' ') << "Parser::rExclusiveOrExpr 0\n";
5117 #endif
5118 
5119  if(!rAndExpr(exp, template_args))
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 
5138  exp=exprt(ID_bitxor);
5139  exp.add_to_operands(std::move(left), std::move(right));
5140  set_location(exp, tk);
5141  }
5142 
5143  return true;
5144 }
5145 
5146 /*
5147  and.expr
5148  : equality.expr
5149  | and.expr '&' equality.expr
5150 */
5151 bool Parser::rAndExpr(exprt &exp, bool template_args)
5152 {
5153 #ifdef DEBUG
5154  indenter _i;
5155  std::cout << std::string(__indent, ' ') << "Parser::rAndExpr 0\n";
5156 #endif
5157 
5158  if(!rEqualityExpr(exp, template_args))
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 
5177  exp=exprt(ID_bitand);
5178  exp.add_to_operands(std::move(left), std::move(right));
5179  set_location(exp, tk);
5180  }
5181 
5182  return true;
5183 }
5184 
5185 /*
5186  equality.expr
5187  : relational.expr
5188  | equality.expr EqualOp relational.expr
5189 */
5190 bool Parser::rEqualityExpr(exprt &exp, bool template_args)
5191 {
5192 #ifdef DEBUG
5193  indenter _i;
5194  std::cout << std::string(__indent, ' ') << "Parser::rEqualityExpr 0\n";
5195 #endif
5196 
5197  if(!rRelationalExpr(exp, template_args))
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 
5217  exp=exprt(tk.kind==TOK_EQ?ID_equal:ID_notequal);
5218  exp.add_to_operands(std::move(left), std::move(right));
5219  set_location(exp, tk);
5220  }
5221 
5222  return true;
5223 }
5224 
5225 /*
5226  relational.expr
5227  : shift.expr
5228  | relational.expr (RelOp | '<' | '>') shift.expr
5229 */
5230 bool Parser::rRelationalExpr(exprt &exp, bool template_args)
5231 {
5232 #ifdef DEBUG
5233  indenter _i;
5234  std::cout << std::string(__indent, ' ') << "Parser::rRelationalExpr 0\n";
5235 #endif
5236 
5237  if(!rShiftExpr(exp, template_args))
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));
5271  set_location(exp, tk);
5272  }
5273 
5274  return true;
5275 }
5276 
5277 /*
5278  shift.expr
5279  : additive.expr
5280  | shift.expr ShiftOp additive.expr
5281 */
5282 bool Parser::rShiftExpr(exprt &exp, bool template_args)
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 ||
5297  (lex.LookAhead(0)==TOK_SHIFTRIGHT && !template_args))
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 
5309  exp=exprt((tk.kind==TOK_SHIFTRIGHT)?ID_shr:ID_shl);
5310  exp.add_to_operands(std::move(left), std::move(right));
5311  set_location(exp, tk);
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));
5358  set_location(exp, tk);
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));
5406  set_location(exp, tk);
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 ||
5437  lex.LookAhead(0)==TOK_ARROWPM)
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 
5449  exp = exprt(ID_pointer_to_member);
5450  exp.add_to_operands(std::move(left), std::move(right));
5451  set_location(exp, tk);
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 
5482  cpp_tokent tk1, tk2;
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)=='&' &&
5497  lex.LookAhead(1)==TOK_INTEGER)
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));
5510  set_location(exp, tk1);
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 
5533  typet type_name;
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
5556  make_subtype(type_name, tname);
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(
5632  is_identifier(lex.LookAhead(0)) && lex.LookAhead(1) == TOK_SCOPE &&
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  {
5682  cpp_declarationt parameter_declaration;
5683  if(!rArgDeclaration(parameter_declaration))
5684  return false;
5685 
5686  code_typet::parametert parameter(typet{});
5687  parameter.swap(parameter_declaration);
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 '*':
5781  exp=exprt(ID_dereference);
5782  break;
5783 
5784  case '&':
5785  exp=exprt(ID_address_of);
5786  break;
5787 
5788  case '+':
5789  exp=exprt(ID_unary_plus);
5790  break;
5791 
5792  case '-':
5793  exp=exprt(ID_unary_minus);
5794  break;
5795 
5796  case '!':
5797  exp=exprt(ID_not);
5798  break;
5799 
5800  case '~':
5801  exp=exprt(ID_bitnot);
5802  break;
5803 
5804  case TOK_INCR:
5805  exp=exprt(ID_side_effect);
5806  exp.set(ID_statement, ID_preincrement);
5807  break;
5808 
5809  case TOK_DECR:
5810  exp=exprt(ID_side_effect);
5811  exp.set(ID_statement, ID_predecrement);
5812  break;
5813 
5814  default:
5815  UNREACHABLE;
5816  }
5817 
5818  exp.add_to_operands(std::move(right));
5819  set_location(exp, tk);
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 
5842  exp=exprt(t==TOK_REAL?ID_complex_real:ID_complex_imag);
5843  exp.add_to_operands(std::move(unary));
5844  set_location(exp, tk);
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 
5866  if(lex.get_token(tk)!=TOK_THROW)
5867  return false;
5868 
5869  int t=lex.LookAhead(0);
5870 
5872  set_location(exp, tk);
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 
5905  if(lex.get_token(tk)!=TOK_TYPEID)
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);
5925  set_location(exp, tk);
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);
5944  set_location(exp, tk);
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 
5971  if(lex.get_token(tk)!=TOK_SIZEOF)
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  {
5986  exp=exprt(ID_sizeof);
5987  exp.add(ID_type_arg).swap(tname);
5988  set_location(exp, tk);
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  {
6008  exp=exprt(ID_sizeof);
6009  exp.add(ID_type_arg).swap(tname);
6010  set_location(exp, tk);
6011  return true;
6012  }
6013  }
6014 
6015  return false;
6016  }
6017 
6018  exprt unary;
6019 
6020  if(!rUnaryExpr(unary))
6021  return false;
6022 
6023  exp=exprt(ID_sizeof);
6024  exp.add_to_operands(std::move(unary));
6025  set_location(exp, tk);
6026  return true;
6027 }
6028 
6029 /*
6030  alignof.expr
6031  | ALIGNOF '(' type.name ')'
6032 */
6033 
6035 {
6036  cpp_tokent tk;
6037 
6038  if(lex.get_token(tk)!=TOK_ALIGNOF)
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 
6052  exp=exprt(ID_alignof);
6053  exp.add(ID_type_arg).swap(tname);
6054  set_location(exp, tk);
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 
6071  if(lex.get_token(tk)!=TOK_NOEXCEPT)
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
6086  exp=exprt(ID_noexcept);
6087  exp.add_to_operands(std::move(subexp));
6088  set_location(exp, tk);
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 
6150  exp=exprt(ID_side_effect);
6151  exp.set(ID_statement, ID_cpp_delete_array);
6152  }
6153  else
6154  {
6155  exp=exprt(ID_side_effect);
6156  exp.set(ID_statement, ID_cpp_delete);
6157  }
6158 
6159  set_location(exp, tk);
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 
6174  exp=exprt(ID_side_effect);
6175  exp.set(ID_statement, ID_cpp_new);
6176  set_location(exp, tk);
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);
6317  set_location(array_type, ob);
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 
6424  exp=exprt(ID_index);
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  {
6463  side_effect_exprt tmp(ID_postincrement, typet(), source_locationt());
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  {
6474  side_effect_exprt tmp(
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=='.')
6501  exp=exprt(ID_member);
6502  else // ARROW
6503  exp=exprt(ID_ptrmember);
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 
6529  if(lex.get_token(tk)!=TOK_MSC_UUIDOF)
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 {
6576  cpp_tokent tk1;
6577 
6578  lex.get_token(tk1);
6579 
6580  if(tk1.kind!=TOK_MSC_IF_EXISTS &&
6581  tk1.kind!=TOK_MSC_IF_NOT_EXISTS)
6582  return false;
6583 
6584  cpp_tokent tk2;
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(
6609  tk1.kind==TOK_MSC_IF_EXISTS?ID_msc_if_exists:
6610  ID_msc_if_not_exists);
6611 
6612  expr.add_to_operands(std::move(name), std::move(op));
6613 
6614  set_location(expr, tk1);
6615 
6616  return true;
6617 }
6618 
6619 std::optional<codet> Parser::rMSC_if_existsStatement()
6620 {
6621  cpp_tokent tk1;
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 
6628  cpp_tokent tk2;
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(
6658  tk1.kind == TOK_MSC_IF_EXISTS ? ID_msc_if_exists : ID_msc_if_not_exists);
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 
6683  typet tname1, tname2;
6684 
6685  switch(tk.kind)
6686  {
6687  case TOK_UNARY_TYPE_PREDICATE:
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 
6697  case TOK_BINARY_TYPE_PREDICATE:
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:
6713  UNREACHABLE;
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);
6753  set_location(exp, tk);
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);
6762  set_location(exp, tk);
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");
6771  set_location(exp, tk);
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);
6780  set_location(exp, 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);
6789  set_location(exp, 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
6798  exp = null_pointer_exprt{pointer_type(typet(ID_nullptr))};
6799  set_location(exp, tk);
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  {
6815  exp = exprt(ID_side_effect);
6816  exp.set(ID_statement, ID_statement_expression);
6817  set_location(exp, tk);
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 
6830  if(!rCommaExpression(exp2))
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 
6857  case TOK_UNARY_TYPE_PREDICATE:
6858  case TOK_BINARY_TYPE_PREDICATE:
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:
6873  case TOK_MSC_IF_NOT_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 
6886  if(!optIntegralTypeOrClassSpec(type))
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));
6916  set_location(exp, tk);
6917  }
6918  else if(lex.LookAhead(0)=='(')
6919  {
6920  lex.get_token(tk);
6921 
6922  exprt exp2;
6923  if(!rFunctionArguments(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());
6932  set_location(exp, tk);
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)=='{' &&
7240  lex.LookAhead(1)==TOK_ASM_STRING)
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 */
7281 std::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 */
7342 std::optional<codet> Parser::rStatement()
7343 {
7344  cpp_tokent tk1, tk2, tk3;
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 
7442  if(!is_identifier(lex.get_token(tk2)))
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 
7457  exprt case_expr;
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 
7467  exprt range_end;
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:
7526  case TOK_MSC_IF_NOT_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 
7563  cpp_usingt cpp_using;
7564 
7565  if(!rUsing(cpp_using))
7566  return {};
7567 
7568  UNIMPLEMENTED;
7569  }
7570 
7571  case TOK_STATIC_ASSERT:
7572  {
7573  cpp_static_assertt cpp_static_assert{nil_exprt(), nil_exprt()};
7574 
7575  if(!rStaticAssert(cpp_static_assert))
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 */
7594 std::optional<codet> Parser::rIfStatement()
7595 {
7596  cpp_tokent tk1, tk2, tk3, tk4;
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 */
7641 std::optional<codet> Parser::rSwitchStatement()
7642 {
7643  cpp_tokent tk1, tk2, tk3;
7644 
7645  if(lex.get_token(tk1)!=TOK_SWITCH)
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 */
7672 std::optional<codet> Parser::rWhileStatement()
7673 {
7674  cpp_tokent tk1, tk2, tk3;
7675 
7676  if(lex.get_token(tk1)!=TOK_WHILE)
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 */
7703 std::optional<codet> Parser::rDoStatement()
7704 {
7705  cpp_tokent tk0, tk1, tk2, tk3, tk4;
7706 
7707  if(lex.get_token(tk0)!=TOK_DO)
7708  return {};
7709 
7710  auto body = rStatement();
7711  if(!body.has_value())
7712  return {};
7713 
7714  if(lex.get_token(tk1)!=TOK_WHILE)
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 */
7740 std::optional<codet> Parser::rForStatement()
7741 {
7742  cpp_tokent tk1, tk2, tk3, tk4;
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
7760  if(!rCommaExpression(exp2))
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  {
7772  if(!rCommaExpression(exp3))
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 */
7797 std::optional<codet> Parser::rTryStatement()
7798 {
7799  cpp_tokent try_token;
7800 
7801  // The 'try' block
7802  if(lex.get_token(try_token) != TOK_TRY)
7803  return {};
7804 
7805  auto try_body = rCompoundStatement();
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  {
7815  cpp_tokent catch_token, op_token, cp_token;
7816 
7817  if(lex.get_token(catch_token)!=TOK_CATCH)
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  {
7827  cpp_tokent ellipsis_token;
7828  lex.get_token(ellipsis_token);
7829  codet ellipsis(ID_ellipsis);
7830  set_location(ellipsis, ellipsis_token);
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 
7847  code_frontend_declt code_decl(
7848  static_cast<symbol_exprt &>(static_cast<exprt &>(declaration)));
7849  set_location(code_decl, catch_token);
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 
7873 std::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 
7880  if(lex.get_token(tk)!=TOK_MSC_TRY)
7881  return {};
7882 
7883  auto body1 = rCompoundStatement();
7884 
7885  if(!body1.has_value())
7886  return {};
7887 
7888  if(lex.LookAhead(0)==TOK_MSC_EXCEPT)
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 
7935 std::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 
7942  if(lex.get_token(tk)!=TOK_MSC_LEAVE)
7943  return {};
7944 
7945  codet statement(ID_msc_leave);
7946  set_location(statement, tk);
7947 
7948  return std::move(statement);
7949 }
7950 
7951 std::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 
7962  if(lex.get_token(tk)!=TOK_GCC_ASM)
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 
8050 std::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 
8062  if(lex.get_token(tk)!=TOK_MSC_ASM)
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 
8081  if(lex.LookAhead(0)!=TOK_ASM_STRING)
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 
8100  if(lex.LookAhead(0)!=TOK_ASM_STRING)
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 */
8126 std::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 
8191  code_expressiont expr_statement(exp);
8192  expr_statement.add_source_location() = exp.source_location();
8193  return std::move(expr_statement);
8194  }
8195  }
8196 }
8197 
8198 bool Parser::rCondition(exprt &statement)
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 */
8237 std::optional<codet> Parser::rDeclarationStatement()
8238 {
8239  cpp_storage_spect storage_spec;
8240  typet cv_q, integral;
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 
8264  if(!optIntegralTypeOrClassSpec(integral))
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 */
8307 std::optional<codet> Parser::rIntegralDeclStatement(
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 
8317  merge_types(cv_q, integral);
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 */
8350 std::optional<codet>
8352 {
8353  typet type_name;
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 
8375  merge_types(cv_q, type_name);
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 
8402 void 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 {
8418  number_of_errors=0;
8419  max_errors=10;
8420 
8421  cpp_itemt item;
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 
8436 bool cpp_parse(cpp_parsert &cpp_parser, message_handlert &message_handler)
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
DeclKind
Definition: parse.cpp:227
@ 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
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
void add(const codet &code)
Definition: std_code.h:168
code_operandst & statements()
Definition: std_code.h:138
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
void set_default()
Definition: std_code.h:1035
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.
Definition: std_code_base.h:29
Globally accessible architectural configuration.
Definition: config.h:132
const declaratorst & declarators() const
const cpp_storage_spect & storage_spec() const
const cpp_member_spect & member_spec() const
std::vector< cpp_declaratort > declaratorst
irept & member_initializers()
void set_is_parameter(bool is_parameter)
irept & throw_decl()
irept & method_qualifier()
cpp_namet & name()
exprt & init_args()
cpp_declarationt & make_declaration()
Definition: cpp_item.h:26
cpp_static_assertt & make_static_assert()
Definition: cpp_item.h:126
cpp_namespace_spect & make_namespace_spec()
Definition: cpp_item.h:76
cpp_usingt & make_using()
Definition: cpp_item.h:101
cpp_linkage_spect & make_linkage_spec()
Definition: cpp_item.h:51
const itemst & items() const
std::vector< class cpp_itemt > itemst
void set_inline(bool value)
bool is_empty() const
void set_virtual(bool value)
void set_friend(bool value)
void set_explicit(bool value)
const itemst & items() const
void set_namespace(const irep_idt &_namespace)
void set_is_inline(bool value)
irep_idt get_base_name() const
Definition: cpp_name.cpp:14
const exprt & as_expr() const
Definition: cpp_name.h:137
bool is_empty() const
bool is_auto() const
int LookAhead(unsigned offset)
int get_token(cpp_tokent &token)
cpp_tokent & current_token()
void Replace(const cpp_tokent &token)
void Restore(post pos)
void Insert(const cpp_tokent &token)
exprt data
Definition: cpp_token.h:23
int kind
Definition: cpp_token.h:22
irep_idt filename
Definition: cpp_token.h:26
void clear()
Definition: cpp_token.h:28
unsigned line_no
Definition: cpp_token.h:25
std::string text
Definition: cpp_token.h:24
void set_namespace(bool value)
Definition: cpp_using.h:39
cpp_namet & name()
Definition: cpp_using.h:24
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
bool empty() const
Definition: dstring.h:89
void clear()
Definition: dstring.h:159
Base class for all expressions.
Definition: expr.h:56
source_locationt & add_source_location()
Definition: expr.h:236
const source_locationt & source_location() const
Definition: expr.h:231
typet & type()
Return the type of the expression.
Definition: expr.h:84
operandst & operands()
Definition: expr.h:94
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:3072
The trinary if-then-else operator.
Definition: std_expr.h:2370
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:364
subt & get_sub()
Definition: irep.h:448
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
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
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
const irep_idt & id() const
Definition: irep.h:388
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
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
static const char * kind2string(kindt kind)
Definition: parse.cpp:97
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
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:3081
The null pointer constant.
Definition: pointer_expr.h:909
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
~save_scopet()
Definition: parse.cpp:172
A side_effect_exprt representation of a function call side effect.
Definition: std_code.h:1692
exprt::operandst & arguments()
Definition: std_code.h:1718
A side_effect_exprt representation of a side effect that throws an exception.
Definition: std_code.h:1757
An expression containing a side effect.
Definition: std_code.h:1450
void set_file(const irep_idt &file)
void set_line(const irep_idt &line)
void set_function(const irep_idt &function)
Expression to hold a symbol (variable)
Definition: std_expr.h:131
The Boolean constant true.
Definition: std_expr.h:3063
void move_to_subtypes(typet &type)
Move the provided type to the subtypes of this type.
Definition: type.cpp:25
subtypest & subtypes()
Definition: type.h:237
Type with a single subtype.
Definition: type.h:180
const typet & subtype() const
Definition: type.h:187
Semantic type conversion.
Definition: std_expr.h:2068
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
bool has_subtypes() const
Definition: type.h:61
source_locationt & add_source_location()
Definition: type.h:77
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:2495
double log(double x)
Definition: math.c:2776
double exp(double x)
Definition: math.c:2546
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
std::string to_string(const string_not_contains_constraintt &expr)
Used for debug printing.
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