//===--- ParseExpr.cpp - Expression Parsing -------------------------------===// // // The LLVM Compiler Infrastructure // // This file was developed by Chris Lattner and is distributed under // the University of Illinois Open Source License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This file implements the Expression parsing implementation. Expressions in // C99 basically consist of a bunch of binary operators with unary operators and // other random stuff at the leaves. // // In the C99 grammar, these unary operators bind tightest and are represented // as the 'cast-expression' production. Everything else is either a binary // operator (e.g. '/') or a ternary operator ("?:"). The unary leaves are // handled by ParseCastExpression, the higher level pieces are handled by // ParseBinaryExpression. // //===----------------------------------------------------------------------===// #include "clang/Parse/Parser.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallString.h" using namespace clang; /// PrecedenceLevels - These are precedences for the binary/ternary operators in /// the C99 grammar. These have been named to relate with the C99 grammar /// productions. Low precedences numbers bind more weakly than high numbers. namespace prec { enum Level { Unknown = 0, // Not binary operator. Comma = 1, // , Assignment = 2, // =, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Conditional = 3, // ? LogicalOr = 4, // || LogicalAnd = 5, // && InclusiveOr = 6, // | ExclusiveOr = 7, // ^ And = 8, // & Equality = 9, // ==, != Relational = 10, // >=, <=, >, < Shift = 11, // <<, >> Additive = 12, // -, + Multiplicative = 13 // *, /, % }; } /// getBinOpPrecedence - Return the precedence of the specified binary operator /// token. This returns: /// static prec::Level getBinOpPrecedence(tok::TokenKind Kind) { switch (Kind) { default: return prec::Unknown; case tok::comma: return prec::Comma; case tok::equal: case tok::starequal: case tok::slashequal: case tok::percentequal: case tok::plusequal: case tok::minusequal: case tok::lesslessequal: case tok::greatergreaterequal: case tok::ampequal: case tok::caretequal: case tok::pipeequal: return prec::Assignment; case tok::question: return prec::Conditional; case tok::pipepipe: return prec::LogicalOr; case tok::ampamp: return prec::LogicalAnd; case tok::pipe: return prec::InclusiveOr; case tok::caret: return prec::ExclusiveOr; case tok::amp: return prec::And; case tok::exclaimequal: case tok::equalequal: return prec::Equality; case tok::lessequal: case tok::less: case tok::greaterequal: case tok::greater: return prec::Relational; case tok::lessless: case tok::greatergreater: return prec::Shift; case tok::plus: case tok::minus: return prec::Additive; case tok::percent: case tok::slash: case tok::star: return prec::Multiplicative; } } /// ParseExpression - Simple precedence-based parser for binary/ternary /// operators. /// /// Note: we diverge from the C99 grammar when parsing the assignment-expression /// production. C99 specifies that the LHS of an assignment operator should be /// parsed as a unary-expression, but consistency dictates that it be a /// conditional-expession. In practice, the important thing here is that the /// LHS of an assignment has to be an l-value, which productions between /// unary-expression and conditional-expression don't produce. Because we want /// consistency, we parse the LHS as a conditional-expression, then check for /// l-value-ness in semantic analysis stages. /// /// multiplicative-expression: [C99 6.5.5] /// cast-expression /// multiplicative-expression '*' cast-expression /// multiplicative-expression '/' cast-expression /// multiplicative-expression '%' cast-expression /// /// additive-expression: [C99 6.5.6] /// multiplicative-expression /// additive-expression '+' multiplicative-expression /// additive-expression '-' multiplicative-expression /// /// shift-expression: [C99 6.5.7] /// additive-expression /// shift-expression '<<' additive-expression /// shift-expression '>>' additive-expression /// /// relational-expression: [C99 6.5.8] /// shift-expression /// relational-expression '<' shift-expression /// relational-expression '>' shift-expression /// relational-expression '<=' shift-expression /// relational-expression '>=' shift-expression /// /// equality-expression: [C99 6.5.9] /// relational-expression /// equality-expression '==' relational-expression /// equality-expression '!=' relational-expression /// /// AND-expression: [C99 6.5.10] /// equality-expression /// AND-expression '&' equality-expression /// /// exclusive-OR-expression: [C99 6.5.11] /// AND-expression /// exclusive-OR-expression '^' AND-expression /// /// inclusive-OR-expression: [C99 6.5.12] /// exclusive-OR-expression /// inclusive-OR-expression '|' exclusive-OR-expression /// /// logical-AND-expression: [C99 6.5.13] /// inclusive-OR-expression /// logical-AND-expression '&&' inclusive-OR-expression /// /// logical-OR-expression: [C99 6.5.14] /// logical-AND-expression /// logical-OR-expression '||' logical-AND-expression /// /// conditional-expression: [C99 6.5.15] /// logical-OR-expression /// logical-OR-expression '?' expression ':' conditional-expression /// [GNU] logical-OR-expression '?' ':' conditional-expression /// /// assignment-expression: [C99 6.5.16] /// conditional-expression /// unary-expression assignment-operator assignment-expression /// /// assignment-operator: one of /// = *= /= %= += -= <<= >>= &= ^= |= /// /// expression: [C99 6.5.17] /// assignment-expression /// expression ',' assignment-expression /// Parser::ExprResult Parser::ParseExpression() { ExprResult LHS = ParseCastExpression(false); if (LHS.isInvalid) return LHS; return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// This routine is called when the '@' is seen and consumed. /// Current token is an Identifier and is not a 'try'. This /// routine is necessary to disambiguate @try-statement from, /// for example, @encode-expression. /// Parser::ExprResult Parser::ParseExpressionWithLeadingAt(SourceLocation AtLoc) { ExprResult LHS = ParseObjCAtExpression(AtLoc); if (LHS.isInvalid) return LHS; return ParseRHSOfBinaryExpression(LHS, prec::Comma); } /// ParseAssignmentExpression - Parse an expr that doesn't include commas. /// Parser::ExprResult Parser::ParseAssignmentExpression() { ExprResult LHS = ParseCastExpression(false); if (LHS.isInvalid) return LHS; return ParseRHSOfBinaryExpression(LHS, prec::Assignment); } Parser::ExprResult Parser::ParseConstantExpression() { ExprResult LHS = ParseCastExpression(false); if (LHS.isInvalid) return LHS; // TODO: Validate that this is a constant expr! return ParseRHSOfBinaryExpression(LHS, prec::Conditional); } /// ParseExpressionWithLeadingIdentifier - This special purpose method is used /// in contexts where we have already consumed an identifier (which we saved in /// 'IdTok'), then discovered that the identifier was really the leading token /// of part of an expression. For example, in "A[1]+B", we consumed "A" (which /// is now in 'IdTok') and the current token is "[". Parser::ExprResult Parser:: ParseExpressionWithLeadingIdentifier(const Token &IdTok) { // We know that 'IdTok' must correspond to this production: // primary-expression: identifier // Let the actions module handle the identifier. ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), *IdTok.getIdentifierInfo(), Tok.is(tok::l_paren)); // Because we have to parse an entire cast-expression before starting the // ParseRHSOfBinaryExpression method (which parses any trailing binops), we // need to handle the 'postfix-expression' rules. We do this by invoking // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: Res = ParsePostfixExpressionSuffix(Res); if (Res.isInvalid) return Res; // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is // done, we know we don't have to do anything for cast-expression, because the // only non-postfix-expression production starts with a '(' token, and we know // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression // to consume any trailing operators (e.g. "+" in this example) and connected // chunks of the expression. return ParseRHSOfBinaryExpression(Res, prec::Comma); } /// ParseExpressionWithLeadingIdentifier - This special purpose method is used /// in contexts where we have already consumed an identifier (which we saved in /// 'IdTok'), then discovered that the identifier was really the leading token /// of part of an assignment-expression. For example, in "A[1]+B", we consumed /// "A" (which is now in 'IdTok') and the current token is "[". Parser::ExprResult Parser:: ParseAssignmentExprWithLeadingIdentifier(const Token &IdTok) { // We know that 'IdTok' must correspond to this production: // primary-expression: identifier // Let the actions module handle the identifier. ExprResult Res = Actions.ActOnIdentifierExpr(CurScope, IdTok.getLocation(), *IdTok.getIdentifierInfo(), Tok.is(tok::l_paren)); // Because we have to parse an entire cast-expression before starting the // ParseRHSOfBinaryExpression method (which parses any trailing binops), we // need to handle the 'postfix-expression' rules. We do this by invoking // ParsePostfixExpressionSuffix to consume any postfix-expression suffixes: Res = ParsePostfixExpressionSuffix(Res); if (Res.isInvalid) return Res; // At this point, the "A[1]" part of "A[1]+B" has been consumed. Once this is // done, we know we don't have to do anything for cast-expression, because the // only non-postfix-expression production starts with a '(' token, and we know // we have an identifier. As such, we can invoke ParseRHSOfBinaryExpression // to consume any trailing operators (e.g. "+" in this example) and connected // chunks of the expression. return ParseRHSOfBinaryExpression(Res, prec::Assignment); } /// ParseAssignmentExpressionWithLeadingStar - This special purpose method is /// used in contexts where we have already consumed a '*' (which we saved in /// 'StarTok'), then discovered that the '*' was really the leading token of an /// expression. For example, in "*(int*)P+B", we consumed "*" (which is /// now in 'StarTok') and the current token is "(". Parser::ExprResult Parser:: ParseAssignmentExpressionWithLeadingStar(const Token &StarTok) { // We know that 'StarTok' must correspond to this production: // unary-expression: unary-operator cast-expression // where 'unary-operator' is '*'. // Parse the cast-expression that follows the '*'. This will parse the // "*(int*)P" part of "*(int*)P+B". ExprResult Res = ParseCastExpression(false); if (Res.isInvalid) return Res; // Combine StarTok + Res to get the new AST for the combined expression.. Res = Actions.ActOnUnaryOp(StarTok.getLocation(), tok::star, Res.Val); if (Res.isInvalid) return Res; // We have to parse an entire cast-expression before starting the // ParseRHSOfBinaryExpression method (which parses any trailing binops). Since // we know that the only production above us is the cast-expression // production, and because the only alternative productions start with a '(' // token (we know we had a '*'), there is no work to do to get a whole // cast-expression. // At this point, the "*(int*)P" part of "*(int*)P+B" has been consumed. Once // this is done, we can invoke ParseRHSOfBinaryExpression to consume any // trailing operators (e.g. "+" in this example) and connected chunks of the // assignment-expression. return ParseRHSOfBinaryExpression(Res, prec::Assignment); } /// ParseRHSOfBinaryExpression - Parse a binary expression that starts with /// LHS and has a precedence of at least MinPrec. Parser::ExprResult Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { unsigned NextTokPrec = getBinOpPrecedence(Tok.getKind()); SourceLocation ColonLoc; while (1) { // If this token has a lower precedence than we are allowed to parse (e.g. // because we are called recursively, or because the token is not a binop), // then we are done! if (NextTokPrec < MinPrec) return LHS; // Consume the operator, saving the operator token for error reporting. Token OpToken = Tok; ConsumeToken(); // Special case handling for the ternary operator. ExprResult TernaryMiddle(true); if (NextTokPrec == prec::Conditional) { if (Tok.isNot(tok::colon)) { // Handle this production specially: // logical-OR-expression '?' expression ':' conditional-expression // In particular, the RHS of the '?' is 'expression', not // 'logical-OR-expression' as we might expect. TernaryMiddle = ParseExpression(); if (TernaryMiddle.isInvalid) { Actions.DeleteExpr(LHS.Val); return TernaryMiddle; } } else { // Special case handling of "X ? Y : Z" where Y is empty: // logical-OR-expression '?' ':' conditional-expression [GNU] TernaryMiddle = ExprResult(false); Diag(Tok, diag::ext_gnu_conditional_expr); } if (Tok.isNot(tok::colon)) { Diag(Tok, diag::err_expected_colon); Diag(OpToken, diag::err_matching, "?"); Actions.DeleteExpr(LHS.Val); Actions.DeleteExpr(TernaryMiddle.Val); return ExprResult(true); } // Eat the colon. ColonLoc = ConsumeToken(); } // Parse another leaf here for the RHS of the operator. ExprResult RHS = ParseCastExpression(false); if (RHS.isInvalid) { Actions.DeleteExpr(LHS.Val); Actions.DeleteExpr(TernaryMiddle.Val); return RHS; } // Remember the precedence of this operator and get the precedence of the // operator immediately to the right of the RHS. unsigned ThisPrec = NextTokPrec; NextTokPrec = getBinOpPrecedence(Tok.getKind()); // Assignment and conditional expressions are right-associative. bool isRightAssoc = NextTokPrec == prec::Conditional || NextTokPrec == prec::Assignment; // Get the precedence of the operator to the right of the RHS. If it binds // more tightly with RHS than we do, evaluate it completely first. if (ThisPrec < NextTokPrec || (ThisPrec == NextTokPrec && isRightAssoc)) { // If this is left-associative, only parse things on the RHS that bind // more tightly than the current operator. If it is left-associative, it // is okay, to bind exactly as tightly. For example, compile A=B=C=D as // A=(B=(C=D)), where each paren is a level of recursion here. RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec + !isRightAssoc); if (RHS.isInvalid) { Actions.DeleteExpr(LHS.Val); Actions.DeleteExpr(TernaryMiddle.Val); return RHS; } NextTokPrec = getBinOpPrecedence(Tok.getKind()); } assert(NextTokPrec <= ThisPrec && "Recursion didn't work!"); if (!LHS.isInvalid) { // Combine the LHS and RHS into the LHS (e.g. build AST). if (TernaryMiddle.isInvalid) LHS = Actions.ActOnBinOp(OpToken.getLocation(), OpToken.getKind(), LHS.Val, RHS.Val); else LHS = Actions.ActOnConditionalOp(OpToken.getLocation(), ColonLoc, LHS.Val, TernaryMiddle.Val, RHS.Val); } else { // We had a semantic error on the LHS. Just free the RHS and continue. Actions.DeleteExpr(TernaryMiddle.Val); Actions.DeleteExpr(RHS.Val); } } } /// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is /// true, parse a unary-expression. /// /// cast-expression: [C99 6.5.4] /// unary-expression /// '(' type-name ')' cast-expression /// /// unary-expression: [C99 6.5.3] /// postfix-expression /// '++' unary-expression /// '--' unary-expression /// unary-operator cast-expression /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' /// [GNU] '&&' identifier /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' /// [GNU] '__extension__' '__real' '__imag' /// /// primary-expression: [C99 6.5.1] /// identifier /// constant /// string-literal /// [C++] boolean-literal [C++ 2.13.5] /// '(' expression ')' /// '__func__' [C99 6.4.2.2] /// [GNU] '__FUNCTION__' /// [GNU] '__PRETTY_FUNCTION__' /// [GNU] '(' compound-statement ')' /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// [OBJC] '[' objc-message-expr ']' /// [OBJC] '@selector' '(' objc-selector-arg ')' [TODO] /// [OBJC] '@protocol' '(' identifier ')' /// [OBJC] '@encode' '(' type-name ')' /// [OBJC] objc-string-literal /// [C++] 'const_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'dynamic_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'reinterpret_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// [C++] 'static_cast' '<' type-name '>' '(' expression ')' [C++ 5.2p1] /// /// constant: [C99 6.4.4] /// integer-constant /// floating-constant /// enumeration-constant -> identifier /// character-constant /// Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { ExprResult Res; tok::TokenKind SavedKind = Tok.getKind(); // This handles all of cast-expression, unary-expression, postfix-expression, // and primary-expression. We handle them together like this for efficiency // and to simplify handling of an expression starting with a '(' token: which // may be one of a parenthesized expression, cast-expression, compound literal // expression, or statement expression. // // If the parsed tokens consist of a primary-expression, the cases below // call ParsePostfixExpressionSuffix to handle the postfix expression // suffixes. Cases that cannot be followed by postfix exprs should // return without invoking ParsePostfixExpressionSuffix. switch (SavedKind) { case tok::l_paren: { // If this expression is limited to being a unary-expression, the parent can // not start a cast expression. ParenParseOption ParenExprType = isUnaryExpression ? CompoundLiteral : CastExpr; TypeTy *CastTy; SourceLocation LParenLoc = Tok.getLocation(); SourceLocation RParenLoc; Res = ParseParenExpression(ParenExprType, CastTy, RParenLoc); if (Res.isInvalid) return Res; switch (ParenExprType) { case SimpleExpr: break; // Nothing else to do. case CompoundStmt: break; // Nothing else to do. case CompoundLiteral: // We parsed '(' type-name ')' '{' ... '}'. If any suffixes of // postfix-expression exist, parse them now. break; case CastExpr: // We parsed '(' type-name ')' and the thing after it wasn't a '{'. Parse // the cast-expression that follows it next. // TODO: For cast expression with CastTy. Res = ParseCastExpression(false); if (!Res.isInvalid) Res = Actions.ActOnCastExpr(LParenLoc, CastTy, RParenLoc, Res.Val); return Res; } // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); } // primary-expression case tok::numeric_constant: // constant: integer-constant // constant: floating-constant Res = Actions.ActOnNumericConstant(Tok); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); case tok::kw_true: case tok::kw_false: return ParseCXXBoolLiteral(); case tok::identifier: { // primary-expression: identifier // constant: enumeration-constant // Consume the identifier so that we can see if it is followed by a '('. // Function designators are allowed to be undeclared (C99 6.5.1p2), so we // need to know whether or not this identifier is a function designator or // not. IdentifierInfo &II = *Tok.getIdentifierInfo(); SourceLocation L = ConsumeToken(); Res = Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren)); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); } case tok::char_constant: // constant: character-constant Res = Actions.ActOnCharacterConstant(Tok); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); case tok::kw___func__: // primary-expression: __func__ [C99 6.4.2.2] case tok::kw___FUNCTION__: // primary-expression: __FUNCTION__ [GNU] case tok::kw___PRETTY_FUNCTION__: // primary-expression: __P..Y_F..N__ [GNU] Res = Actions.ActOnPreDefinedExpr(Tok.getLocation(), SavedKind); ConsumeToken(); // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(Res); case tok::string_literal: // primary-expression: string-literal case tok::wide_string_literal: Res = ParseStringLiteralExpression(); if (Res.isInvalid) return Res; // This can be followed by postfix-expr pieces (e.g. "foo"[1]). return ParsePostfixExpressionSuffix(Res); case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: case tok::kw___builtin_types_compatible_p: return ParseBuiltinPrimaryExpression(); case tok::plusplus: // unary-expression: '++' unary-expression case tok::minusminus: { // unary-expression: '--' unary-expression SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(true); if (!Res.isInvalid) Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); return Res; } case tok::amp: // unary-expression: '&' cast-expression case tok::star: // unary-expression: '*' cast-expression case tok::plus: // unary-expression: '+' cast-expression case tok::minus: // unary-expression: '-' cast-expression case tok::tilde: // unary-expression: '~' cast-expression case tok::exclaim: // unary-expression: '!' cast-expression case tok::kw___real: // unary-expression: '__real' cast-expression [GNU] case tok::kw___imag: // unary-expression: '__imag' cast-expression [GNU] case tok::kw___extension__:{//unary-expression:'__extension__' cast-expr [GNU] // FIXME: Extension should silence extwarns in subexpressions. SourceLocation SavedLoc = ConsumeToken(); Res = ParseCastExpression(false); if (!Res.isInvalid) Res = Actions.ActOnUnaryOp(SavedLoc, SavedKind, Res.Val); return Res; } case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw___alignof: // unary-expression: '__alignof' unary-expression // unary-expression: '__alignof' '(' type-name ')' return ParseSizeofAlignofExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); return ExprResult(true); } Diag(AmpAmpLoc, diag::ext_gnu_address_of_label); Res = Actions.ActOnAddrLabel(AmpAmpLoc, Tok.getLocation(), Tok.getIdentifierInfo()); ConsumeToken(); return Res; } case tok::kw_const_cast: case tok::kw_dynamic_cast: case tok::kw_reinterpret_cast: case tok::kw_static_cast: return ParseCXXCasts(); case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); } case tok::l_square: // These can be followed by postfix-expr pieces. return ParsePostfixExpressionSuffix(ParseObjCMessageExpression()); default: Diag(Tok, diag::err_expected_expression); return ExprResult(true); } // unreachable. abort(); } /// ParsePostfixExpressionSuffix - Once the leading part of a postfix-expression /// is parsed, this method parses any suffixes that apply. /// /// postfix-expression: [C99 6.5.2] /// primary-expression /// postfix-expression '[' expression ']' /// postfix-expression '(' argument-expression-list[opt] ')' /// postfix-expression '.' identifier /// postfix-expression '->' identifier /// postfix-expression '++' /// postfix-expression '--' /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// /// argument-expression-list: [C99 6.5.2] /// argument-expression /// argument-expression-list ',' assignment-expression /// Parser::ExprResult Parser::ParsePostfixExpressionSuffix(ExprResult LHS) { // Now that the primary-expression piece of the postfix-expression has been // parsed, see if there are any postfix-expression pieces here. SourceLocation Loc; while (1) { switch (Tok.getKind()) { default: // Not a postfix-expression suffix. return LHS; case tok::l_square: { // postfix-expression: p-e '[' expression ']' Loc = ConsumeBracket(); ExprResult Idx = ParseExpression(); SourceLocation RLoc = Tok.getLocation(); if (!LHS.isInvalid && !Idx.isInvalid && Tok.is(tok::r_square)) LHS = Actions.ActOnArraySubscriptExpr(LHS.Val, Loc, Idx.Val, RLoc); else LHS = ExprResult(true); // Match the ']'. MatchRHSPunctuation(tok::r_square, Loc); break; } case tok::l_paren: { // p-e: p-e '(' argument-expression-list[opt] ')' llvm::SmallVector ArgExprs; llvm::SmallVector CommaLocs; Loc = ConsumeParen(); if (Tok.isNot(tok::r_paren)) { while (1) { ExprResult ArgExpr = ParseAssignmentExpression(); if (ArgExpr.isInvalid) { SkipUntil(tok::r_paren); return ExprResult(true); } else ArgExprs.push_back(ArgExpr.Val); if (Tok.isNot(tok::comma)) break; // Move to the next argument, remember where the comma was. CommaLocs.push_back(ConsumeToken()); } } // Match the ')'. if (!LHS.isInvalid && Tok.is(tok::r_paren)) { assert((ArgExprs.size() == 0 || ArgExprs.size()-1 == CommaLocs.size())&& "Unexpected number of commas!"); LHS = Actions.ActOnCallExpr(LHS.Val, Loc, &ArgExprs[0], ArgExprs.size(), &CommaLocs[0], Tok.getLocation()); } MatchRHSPunctuation(tok::r_paren, Loc); break; } case tok::arrow: // postfix-expression: p-e '->' identifier case tok::period: { // postfix-expression: p-e '.' identifier tok::TokenKind OpKind = Tok.getKind(); SourceLocation OpLoc = ConsumeToken(); // Eat the "." or "->" token. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); return ExprResult(true); } if (!LHS.isInvalid) LHS = Actions.ActOnMemberReferenceExpr(LHS.Val, OpLoc, OpKind, Tok.getLocation(), *Tok.getIdentifierInfo()); ConsumeToken(); break; } case tok::plusplus: // postfix-expression: postfix-expression '++' case tok::minusminus: // postfix-expression: postfix-expression '--' if (!LHS.isInvalid) LHS = Actions.ActOnPostfixUnaryOp(Tok.getLocation(), Tok.getKind(), LHS.Val); ConsumeToken(); break; } } } /// ParseSizeofAlignofExpression - Parse a sizeof or alignof expression. /// unary-expression: [C99 6.5.3] /// 'sizeof' unary-expression /// 'sizeof' '(' type-name ')' /// [GNU] '__alignof' unary-expression /// [GNU] '__alignof' '(' type-name ')' Parser::ExprResult Parser::ParseSizeofAlignofExpression() { assert((Tok.is(tok::kw_sizeof) || Tok.is(tok::kw___alignof)) && "Not a sizeof/alignof expression!"); Token OpTok = Tok; ConsumeToken(); // If the operand doesn't start with an '(', it must be an expression. ExprResult Operand; if (Tok.isNot(tok::l_paren)) { Operand = ParseCastExpression(true); } else { // If it starts with a '(', we know that it is either a parenthesized // type-name, or it is a unary-expression that starts with a compound // literal, or starts with a primary-expression that is a parenthesized // expression. ParenParseOption ExprType = CastExpr; TypeTy *CastTy; SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; Operand = ParseParenExpression(ExprType, CastTy, RParenLoc); // If ParseParenExpression parsed a '(typename)' sequence only, the this is // sizeof/alignof a type. Otherwise, it is sizeof/alignof an expression. if (ExprType == CastExpr) { return Actions.ActOnSizeOfAlignOfTypeExpr(OpTok.getLocation(), OpTok.is(tok::kw_sizeof), LParenLoc, CastTy, RParenLoc); } } // If we get here, the operand to the sizeof/alignof was an expresion. if (!Operand.isInvalid) Operand = Actions.ActOnUnaryOp(OpTok.getLocation(), OpTok.getKind(), Operand.Val); return Operand; } /// ParseBuiltinPrimaryExpression /// /// primary-expression: [C99 6.5.1] /// [GNU] '__builtin_va_arg' '(' assignment-expression ',' type-name ')' /// [GNU] '__builtin_offsetof' '(' type-name ',' offsetof-member-designator')' /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier /// [GNU] offsetof-member-designator '.' identifier /// [GNU] offsetof-member-designator '[' expression ']' /// Parser::ExprResult Parser::ParseBuiltinPrimaryExpression() { ExprResult Res(false); const IdentifierInfo *BuiltinII = Tok.getIdentifierInfo(); tok::TokenKind T = Tok.getKind(); SourceLocation StartLoc = ConsumeToken(); // Eat the builtin identifier. // All of these start with an open paren. if (Tok.isNot(tok::l_paren)) { Diag(Tok, diag::err_expected_lparen_after, BuiltinII->getName()); return ExprResult(true); } SourceLocation LParenLoc = ConsumeParen(); // TODO: Build AST. switch (T) { default: assert(0 && "Not a builtin primary expression!"); case tok::kw___builtin_va_arg: { ExprResult Expr = ParseAssignmentExpression(); if (Expr.isInvalid) { SkipUntil(tok::r_paren); return Res; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); TypeTy *Ty = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); return ExprResult(true); } Res = Actions.ActOnVAArg(StartLoc, Expr.Val, Ty, ConsumeParen()); break; } case tok::kw___builtin_offsetof: { SourceLocation TypeLoc = Tok.getLocation(); TypeTy *Ty = ParseTypeName(); if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); // We must have at least one identifier here. if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return true; } // Keep track of the various subcomponents we see. llvm::SmallVector Comps; Comps.push_back(Action::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocStart = Comps.back().LocEnd = ConsumeToken(); while (1) { if (Tok.is(tok::period)) { // offsetof-member-designator: offsetof-member-designator '.' identifier Comps.push_back(Action::OffsetOfComponent()); Comps.back().isBrackets = false; Comps.back().LocStart = ConsumeToken(); if (Tok.isNot(tok::identifier)) { Diag(Tok, diag::err_expected_ident); SkipUntil(tok::r_paren); return true; } Comps.back().U.IdentInfo = Tok.getIdentifierInfo(); Comps.back().LocEnd = ConsumeToken(); } else if (Tok.is(tok::l_square)) { // offsetof-member-designator: offsetof-member-design '[' expression ']' Comps.push_back(Action::OffsetOfComponent()); Comps.back().isBrackets = true; Comps.back().LocStart = ConsumeBracket(); Res = ParseExpression(); if (Res.isInvalid) { SkipUntil(tok::r_paren); return Res; } Comps.back().U.E = Res.Val; Comps.back().LocEnd = MatchRHSPunctuation(tok::r_square, Comps.back().LocStart); } else if (Tok.is(tok::r_paren)) { Res = Actions.ActOnBuiltinOffsetOf(StartLoc, TypeLoc, Ty, &Comps[0], Comps.size(), ConsumeParen()); break; } else { // Error occurred. return ExprResult(true); } } break; } case tok::kw___builtin_choose_expr: { ExprResult Cond = ParseAssignmentExpression(); if (Cond.isInvalid) { SkipUntil(tok::r_paren); return Cond; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); ExprResult Expr1 = ParseAssignmentExpression(); if (Expr1.isInvalid) { SkipUntil(tok::r_paren); return Expr1; } if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); ExprResult Expr2 = ParseAssignmentExpression(); if (Expr2.isInvalid) { SkipUntil(tok::r_paren); return Expr2; } if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); return ExprResult(true); } Res = Actions.ActOnChooseExpr(StartLoc, Cond.Val, Expr1.Val, Expr2.Val, ConsumeParen()); break; } case tok::kw___builtin_types_compatible_p: TypeTy *Ty1 = ParseTypeName(); if (ExpectAndConsume(tok::comma, diag::err_expected_comma, "",tok::r_paren)) return ExprResult(true); TypeTy *Ty2 = ParseTypeName(); if (Tok.isNot(tok::r_paren)) { Diag(Tok, diag::err_expected_rparen); return ExprResult(true); } Res = Actions.ActOnTypesCompatibleExpr(StartLoc, Ty1, Ty2, ConsumeParen()); break; } // These can be followed by postfix-expr pieces because they are // primary-expressions. return ParsePostfixExpressionSuffix(Res); } /// ParseParenExpression - This parses the unit that starts with a '(' token, /// based on what is allowed by ExprType. The actual thing parsed is returned /// in ExprType. /// /// primary-expression: [C99 6.5.1] /// '(' expression ')' /// [GNU] '(' compound-statement ')' (if !ParenExprOnly) /// postfix-expression: [C99 6.5.2] /// '(' type-name ')' '{' initializer-list '}' /// '(' type-name ')' '{' initializer-list ',' '}' /// cast-expression: [C99 6.5.4] /// '(' type-name ')' cast-expression /// Parser::ExprResult Parser::ParseParenExpression(ParenParseOption &ExprType, TypeTy *&CastTy, SourceLocation &RParenLoc) { assert(Tok.is(tok::l_paren) && "Not a paren expr!"); SourceLocation OpenLoc = ConsumeParen(); ExprResult Result(true); CastTy = 0; if (ExprType >= CompoundStmt && Tok.is(tok::l_brace)) { Diag(Tok, diag::ext_gnu_statement_expr); Parser::StmtResult Stmt = ParseCompoundStatement(true); ExprType = CompoundStmt; // If the substmt parsed correctly, build the AST node. if (!Stmt.isInvalid && Tok.is(tok::r_paren)) Result = Actions.ActOnStmtExpr(OpenLoc, Stmt.Val, Tok.getLocation()); } else if (ExprType >= CompoundLiteral && isTypeSpecifierQualifier()) { // Otherwise, this is a compound literal expression or cast expression. TypeTy *Ty = ParseTypeName(); // Match the ')'. if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else MatchRHSPunctuation(tok::r_paren, OpenLoc); if (Tok.is(tok::l_brace)) { if (!getLang().C99) // Compound literals don't exist in C90. Diag(OpenLoc, diag::ext_c99_compound_literal); Result = ParseInitializer(); ExprType = CompoundLiteral; if (!Result.isInvalid) return Actions.ActOnCompoundLiteral(OpenLoc, Ty, RParenLoc, Result.Val); } else if (ExprType == CastExpr) { // Note that this doesn't parse the subsequence cast-expression, it just // returns the parsed type to the callee. ExprType = CastExpr; CastTy = Ty; return ExprResult(false); } else { Diag(Tok, diag::err_expected_lbrace_in_compound_literal); return ExprResult(true); } return Result; } else { Result = ParseExpression(); ExprType = SimpleExpr; if (!Result.isInvalid && Tok.is(tok::r_paren)) Result = Actions.ActOnParenExpr(OpenLoc, Tok.getLocation(), Result.Val); } // Match the ')'. if (Result.isInvalid) SkipUntil(tok::r_paren); else { if (Tok.is(tok::r_paren)) RParenLoc = ConsumeParen(); else MatchRHSPunctuation(tok::r_paren, OpenLoc); } return Result; } /// ParseStringLiteralExpression - This handles the various token types that /// form string literals, and also handles string concatenation [C99 5.1.1.2, /// translation phase #6]. /// /// primary-expression: [C99 6.5.1] /// string-literal Parser::ExprResult Parser::ParseStringLiteralExpression() { assert(isTokenStringLiteral() && "Not a string literal!"); // String concat. Note that keywords like __func__ and __FUNCTION__ are not // considered to be strings for concatenation purposes. llvm::SmallVector StringToks; do { StringToks.push_back(Tok); ConsumeStringToken(); } while (isTokenStringLiteral()); // Pass the set of string tokens, ready for concatenation, to the actions. return Actions.ActOnStringLiteral(&StringToks[0], StringToks.size()); }