ParseInit.cpp revision 220ad7c8d1adc23799e480faf189332f1eb032e6
1//===--- ParseInit.cpp - Initializer Parsing ------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// 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 14#include "clang/Parse/Designator.h" 15#include "clang/Parse/Parser.h" 16#include "clang/Basic/Diagnostic.h" 17#include "llvm/ADT/SmallString.h" 18using namespace clang; 19 20 21/// MayBeDesignationStart - Return true if this token might be the start of a 22/// designator. If we can tell it is impossible that it is a designator, return 23/// false. 24static bool MayBeDesignationStart(tok::TokenKind K, Preprocessor &PP) { 25 switch (K) { 26 default: return false; 27 case tok::period: // designator: '.' identifier 28 case tok::l_square: // designator: array-designator 29 return true; 30 case tok::identifier: // designation: identifier ':' 31 return PP.LookAhead(0).is(tok::colon); 32 } 33} 34 35/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production 36/// checking to see if the token stream starts with a designator. 37/// 38/// designation: 39/// designator-list '=' 40/// [GNU] array-designator 41/// [GNU] identifier ':' 42/// 43/// designator-list: 44/// designator 45/// designator-list designator 46/// 47/// designator: 48/// array-designator 49/// '.' identifier 50/// 51/// array-designator: 52/// '[' constant-expression ']' 53/// [GNU] '[' constant-expression '...' constant-expression ']' 54/// 55/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an 56/// initializer (because it is an expression). We need to consider this case 57/// when parsing array designators. 58/// 59Parser::ExprResult Parser:: 60ParseInitializerWithPotentialDesignator(InitListDesignations &Designations, 61 unsigned InitNum) { 62 63 // If this is the old-style GNU extension: 64 // designation ::= identifier ':' 65 // Handle it as a field designator. Otherwise, this must be the start of a 66 // normal expression. 67 if (Tok.is(tok::identifier)) { 68 Diag(Tok, diag::ext_gnu_old_style_field_designator); 69 70 Designation &D = Designations.CreateDesignation(InitNum); 71 D.AddDesignator(Designator::getField(Tok.getIdentifierInfo())); 72 ConsumeToken(); // Eat the identifier. 73 74 assert(Tok.is(tok::colon) && "MayBeDesignationStart not working properly!"); 75 ConsumeToken(); 76 return ParseInitializer(); 77 } 78 79 // Desig - This is initialized when we see our first designator. We may have 80 // an objc message send with no designator, so we don't want to create this 81 // eagerly. 82 Designation *Desig = 0; 83 84 // Parse each designator in the designator list until we find an initializer. 85 while (Tok.is(tok::period) || Tok.is(tok::l_square)) { 86 if (Tok.is(tok::period)) { 87 // designator: '.' identifier 88 ConsumeToken(); 89 90 // Create designation if we haven't already. 91 if (Desig == 0) 92 Desig = &Designations.CreateDesignation(InitNum); 93 94 if (Tok.isNot(tok::identifier)) { 95 Diag(Tok.getLocation(), diag::err_expected_field_designator); 96 return ExprResult(true); 97 } 98 99 Desig->AddDesignator(Designator::getField(Tok.getIdentifierInfo())); 100 ConsumeToken(); // Eat the identifier. 101 continue; 102 } 103 104 // We must have either an array designator now or an objc message send. 105 assert(Tok.is(tok::l_square) && "Unexpected token!"); 106 107 // Handle the two forms of array designator: 108 // array-designator: '[' constant-expression ']' 109 // array-designator: '[' constant-expression '...' constant-expression ']' 110 // 111 // Also, we have to handle the case where the expression after the 112 // designator an an objc message send: '[' objc-message-expr ']'. 113 // Interesting cases are: 114 // [foo bar] -> objc message send 115 // [foo] -> array designator 116 // [foo ... bar] -> array designator 117 // [4][foo bar] -> obsolete GNU designation with objc message send. 118 // 119 SourceLocation StartLoc = ConsumeBracket(); 120 121 // If Objective-C is enabled and this is a typename or other identifier 122 // receiver, parse this as a message send expression. 123 if (getLang().ObjC1 && isTokObjCMessageIdentifierReceiver()) { 124 // If we have exactly one array designator, this used the GNU 125 // 'designation: array-designator' extension, otherwise there should be no 126 // designators at all! 127 if (Desig) { 128 if (Desig->getNumDesignators() == 1 && 129 (Desig->getDesignator(0).isArrayDesignator() || 130 Desig->getDesignator(0).isArrayRangeDesignator())) 131 Diag(StartLoc, diag::ext_gnu_missing_equal_designator); 132 else 133 Diag(Tok, diag::err_expected_equal_designator); 134 } 135 136 IdentifierInfo *Name = Tok.getIdentifierInfo(); 137 ConsumeToken(); 138 return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, Name, 0); 139 } 140 141 // Note that we parse this as an assignment expression, not a constant 142 // expression (allowing *=, =, etc) to handle the objc case. Sema needs 143 // to validate that the expression is a constant. 144 ExprResult Idx = ParseAssignmentExpression(); 145 if (Idx.isInvalid) { 146 SkipUntil(tok::r_square); 147 return Idx; 148 } 149 150 // Given an expression, we could either have a designator (if the next 151 // tokens are '...' or ']' or an objc message send. If this is an objc 152 // message send, handle it now. An objc-message send is the start of 153 // an assignment-expression production. 154 if (getLang().ObjC1 && Tok.isNot(tok::ellipsis) && 155 Tok.isNot(tok::r_square)) { 156 157 // If we have exactly one array designator, this used the GNU 158 // 'designation: array-designator' extension, otherwise there should be no 159 // designators at all! 160 if (Desig) { 161 if (Desig->getNumDesignators() == 1 && 162 (Desig->getDesignator(0).isArrayDesignator() || 163 Desig->getDesignator(0).isArrayRangeDesignator())) 164 Diag(StartLoc, diag::ext_gnu_missing_equal_designator); 165 else 166 Diag(Tok, diag::err_expected_equal_designator); 167 } 168 169 return ParseAssignmentExprWithObjCMessageExprStart(StartLoc, 0,Idx.Val); 170 } 171 172 // Create designation if we haven't already. 173 if (Desig == 0) 174 Desig = &Designations.CreateDesignation(InitNum); 175 176 // If this is a normal array designator, remember it. 177 if (Tok.isNot(tok::ellipsis)) { 178 Desig->AddDesignator(Designator::getArray(Idx.Val)); 179 } else { 180 // Handle the gnu array range extension. 181 Diag(Tok, diag::ext_gnu_array_range); 182 ConsumeToken(); 183 184 ExprResult RHS = ParseConstantExpression(); 185 if (RHS.isInvalid) { 186 Actions.DeleteExpr(Idx.Val); 187 SkipUntil(tok::r_square); 188 return RHS; 189 } 190 Desig->AddDesignator(Designator::getArrayRange(Idx.Val, RHS.Val)); 191 } 192 193 MatchRHSPunctuation(tok::r_square, StartLoc); 194 } 195 196 // Okay, we're done with the designator sequence. We know that there must be 197 // at least one designator, because the only case we can get into this method 198 // without a designator is when we have an objc message send. That case is 199 // handled and returned from above. 200 assert(Desig && "Designator didn't get created?"); 201 202 // Handle a normal designator sequence end, which is an equal. 203 if (Tok.is(tok::equal)) { 204 ConsumeToken(); 205 return ParseInitializer(); 206 } 207 208 // We read some number of designators and found something that isn't an = or 209 // an initializer. If we have exactly one array designator, this 210 // is the GNU 'designation: array-designator' extension. Otherwise, it is a 211 // parse error. 212 if (Desig->getNumDesignators() == 1 && 213 (Desig->getDesignator(0).isArrayDesignator() || 214 Desig->getDesignator(0).isArrayRangeDesignator())) { 215 Diag(Tok, diag::ext_gnu_missing_equal_designator); 216 return ParseInitializer(); 217 } 218 219 Diag(Tok, diag::err_expected_equal_designator); 220 return true; 221} 222 223 224/// ParseBraceInitializer - Called when parsing an initializer that has a 225/// leading open brace. 226/// 227/// initializer: [C99 6.7.8] 228/// '{' initializer-list '}' 229/// '{' initializer-list ',' '}' 230/// [GNU] '{' '}' 231/// 232/// initializer-list: 233/// designation[opt] initializer 234/// initializer-list ',' designation[opt] initializer 235/// 236Parser::ExprResult Parser::ParseBraceInitializer() { 237 SourceLocation LBraceLoc = ConsumeBrace(); 238 239 /// InitExprs - This is the actual list of expressions contained in the 240 /// initializer. 241 llvm::SmallVector<ExprTy*, 8> InitExprs; 242 243 /// ExprDesignators - For each initializer, keep track of the designator that 244 /// was specified for it, if any. 245 InitListDesignations InitExprDesignations(Actions); 246 247 // We support empty initializers, but tell the user that they aren't using 248 // C99-clean code. 249 if (Tok.is(tok::r_brace)) { 250 Diag(LBraceLoc, diag::ext_gnu_empty_initializer); 251 // Match the '}'. 252 return Actions.ActOnInitList(LBraceLoc, 0, 0, InitExprDesignations, 253 ConsumeBrace()); 254 } 255 256 bool InitExprsOk = true; 257 258 while (1) { 259 // Parse: designation[opt] initializer 260 261 // If we know that this cannot be a designation, just parse the nested 262 // initializer directly. 263 ExprResult SubElt; 264 if (!MayBeDesignationStart(Tok.getKind(), PP)) 265 SubElt = ParseInitializer(); 266 else 267 SubElt = ParseInitializerWithPotentialDesignator(InitExprDesignations, 268 InitExprs.size()); 269 270 // If we couldn't parse the subelement, bail out. 271 if (!SubElt.isInvalid) { 272 InitExprs.push_back(SubElt.Val); 273 } else { 274 InitExprsOk = false; 275 276 // We have two ways to try to recover from this error: if the code looks 277 // gramatically ok (i.e. we have a comma coming up) try to continue 278 // parsing the rest of the initializer. This allows us to emit 279 // diagnostics for later elements that we find. If we don't see a comma, 280 // assume there is a parse error, and just skip to recover. 281 if (Tok.isNot(tok::comma)) { 282 SkipUntil(tok::r_brace, false, true); 283 break; 284 } 285 } 286 287 // If we don't have a comma continued list, we're done. 288 if (Tok.isNot(tok::comma)) break; 289 290 // TODO: save comma locations if some client cares. 291 ConsumeToken(); 292 293 // Handle trailing comma. 294 if (Tok.is(tok::r_brace)) break; 295 } 296 if (InitExprsOk && Tok.is(tok::r_brace)) 297 return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(), 298 InitExprDesignations, ConsumeBrace()); 299 300 // On error, delete any parsed subexpressions. 301 for (unsigned i = 0, e = InitExprs.size(); i != e; ++i) 302 Actions.DeleteExpr(InitExprs[i]); 303 304 // Match the '}'. 305 MatchRHSPunctuation(tok::r_brace, LBraceLoc); 306 return ExprResult(true); // an error occurred. 307} 308 309