Implement a first cut at binary expression parsing using a simple operator
precedence-based parser. llvm-svn: 38874
This commit is contained in:
		
							parent
							
								
									89c50c65af
								
							
						
					
					
						commit
						cde626ae9b
					
				| 
						 | 
					@ -7,7 +7,15 @@
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//===----------------------------------------------------------------------===//
 | 
					//===----------------------------------------------------------------------===//
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//  This file implements the Expression parsing implementation.
 | 
					// 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 trinary operator ("?:").  The unary leaves are
 | 
				
			||||||
 | 
					// handled by ParseCastExpression, the higher level pieces are handled by
 | 
				
			||||||
 | 
					// ParseBinaryExpression.
 | 
				
			||||||
//
 | 
					//
 | 
				
			||||||
//===----------------------------------------------------------------------===//
 | 
					//===----------------------------------------------------------------------===//
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +46,7 @@ Parser::ExprResult Parser::ParseInitializer() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Parser::ExprResult Parser::ParseExpression() {
 | 
					Parser::ExprResult Parser::ParseExpression() {
 | 
				
			||||||
  return ParseCastExpression(false);
 | 
					  return ParseBinaryExpression();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Expr that doesn't include commas.
 | 
					// Expr that doesn't include commas.
 | 
				
			||||||
| 
						 | 
					@ -46,6 +54,232 @@ Parser::ExprResult Parser::ParseAssignmentExpression() {
 | 
				
			||||||
  return ParseExpression();
 | 
					  return ParseExpression();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// PrecedenceLevels - These are precedences for the binary/trinary 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,    // &
 | 
				
			||||||
 | 
					    MinMax         = 9,   // <?, >?           min, max (GCC extensions)
 | 
				
			||||||
 | 
					    Equality       = 10,   // ==, !=
 | 
				
			||||||
 | 
					    Relational     = 11,   //  >=, <=, >, <
 | 
				
			||||||
 | 
					    Shift          = 12,   // <<, >>
 | 
				
			||||||
 | 
					    Additive       = 13,   // -, +
 | 
				
			||||||
 | 
					    Multiplicative = 14    // *, /, %
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// 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::lessquestion:
 | 
				
			||||||
 | 
					  case tok::greaterquestion:      return prec::MinMax;
 | 
				
			||||||
 | 
					  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;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// ParseBinaryExpression - Simple precedence-based parser for binary/trinary
 | 
				
			||||||
 | 
					/// operators.
 | 
				
			||||||
 | 
					///
 | 
				
			||||||
 | 
					///       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::ParseBinaryExpression() {
 | 
				
			||||||
 | 
					  ExprResult LHS = ParseCastExpression(false);
 | 
				
			||||||
 | 
					  if (LHS.isInvalid) return LHS;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  return ParseRHSOfBinaryExpression(LHS, prec::Comma);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// 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());
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  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.
 | 
				
			||||||
 | 
					    LexerToken OpToken = Tok;
 | 
				
			||||||
 | 
					    ConsumeToken();
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Parse the RHS of the operator.
 | 
				
			||||||
 | 
					    ExprResult RHS;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Special case handling of "X ? Y : Z" were Y is empty.  This is a GCC
 | 
				
			||||||
 | 
					    // extension.
 | 
				
			||||||
 | 
					    if (OpToken.getKind() != tok::question || Tok.getKind() != tok::colon) {
 | 
				
			||||||
 | 
					      RHS = ParseCastExpression(false);
 | 
				
			||||||
 | 
					      if (RHS.isInvalid) return RHS;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      RHS = ExprResult(false);
 | 
				
			||||||
 | 
					      Diag(Tok, diag::ext_gnu_conditional_expr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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());
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // FIXME: ASSIGNMENT IS RIGHT ASSOCIATIVE.
 | 
				
			||||||
 | 
					    // FIXME: do we want to handle assignment here??
 | 
				
			||||||
 | 
					    // ASSIGNMENT: Parse LHS as conditional expr, then catch errors in semantic
 | 
				
			||||||
 | 
					    // analysis.
 | 
				
			||||||
 | 
					    bool isRightAssoc = OpToken.getKind() == tok::question;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // 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.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // FIXME: Is this enough for '?:' operators?  The second term is suppsed to
 | 
				
			||||||
 | 
					    // be 'expression', not 'assignment'.
 | 
				
			||||||
 | 
					    if (ThisPrec < NextTokPrec ||
 | 
				
			||||||
 | 
					        (ThisPrec == NextTokPrec && isRightAssoc)) {
 | 
				
			||||||
 | 
					      RHS = ParseRHSOfBinaryExpression(RHS, ThisPrec+1);
 | 
				
			||||||
 | 
					      if (RHS.isInvalid) return RHS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      NextTokPrec = getBinOpPrecedence(Tok.getKind());
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    assert(NextTokPrec <= ThisPrec && "Recursion didn't work!");
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    // Handle the special case of our one trinary operator here.
 | 
				
			||||||
 | 
					    if (OpToken.getKind() == tok::question) {
 | 
				
			||||||
 | 
					      if (Tok.getKind() != tok::colon) {
 | 
				
			||||||
 | 
					        Diag(Tok, diag::err_expected_colon);
 | 
				
			||||||
 | 
					        Diag(OpToken, diag::err_matching, "?");
 | 
				
			||||||
 | 
					        return ExprResult(true);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Eat the colon.
 | 
				
			||||||
 | 
					      ConsumeToken();
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Parse the value of the colon.
 | 
				
			||||||
 | 
					      ExprResult AfterColonVal = ParseCastExpression(false);
 | 
				
			||||||
 | 
					      if (AfterColonVal.isInvalid) return AfterColonVal;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Parse anything after the RRHS that has a higher precedence than ?.
 | 
				
			||||||
 | 
					      AfterColonVal = ParseRHSOfBinaryExpression(AfterColonVal, ThisPrec+1);
 | 
				
			||||||
 | 
					      if (AfterColonVal.isInvalid) return AfterColonVal;
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // TODO: Combine LHS = LHS ? RHS : AfterColonVal.
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      // Figure out the precedence of the token after the : part.
 | 
				
			||||||
 | 
					      NextTokPrec = getBinOpPrecedence(Tok.getKind());
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      // TODO: combine the LHS and RHS into the LHS (e.g. build AST).
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
 | 
					/// ParseCastExpression - Parse a cast-expression, or, if isUnaryExpression is
 | 
				
			||||||
/// true, parse a unary-expression.
 | 
					/// true, parse a unary-expression.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -262,6 +262,8 @@ DIAG(ext_gnu_address_of_label, EXTENSION,
 | 
				
			||||||
     "use of GNU address-of-label extension")
 | 
					     "use of GNU address-of-label extension")
 | 
				
			||||||
DIAG(ext_gnu_statement_expr, EXTENSION,
 | 
					DIAG(ext_gnu_statement_expr, EXTENSION,
 | 
				
			||||||
     "use of GNU statement expression extension")
 | 
					     "use of GNU statement expression extension")
 | 
				
			||||||
 | 
					DIAG(ext_gnu_conditional_expr, EXTENSION,
 | 
				
			||||||
 | 
					     "use of GNU ?: expression extension, eliding middle term")
 | 
				
			||||||
     
 | 
					     
 | 
				
			||||||
// Generic errors.
 | 
					// Generic errors.
 | 
				
			||||||
DIAG(err_parse_error, ERROR,
 | 
					DIAG(err_parse_error, ERROR,
 | 
				
			||||||
| 
						 | 
					@ -300,6 +302,8 @@ DIAG(err_expected_colon_after, ERROR,
 | 
				
			||||||
     "expected ':' after %s")
 | 
					     "expected ':' after %s")
 | 
				
			||||||
DIAG(err_label_end_of_compound_statement, ERROR,
 | 
					DIAG(err_label_end_of_compound_statement, ERROR,
 | 
				
			||||||
     "label at end of compound statement: expected statement")
 | 
					     "label at end of compound statement: expected statement")
 | 
				
			||||||
 | 
					DIAG(err_expected_colon, ERROR,
 | 
				
			||||||
 | 
					     "expected ':'")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// err_matching - this is used as a continuation of a previous error, e.g. to 
 | 
					/// err_matching - this is used as a continuation of a previous error, e.g. to 
 | 
				
			||||||
/// specify the '(' when we expected a ')'.  This should probably be some
 | 
					/// specify the '(' when we expected a ')'.  This should probably be some
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -180,6 +180,8 @@ private:
 | 
				
			||||||
  //ExprResult ParseExpression();  // Above.
 | 
					  //ExprResult ParseExpression();  // Above.
 | 
				
			||||||
  ExprResult ParseAssignmentExpression();  // Expr that doesn't include commas.
 | 
					  ExprResult ParseAssignmentExpression();  // Expr that doesn't include commas.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ExprResult ParseBinaryExpression();
 | 
				
			||||||
 | 
					  ExprResult ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec);
 | 
				
			||||||
  ExprResult ParseCastExpression(bool isUnaryExpression);
 | 
					  ExprResult ParseCastExpression(bool isUnaryExpression);
 | 
				
			||||||
  ExprResult ParseSizeofAlignofExpression();
 | 
					  ExprResult ParseSizeofAlignofExpression();
 | 
				
			||||||
  
 | 
					  
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue