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