ParseInit.cpp revision 04d6666eee19bbf25bdfcb8e79eb8b00ace03f0c
15f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===--- ParseInit.cpp - Initializer Parsing ------------------------------===//
25f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
35f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//                     The LLVM Compiler Infrastructure
45f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
55f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// This file was developed by Chris Lattner and is distributed under
65f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// the University of Illinois Open Source License. See LICENSE.TXT for details.
75f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
85f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===//
95f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer// This file implements initializer parsing as specified by C99 6.7.8.
115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//
125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer//===----------------------------------------------------------------------===//
135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Parse/Parser.h"
155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer#include "clang/Basic/Diagnostic.h"
164aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff#include "llvm/ADT/SmallString.h"
175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerusing namespace clang;
185f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// MayBeDesignationStart - Return true if this token might be the start of a
215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// designator.
225f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencerstatic bool MayBeDesignationStart(tok::TokenKind K) {
235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  switch (K) {
245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  default: return false;
255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  case tok::period:      // designator: '.' identifier
265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  case tok::l_square:    // designator: array-designator
275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  case tok::identifier:  // designation: identifier ':'
285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return true;
295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  }
305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// ParseInitializerWithPotentialDesignator - Parse the 'initializer' production
335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// checking to see if the token stream starts with a designator.
345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       designation:
365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         designator-list '='
375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// [GNU]   array-designator
385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// [GNU]   identifier ':'
395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       designator-list:
415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         designator
425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         designator-list designator
435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       designator:
455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         array-designator
465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         '.' identifier
475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       array-designator:
495f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         '[' constant-expression ']'
505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// [GNU]   '[' constant-expression '...' constant-expression ']'
515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// NOTE: [OBC] allows '[ objc-receiver objc-message-args ]' as an
535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// initializer.  We need to consider this case when parsing array designators.
545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid SpencerParser::ExprResult Parser::ParseInitializerWithPotentialDesignator() {
565f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Parse each designator in the designator list until we find an initializer.
575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  while (1) {
585f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    switch (Tok.getKind()) {
595f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    case tok::equal:
605f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // We read some number (at least one due to the grammar we implemented)
615f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // of designators and found an '=' sign.  The following tokens must be
625f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // the initializer.
635f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ConsumeToken();
645f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      return ParseInitializer();
655f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    default: {
675f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // We read some number (at least one due to the grammar we implemented)
685f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // of designators and found something that isn't an = or an initializer.
695f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // If we have exactly one array designator [TODO CHECK], this is the GNU
705f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // 'designation: array-designator' extension.  Otherwise, it is a parse
715f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // error.
725f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      SourceLocation Loc = Tok.getLocation();
735f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ExprResult Init = ParseInitializer();
745f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      if (Init.isInvalid) return Init;
755f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
765f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      Diag(Tok, diag::ext_gnu_missing_equal_designator);
775f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      return Init;
785f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    }
795f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    case tok::period:
805f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // designator: '.' identifier
815f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ConsumeToken();
825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      if (ExpectAndConsume(tok::identifier, diag::err_expected_ident))
835f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        return ExprResult(true);
845f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      break;
855f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
865f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    case tok::l_square: {
875f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // array-designator: '[' constant-expression ']'
885f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // array-designator: '[' constant-expression '...' constant-expression ']'
895f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      SourceLocation StartLoc = ConsumeBracket();
905f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ExprResult Idx = ParseConstantExpression();
925f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      if (Idx.isInvalid) {
935f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        SkipUntil(tok::r_square);
945f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        return Idx;
955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      }
965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
975f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // Handle the gnu array range extension.
9804d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner      if (Tok.is(tok::ellipsis)) {
995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        Diag(Tok, diag::ext_gnu_array_range);
1005f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        ConsumeToken();
1015f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1025f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        ExprResult RHS = ParseConstantExpression();
1035f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        if (RHS.isInvalid) {
1045f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer          SkipUntil(tok::r_square);
1055f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer          return RHS;
1065f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        }
1075f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      }
1085f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1095f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      MatchRHSPunctuation(tok::r_square, StartLoc);
1105f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      break;
1115f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    }
1125f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    case tok::identifier: {
1135f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // Due to the GNU "designation: identifier ':'" extension, we don't know
1145f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // whether something starting with an identifier is an
1155f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // assignment-expression or if it is an old-style structure field
1165f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // designator.
1175f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // TODO: Check that this is the first designator.
118d217773f106856a11879ec79dc468efefaf2ee75Chris Lattner      Token Ident = Tok;
1195f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      ConsumeToken();
1205f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1215f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // If this is the gross GNU extension, handle it now.
12204d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner      if (Tok.is(tok::colon)) {
1235f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        Diag(Ident, diag::ext_gnu_old_style_field_designator);
1245f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        ConsumeToken();
1255f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer        return ParseInitializer();
1265f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      }
1275f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1285f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // Otherwise, we just consumed the first token of an expression.  Parse
1295f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      // the rest of it now.
1305f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer      return ParseAssignmentExprWithLeadingIdentifier(Ident);
1315f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    }
1325f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    }
1335f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  }
1345f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
1355f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1365f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1375f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// ParseInitializer
1385f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       initializer: [C99 6.7.8]
1395f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         assignment-expression
1405f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         '{' initializer-list '}'
1415f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         '{' initializer-list ',' '}'
1425f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer/// [GNU]   '{' '}'
1435f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
1445f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///       initializer-list:
1455f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         designation[opt] initializer
1465f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///         initializer-list ',' designation[opt] initializer
1475f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer///
1485f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid SpencerParser::ExprResult Parser::ParseInitializer() {
14904d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner  if (Tok.isNot(tok::l_brace))
1505f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    return ParseAssignmentExpression();
1515f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1525f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  SourceLocation LBraceLoc = ConsumeBrace();
1535f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1545f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // We support empty initializers, but tell the user that they aren't using
1555f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // C99-clean code.
15604d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner  if (Tok.is(tok::r_brace)) {
1575f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer    Diag(LBraceLoc, diag::ext_gnu_empty_initializer);
1584aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // Match the '}'.
159f69936d1ba843c2d3186e4aa2faa87c68e5bf2fbSteve Naroff    return Actions.ActOnInitList(LBraceLoc, 0, 0, ConsumeBrace());
1604aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff  }
1614aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff  llvm::SmallVector<ExprTy*, 8> InitExprs;
1624aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff  bool InitExprsOk = true;
1634aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff
1644aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff  while (1) {
1654aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // Parse: designation[opt] initializer
1665f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1674aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // If we know that this cannot be a designation, just parse the nested
1684aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // initializer directly.
1694aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    ExprResult SubElt;
1704aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    if (!MayBeDesignationStart(Tok.getKind()))
1714aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      SubElt = ParseInitializer();
1724aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    else
1734aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      SubElt = ParseInitializerWithPotentialDesignator();
1744aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff
1754aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // If we couldn't parse the subelement, bail out.
1764aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    if (SubElt.isInvalid) {
1774aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      InitExprsOk = false;
1784aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      SkipUntil(tok::r_brace);
1794aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      break;
1804aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    } else
1814aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff      InitExprs.push_back(SubElt.Val);
1825f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
1834aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // If we don't have a comma continued list, we're done.
18404d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner    if (Tok.isNot(tok::comma)) break;
1854aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff
1864aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // FIXME: save comma locations.
1874aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    ConsumeToken();
1884aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff
1894aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff    // Handle trailing comma.
19004d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner    if (Tok.is(tok::r_brace)) break;
1915f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  }
19204d6666eee19bbf25bdfcb8e79eb8b00ace03f0cChris Lattner  if (InitExprsOk && Tok.is(tok::r_brace))
193f69936d1ba843c2d3186e4aa2faa87c68e5bf2fbSteve Naroff    return Actions.ActOnInitList(LBraceLoc, &InitExprs[0], InitExprs.size(),
1944aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff                                 ConsumeBrace());
1955f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  // Match the '}'.
1965f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer  MatchRHSPunctuation(tok::r_brace, LBraceLoc);
1974aa88f8d8469ced8fe04a0c411bbccc5d313e055Steve Naroff  return ExprResult(true); // an error occurred.
1985f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer}
1995f016e2cb5d11daeb237544de1c5d59f20fe1a6eReid Spencer
200