ParseInit.cpp 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. //===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
  2. //
  3. // The LLVM Compiler Infrastructure
  4. //
  5. // This file was developed by Chris Lattner and is distributed under
  6. // the University of Illinois Open Source License. See LICENSE.TXT for details.
  7. //
  8. //===----------------------------------------------------------------------===//
  9. //
  10. // This file implements initializer parsing as specified by C99 6.7.8.
  11. //
  12. //===----------------------------------------------------------------------===//
  13. #include "clang/Parse/Parser.h"
  14. #include "clang/Basic/Diagnostic.h"
  15. using namespace clang;
  16. /// MayBeDesignationStart - Return true if this token might be the start of a
  17. /// designator.
  18. static bool MayBeDesignationStart(tok::TokenKind K) {
  19. switch (K) {
  20. default: return false;
  21. case tok::period: // designator: '.' identifier
  22. case tok::l_square: // designator: array-designator
  23. case tok::identifier: // designation: identifier ':'
  24. return true;
  25. }
  26. }
  27. /// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
  28. /// checking to see if the token stream starts with a designator.
  29. ///
  30. /// designation:
  31. /// designator-list '='
  32. /// [GNU] array-designator
  33. /// [GNU] identifier ':'
  34. ///
  35. /// designator-list:
  36. /// designator
  37. /// designator-list designator
  38. ///
  39. /// designator:
  40. /// array-designator
  41. /// '.' identifier
  42. ///
  43. /// array-designator:
  44. /// '[' constant-expression ']'
  45. /// [GNU] '[' constant-expression '...' constant-expression ']'
  46. ///
  47. /// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
  48. /// initializer. We need to consider this case when parsing array designators.
  49. ///
  50. Parser::ExprResult Parser::ParseInitializerWithPotentialDesignator() {
  51. // Parse each designator in the designator list until we find an initializer.
  52. while (1) {
  53. switch (Tok.getKind()) {
  54. case tok::equal:
  55. // We read some number (at least one due to the grammar we implemented)
  56. // of designators and found an '=' sign. The following tokens must be
  57. // the initializer.
  58. ConsumeToken();
  59. return ParseInitializer();
  60. default: {
  61. // We read some number (at least one due to the grammar we implemented)
  62. // of designators and found something that isn't an = or an initializer.
  63. // If we have exactly one array designator [TODO CHECK], this is the GNU
  64. // 'designation: array-designator' extension. Otherwise, it is a parse
  65. // error.
  66. SourceLocation Loc = Tok.getLocation();
  67. ExprResult Init = ParseInitializer();
  68. if (Init.isInvalid) return Init;
  69. Diag(Tok, diag::ext_gnu_missing_equal_designator);
  70. return Init;
  71. }
  72. case tok::period:
  73. // designator: '.' identifier
  74. ConsumeToken();
  75. if (ExpectAndConsume(tok::identifier, diag::err_expected_ident))
  76. return ExprResult(true);
  77. break;
  78. case tok::l_square: {
  79. // array-designator: '[' constant-expression ']'
  80. // array-designator: '[' constant-expression '...' constant-expression ']'
  81. SourceLocation StartLoc = ConsumeBracket();
  82. ExprResult Idx = ParseConstantExpression();
  83. if (Idx.isInvalid) {
  84. SkipUntil(tok::r_square);
  85. return Idx;
  86. }
  87. // Handle the gnu array range extension.
  88. if (Tok.getKind() == tok::ellipsis) {
  89. Diag(Tok, diag::ext_gnu_array_range);
  90. ConsumeToken();
  91. ExprResult RHS = ParseConstantExpression();
  92. if (RHS.isInvalid) {
  93. SkipUntil(tok::r_square);
  94. return RHS;
  95. }
  96. }
  97. MatchRHSPunctuation(tok::r_square, StartLoc);
  98. break;
  99. }
  100. case tok::identifier: {
  101. // Due to the GNU "designation: identifier ':'" extension, we don't know
  102. // whether something starting with an identifier is an
  103. // assignment-expression or if it is an old-style structure field
  104. // designator.
  105. // TODO: Check that this is the first designator.
  106. LexerToken Ident = Tok;
  107. ConsumeToken();
  108. // If this is the gross GNU extension, handle it now.
  109. if (Tok.getKind() == tok::colon) {
  110. Diag(Ident, diag::ext_gnu_old_style_field_designator);
  111. ConsumeToken();
  112. return ParseInitializer();
  113. }
  114. // Otherwise, we just consumed the first token of an expression. Parse
  115. // the rest of it now.
  116. return ParseAssignmentExprWithLeadingIdentifier(Ident);
  117. }
  118. }
  119. }
  120. }
  121. /// ParseInitializer
  122. /// initializer: [C99 6.7.8]
  123. /// assignment-expression
  124. /// '{' initializer-list '}'
  125. /// '{' initializer-list ',' '}'
  126. /// [GNU] '{' '}'
  127. ///
  128. /// initializer-list:
  129. /// designation[opt] initializer
  130. /// initializer-list ',' designation[opt] initializer
  131. ///
  132. Parser::ExprResult Parser::ParseInitializer() {
  133. if (Tok.getKind() != tok::l_brace)
  134. return ParseAssignmentExpression();
  135. SourceLocation LBraceLoc = ConsumeBrace();
  136. // We support empty initializers, but tell the user that they aren't using
  137. // C99-clean code.
  138. if (Tok.getKind() == tok::r_brace)
  139. Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
  140. else {
  141. while (1) {
  142. // Parse: designation[opt] initializer
  143. // If we know that this cannot be a designation, just parse the nested
  144. // initializer directly.
  145. ExprResult SubElt;
  146. if (!MayBeDesignationStart(Tok.getKind()))
  147. SubElt = ParseInitializer();
  148. else
  149. SubElt = ParseInitializerWithPotentialDesignator();
  150. // If we couldn't parse the subelement, bail out.
  151. if (SubElt.isInvalid) {
  152. SkipUntil(tok::r_brace);
  153. return SubElt;
  154. }
  155. // If we don't have a comma continued list, we're done.
  156. if (Tok.getKind() != tok::comma) break;
  157. ConsumeToken();
  158. // Handle trailing comma.
  159. if (Tok.getKind() == tok::r_brace) break;
  160. }
  161. }
  162. // Match the '}'.
  163. MatchRHSPunctuation(tok::r_brace, LBraceLoc);
  164. return ExprResult(false);
  165. }