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